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-2016 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 #include "scip/cons_nonlinear.h"
40 #include "scip/cons_quadratic.h"
41 #include "scip/cons_linear.h"
42 #include "scip/cons_and.h"
43 #include "scip/cons_varbound.h"
44 #include "scip/intervalarith.h"
45 #include "scip/heur_subnlp.h"
46 #include "scip/heur_trysol.h"
47 #include "scip/debug.h"
48 #include "nlpi/nlpi.h"
49 #include "nlpi/nlpi_ipopt.h"
50 
51 /* constraint handler properties */
52 #define CONSHDLR_NAME "quadratic"
53 #define CONSHDLR_DESC "quadratic constraints of the form lhs <= b' x + x' A x <= rhs"
54 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
55 #define CONSHDLR_ENFOPRIORITY -50 /**< priority of the constraint handler for constraint enforcing */
56 #define CONSHDLR_CHECKPRIORITY -4000000 /**< priority of the constraint handler for checking feasibility */
57 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
58 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
59 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
60  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
61 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
62 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
63 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
64 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
65 
66 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
67 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
68 
69 #define MAXDNOM 10000LL /**< maximal denominator for simple rational fixed values */
70 #define NONLINCONSUPGD_PRIORITY 40000 /**< priority of upgrading nonlinear constraints */
71 #define INITLPMAXVARVAL 1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
72 
73 /* Activating this define enables reformulation of bilinear terms x*y with implications from x to y into linear terms.
74  * 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,
75  * then the implication may not be enforced in a solution.
76  * This issue need to be fixed before this feature can be enabled.
77  */
78 /* #define CHECKIMPLINBILINEAR */
79 
80 /* enable new propagation for bivariate quadratic terms */
81 #define PROPBILINNEW
82 
83 /* epsilon for differentiating between a boundary and interior point */
84 #define INTERIOR_EPS 1e-1
85 
86 /* scaling factor for gauge function */
87 #define GAUGESCALE 0.99999
88 
89 /* enable assert on feasibility of cuts added in INITLP (see also 82ec3324)
90  * off by default, as I (SV) believe we cannot ensure that infeasibility
91  * can always be ensured by other means (propagation)
92  */
93 /* #define ASSERT_INITLP_FEASCUT */
94 
95 /*
96  * Data structures
97  */
98 
99 /** eventdata for variable bound change events in quadratic constraints */
100 struct SCIP_QuadVarEventData
101 {
102  SCIP_CONSDATA* consdata; /**< the constraint data */
103  int varidx; /**< the index of the variable which bound change is caught, positive for linear variables, negative for quadratic variables */
104  int filterpos; /**< position of eventdata in SCIP's event filter */
105 };
106 
107 /** Data of a quadratic constraint. */
108 struct SCIP_ConsData
109 {
110  SCIP_Real lhs; /**< left hand side of constraint */
111  SCIP_Real rhs; /**< right hand side of constraint */
112 
113  int nlinvars; /**< number of linear variables */
114  int linvarssize; /**< length of linear variable arrays */
115  SCIP_VAR** linvars; /**< linear variables */
116  SCIP_Real* lincoefs; /**< coefficients of linear variables */
117  SCIP_QUADVAREVENTDATA** lineventdata; /**< eventdata for bound change of linear variable */
118 
119  int nquadvars; /**< number of variables in quadratic terms */
120  int quadvarssize; /**< length of quadratic variable terms arrays */
121  SCIP_QUADVARTERM* quadvarterms; /**< array with quadratic variable terms */
122 
123  int nbilinterms; /**< number of bilinear terms */
124  int bilintermssize; /**< length of bilinear term arrays */
125  SCIP_BILINTERM* bilinterms; /**< bilinear terms array */
126 
127  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
128 
129  unsigned int linvarssorted:1; /**< are the linear variables already sorted? */
130  unsigned int linvarsmerged:1; /**< are equal linear variables already merged? */
131  unsigned int quadvarssorted:1; /**< are the quadratic variables already sorted? */
132  unsigned int quadvarsmerged:1; /**< are equal quadratic variables already merged? */
133  unsigned int bilinsorted:1; /**< are the bilinear terms already sorted? */
134  unsigned int bilinmerged:1; /**< are equal bilinear terms (and bilinear terms with zero coefficient) already merged? */
135 
136  unsigned int isconvex:1; /**< is quadratic function is convex ? */
137  unsigned int isconcave:1; /**< is quadratic function is concave ? */
138  unsigned int iscurvchecked:1; /**< is quadratic function checked on convexity or concavity ? */
139  unsigned int isremovedfixings:1; /**< did we removed fixed/aggr/multiaggr variables ? */
140  unsigned int ispropagated:1; /**< was the constraint propagated with respect to the current bounds ? */
141  unsigned int ispresolved:1; /**< did we checked for possibilities of upgrading or implicit integer variables ? */
142  unsigned int initialmerge:1; /**< did we perform an initial merge and clean in presolving yet ? */
143 #ifdef CHECKIMPLINBILINEAR
144  unsigned int isimpladded:1; /**< has there been an implication added for a binary variable in a bilinear term? */
145 #endif
146  unsigned int isgaugeavailable:1; /**< is the gauge function computed? */
147 
148  SCIP_Real minlinactivity; /**< sum of minimal activities of all linear terms with finite minimal activity */
149  SCIP_Real maxlinactivity; /**< sum of maximal activities of all linear terms with finite maximal activity */
150  int minlinactivityinf; /**< number of linear terms with infinite minimal activity */
151  int maxlinactivityinf; /**< number of linear terms with infinity maximal activity */
152  SCIP_INTERVAL quadactivitybounds; /**< bounds on the activity of the quadratic term, if up to date, otherwise empty interval */
153  SCIP_Real activity; /**< activity of quadratic function w.r.t. current solution */
154  SCIP_Real lhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
155  SCIP_Real rhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
156 
157  int linvar_maydecrease; /**< index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
158  int linvar_mayincrease; /**< index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
159 
160  SCIP_VAR** sepaquadvars; /**< variables corresponding to quadvarterms to use in separation, only available in solving stage */
161  int* sepabilinvar2pos; /**< position of second variable in bilinear terms to use in separation, only available in solving stage */
162  SCIP_Real lincoefsmin; /**< minimal absolute value of coefficients in linear part, only available in solving stage */
163  SCIP_Real lincoefsmax; /**< maximal absolute value of coefficients in linear part, only available in solving stage */
164 
165  SCIP_Real* factorleft; /**< coefficients of left factor if constraint function is factorable */
166  SCIP_Real* factorright; /**< coefficients of right factor if constraint function is factorable */
167 
168  SCIP_Real* gaugecoefs; /**< coefficients of the gauge function */
169  SCIP_Real gaugeconst; /**< constant of the gauge function */
170  SCIP_Real* interiorpoint; /**< interior point of the region defined by the convex function */
171  SCIP_Real interiorpointval; /**< function value at interior point */
172 };
173 
174 /** quadratic constraint update method */
176 {
177  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)); /**< method to call for upgrading quadratic constraint */
178  int priority; /**< priority of upgrading method */
179  SCIP_Bool active; /**< is upgrading enabled */
180 };
181 typedef struct SCIP_QuadConsUpgrade SCIP_QUADCONSUPGRADE; /**< quadratic constraint update method */
183 /** constraint handler data */
184 struct SCIP_ConshdlrData
185 {
186  int replacebinaryprodlength; /**< length of linear term which when multiplied with a binary variable is replaced by an auxiliary variable and an equivalent linear formulation */
187  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 */
188  SCIP_Bool binreforminitial; /**< whether to make constraints added due to replacing products with binary variables initial */
189  SCIP_Real binreformmaxcoef; /**< factor on 1/feastol to limit coefficients and coef range in linear constraints created by binary reformulation */
190  SCIP_Real mincutefficacysepa; /**< minimal efficacy of a cut in order to add it to relaxation during separation */
191  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) */
192  char scaling; /**< scaling method of constraints in feasibility check */
193  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
194  SCIP_Bool linearizeheursol; /**< whether linearizations of convex quadratic constraints should be added to cutpool when some heuristics finds a new solution */
195  SCIP_Bool checkcurvature; /**< whether functions should be checked for convexity/concavity */
196  SCIP_Bool checkfactorable; /**< whether functions should be checked to be factorable */
197  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
198  SCIP_Bool disaggregate; /**< whether to disaggregate quadratic constraints */
199  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve */
200  int maxproproundspresolve; /**< limit on number of propagation rounds for a single constraint within one presolving round */
201  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
202  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
203  SCIP_Bool gaugecuts; /**< should convex quadratics generated strong cuts via gauge function? */
204  char interiorcomputation;/**< how the interior point should be computed: 'a'ny point per constraint,
205  * 'm'ost interior per constraint
206  */
207  char branchscoring; /**< method to use to compute score of branching candidates */
208  int enfolplimit; /**< maximum number of enforcement round before declaring the LP relaxation
209  * infeasible (-1: no limit); WARNING: if this parameter is not set to -1,
210  * SCIP might declare sub-optimal solutions optimal or feasible instances
211  * infeasible; thus, the result returned by SCIP might be incorrect!
212  */
213  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
214  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
215  SCIP_EVENTHDLR* eventhdlr; /**< our handler for variable bound change events */
216  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
217  SCIP_Bool sepanlp; /**< where linearization of the NLP relaxation solution added? */
218  SCIP_NODE* lastenfolpnode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
219  int nenfolprounds; /**< counter on number of enforcement rounds for the current node */
220  SCIP_QUADCONSUPGRADE** quadconsupgrades; /**< quadratic constraint upgrade methods for specializing quadratic constraints */
221  int quadconsupgradessize; /**< size of quadconsupgrade array */
222  int nquadconsupgrades; /**< number of quadratic constraint upgrade methods */
223 };
224 
225 
226 /*
227  * local methods for managing quadratic constraint update methods
228  */
229 
230 
231 /** checks whether a quadratic constraint upgrade method has already be registered */
232 static
234  SCIP* scip, /**< SCIP data structure */
235  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
236  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
237  const char* conshdlrname /**< name of the constraint handler */
238  )
239 {
240  int i;
241 
242  assert(scip != NULL);
243  assert(conshdlrdata != NULL);
244  assert(quadconsupgd != NULL);
245  assert(conshdlrname != NULL);
246 
247  for( i = conshdlrdata->nquadconsupgrades - 1; i >= 0; --i )
248  {
249  if( conshdlrdata->quadconsupgrades[i]->quadconsupgd == quadconsupgd )
250  {
251  SCIPwarningMessage(scip, "Try to add already known upgrade message for constraint handler <%s>.\n", conshdlrname);
252  return TRUE;
253  }
254  }
255 
256  return FALSE;
257 }
258 
259 /*
260  * Local methods
261  */
262 
263 /** translate from one value of infinity to another
264  *
265  * if val is >= infty1, then give infty2, else give val
266  */
267 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
269 /** catches variable bound change events on a linear variable in a quadratic constraint */
270 static
272  SCIP* scip, /**< SCIP data structure */
273  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
274  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
275  int linvarpos /**< position of variable in linear variables array */
276  )
277 {
278  SCIP_CONSDATA* consdata;
279  SCIP_QUADVAREVENTDATA* eventdata;
280  SCIP_EVENTTYPE eventtype;
281 
282  assert(scip != NULL);
283  assert(eventhdlr != NULL);
284  assert(cons != NULL);
285 
286  consdata = SCIPconsGetData(cons);
287  assert(consdata != NULL);
288 
289  assert(linvarpos >= 0);
290  assert(linvarpos < consdata->nlinvars);
291  assert(consdata->lineventdata != NULL);
292 
293  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
294 
295  eventdata->consdata = consdata;
296  eventdata->varidx = linvarpos;
297 
298  eventtype = SCIP_EVENTTYPE_VARFIXED;
299  if( !SCIPisInfinity(scip, consdata->rhs) )
300  {
301  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
302  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
303  if( consdata->lincoefs[linvarpos] > 0.0 )
304  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
305  else
306  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
307  }
308  if( !SCIPisInfinity(scip, -consdata->lhs) )
309  {
310  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
311  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
312  if( consdata->lincoefs[linvarpos] > 0.0 )
313  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
314  else
315  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
316  }
317 
318  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
319 
320  consdata->lineventdata[linvarpos] = eventdata;
321 
322  /* invalidate activity information
323  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
324  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
325  */
326  consdata->minlinactivity = SCIP_INVALID;
327  consdata->maxlinactivity = SCIP_INVALID;
328  consdata->minlinactivityinf = -1;
329  consdata->maxlinactivityinf = -1;
330 
331  return SCIP_OKAY;
332 }
333 
334 /** drops variable bound change events on a linear variable in a quadratic constraint */
335 static
337  SCIP* scip, /**< SCIP data structure */
338  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
339  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
340  int linvarpos /**< position of variable in linear variables array */
341  )
342 {
343  SCIP_CONSDATA* consdata;
344  SCIP_EVENTTYPE eventtype;
345 
346  assert(scip != NULL);
347  assert(eventhdlr != NULL);
348  assert(cons != NULL);
349 
350  consdata = SCIPconsGetData(cons);
351  assert(consdata != NULL);
352 
353  assert(linvarpos >= 0);
354  assert(linvarpos < consdata->nlinvars);
355  assert(consdata->lineventdata != NULL);
356  assert(consdata->lineventdata[linvarpos] != NULL);
357  assert(consdata->lineventdata[linvarpos]->consdata == consdata);
358  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
359  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
360 
361  eventtype = SCIP_EVENTTYPE_VARFIXED;
362  if( !SCIPisInfinity(scip, consdata->rhs) )
363  {
364  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
365  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
366  if( consdata->lincoefs[linvarpos] > 0.0 )
367  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
368  else
369  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
370  }
371  if( !SCIPisInfinity(scip, -consdata->lhs) )
372  {
373  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
374  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
375  if( consdata->lincoefs[linvarpos] > 0.0 )
376  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
377  else
378  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
379  }
380 
381  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
382 
383  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866 */
384 
385  return SCIP_OKAY;
386 }
387 
388 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
389 static
391  SCIP* scip, /**< SCIP data structure */
392  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
393  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
394  int quadvarpos /**< position of variable in quadratic variables array */
395  )
396 {
397  SCIP_CONSDATA* consdata;
398  SCIP_QUADVAREVENTDATA* eventdata;
399  SCIP_EVENTTYPE eventtype;
400 
401  assert(scip != NULL);
402  assert(eventhdlr != NULL);
403  assert(cons != NULL);
404 
405  consdata = SCIPconsGetData(cons);
406  assert(consdata != NULL);
407 
408  assert(quadvarpos >= 0);
409  assert(quadvarpos < consdata->nquadvars);
410  assert(consdata->quadvarterms[quadvarpos].eventdata == NULL);
411 
412  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
413 
415 #ifdef CHECKIMPLINBILINEAR
416  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
417 #endif
418  eventdata->consdata = consdata;
419  eventdata->varidx = -quadvarpos-1;
420  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
421 
422  consdata->quadvarterms[quadvarpos].eventdata = eventdata;
423 
424  /* invalidate activity information
425  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
426  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
427  */
428  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
429 
430  return SCIP_OKAY;
431 }
432 
433 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
434 static
436  SCIP* scip, /**< SCIP data structure */
437  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
438  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
439  int quadvarpos /**< position of variable in quadratic variables array */
440  )
441 {
442  SCIP_CONSDATA* consdata;
443  SCIP_EVENTTYPE eventtype;
444 
445  assert(scip != NULL);
446  assert(eventhdlr != NULL);
447  assert(cons != NULL);
448 
449  consdata = SCIPconsGetData(cons);
450  assert(consdata != NULL);
451 
452  assert(quadvarpos >= 0);
453  assert(quadvarpos < consdata->nquadvars);
454  assert(consdata->quadvarterms[quadvarpos].eventdata != NULL);
455  assert(consdata->quadvarterms[quadvarpos].eventdata->consdata == consdata);
456  assert(consdata->quadvarterms[quadvarpos].eventdata->varidx == -quadvarpos-1);
457  assert(consdata->quadvarterms[quadvarpos].eventdata->filterpos >= 0);
458 
460 #ifdef CHECKIMPLINBILINEAR
461  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
462 #endif
463 
464  SCIP_CALL( SCIPdropVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->quadvarterms[quadvarpos].eventdata, consdata->quadvarterms[quadvarpos].eventdata->filterpos) );
465 
466  SCIPfreeBlockMemory(scip, &consdata->quadvarterms[quadvarpos].eventdata);
467 
468  return SCIP_OKAY;
469 }
470 
471 /** catch variable events */
472 static
474  SCIP* scip, /**< SCIP data structure */
475  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
476  SCIP_CONS* cons /**< constraint for which to catch bound change events */
477  )
478 {
479  SCIP_CONSDATA* consdata;
480  int i;
481 
482  assert(scip != NULL);
483  assert(cons != NULL);
484  assert(eventhdlr != NULL);
485 
486  consdata = SCIPconsGetData(cons);
487  assert(consdata != NULL);
488  assert(consdata->lineventdata == NULL);
489 
490  /* we will update isremovedfixings, so reset it to TRUE first */
491  consdata->isremovedfixings = TRUE;
492 
493  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
494  for( i = 0; i < consdata->nlinvars; ++i )
495  {
496  SCIP_CALL( catchLinearVarEvents(scip, eventhdlr, cons, i) );
497 
498  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(consdata->linvars[i]);
499  }
500 
501  for( i = 0; i < consdata->nquadvars; ++i )
502  {
503  assert(consdata->quadvarterms[i].eventdata == NULL);
504 
505  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, i) );
506 
507  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(consdata->quadvarterms[i].var);
508  }
509 
510  consdata->ispropagated = FALSE;
511 
512  return SCIP_OKAY;
513 }
514 
515 /** drop variable events */
516 static
518  SCIP* scip, /**< SCIP data structure */
519  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
520  SCIP_CONS* cons /**< constraint for which to drop bound change events */
521  )
522 {
523  SCIP_CONSDATA* consdata;
524  int i;
525 
526  assert(scip != NULL);
527  assert(eventhdlr != NULL);
528  assert(cons != NULL);
529 
530  consdata = SCIPconsGetData(cons);
531  assert(consdata != NULL);
532 
533  if( consdata->lineventdata != NULL )
534  {
535  for( i = 0; i < consdata->nlinvars; ++i )
536  {
537  if( consdata->lineventdata[i] != NULL )
538  {
539  SCIP_CALL( dropLinearVarEvents(scip, eventhdlr, cons, i) );
540  }
541  }
542  SCIPfreeBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize);
543  }
544 
545  for( i = 0; i < consdata->nquadvars; ++i )
546  {
547  if( consdata->quadvarterms[i].eventdata != NULL )
548  {
549  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, i) );
550  }
551  }
552 
553  return SCIP_OKAY;
554 }
555 
556 /** locks a linear variable in a constraint */
557 static
559  SCIP* scip, /**< SCIP data structure */
560  SCIP_CONS* cons, /**< constraint where to lock a variable */
561  SCIP_VAR* var, /**< variable to lock */
562  SCIP_Real coef /**< coefficient of variable in constraint */
563  )
564 {
565  SCIP_CONSDATA* consdata;
566 
567  assert(scip != NULL);
568  assert(cons != NULL);
569  assert(var != NULL);
570  assert(coef != 0.0);
571 
572  consdata = SCIPconsGetData(cons);
573  assert(consdata != NULL);
574 
575  if( coef > 0.0 )
576  {
577  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
578  }
579  else
580  {
581  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
582  }
583 
584  return SCIP_OKAY;
585 }
586 
587 /** unlocks a linear variable in a constraint */
588 static
590  SCIP* scip, /**< SCIP data structure */
591  SCIP_CONS* cons, /**< constraint where to unlock a variable */
592  SCIP_VAR* var, /**< variable to unlock */
593  SCIP_Real coef /**< coefficient of variable in constraint */
594  )
595 {
596  SCIP_CONSDATA* consdata;
597 
598  assert(scip != NULL);
599  assert(cons != NULL);
600  assert(var != NULL);
601  assert(coef != 0.0);
602 
603  consdata = SCIPconsGetData(cons);
604  assert(consdata != NULL);
605 
606  if( coef > 0.0 )
607  {
608  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
609  }
610  else
611  {
612  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
613  }
614 
615  return SCIP_OKAY;
616 }
617 
618 /** locks a quadratic variable in a constraint */
619 static
621  SCIP* scip, /**< SCIP data structure */
622  SCIP_CONS* cons, /**< constraint where to lock a variable */
623  SCIP_VAR* var /**< variable to lock */
624  )
625 {
626  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
627 
628  return SCIP_OKAY;
629 }
630 
631 /** unlocks a quadratic variable in a constraint */
632 static
634  SCIP* scip, /**< SCIP data structure */
635  SCIP_CONS* cons, /**< constraint where to unlock a variable */
636  SCIP_VAR* var /**< variable to unlock */
637  )
638 {
639  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
640 
641  return SCIP_OKAY;
642 }
643 
644 /** computes the minimal and maximal activity for the linear part in a constraint data
645  *
646  * Only sums up terms that contribute finite values.
647  * Gives the number of terms that contribute infinite values.
648  * Only computes those activities where the corresponding side of the constraint is finite.
649  */
650 static
652  SCIP* scip, /**< SCIP data structure */
653  SCIP_CONSDATA* consdata, /**< constraint data */
654  SCIP_Real intervalinfty /**< infinity value used in interval operations */
655  )
656 { /*lint --e{666}*/
657  SCIP_ROUNDMODE prevroundmode;
658  int i;
659  SCIP_Real bnd;
660 
661  assert(scip != NULL);
662  assert(consdata != NULL);
663 
664  /* if variable bounds are not strictly consistent, then the activity update methods may yield inconsistent activities
665  * in this case, we also recompute the activities
666  */
667  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID && /*lint !e777 */
668  (consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity) )
669  {
670  /* activities should be up-to-date */
671  assert(consdata->minlinactivityinf >= 0);
672  assert(consdata->maxlinactivityinf >= 0);
673  return;
674  }
675 
676  consdata->minlinactivityinf = 0;
677  consdata->maxlinactivityinf = 0;
678 
679  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
680  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
681  */
682  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
683  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
684 
685  if( consdata->nlinvars == 0 )
686  return;
687 
688  /* if the activities computed here should be still up-to-date after bound changes,
689  * variable events need to be caught */
690  assert(consdata->lineventdata != NULL);
691 
692  prevroundmode = SCIPintervalGetRoundingMode();
693 
694  if( !SCIPisInfinity(scip, consdata->rhs) )
695  {
696  /* compute minimal activity only if there is a finite right hand side */
698 
699  for( i = 0; i < consdata->nlinvars; ++i )
700  {
701  assert(consdata->lineventdata[i] != NULL);
702  if( consdata->lincoefs[i] >= 0.0 )
703  {
704  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
705  if( SCIPisInfinity(scip, -bnd) )
706  {
707  ++consdata->minlinactivityinf;
708  continue;
709  }
710  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
711  }
712  else
713  {
714  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
715  if( SCIPisInfinity(scip, bnd) )
716  {
717  ++consdata->minlinactivityinf;
718  continue;
719  }
720  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
721  }
722  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
723  }
724  }
725 
726  if( !SCIPisInfinity(scip, -consdata->lhs) )
727  {
728  /* compute maximal activity only if there is a finite left hand side */
730 
731  for( i = 0; i < consdata->nlinvars; ++i )
732  {
733  assert(consdata->lineventdata[i] != NULL);
734  if( consdata->lincoefs[i] >= 0.0 )
735  {
736  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
737  if( SCIPisInfinity(scip, bnd) )
738  {
739  ++consdata->maxlinactivityinf;
740  continue;
741  }
742  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
743  }
744  else
745  {
746  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
747  if( SCIPisInfinity(scip, -bnd) )
748  {
749  ++consdata->maxlinactivityinf;
750  continue;
751  }
752  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
753  }
754  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
755  }
756  }
757 
758  SCIPintervalSetRoundingMode(prevroundmode);
759 
760  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
761 }
762 
763 /** update the linear activities after a change in the lower bound of a variable */
764 static
766  SCIP* scip, /**< SCIP data structure */
767  SCIP_CONSDATA* consdata, /**< constraint data */
768  SCIP_Real coef, /**< coefficient of variable in constraint */
769  SCIP_Real oldbnd, /**< previous lower bound of variable */
770  SCIP_Real newbnd /**< new lower bound of variable */
771  )
772 {
773  SCIP_ROUNDMODE prevroundmode;
774 
775  assert(scip != NULL);
776  assert(consdata != NULL);
777  /* we can't deal with lower bounds at infinity */
778  assert(!SCIPisInfinity(scip, oldbnd));
779  assert(!SCIPisInfinity(scip, newbnd));
780 
781  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
782 
783  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
784  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
785  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
786  */
787 
788  if( coef > 0.0 )
789  {
790  /* we should only be called if rhs is finite */
791  assert(!SCIPisInfinity(scip, consdata->rhs));
792 
793  /* we have no min activities computed so far, so cannot update */
794  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
795  return;
796 
797  assert(!SCIPisInfinity(scip, -consdata->minlinactivity));
798 
799  prevroundmode = SCIPintervalGetRoundingMode();
801 
802  /* update min activity */
803  if( SCIPisInfinity(scip, -oldbnd) )
804  {
805  --consdata->minlinactivityinf;
806  assert(consdata->minlinactivityinf >= 0);
807  }
808  else
809  {
810  SCIP_Real minuscoef;
811  minuscoef = -coef;
812  consdata->minlinactivity += minuscoef * oldbnd;
813  }
814 
815  if( SCIPisInfinity(scip, -newbnd) )
816  {
817  ++consdata->minlinactivityinf;
818  }
819  else
820  {
821  consdata->minlinactivity += coef * newbnd;
822  }
823 
824  SCIPintervalSetRoundingMode(prevroundmode);
825  }
826  else
827  {
828  /* we should only be called if lhs is finite */
829  assert(!SCIPisInfinity(scip, -consdata->lhs));
830 
831  /* we have no max activities computed so far, so cannot update */
832  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
833  return;
834 
835  assert(!SCIPisInfinity(scip, consdata->maxlinactivity));
836 
837  prevroundmode = SCIPintervalGetRoundingMode();
839 
840  /* update max activity */
841  if( SCIPisInfinity(scip, -oldbnd) )
842  {
843  --consdata->maxlinactivityinf;
844  assert(consdata->maxlinactivityinf >= 0);
845  }
846  else
847  {
848  SCIP_Real minuscoef;
849  minuscoef = -coef;
850  consdata->maxlinactivity += minuscoef * oldbnd;
851  }
852 
853  if( SCIPisInfinity(scip, -newbnd) )
854  {
855  ++consdata->maxlinactivityinf;
856  }
857  else
858  {
859  consdata->maxlinactivity += coef * newbnd;
860  }
861 
862  SCIPintervalSetRoundingMode(prevroundmode);
863  }
864 }
865 
866 /** update the linear activities after a change in the upper bound of a variable */
867 static
869  SCIP* scip, /**< SCIP data structure */
870  SCIP_CONSDATA* consdata, /**< constraint data */
871  SCIP_Real coef, /**< coefficient of variable in constraint */
872  SCIP_Real oldbnd, /**< previous lower bound of variable */
873  SCIP_Real newbnd /**< new lower bound of variable */
874  )
875 {
876  SCIP_ROUNDMODE prevroundmode;
877 
878  assert(scip != NULL);
879  assert(consdata != NULL);
880  /* we can't deal with upper bounds at -infinity */
881  assert(!SCIPisInfinity(scip, -oldbnd));
882  assert(!SCIPisInfinity(scip, -newbnd));
883 
884  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
885 
886  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
887  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
888  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
889  */
890 
891  if( coef > 0.0 )
892  {
893  /* we should only be called if lhs is finite */
894  assert(!SCIPisInfinity(scip, -consdata->lhs));
895 
896  /* we have no max activities computed so far, so cannot update */
897  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
898  return;
899 
900  assert(!SCIPisInfinity(scip, consdata->maxlinactivity));
901 
902  prevroundmode = SCIPintervalGetRoundingMode();
904 
905  /* update max activity */
906  if( SCIPisInfinity(scip, oldbnd) )
907  {
908  --consdata->maxlinactivityinf;
909  assert(consdata->maxlinactivityinf >= 0);
910  }
911  else
912  {
913  SCIP_Real minuscoef;
914  minuscoef = -coef;
915  consdata->maxlinactivity += minuscoef * oldbnd;
916  }
917 
918  if( SCIPisInfinity(scip, newbnd) )
919  {
920  ++consdata->maxlinactivityinf;
921  }
922  else
923  {
924  consdata->maxlinactivity += coef * newbnd;
925  }
926 
927  SCIPintervalSetRoundingMode(prevroundmode);
928  }
929  else
930  {
931  /* we should only be called if rhs is finite */
932  assert(!SCIPisInfinity(scip, consdata->rhs));
933 
934  /* we have no min activities computed so far, so cannot update */
935  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
936  return;
937 
938  assert(!SCIPisInfinity(scip, -consdata->minlinactivity));
939 
940  prevroundmode = SCIPintervalGetRoundingMode();
942 
943  /* update min activity */
944  if( SCIPisInfinity(scip, oldbnd) )
945  {
946  --consdata->minlinactivityinf;
947  assert(consdata->minlinactivityinf >= 0);
948  }
949  else
950  {
951  SCIP_Real minuscoef;
952  minuscoef = -coef;
953  consdata->minlinactivity += minuscoef * oldbnd;
954  }
955 
956  if( SCIPisInfinity(scip, newbnd) )
957  {
958  ++consdata->minlinactivityinf;
959  }
960  else
961  {
962  consdata->minlinactivity += coef * newbnd;
963  }
964 
965  SCIPintervalSetRoundingMode(prevroundmode);
966  }
967 }
968 
969 /** processes variable fixing or bound change event */
970 static
971 SCIP_DECL_EVENTEXEC(processVarEvent)
972 {
973  SCIP_CONSDATA* consdata;
974  SCIP_EVENTTYPE eventtype;
975  int varidx;
976 
977  assert(scip != NULL);
978  assert(event != NULL);
979  assert(eventdata != NULL);
980  assert(eventhdlr != NULL);
981 
982  consdata = ((SCIP_QUADVAREVENTDATA*)eventdata)->consdata;
983  assert(consdata != NULL);
984 
985  varidx = ((SCIP_QUADVAREVENTDATA*)eventdata)->varidx;
986  assert(varidx < 0 || varidx < consdata->nlinvars);
987  assert(varidx >= 0 || -varidx-1 < consdata->nquadvars);
988 
989  eventtype = SCIPeventGetType(event);
990 
991  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
992  {
993  if( varidx < 0 )
994  {
995  SCIP_QUADVARTERM* quadvarterm;
996  SCIP_VAR* var;
997 
998  quadvarterm = &consdata->quadvarterms[-varidx-1];
999  var = quadvarterm->var;
1000 
1001  /* 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()
1002  * we currently do this only if the binary variable does not show up in any bilinear terms
1003  * unfortunately, SCIP does not have an eventtype for vartype changes (nor do they always count as presolve reductions) and the bounds are
1004  * not updated yet when this event is processed, so we cannot use SCIPvarIsBinary here to check if the tightened integer variable will be binary
1005  */
1006  if( SCIPgetStage(scip) < SCIP_STAGE_SOLVING && SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER && quadvarterm->sqrcoef != 0.0 && quadvarterm->nadjbilin == 0 &&
1007  ( ((eventtype & SCIP_EVENTTYPE_LBTIGHTENED) && SCIPeventGetNewbound(event) > -0.5 && SCIPvarGetUbGlobal(var) < 1.5) ||
1008  ((eventtype & SCIP_EVENTTYPE_UBTIGHTENED) && SCIPeventGetNewbound(event) < 1.5 && SCIPvarGetLbGlobal(var) > -0.5) ) )
1009  {
1010  consdata->quadvarsmerged = FALSE;
1011  consdata->initialmerge = FALSE;
1012  }
1013 
1014  /* mark activity bounds for quad term as not up to date anymore */
1015  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
1016  }
1017  else
1018  {
1019  /* update activity bounds for linear terms */
1020  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
1021  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1022  else
1023  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1024  }
1025 
1026  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1027  consdata->ispropagated = FALSE;
1028  }
1029 
1030  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1031  {
1032  consdata->isremovedfixings = FALSE;
1033  }
1034 
1035 #ifdef CHECKIMPLINBILINEAR
1036  if( eventtype & SCIP_EVENTTYPE_IMPLADDED )
1037  {
1038  assert(varidx < 0); /* we catch impladded events only for quadratic variables */
1039  /* 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 */
1040  if( SCIPvarIsBinary(SCIPeventGetVar(event)) && consdata->quadvarterms[-varidx-1].nadjbilin > 0 )
1041  consdata->isimpladded = TRUE;
1042  }
1043 #endif
1044 
1045  return SCIP_OKAY;
1046 }
1047 
1048 /** ensures, that linear vars and coefs arrays can store at least num entries */
1049 static
1051  SCIP* scip, /**< SCIP data structure */
1052  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1053  int num /**< minimum number of entries to store */
1054  )
1055 {
1056  assert(scip != NULL);
1057  assert(consdata != NULL);
1058  assert(consdata->nlinvars <= consdata->linvarssize);
1059 
1060  if( num > consdata->linvarssize )
1061  {
1062  int newsize;
1063 
1064  newsize = SCIPcalcMemGrowSize(scip, num);
1065  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1066  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1067  if( consdata->lineventdata != NULL )
1068  {
1069  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1070  }
1071  consdata->linvarssize = newsize;
1072  }
1073  assert(num <= consdata->linvarssize);
1074 
1075  return SCIP_OKAY;
1076 }
1077 
1078 /** ensures, that quadratic variable terms array can store at least num entries */
1079 static
1081  SCIP* scip, /**< SCIP data structure */
1082  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1083  int num /**< minimum number of entries to store */
1084  )
1085 {
1086  assert(scip != NULL);
1087  assert(consdata != NULL);
1088  assert(consdata->nquadvars <= consdata->quadvarssize);
1089 
1090  if( num > consdata->quadvarssize )
1091  {
1092  int newsize;
1093 
1094  newsize = SCIPcalcMemGrowSize(scip, num);
1095  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->quadvarterms, consdata->quadvarssize, newsize) );
1096  consdata->quadvarssize = newsize;
1097  }
1098  assert(num <= consdata->quadvarssize);
1099 
1100  return SCIP_OKAY;
1101 }
1102 
1103 /** ensures, that adjacency array can store at least num entries */
1104 static
1106  SCIP* scip, /**< SCIP data structure */
1107  SCIP_QUADVARTERM* quadvarterm, /**< quadratic variable term */
1108  int num /**< minimum number of entries to store */
1109  )
1110 {
1111  assert(scip != NULL);
1112  assert(quadvarterm != NULL);
1113  assert(quadvarterm->nadjbilin <= quadvarterm->adjbilinsize);
1114 
1115  if( num > quadvarterm->adjbilinsize )
1116  {
1117  int newsize;
1118 
1119  newsize = SCIPcalcMemGrowSize(scip, num);
1120  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvarterm->adjbilin, quadvarterm->adjbilinsize, newsize) );
1121  quadvarterm->adjbilinsize = newsize;
1122  }
1123  assert(num <= quadvarterm->adjbilinsize);
1124 
1125  return SCIP_OKAY;
1126 }
1127 
1128 /** ensures, that bilinear term arrays can store at least num entries */
1129 static
1131  SCIP* scip, /**< SCIP data structure */
1132  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1133  int num /**< minimum number of entries to store */
1134  )
1135 {
1136  assert(scip != NULL);
1137  assert(consdata != NULL);
1138  assert(consdata->nbilinterms <= consdata->bilintermssize);
1139 
1140  if( num > consdata->bilintermssize )
1141  {
1142  int newsize;
1143 
1144  newsize = SCIPcalcMemGrowSize(scip, num);
1145  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize, newsize) );
1146  consdata->bilintermssize = newsize;
1147  }
1148  assert(num <= consdata->bilintermssize);
1149 
1150  return SCIP_OKAY;
1151 }
1152 
1153 /** creates empty constraint data structure */
1154 static
1156  SCIP* scip, /**< SCIP data structure */
1157  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1158  )
1159 {
1160  assert(scip != NULL);
1161  assert(consdata != NULL);
1162 
1163  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1164  BMSclearMemory(*consdata);
1165 
1166  (*consdata)->lhs = -SCIPinfinity(scip);
1167  (*consdata)->rhs = SCIPinfinity(scip);
1168 
1169  (*consdata)->linvarssorted = TRUE;
1170  (*consdata)->linvarsmerged = TRUE;
1171  (*consdata)->quadvarssorted = TRUE;
1172  (*consdata)->quadvarsmerged = TRUE;
1173  (*consdata)->bilinsorted = TRUE;
1174  (*consdata)->bilinmerged = TRUE;
1175 
1176  (*consdata)->isremovedfixings = TRUE;
1177  (*consdata)->ispropagated = TRUE;
1178  (*consdata)->initialmerge = FALSE;
1179 
1180  (*consdata)->linvar_maydecrease = -1;
1181  (*consdata)->linvar_mayincrease = -1;
1182 
1183  (*consdata)->minlinactivity = SCIP_INVALID;
1184  (*consdata)->maxlinactivity = SCIP_INVALID;
1185  (*consdata)->minlinactivityinf = -1;
1186  (*consdata)->maxlinactivityinf = -1;
1187 
1188  (*consdata)->isgaugeavailable = FALSE;
1189 
1190  return SCIP_OKAY;
1191 }
1192 
1193 /** creates constraint data structure */
1194 static
1196  SCIP* scip, /**< SCIP data structure */
1197  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1198  SCIP_Real lhs, /**< left hand side of constraint */
1199  SCIP_Real rhs, /**< right hand side of constraint */
1200  int nlinvars, /**< number of linear variables */
1201  SCIP_VAR** linvars, /**< array of linear variables */
1202  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1203  int nquadvars, /**< number of quadratic variables */
1204  SCIP_QUADVARTERM* quadvarterms, /**< array of quadratic variable terms */
1205  int nbilinterms, /**< number of bilinear terms */
1206  SCIP_BILINTERM* bilinterms, /**< array of bilinear terms */
1207  SCIP_Bool capturevars /**< whether we should capture variables */
1208  )
1209 {
1210  int i;
1211 
1212  assert(scip != NULL);
1213  assert(consdata != NULL);
1214 
1215  assert(nlinvars == 0 || linvars != NULL);
1216  assert(nlinvars == 0 || lincoefs != NULL);
1217  assert(nquadvars == 0 || quadvarterms != NULL);
1218  assert(nbilinterms == 0 || bilinterms != NULL);
1219 
1220  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1221  BMSclearMemory(*consdata);
1222 
1223  (*consdata)->minlinactivity = SCIP_INVALID;
1224  (*consdata)->maxlinactivity = SCIP_INVALID;
1225  (*consdata)->minlinactivityinf = -1;
1226  (*consdata)->maxlinactivityinf = -1;
1227 
1228  (*consdata)->lhs = lhs;
1229  (*consdata)->rhs = rhs;
1230 
1231  if( nlinvars > 0 )
1232  {
1233  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1234  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1235  (*consdata)->nlinvars = nlinvars;
1236  (*consdata)->linvarssize = nlinvars;
1237 
1238  if( capturevars )
1239  for( i = 0; i < nlinvars; ++i )
1240  {
1241  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1242  }
1243  }
1244  else
1245  {
1246  (*consdata)->linvarssorted = TRUE;
1247  (*consdata)->linvarsmerged = TRUE;
1248  (*consdata)->minlinactivity = 0.0;
1249  (*consdata)->maxlinactivity = 0.0;
1250  (*consdata)->minlinactivityinf = 0;
1251  (*consdata)->maxlinactivityinf = 0;
1252  }
1253 
1254  if( nquadvars > 0 )
1255  {
1256  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms, quadvarterms, nquadvars) );
1257 
1258  for( i = 0; i < nquadvars; ++i )
1259  {
1260  (*consdata)->quadvarterms[i].eventdata = NULL;
1261  if( quadvarterms[i].nadjbilin )
1262  {
1263  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms[i].adjbilin, quadvarterms[i].adjbilin, quadvarterms[i].nadjbilin) );
1264  (*consdata)->quadvarterms[i].adjbilinsize = quadvarterms[i].nadjbilin;
1265  }
1266  else
1267  {
1268  assert((*consdata)->quadvarterms[i].nadjbilin == 0);
1269  (*consdata)->quadvarterms[i].adjbilin = NULL;
1270  (*consdata)->quadvarterms[i].adjbilinsize = 0;
1271  }
1272  if( capturevars )
1273  {
1274  SCIP_CALL( SCIPcaptureVar(scip, quadvarterms[i].var) );
1275  }
1276  }
1277 
1278  (*consdata)->nquadvars = nquadvars;
1279  (*consdata)->quadvarssize = nquadvars;
1280  SCIPintervalSetEmpty(&(*consdata)->quadactivitybounds);
1281  }
1282  else
1283  {
1284  (*consdata)->quadvarssorted = TRUE;
1285  (*consdata)->quadvarsmerged = TRUE;
1286  SCIPintervalSet(&(*consdata)->quadactivitybounds, 0.0);
1287  }
1288 
1289  if( nbilinterms > 0 )
1290  {
1291  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->bilinterms, bilinterms, nbilinterms) );
1292  (*consdata)->nbilinterms = nbilinterms;
1293  (*consdata)->bilintermssize = nbilinterms;
1294  }
1295  else
1296  {
1297  (*consdata)->bilinsorted = TRUE;
1298  (*consdata)->bilinmerged = TRUE;
1299  }
1300 
1301  (*consdata)->linvar_maydecrease = -1;
1302  (*consdata)->linvar_mayincrease = -1;
1303 
1304  (*consdata)->activity = SCIP_INVALID;
1305  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1306  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1307 
1308  (*consdata)->isgaugeavailable = FALSE;
1309 
1310  return SCIP_OKAY;
1311 }
1312 
1313 /** frees constraint data structure */
1314 static
1316  SCIP* scip, /**< SCIP data structure */
1317  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1318  )
1319 {
1320  int i;
1321 
1322  assert(scip != NULL);
1323  assert(consdata != NULL);
1324  assert(*consdata != NULL);
1325 
1326  /* free sepa arrays, may exists if constraint is deleted in solving stage */
1327  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepaquadvars, (*consdata)->nquadvars);
1328  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepabilinvar2pos, (*consdata)->nbilinterms);
1329 
1330  /* release linear variables and free linear part */
1331  if( (*consdata)->linvarssize > 0 )
1332  {
1333  for( i = 0; i < (*consdata)->nlinvars; ++i )
1334  {
1335  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1336  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1337  }
1338  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1339  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1340  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1341  }
1342  assert((*consdata)->linvars == NULL);
1343  assert((*consdata)->lincoefs == NULL);
1344  assert((*consdata)->lineventdata == NULL);
1345 
1346  /* release quadratic variables and free quadratic variable term part */
1347  for( i = 0; i < (*consdata)->nquadvars; ++i )
1348  {
1349  assert((*consdata)->quadvarterms[i].eventdata == NULL); /* variable events should have been dropped earlier */
1350  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms[i].adjbilin, (*consdata)->quadvarterms[i].adjbilinsize);
1351  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->quadvarterms[i].var) );
1352  }
1353  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms, (*consdata)->quadvarssize);
1354 
1355  /* free bilinear terms */
1356  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilinterms, (*consdata)->bilintermssize);
1357 
1358  /* free nonlinear row representation */
1359  if( (*consdata)->nlrow != NULL )
1360  {
1361  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1362  }
1363 
1364  /* free interior point information, may exists if constraint is deleted in solving stage */
1365  SCIPfreeMemoryArrayNull(scip, &(*consdata)->interiorpoint);
1366  SCIPfreeMemoryArrayNull(scip, &(*consdata)->gaugecoefs);
1367 
1368  SCIPfreeBlockMemory(scip, consdata);
1369  *consdata = NULL;
1370 
1371  return SCIP_OKAY;
1372 }
1373 
1374 /** sorts linear part of constraint data */
1375 static
1377  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1378  )
1379 {
1380  assert(consdata != NULL);
1381 
1382  if( consdata->linvarssorted )
1383  return;
1384 
1385  if( consdata->nlinvars <= 1 )
1386  {
1387  consdata->linvarssorted = TRUE;
1388  return;
1389  }
1390 
1391  if( consdata->lineventdata == NULL )
1392  {
1393  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1394  }
1395  else
1396  {
1397  int i;
1398 
1399  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1400 
1401  /* update variable indices in event data */
1402  for( i = 0; i < consdata->nlinvars; ++i )
1403  if( consdata->lineventdata[i] != NULL )
1404  consdata->lineventdata[i]->varidx = i;
1405  }
1406 
1407  consdata->linvarssorted = TRUE;
1408 }
1409 
1410 #ifdef SCIP_DISABLED_CODE /* no-one needs this routine currently */
1411 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1412 static
1413 int consdataFindLinearVar(
1414  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1415  SCIP_VAR* var /**< variable to search for */
1416  )
1417 {
1418  int pos;
1419 
1420  assert(consdata != NULL);
1421  assert(var != NULL);
1422 
1423  if( consdata->nlinvars == 0 )
1424  return -1;
1425 
1426  consdataSortLinearVars(consdata);
1427 
1428  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1429  pos = -1;
1430 
1431  return pos;
1432 }
1433 #endif
1434 
1435 /** index comparison method for quadratic variable terms: compares two indices of the quadratic variable set in the quadratic constraint */
1436 static
1437 SCIP_DECL_SORTINDCOMP(quadVarTermComp)
1438 { /*lint --e{715}*/
1439  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1440 
1441  assert(consdata != NULL);
1442  assert(0 <= ind1 && ind1 < consdata->nquadvars);
1443  assert(0 <= ind2 && ind2 < consdata->nquadvars);
1444 
1445  return SCIPvarCompare(consdata->quadvarterms[ind1].var, consdata->quadvarterms[ind2].var);
1446 }
1447 
1448 /** sorting of quadratic variable terms */
1449 static
1451  SCIP* scip, /**< SCIP data structure */
1452  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1453  )
1454 {
1455  int* perm;
1456  int i;
1457  int nexti;
1458  int v;
1459  SCIP_QUADVARTERM quadterm;
1460 
1461  assert(scip != NULL);
1462  assert(consdata != NULL);
1463 
1464  if( consdata->quadvarssorted )
1465  return SCIP_OKAY;
1466 
1467  if( consdata->nquadvars == 0 )
1468  {
1469  consdata->quadvarssorted = TRUE;
1470  return SCIP_OKAY;
1471  }
1472 
1473  /* get temporary memory to store the sorted permutation */
1474  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nquadvars) );
1475 
1476  /* call bubble sort */
1477  SCIPsort(perm, quadVarTermComp, (void*)consdata, consdata->nquadvars);
1478 
1479  /* permute the quadratic variable terms according to the resulting permutation */
1480  for( v = 0; v < consdata->nquadvars; ++v )
1481  {
1482  if( perm[v] != v )
1483  {
1484  quadterm = consdata->quadvarterms[v];
1485 
1486  i = v;
1487  do
1488  {
1489  assert(0 <= perm[i] && perm[i] < consdata->nquadvars);
1490  assert(perm[i] != i);
1491  consdata->quadvarterms[i] = consdata->quadvarterms[perm[i]];
1492  if( consdata->quadvarterms[i].eventdata != NULL )
1493  {
1494  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1495  }
1496  nexti = perm[i];
1497  perm[i] = i;
1498  i = nexti;
1499  }
1500  while( perm[i] != v );
1501  consdata->quadvarterms[i] = quadterm;
1502  if( consdata->quadvarterms[i].eventdata != NULL )
1503  {
1504  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1505  }
1506  perm[i] = i;
1507  }
1508  }
1509  consdata->quadvarssorted = TRUE;
1510 
1511  /* free temporary memory */
1512  SCIPfreeBufferArray(scip, &perm);
1513 
1514  return SCIP_OKAY;
1515 }
1516 
1517 /** returns the position of variable in the quadratic variable terms array of a constraint, or -1 if not found */
1518 static
1520  SCIP* scip, /**< SCIP data structure */
1521  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1522  SCIP_VAR* var, /**< variable to search for */
1523  int* pos /**< buffer where to store position of var in quadvarterms array, or -1 if not found */
1524  )
1525 {
1526  int left;
1527  int right;
1528  int cmpres;
1529 
1530  assert(consdata != NULL);
1531  assert(var != NULL);
1532  assert(pos != NULL);
1533 
1534  if( consdata->nquadvars == 0 )
1535  {
1536  *pos = -1;
1537  return SCIP_OKAY;
1538  }
1539 
1540  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
1541 
1542  left = 0;
1543  right = consdata->nquadvars - 1;
1544  while( left <= right )
1545  {
1546  int middle;
1547 
1548  middle = (left+right)/2;
1549  assert(0 <= middle && middle < consdata->nquadvars);
1550 
1551  cmpres = SCIPvarCompare(var, consdata->quadvarterms[middle].var);
1552 
1553  if( cmpres < 0 )
1554  right = middle - 1;
1555  else if( cmpres > 0 )
1556  left = middle + 1;
1557  else
1558  {
1559  *pos = middle;
1560  return SCIP_OKAY;
1561  }
1562  }
1563  assert(left == right+1);
1564 
1565  *pos = -1;
1566 
1567  return SCIP_OKAY;
1568 }
1569 
1570 /** index comparison method for bilinear terms: compares two index pairs of the bilinear term set in the quadratic constraint */
1571 static
1572 SCIP_DECL_SORTINDCOMP(bilinTermComp)
1573 { /*lint --e{715}*/
1574  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1575  int var1cmp;
1576 
1577  assert(consdata != NULL);
1578  assert(0 <= ind1 && ind1 < consdata->nbilinterms);
1579  assert(0 <= ind2 && ind2 < consdata->nbilinterms);
1580 
1581  var1cmp = SCIPvarCompare(consdata->bilinterms[ind1].var1, consdata->bilinterms[ind2].var1);
1582  if( var1cmp != 0 )
1583  return var1cmp;
1584 
1585  return SCIPvarCompare(consdata->bilinterms[ind1].var2, consdata->bilinterms[ind2].var2);
1586 }
1587 
1588 #ifndef NDEBUG
1589 /** checks if all bilinear terms are sorted correctly */
1590 static
1592  SCIP_CONSDATA* consdata
1593  )
1594 {
1595  int i;
1596 
1597  assert(consdata != NULL);
1598 
1599  /* nothing to check if the bilinear terms have not been sorted yet */
1600  if( !consdata->bilinsorted )
1601  return TRUE;
1602 
1603  for( i = 0; i < consdata->nbilinterms - 1; ++i )
1604  {
1605  if( bilinTermComp(consdata, i, i+1) > 0 )
1606  return FALSE;
1607  }
1608  return TRUE;
1609 }
1610 #endif
1611 
1612 /** sorting of bilinear terms */
1613 static
1615  SCIP* scip, /**< SCIP data structure */
1616  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1617  )
1618 {
1619  int* perm;
1620  int* invperm;
1621  int i;
1622  int nexti;
1623  int v;
1624  SCIP_BILINTERM bilinterm;
1625 
1626  assert(scip != NULL);
1627  assert(consdata != NULL);
1628 
1629  if( consdata->bilinsorted )
1630  return SCIP_OKAY;
1631 
1632  if( consdata->nbilinterms == 0 )
1633  {
1634  consdata->bilinsorted = TRUE;
1635  return SCIP_OKAY;
1636  }
1637 
1638  /* get temporary memory to store the sorted permutation and the inverse permutation */
1639  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nbilinterms) );
1640  SCIP_CALL( SCIPallocBufferArray(scip, &invperm, consdata->nbilinterms) );
1641 
1642  /* call bubble sort */
1643  SCIPsort(perm, bilinTermComp, (void*)consdata, consdata->nbilinterms);
1644 
1645  /* compute inverted permutation */
1646  for( v = 0; v < consdata->nbilinterms; ++v )
1647  {
1648  assert(0 <= perm[v] && perm[v] < consdata->nbilinterms);
1649  invperm[perm[v]] = v;
1650  }
1651 
1652  /* permute the bilinear terms according to the resulting permutation */
1653  for( v = 0; v < consdata->nbilinterms; ++v )
1654  {
1655  if( perm[v] != v )
1656  {
1657  bilinterm = consdata->bilinterms[v];
1658 
1659  i = v;
1660  do
1661  {
1662  assert(0 <= perm[i] && perm[i] < consdata->nbilinterms);
1663  assert(perm[i] != i);
1664  consdata->bilinterms[i] = consdata->bilinterms[perm[i]];
1665  nexti = perm[i];
1666  perm[i] = i;
1667  i = nexti;
1668  }
1669  while( perm[i] != v );
1670  consdata->bilinterms[i] = bilinterm;
1671  perm[i] = i;
1672  }
1673  }
1674 
1675  /* update the adjacency information in the quadratic variable terms */
1676  for( v = 0; v < consdata->nquadvars; ++v )
1677  for( i = 0; i < consdata->quadvarterms[v].nadjbilin; ++i )
1678  consdata->quadvarterms[v].adjbilin[i] = invperm[consdata->quadvarterms[v].adjbilin[i]];
1679 
1680  consdata->bilinsorted = TRUE;
1681  assert(consdataCheckBilinTermsSort(consdata));
1682 
1683  /* free temporary memory */
1684  SCIPfreeBufferArray(scip, &perm);
1685  SCIPfreeBufferArray(scip, &invperm);
1686 
1687  return SCIP_OKAY;
1688 }
1689 
1690 /** moves a linear variable from one position to another */
1691 static
1693  SCIP_CONSDATA* consdata, /**< constraint data */
1694  int oldpos, /**< position of variable that shall be moved */
1695  int newpos /**< new position of variable */
1696  )
1697 {
1698  assert(consdata != NULL);
1699  assert(oldpos >= 0);
1700  assert(oldpos < consdata->nlinvars);
1701  assert(newpos >= 0);
1702  assert(newpos < consdata->linvarssize);
1703 
1704  if( newpos == oldpos )
1705  return;
1706 
1707  consdata->linvars [newpos] = consdata->linvars [oldpos];
1708  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1709 
1710  if( consdata->lineventdata != NULL )
1711  {
1712  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1713 
1714  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1715  consdata->lineventdata[newpos]->varidx = newpos;
1716 
1717  consdata->lineventdata[oldpos] = NULL;
1718  }
1719 
1720  consdata->linvarssorted = FALSE;
1721 }
1722 
1723 /** moves a quadratic variable from one position to another */
1724 static
1726  SCIP_CONSDATA* consdata, /**< constraint data */
1727  int oldpos, /**< position of variable that shall be moved */
1728  int newpos /**< new position of variable */
1729  )
1730 {
1731  assert(consdata != NULL);
1732  assert(oldpos >= 0);
1733  assert(oldpos < consdata->nquadvars);
1734  assert(newpos >= 0);
1735  assert(newpos < consdata->quadvarssize);
1736 
1737  if( newpos == oldpos )
1738  return;
1739 
1740  assert(newpos >= consdata->nquadvars || consdata->quadvarterms[newpos].eventdata == NULL);
1741 
1742  consdata->quadvarterms[newpos] = consdata->quadvarterms[oldpos];
1743 
1744  if( consdata->quadvarterms[newpos].eventdata != NULL )
1745  {
1746  consdata->quadvarterms[newpos].eventdata->varidx = -newpos-1;
1747  consdata->quadvarterms[oldpos].eventdata = NULL;
1748  }
1749 
1750  consdata->quadvarssorted = FALSE;
1751 }
1752 
1753 /** adds linear coefficient in quadratic constraint */
1754 static
1756  SCIP* scip, /**< SCIP data structure */
1757  SCIP_CONS* cons, /**< quadratic constraint */
1758  SCIP_VAR* var, /**< variable of constraint entry */
1759  SCIP_Real coef /**< coefficient of constraint entry */
1760  )
1761 {
1762  SCIP_CONSDATA* consdata;
1763  SCIP_Bool transformed;
1764 
1765  assert(scip != NULL);
1766  assert(cons != NULL);
1767  assert(var != NULL);
1768 
1769  /* ignore coefficient if it is nearly zero */
1770  if( SCIPisZero(scip, coef) )
1771  return SCIP_OKAY;
1772 
1773  consdata = SCIPconsGetData(cons);
1774  assert(consdata != NULL);
1775 
1776  /* are we in the transformed problem? */
1777  transformed = SCIPconsIsTransformed(cons);
1778 
1779  /* always use transformed variables in transformed constraints */
1780  if( transformed )
1781  {
1782  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1783  }
1784  assert(var != NULL);
1785  assert(transformed == SCIPvarIsTransformed(var));
1786 
1787  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1788  consdata->linvars [consdata->nlinvars] = var;
1789  consdata->lincoefs[consdata->nlinvars] = coef;
1790 
1791  ++consdata->nlinvars;
1792 
1793  /* catch variable events */
1794  if( SCIPconsIsEnabled(cons) )
1795  {
1796  SCIP_CONSHDLR* conshdlr;
1797  SCIP_CONSHDLRDATA* conshdlrdata;
1798 
1799  /* get event handler */
1800  conshdlr = SCIPconsGetHdlr(cons);
1801  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1802  assert(conshdlrdata != NULL);
1803  assert(conshdlrdata->eventhdlr != NULL);
1804 
1805  assert(consdata->lineventdata != NULL);
1806  consdata->lineventdata[consdata->nlinvars-1] = NULL;
1807 
1808  /* catch bound change events of variable */
1809  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nlinvars-1) );
1810  }
1811 
1812  /* invalidate activity information */
1813  consdata->activity = SCIP_INVALID;
1814  consdata->minlinactivity = SCIP_INVALID;
1815  consdata->maxlinactivity = SCIP_INVALID;
1816  consdata->minlinactivityinf = -1;
1817  consdata->maxlinactivityinf = -1;
1818 
1819  /* invalidate nonlinear row */
1820  if( consdata->nlrow != NULL )
1821  {
1822  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1823  }
1824 
1825  /* install rounding locks for new variable */
1826  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1827 
1828  /* capture new variable */
1829  SCIP_CALL( SCIPcaptureVar(scip, var) );
1830 
1831  consdata->ispropagated = FALSE;
1832  consdata->ispresolved = FALSE;
1833  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
1834  if( consdata->nlinvars == 1 )
1835  consdata->linvarssorted = TRUE;
1836  else
1837  consdata->linvarssorted = consdata->linvarssorted && (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1838  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1839  consdata->linvarsmerged = FALSE;
1840 
1841  return SCIP_OKAY;
1842 }
1843 
1844 /** deletes linear coefficient at given position from quadratic constraint data */
1845 static
1847  SCIP* scip, /**< SCIP data structure */
1848  SCIP_CONS* cons, /**< quadratic constraint */
1849  int pos /**< position of coefficient to delete */
1850  )
1851 {
1852  SCIP_CONSDATA* consdata;
1853  SCIP_VAR* var;
1854  SCIP_Real coef;
1855 
1856  assert(scip != NULL);
1857  assert(cons != NULL);
1858 
1859  consdata = SCIPconsGetData(cons);
1860  assert(consdata != NULL);
1861  assert(0 <= pos && pos < consdata->nlinvars);
1862 
1863  var = consdata->linvars[pos];
1864  coef = consdata->lincoefs[pos];
1865  assert(var != NULL);
1866 
1867  /* remove rounding locks for deleted variable */
1868  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1869 
1870  /* if we catch variable events, drop the events on the variable */
1871  if( consdata->lineventdata != NULL )
1872  {
1873  SCIP_CONSHDLR* conshdlr;
1874  SCIP_CONSHDLRDATA* conshdlrdata;
1875 
1876  /* get event handler */
1877  conshdlr = SCIPconsGetHdlr(cons);
1878  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1879  assert(conshdlrdata != NULL);
1880  assert(conshdlrdata->eventhdlr != NULL);
1881 
1882  /* drop bound change events of variable */
1883  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1884  }
1885 
1886  /* release variable */
1887  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
1888 
1889  /* move the last variable to the free slot */
1890  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
1891 
1892  --consdata->nlinvars;
1893 
1894  /* invalidate activity */
1895  consdata->activity = SCIP_INVALID;
1896  consdata->minlinactivity = SCIP_INVALID;
1897  consdata->maxlinactivity = SCIP_INVALID;
1898  consdata->minlinactivityinf = -1;
1899  consdata->maxlinactivityinf = -1;
1900 
1901  /* invalidate nonlinear row */
1902  if( consdata->nlrow != NULL )
1903  {
1904  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1905  }
1906 
1907  consdata->ispropagated = FALSE;
1908  consdata->ispresolved = FALSE;
1909 
1910  return SCIP_OKAY;
1911 }
1912 
1913 /** changes linear coefficient value at given position of quadratic constraint */
1914 static
1916  SCIP* scip, /**< SCIP data structure */
1917  SCIP_CONS* cons, /**< quadratic constraint */
1918  int pos, /**< position of linear coefficient to change */
1919  SCIP_Real newcoef /**< new value of linear coefficient */
1920  )
1921 {
1922  SCIP_CONSHDLR* conshdlr;
1923  SCIP_CONSHDLRDATA* conshdlrdata;
1924  SCIP_CONSDATA* consdata;
1925  SCIP_VAR* var;
1926  SCIP_Real coef;
1927 
1928  assert(scip != NULL);
1929  assert(cons != NULL);
1930  assert(!SCIPisZero(scip, newcoef));
1931 
1932  conshdlrdata = NULL;
1933 
1934  consdata = SCIPconsGetData(cons);
1935  assert(consdata != NULL);
1936  assert(0 <= pos);
1937  assert(pos < consdata->nlinvars);
1938  assert(!SCIPisZero(scip, newcoef));
1939 
1940  var = consdata->linvars[pos];
1941  coef = consdata->lincoefs[pos];
1942  assert(var != NULL);
1943  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
1944 
1945  /* invalidate activity */
1946  consdata->activity = SCIP_INVALID;
1947  consdata->minlinactivity = SCIP_INVALID;
1948  consdata->maxlinactivity = SCIP_INVALID;
1949  consdata->minlinactivityinf = -1;
1950  consdata->maxlinactivityinf = -1;
1951 
1952  /* invalidate nonlinear row */
1953  if( consdata->nlrow != NULL )
1954  {
1955  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1956  }
1957 
1958  /* if necessary, remove the rounding locks and event catching of the variable */
1959  if( newcoef * coef < 0.0 )
1960  {
1961  if( SCIPconsIsLocked(cons) )
1962  {
1963  assert(SCIPconsIsTransformed(cons));
1964 
1965  /* remove rounding locks for variable with old coefficient */
1966  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1967  }
1968 
1969  if( consdata->lineventdata[pos] != NULL )
1970  {
1971  /* get event handler */
1972  conshdlr = SCIPconsGetHdlr(cons);
1973  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1974  assert(conshdlrdata != NULL);
1975  assert(conshdlrdata->eventhdlr != NULL);
1976 
1977  /* drop bound change events of variable */
1978  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1979  }
1980  }
1981 
1982  /* change the coefficient */
1983  consdata->lincoefs[pos] = newcoef;
1984 
1985  /* if necessary, install the rounding locks and event catching of the variable again */
1986  if( newcoef * coef < 0.0 )
1987  {
1988  if( SCIPconsIsLocked(cons) )
1989  {
1990  /* install rounding locks for variable with new coefficient */
1991  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
1992  }
1993 
1994  if( conshdlrdata != NULL )
1995  {
1996  assert(SCIPconsIsEnabled(cons));
1997 
1998  /* catch bound change events of variable */
1999  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2000  }
2001  }
2002 
2003  consdata->ispropagated = FALSE;
2004  consdata->ispresolved = FALSE;
2005 
2006  return SCIP_OKAY;
2007 }
2008 
2009 /** adds quadratic variable term to quadratic constraint */
2010 static
2012  SCIP* scip, /**< SCIP data structure */
2013  SCIP_CONS* cons, /**< quadratic constraint */
2014  SCIP_VAR* var, /**< variable to add */
2015  SCIP_Real lincoef, /**< linear coefficient of variable */
2016  SCIP_Real sqrcoef /**< square coefficient of variable */
2017  )
2018 {
2019  SCIP_CONSDATA* consdata;
2020  SCIP_Bool transformed;
2021  SCIP_QUADVARTERM* quadvarterm;
2022 
2023  assert(scip != NULL);
2024  assert(cons != NULL);
2025  assert(var != NULL);
2026 
2027  consdata = SCIPconsGetData(cons);
2028  assert(consdata != NULL);
2029 
2030  /* are we in the transformed problem? */
2031  transformed = SCIPconsIsTransformed(cons);
2032 
2033  /* always use transformed variables in transformed constraints */
2034  if( transformed )
2035  {
2036  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
2037  }
2038  assert(var != NULL);
2039  assert(transformed == SCIPvarIsTransformed(var));
2040 
2041  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars+1) );
2042 
2043  quadvarterm = &consdata->quadvarterms[consdata->nquadvars];
2044  quadvarterm->var = var;
2045  quadvarterm->lincoef = lincoef;
2046  quadvarterm->sqrcoef = sqrcoef;
2047  quadvarterm->adjbilinsize = 0;
2048  quadvarterm->nadjbilin = 0;
2049  quadvarterm->adjbilin = NULL;
2050  quadvarterm->eventdata = NULL;
2051 
2052  ++consdata->nquadvars;
2053 
2054  /* capture variable */
2055  SCIP_CALL( SCIPcaptureVar(scip, var) );
2056 
2057  /* catch variable events, if we do so */
2058  if( SCIPconsIsEnabled(cons) )
2059  {
2060  SCIP_CONSHDLR* conshdlr;
2061  SCIP_CONSHDLRDATA* conshdlrdata;
2062 
2063  /* get event handler */
2064  conshdlr = SCIPconsGetHdlr(cons);
2065  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2066  assert(conshdlrdata != NULL);
2067  assert(conshdlrdata->eventhdlr != NULL);
2068 
2069  /* catch bound change events of variable */
2070  SCIP_CALL( catchQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nquadvars-1) );
2071  }
2072 
2073  /* invalidate activity information */
2074  consdata->activity = SCIP_INVALID;
2075  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2076 
2077  /* invalidate nonlinear row */
2078  if( consdata->nlrow != NULL )
2079  {
2080  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2081  }
2082 
2083  /* install rounding locks for new variable */
2084  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2085 
2086  consdata->ispropagated = FALSE;
2087  consdata->ispresolved = FALSE;
2088  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
2089  if( consdata->nquadvars == 1 )
2090  consdata->quadvarssorted = TRUE;
2091  else
2092  consdata->quadvarssorted = consdata->quadvarssorted &&
2093  (SCIPvarCompare(consdata->quadvarterms[consdata->nquadvars-2].var, consdata->quadvarterms[consdata->nquadvars-1].var) == -1);
2094  /* also set to FALSE if nquadvars == 1, since the new variable should be checked for linearity and other stuff in mergeAndClean ... */
2095  consdata->quadvarsmerged = FALSE;
2096 
2097  consdata->iscurvchecked = FALSE;
2098 
2099  return SCIP_OKAY;
2100 }
2101 
2102 /** deletes quadratic variable term at given position from quadratic constraint data */
2103 static
2105  SCIP* scip, /**< SCIP data structure */
2106  SCIP_CONS* cons, /**< quadratic constraint */
2107  int pos /**< position of term to delete */
2108  )
2109 {
2110  SCIP_CONSDATA* consdata;
2111  SCIP_VAR* var;
2112 
2113  assert(scip != NULL);
2114  assert(cons != NULL);
2115 
2116  consdata = SCIPconsGetData(cons);
2117  assert(consdata != NULL);
2118  assert(0 <= pos && pos < consdata->nquadvars);
2119 
2120  var = consdata->quadvarterms[pos].var;
2121  assert(var != NULL);
2122  assert(consdata->quadvarterms[pos].nadjbilin == 0);
2123 
2124  /* remove rounding locks for deleted variable */
2125  SCIP_CALL( unlockQuadraticVariable(scip, cons, var) );
2126 
2127  /* if we catch variable events, drop the events on the variable */
2128  if( consdata->quadvarterms[pos].eventdata != NULL )
2129  {
2130  SCIP_CONSHDLR* conshdlr;
2131  SCIP_CONSHDLRDATA* conshdlrdata;
2132 
2133  /* get event handler */
2134  conshdlr = SCIPconsGetHdlr(cons);
2135  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2136  assert(conshdlrdata != NULL);
2137  assert(conshdlrdata->eventhdlr != NULL);
2138 
2139  /* drop bound change events of variable */
2140  SCIP_CALL( dropQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2141  }
2142 
2143  /* release variable */
2144  SCIP_CALL( SCIPreleaseVar(scip, &consdata->quadvarterms[pos].var) );
2145 
2146  /* free adjacency array */
2147  SCIPfreeBlockMemoryArrayNull(scip, &consdata->quadvarterms[pos].adjbilin, consdata->quadvarterms[pos].adjbilinsize);
2148 
2149  /* move the last variable term to the free slot */
2150  consdataMoveQuadVarTerm(consdata, consdata->nquadvars-1, pos);
2151 
2152  --consdata->nquadvars;
2153 
2154  /* invalidate activity */
2155  consdata->activity = SCIP_INVALID;
2156  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2157 
2158  /* invalidate nonlinear row */
2159  if( consdata->nlrow != NULL )
2160  {
2161  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2162  }
2163 
2164  consdata->ispropagated = FALSE;
2165  consdata->ispresolved = FALSE;
2166  consdata->iscurvchecked = FALSE;
2167 
2168  return SCIP_OKAY;
2169 }
2170 
2171 /** replace variable in quadratic variable term at given position of quadratic constraint data
2172  *
2173  * Allows to replace x by coef*y+offset, thereby maintaining linear and square coefficients and bilinear terms.
2174  */
2175 static
2177  SCIP* scip, /**< SCIP data structure */
2178  SCIP_CONS* cons, /**< quadratic constraint */
2179  int pos, /**< position of term to replace */
2180  SCIP_VAR* var, /**< new variable */
2181  SCIP_Real coef, /**< linear coefficient of new variable */
2182  SCIP_Real offset /**< offset of new variable */
2183  )
2184 {
2185  SCIP_CONSDATA* consdata;
2186  SCIP_QUADVARTERM* quadvarterm;
2187  SCIP_EVENTHDLR* eventhdlr;
2188  SCIP_BILINTERM* bilinterm;
2189  SCIP_Real constant;
2190 
2191  int i;
2192  SCIP_VAR* var2;
2193 
2194  consdata = SCIPconsGetData(cons);
2195  assert(consdata != NULL);
2196  assert(pos >= 0);
2197  assert(pos < consdata->nquadvars);
2198 
2199  quadvarterm = &consdata->quadvarterms[pos];
2200 
2201  /* remove rounding locks for old variable */
2202  SCIP_CALL( unlockQuadraticVariable(scip, cons, quadvarterm->var) );
2203 
2204  /* if we catch variable events, drop the events on the old variable */
2205  if( quadvarterm->eventdata != NULL )
2206  {
2207  SCIP_CONSHDLR* conshdlr;
2208  SCIP_CONSHDLRDATA* conshdlrdata;
2209 
2210  /* get event handler */
2211  conshdlr = SCIPconsGetHdlr(cons);
2212  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2213  assert(conshdlrdata != NULL);
2214  assert(conshdlrdata->eventhdlr != NULL);
2215 
2216  eventhdlr = conshdlrdata->eventhdlr;
2217 
2218  /* drop bound change events of variable */
2219  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, pos) );
2220  }
2221  else
2222  {
2223  eventhdlr = NULL;
2224  }
2225 
2226  /* compute constant and put into lhs/rhs */
2227  constant = quadvarterm->lincoef * offset + quadvarterm->sqrcoef * offset * offset;
2228  if( constant != 0.0 )
2229  {
2230  /* maintain constant part */
2231  if( !SCIPisInfinity(scip, -consdata->lhs) )
2232  consdata->lhs -= constant;
2233  if( !SCIPisInfinity(scip, consdata->rhs) )
2234  consdata->rhs -= constant;
2235  }
2236 
2237  /* update linear and square coefficient */
2238  quadvarterm->lincoef *= coef;
2239  quadvarterm->lincoef += 2.0 * quadvarterm->sqrcoef * coef * offset;
2240  quadvarterm->sqrcoef *= coef * coef;
2241 
2242  /* update bilinear terms */
2243  for( i = 0; i < quadvarterm->nadjbilin; ++i )
2244  {
2245  bilinterm = &consdata->bilinterms[quadvarterm->adjbilin[i]];
2246 
2247  if( bilinterm->var1 == quadvarterm->var )
2248  {
2249  bilinterm->var1 = var;
2250  var2 = bilinterm->var2;
2251  }
2252  else
2253  {
2254  assert(bilinterm->var2 == quadvarterm->var);
2255  bilinterm->var2 = var;
2256  var2 = bilinterm->var1;
2257  }
2258 
2259  if( var == var2 )
2260  {
2261  /* looks like we actually have a square term here */
2262  quadvarterm->lincoef += bilinterm->coef * offset;
2263  quadvarterm->sqrcoef += bilinterm->coef * coef;
2264  /* deleting bilinear terms is expensive, since it requires updating adjacency information
2265  * thus, for now we just set the coefficient to 0.0 and clear in later when the bilinear terms are merged */
2266  bilinterm->coef = 0.0;
2267  continue;
2268  }
2269 
2270  /* swap var1 and var2 if they are in wrong order */
2271  if( SCIPvarCompare(bilinterm->var1, bilinterm->var2) > 0 )
2272  {
2273  SCIP_VAR* tmp;
2274  tmp = bilinterm->var1;
2275  bilinterm->var1 = bilinterm->var2;
2276  bilinterm->var2 = tmp;
2277  }
2278  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2279 
2280  if( offset != 0.0 )
2281  {
2282  /* need to find var2 and add offset*bilinterm->coef to linear coefficient */
2283  int var2pos;
2284 
2285  var2pos = 0;
2286  while( consdata->quadvarterms[var2pos].var != var2 )
2287  {
2288  ++var2pos;
2289  assert(var2pos < consdata->nquadvars);
2290  }
2291 
2292  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2293  }
2294 
2295  bilinterm->coef *= coef;
2296  }
2297 
2298  /* release old variable */
2299  SCIP_CALL( SCIPreleaseVar(scip, &quadvarterm->var) );
2300 
2301  /* set new variable */
2302  quadvarterm->var = var;
2303 
2304  /* capture new variable */
2305  SCIP_CALL( SCIPcaptureVar(scip, quadvarterm->var) );
2306 
2307  /* catch variable events, if we do so */
2308  if( eventhdlr != NULL )
2309  {
2310  assert(SCIPconsIsEnabled(cons));
2311 
2312  /* catch bound change events of variable */
2313  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, pos) );
2314  }
2315 
2316  /* invalidate activity information */
2317  consdata->activity = SCIP_INVALID;
2318  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2319 
2320  /* invalidate nonlinear row */
2321  if( consdata->nlrow != NULL )
2322  {
2323  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2324  }
2325 
2326  /* install rounding locks for new variable */
2327  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2328 
2329  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
2330  consdata->quadvarssorted = (consdata->nquadvars == 1);
2331  consdata->quadvarsmerged = FALSE;
2332  consdata->bilinsorted &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2333  consdata->bilinmerged &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2334 
2335  consdata->ispropagated = FALSE;
2336  consdata->ispresolved = FALSE;
2337  consdata->iscurvchecked = FALSE;
2338 
2339  return SCIP_OKAY;
2340 }
2341 
2342 /** adds a bilinear term to quadratic constraint */
2343 static
2345  SCIP* scip, /**< SCIP data structure */
2346  SCIP_CONS* cons, /**< quadratic constraint */
2347  int var1pos, /**< position of first variable in quadratic variables array */
2348  int var2pos, /**< position of second variable in quadratic variables array */
2349  SCIP_Real coef /**< coefficient of bilinear term */
2350  )
2351 {
2352  SCIP_CONSDATA* consdata;
2353  SCIP_BILINTERM* bilinterm;
2354 
2355  assert(scip != NULL);
2356  assert(cons != NULL);
2357 
2358  if( var1pos == var2pos )
2359  {
2360  SCIPerrorMessage("tried to add bilinear term where both variables are the same\n");
2361  return SCIP_INVALIDDATA;
2362  }
2363 
2364  consdata = SCIPconsGetData(cons);
2365  assert(consdata != NULL);
2366 
2367  /* check if the bilinear terms are sorted */
2368  assert(consdataCheckBilinTermsSort(consdata));
2369 
2370  assert(var1pos >= 0);
2371  assert(var1pos < consdata->nquadvars);
2372  assert(var2pos >= 0);
2373  assert(var2pos < consdata->nquadvars);
2374 
2375  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nbilinterms + 1) );
2376 
2377  bilinterm = &consdata->bilinterms[consdata->nbilinterms];
2378  if( SCIPvarCompare(consdata->quadvarterms[var1pos].var, consdata->quadvarterms[var2pos].var) < 0 )
2379  {
2380  bilinterm->var1 = consdata->quadvarterms[var1pos].var;
2381  bilinterm->var2 = consdata->quadvarterms[var2pos].var;
2382  }
2383  else
2384  {
2385  bilinterm->var1 = consdata->quadvarterms[var2pos].var;
2386  bilinterm->var2 = consdata->quadvarterms[var1pos].var;
2387  }
2388  bilinterm->coef = coef;
2389 
2390  if( bilinterm->var1 == bilinterm->var2 )
2391  {
2392  SCIPerrorMessage("tried to add bilinear term where both variables are the same, but appear at different positions in quadvarterms array\n");
2393  return SCIP_INVALIDDATA;
2394  }
2395  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2396 
2397  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var1pos], consdata->quadvarterms[var1pos].nadjbilin + 1) );
2398  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var2pos], consdata->quadvarterms[var2pos].nadjbilin + 1) );
2399 
2400  consdata->quadvarterms[var1pos].adjbilin[consdata->quadvarterms[var1pos].nadjbilin] = consdata->nbilinterms;
2401  consdata->quadvarterms[var2pos].adjbilin[consdata->quadvarterms[var2pos].nadjbilin] = consdata->nbilinterms;
2402  ++consdata->quadvarterms[var1pos].nadjbilin;
2403  ++consdata->quadvarterms[var2pos].nadjbilin;
2404 
2405  ++consdata->nbilinterms;
2406 
2407  /* invalidate activity information */
2408  consdata->activity = SCIP_INVALID;
2409  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2410 
2411  /* invalidate nonlinear row */
2412  if( consdata->nlrow != NULL )
2413  {
2414  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2415  }
2416 
2417  consdata->ispropagated = FALSE;
2418  consdata->ispresolved = FALSE;
2419  if( consdata->nbilinterms == 1 )
2420  {
2421  consdata->bilinsorted = TRUE;
2422 
2423  /* we have to take care of the bilinear term in mergeAndCleanBilinearTerms() if the coefficient is zero */
2424  consdata->bilinmerged = !SCIPisZero(scip, consdata->bilinterms[0].coef);
2425  }
2426  else
2427  {
2428  consdata->bilinsorted = consdata->bilinsorted
2429  && (bilinTermComp(consdata, consdata->nbilinterms-2, consdata->nbilinterms-1) <= 0);
2430  consdata->bilinmerged = FALSE;
2431  }
2432 
2433  consdata->iscurvchecked = FALSE;
2434 
2435  /* check if the bilinear terms are sorted */
2436  assert(consdataCheckBilinTermsSort(consdata));
2437 
2438  return SCIP_OKAY;
2439 }
2440 
2441 /** removes a set of bilinear terms and updates adjacency information in quad var terms
2442  *
2443  * Note: this function sorts the given array termposs.
2444  */
2445 static
2447  SCIP* scip, /**< SCIP data structure */
2448  SCIP_CONS* cons, /**< quadratic constraint */
2449  int nterms, /**< number of terms to delete */
2450  int* termposs /**< indices of terms to delete */
2451  )
2452 {
2453  SCIP_CONSDATA* consdata;
2454  int* newpos;
2455  int i;
2456  int j;
2457  int offset;
2458 
2459  assert(scip != NULL);
2460  assert(cons != NULL);
2461  assert(nterms == 0 || termposs != NULL);
2462 
2463  if( nterms == 0 )
2464  return SCIP_OKAY;
2465 
2466  consdata = SCIPconsGetData(cons);
2467  assert(consdata != NULL);
2468 
2469  SCIPsortInt(termposs, nterms);
2470 
2471  SCIP_CALL( SCIPallocBufferArray(scip, &newpos, consdata->nbilinterms) );
2472 
2473  i = 0;
2474  offset = 0;
2475  for( j = 0; j < consdata->nbilinterms; ++j )
2476  {
2477  /* if j'th term is deleted, increase offset and continue */
2478  if( i < nterms && j == termposs[i] )
2479  {
2480  ++offset;
2481  ++i;
2482  newpos[j] = -1;
2483  continue;
2484  }
2485 
2486  /* otherwise, move it forward and remember new position */
2487  if( offset > 0 )
2488  consdata->bilinterms[j-offset] = consdata->bilinterms[j];
2489  newpos[j] = j - offset;
2490  }
2491  assert(offset == nterms);
2492 
2493  /* update adjacency and activity information in quad var terms */
2494  for( i = 0; i < consdata->nquadvars; ++i )
2495  {
2496  offset = 0;
2497  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2498  {
2499  assert(consdata->quadvarterms[i].adjbilin[j] < consdata->nbilinterms);
2500  if( newpos[consdata->quadvarterms[i].adjbilin[j]] == -1 )
2501  {
2502  /* corresponding bilinear term was deleted, thus increase offset */
2503  ++offset;
2504  }
2505  else
2506  {
2507  /* update index of j'th bilinear term and store at position j-offset */
2508  consdata->quadvarterms[i].adjbilin[j-offset] = newpos[consdata->quadvarterms[i].adjbilin[j]];
2509  }
2510  }
2511  consdata->quadvarterms[i].nadjbilin -= offset;
2512  /* some bilinear term was removed, so invalidate activity bounds */
2513  }
2514 
2515  consdata->nbilinterms -= nterms;
2516 
2517  SCIPfreeBufferArray(scip, &newpos);
2518 
2519  /* some quad vars may be linear now */
2520  consdata->quadvarsmerged = FALSE;
2521 
2522  consdata->ispropagated = FALSE;
2523  consdata->ispresolved = FALSE;
2524  consdata->iscurvchecked = FALSE;
2525 
2526  /* invalidate activity */
2527  consdata->activity = SCIP_INVALID;
2528  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2529 
2530  /* invalidate nonlinear row */
2531  if( consdata->nlrow != NULL )
2532  {
2533  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2534  }
2535 
2536  return SCIP_OKAY;
2537 }
2538 
2539 /** merges quad var terms that correspond to the same variable and does additional cleanup
2540  *
2541  * If a quadratic variable terms is actually linear, makes a linear term out of it
2542  * also replaces squares of binary variables by the binary variables, i.e., adds sqrcoef to lincoef.
2543  */
2544 static
2546  SCIP* scip, /**< SCIP data structure */
2547  SCIP_CONS* cons /**< quadratic constraint */
2548  )
2549 {
2550  SCIP_QUADVARTERM* quadvarterm;
2551  SCIP_CONSDATA* consdata;
2552  int i;
2553  int j;
2554 
2555  assert(scip != NULL);
2556  assert(cons != NULL);
2557 
2558  consdata = SCIPconsGetData(cons);
2559 
2560  if( consdata->quadvarsmerged )
2561  return SCIP_OKAY;
2562 
2563  if( consdata->nquadvars == 0 )
2564  {
2565  consdata->quadvarsmerged = TRUE;
2566  return SCIP_OKAY;
2567  }
2568 
2569  i = 0;
2570  while( i < consdata->nquadvars )
2571  {
2572  /* make sure quad var terms are sorted (do this in every round, since we may move variables around) */
2573  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
2574 
2575  quadvarterm = &consdata->quadvarterms[i];
2576 
2577  for( j = i+1; j < consdata->nquadvars && consdata->quadvarterms[j].var == quadvarterm->var; ++j )
2578  {
2579  /* add quad var term j to current term i */
2580  quadvarterm->lincoef += consdata->quadvarterms[j].lincoef;
2581  quadvarterm->sqrcoef += consdata->quadvarterms[j].sqrcoef;
2582  if( consdata->quadvarterms[j].nadjbilin > 0 )
2583  {
2584  /* move adjacency information from j to i */
2585  SCIP_CALL( consdataEnsureAdjBilinSize(scip, quadvarterm, quadvarterm->nadjbilin + consdata->quadvarterms[j].nadjbilin) );
2586  BMScopyMemoryArray(&quadvarterm->adjbilin[quadvarterm->nadjbilin], consdata->quadvarterms[j].adjbilin, consdata->quadvarterms[j].nadjbilin); /*lint !e866*/
2587  quadvarterm->nadjbilin += consdata->quadvarterms[j].nadjbilin;
2588  consdata->quadvarterms[j].nadjbilin = 0;
2589  }
2590  consdata->quadvarterms[j].lincoef = 0.0;
2591  consdata->quadvarterms[j].sqrcoef = 0.0;
2592  /* mark that activity information in quadvarterm is not up to date anymore */
2593  }
2594 
2595  /* remove quad var terms i+1..j-1 backwards */
2596  for( j = j-1; j > i; --j )
2597  {
2598  SCIP_CALL( delQuadVarTermPos(scip, cons, j) );
2599  }
2600 
2601  /* for binary variables, x^2 = x
2602  * however, we may destroy convexity of a quadratic term that involves also bilinear terms
2603  * thus, we do this step only if the variable does not appear in any bilinear term */
2604  if( quadvarterm->sqrcoef != 0.0 && SCIPvarIsBinary(quadvarterm->var) && quadvarterm->nadjbilin == 0 )
2605  {
2606  SCIPdebugMessage("replace square of binary variable by itself: <%s>^2 --> <%s>\n", SCIPvarGetName(quadvarterm->var), SCIPvarGetName(quadvarterm->var));
2607  quadvarterm->lincoef += quadvarterm->sqrcoef;
2608  quadvarterm->sqrcoef = 0.0;
2609 
2610  /* invalidate nonlinear row */
2611  if( consdata->nlrow != NULL )
2612  {
2613  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2614  }
2615  }
2616 
2617  /* if its 0.0 or linear, get rid of it */
2618  if( SCIPisZero(scip, quadvarterm->sqrcoef) && quadvarterm->nadjbilin == 0 )
2619  {
2620  if( !SCIPisZero(scip, quadvarterm->lincoef) )
2621  {
2622  /* seem to be a linear term now, thus add as linear term */
2623  SCIP_CALL( addLinearCoef(scip, cons, quadvarterm->var, quadvarterm->lincoef) );
2624  }
2625  /* remove term at pos i */
2626  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2627  }
2628  else
2629  {
2630  ++i;
2631  }
2632  }
2633 
2634  consdata->quadvarsmerged = TRUE;
2635  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2636 
2637  return SCIP_OKAY;
2638 }
2639 
2640 /** merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
2641 static
2643  SCIP* scip, /**< SCIP data structure */
2644  SCIP_CONS* cons /**< quadratic constraint */
2645  )
2646 {
2647  SCIP_CONSDATA* consdata;
2648  SCIP_Real newcoef;
2649  int i;
2650  int j;
2651  int qvarpos;
2652 
2653  assert(scip != NULL);
2654  assert(cons != NULL);
2655 
2656  consdata = SCIPconsGetData(cons);
2657 
2658  if( consdata->linvarsmerged )
2659  return SCIP_OKAY;
2660 
2661  if( consdata->nlinvars == 0 )
2662  {
2663  consdata->linvarsmerged = TRUE;
2664  return SCIP_OKAY;
2665  }
2666 
2667  i = 0;
2668  while( i < consdata->nlinvars )
2669  {
2670  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
2671  consdataSortLinearVars(consdata);
2672 
2673  /* sum up coefficients that correspond to variable i */
2674  newcoef = consdata->lincoefs[i];
2675  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
2676  newcoef += consdata->lincoefs[j];
2677  /* delete the additional variables in backward order */
2678  for( j = j-1; j > i; --j )
2679  {
2680  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
2681  }
2682 
2683  /* check if there is already a quadratic variable term with this variable */
2684  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->linvars[i], &qvarpos) );
2685  if( qvarpos >= 0)
2686  {
2687  /* add newcoef to linear coefficient of quadratic variable and mark linear variable as to delete */
2688  assert(qvarpos < consdata->nquadvars);
2689  assert(consdata->quadvarterms[qvarpos].var == consdata->linvars[i]);
2690  consdata->quadvarterms[qvarpos].lincoef += newcoef;
2691  newcoef = 0.0;
2692  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2693  }
2694 
2695  /* delete also entry at position i, if it became zero (or was zero before) */
2696  if( SCIPisZero(scip, newcoef) )
2697  {
2698  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2699  }
2700  else
2701  {
2702  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
2703  ++i;
2704  }
2705  }
2706 
2707  consdata->linvarsmerged = TRUE;
2708 
2709  return SCIP_OKAY;
2710 }
2711 
2712 /** merges bilinear terms with same variables into a single term, removes bilinear terms with coefficient 0.0 */
2713 static
2715  SCIP* scip, /**< SCIP data structure */
2716  SCIP_CONS* cons /**< quadratic constraint */
2717  )
2718 {
2719  SCIP_CONSDATA* consdata;
2720  SCIP_BILINTERM* bilinterm;
2721  int i;
2722  int j;
2723  int* todelete;
2724  int ntodelete;
2725 
2726  assert(scip != NULL);
2727  assert(cons != NULL);
2728 
2729  consdata = SCIPconsGetData(cons);
2730 
2731  /* check if the bilinear terms are sorted */
2732  assert(consdataCheckBilinTermsSort(consdata));
2733 
2734  if( consdata->bilinmerged )
2735  return SCIP_OKAY;
2736 
2737  if( consdata->nbilinterms == 0 )
2738  {
2739  consdata->bilinmerged = TRUE;
2740  return SCIP_OKAY;
2741  }
2742 
2743  /* alloc memory for array of terms that need to be deleted finally */
2744  ntodelete = 0;
2745  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
2746 
2747  /* make sure bilinear terms are sorted */
2748  SCIP_CALL( consdataSortBilinTerms(scip, consdata) );
2749 
2750  i = 0;
2751  while( i < consdata->nbilinterms )
2752  {
2753  bilinterm = &consdata->bilinterms[i];
2754 
2755  /* sum up coefficients that correspond to same variables as term i */
2756  for( j = i+1; j < consdata->nbilinterms && bilinterm->var1 == consdata->bilinterms[j].var1 && bilinterm->var2 == consdata->bilinterms[j].var2; ++j )
2757  {
2758  bilinterm->coef += consdata->bilinterms[j].coef;
2759  todelete[ntodelete++] = j;
2760  }
2761 
2762  /* delete also entry at position i, if it became zero (or was zero before) */
2763  if( SCIPisZero(scip, bilinterm->coef) )
2764  {
2765  todelete[ntodelete++] = i;
2766  }
2767 
2768  /* continue with term after the current series */
2769  i = j;
2770  }
2771 
2772  /* delete bilinear terms */
2773  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
2774 
2775  SCIPfreeBufferArray(scip, &todelete);
2776 
2777  consdata->bilinmerged = TRUE;
2778 
2779  /* check if the bilinear terms are sorted */
2780  assert(consdataCheckBilinTermsSort(consdata));
2781 
2782  return SCIP_OKAY;
2783 }
2784 
2785 /** removes fixes (or aggregated) variables from a quadratic constraint */
2786 static
2788  SCIP* scip, /**< SCIP data structure */
2789  SCIP_CONS* cons /**< quadratic constraint */
2790  )
2791 {
2792  SCIP_CONSDATA* consdata;
2793  SCIP_BILINTERM* bilinterm;
2794  SCIP_Real coef;
2795  SCIP_Real offset;
2796  SCIP_VAR* var;
2797  SCIP_VAR* var2;
2798  int var2pos;
2799  int i;
2800  int j;
2801  int k;
2802 
2803  SCIP_Bool have_change;
2804 
2805  assert(scip != NULL);
2806  assert(cons != NULL);
2807 
2808  consdata = SCIPconsGetData(cons);
2809 
2810  have_change = FALSE;
2811  i = 0;
2812  while( i < consdata->nlinvars )
2813  {
2814  var = consdata->linvars[i];
2815 
2816  if( SCIPvarIsActive(var) )
2817  {
2818  ++i;
2819  continue;
2820  }
2821 
2822  have_change = TRUE;
2823 
2824  coef = consdata->lincoefs[i];
2825  offset = 0.0;
2826 
2827  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2828 
2829  SCIPdebugMessage(" linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]),
2830  coef, SCIPvarGetName(var), offset);
2831 
2832  /* delete previous variable (this will move another variable to position i) */
2833  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2834 
2835  /* put constant part into bounds */
2836  if( offset != 0.0 )
2837  {
2838  if( !SCIPisInfinity(scip, -consdata->lhs) )
2839  consdata->lhs -= offset;
2840  if( !SCIPisInfinity(scip, consdata->rhs) )
2841  consdata->rhs -= offset;
2842  }
2843 
2844  /* nothing left to do if variable had been fixed */
2845  if( coef == 0.0 )
2846  continue;
2847 
2848  /* if GetProbvar gave a linear variable, just add it
2849  * if it's a multilinear variable, add it's disaggregated variables */
2850  if( SCIPvarIsActive(var) )
2851  {
2852  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
2853  }
2854  else
2855  {
2856  int naggrs;
2857  SCIP_VAR** aggrvars;
2858  SCIP_Real* aggrscalars;
2859  SCIP_Real aggrconstant;
2860 
2861  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2862 
2863  naggrs = SCIPvarGetMultaggrNVars(var);
2864  aggrvars = SCIPvarGetMultaggrVars(var);
2865  aggrscalars = SCIPvarGetMultaggrScalars(var);
2866  aggrconstant = SCIPvarGetMultaggrConstant(var);
2867 
2868  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
2869 
2870  for( j = 0; j < naggrs; ++j )
2871  {
2872  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
2873  }
2874 
2875  if( aggrconstant != 0.0 )
2876  {
2877  if( !SCIPisInfinity(scip, -consdata->lhs) )
2878  consdata->lhs -= coef * aggrconstant;
2879  if( !SCIPisInfinity(scip, consdata->rhs) )
2880  consdata->rhs -= coef * aggrconstant;
2881  }
2882  }
2883  }
2884 
2885  i = 0;
2886  while( i < consdata->nquadvars )
2887  {
2888  var = consdata->quadvarterms[i].var;
2889 
2890  if( SCIPvarIsActive(var) )
2891  {
2892  ++i;
2893  continue;
2894  }
2895 
2896  have_change = TRUE;
2897 
2898  coef = 1.0;
2899  offset = 0.0;
2900  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2901 
2902  SCIPdebugMessage(" quadratic variable <%s> with status %d is replaced by %g * <%s> + %g\n", SCIPvarGetName(consdata->quadvarterms[i].var),
2903  SCIPvarGetStatus(consdata->quadvarterms[i].var), coef, SCIPvarGetName(var), offset);
2904 
2905  /* handle fixed variable */
2906  if( coef == 0.0 )
2907  {
2908  /* if not fixed to 0.0, add to linear coefs of vars in bilinear terms, and deal with linear and square term as constant */
2909  if( offset != 0.0 )
2910  {
2911  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2912  {
2913  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
2914 
2915  var2 = bilinterm->var1 == consdata->quadvarterms[i].var ? bilinterm->var2 : bilinterm->var1;
2916  assert(var2 != consdata->quadvarterms[i].var);
2917 
2918  var2pos = 0;
2919  while( consdata->quadvarterms[var2pos].var != var2 )
2920  {
2921  ++var2pos;
2922  assert(var2pos < consdata->nquadvars);
2923  }
2924  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2925  }
2926 
2927  offset = consdata->quadvarterms[i].lincoef * offset + consdata->quadvarterms[i].sqrcoef * offset * offset;
2928  if( !SCIPisInfinity(scip, -consdata->lhs) )
2929  consdata->lhs -= offset;
2930  if( !SCIPisInfinity(scip, consdata->rhs) )
2931  consdata->rhs -= offset;
2932  }
2933 
2934  /* remove bilinear terms */
2935  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
2936 
2937  /* delete quad. var term i */
2938  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2939 
2940  continue;
2941  }
2942 
2943  assert(var != NULL);
2944 
2945  /* if GetProbvar gave an active variable, replace the quad var term so that it uses the new variable */
2946  if( SCIPvarIsActive(var) )
2947  {
2948  /* replace x by coef*y+offset */
2949  SCIP_CALL( replaceQuadVarTermPos(scip, cons, i, var, coef, offset) );
2950 
2951  continue;
2952  }
2953  else
2954  {
2955  /* if GetProbVar gave a multi-aggregated variable, add new quad var terms and new bilinear terms
2956  * x is replaced by coef * (sum_i a_ix_i + b) + offset
2957  * lcoef * x + scoef * x^2 + bcoef * x * y ->
2958  * (b*coef + offset) * (lcoef + (b*coef + offset) * scoef)
2959  * + sum_i a_i*coef * (lcoef + 2 (b*coef + offset) * scoef) x_i
2960  * + sum_i (a_i*coef)^2 * scoef * x_i^2
2961  * + 2 sum_{i,j, i<j} (a_i a_j coef^2 scoef) x_i x_j
2962  * + bcoef * (b*coef + offset + coef * sum_i a_ix_i) y
2963  */
2964  int naggrs;
2965  SCIP_VAR** aggrvars; /* x_i */
2966  SCIP_Real* aggrscalars; /* a_i */
2967  SCIP_Real aggrconstant; /* b */
2968  int nquadtermsold;
2969 
2970  SCIP_Real lcoef;
2971  SCIP_Real scoef;
2972 
2973  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2974 
2975  naggrs = SCIPvarGetMultaggrNVars(var);
2976  aggrvars = SCIPvarGetMultaggrVars(var);
2977  aggrscalars = SCIPvarGetMultaggrScalars(var);
2978  aggrconstant = SCIPvarGetMultaggrConstant(var);
2979 
2980  lcoef = consdata->quadvarterms[i].lincoef;
2981  scoef = consdata->quadvarterms[i].sqrcoef;
2982 
2983  nquadtermsold = consdata->nquadvars;
2984 
2985  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars + naggrs) );
2986 
2987  /* take care of constant part */
2988  if( aggrconstant != 0.0 || offset != 0.0 )
2989  {
2990  SCIP_Real constant;
2991  constant = (aggrconstant * coef + offset) * (lcoef + (aggrconstant * coef + offset) * scoef);
2992  if( !SCIPisInfinity(scip, -consdata->lhs) )
2993  consdata->lhs -= constant;
2994  if( !SCIPisInfinity(scip, consdata->rhs) )
2995  consdata->rhs -= constant;
2996  }
2997 
2998  /* add x_i's with linear and square coefficients */
2999  for( j = 0; j < naggrs; ++j )
3000  {
3001  SCIP_CALL( addQuadVarTerm(scip, cons, aggrvars[j],
3002  coef * aggrscalars[j] * (lcoef + 2.0 * scoef * (coef * aggrconstant + offset)),
3003  coef * coef * aggrscalars[j] * aggrscalars[j] * scoef) );
3004  }
3005 
3006  /* ensure space for bilinear terms */
3007  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nquadvars + (scoef != 0.0 ? (naggrs * (naggrs-1))/2 : 0) + consdata->quadvarterms[j].nadjbilin * naggrs) );
3008 
3009  /* add x_j*x_k's */
3010  if( scoef != 0.0 )
3011  {
3012  for( j = 0; j < naggrs; ++j )
3013  for( k = 0; k < j; ++k )
3014  {
3015  assert(aggrvars[j] != aggrvars[k]);
3016  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, nquadtermsold + k,
3017  2.0 * aggrscalars[j] * aggrscalars[k] * coef * coef * scoef) );
3018  }
3019  }
3020 
3021  /* add x_i*y's */
3022  for( k = 0; k < consdata->quadvarterms[i].nadjbilin; ++k )
3023  {
3024  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[k]];
3025  var2 = (bilinterm->var1 == consdata->quadvarterms[i].var) ? bilinterm->var2 : bilinterm->var1;
3026  assert(var2 != consdata->quadvarterms[i].var);
3027 
3028  /* this is not efficient, but we cannot sort the quadratic terms here, since we currently iterate over them */
3029  var2pos = 0;
3030  while( consdata->quadvarterms[var2pos].var != var2 )
3031  {
3032  ++var2pos;
3033  assert(var2pos < consdata->nquadvars);
3034  }
3035 
3036  for( j = 0; j < naggrs; ++j )
3037  {
3038  if( aggrvars[j] == var2 )
3039  { /* x_i == y, so we have a square term here */
3040  consdata->quadvarterms[var2pos].sqrcoef += bilinterm->coef * coef * aggrscalars[j];
3041  }
3042  else
3043  { /* x_i != y, so we need to add a bilinear term here */
3044  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, var2pos, bilinterm->coef * coef * aggrscalars[j]) );
3045  }
3046  }
3047 
3048  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * (aggrconstant * coef + offset);
3049  }
3050 
3051  /* remove bilinear terms */
3052  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3053 
3054  /* delete quad. var term i */
3055  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3056  }
3057  }
3058 
3059  consdata->isremovedfixings = TRUE;
3060 
3061  SCIPdebugMessage("removed fixations from <%s>\n -> ", SCIPconsGetName(cons));
3062  SCIPdebugPrintCons(scip, cons, NULL);
3063 
3064 #ifndef NDEBUG
3065  for( i = 0; i < consdata->nlinvars; ++i )
3066  assert(SCIPvarIsActive(consdata->linvars[i]));
3067 
3068  for( i = 0; i < consdata->nquadvars; ++i )
3069  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
3070 #endif
3071 
3072  if( !have_change )
3073  return SCIP_OKAY;
3074 
3075  /* some quadratic variable may have been replaced by an already existing linear variable
3076  * in this case, we want the linear variable to be removed, which happens in mergeAndCleanLinearVars
3077  */
3078  consdata->linvarsmerged = FALSE;
3079 
3080  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
3081  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
3082  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
3083 
3084 #ifndef NDEBUG
3085  for( i = 0; i < consdata->nbilinterms; ++i )
3086  {
3087  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
3088  assert(consdata->bilinterms[i].coef != 0.0);
3089  assert(SCIPvarCompare(consdata->bilinterms[i].var1, consdata->bilinterms[i].var2) < 0);
3090  }
3091 #endif
3092 
3093  return SCIP_OKAY;
3094 }
3095 
3096 /** create a nonlinear row representation of the constraint and stores them in consdata */
3097 static
3099  SCIP* scip, /**< SCIP data structure */
3100  SCIP_CONS* cons /**< quadratic constraint */
3101  )
3102 {
3103  SCIP_CONSDATA* consdata;
3104  int nquadvars; /* number of variables in quadratic terms */
3105  SCIP_VAR** quadvars; /* variables in quadratic terms */
3106  int nquadelems; /* number of quadratic elements (square and bilinear terms) */
3107  SCIP_QUADELEM* quadelems; /* quadratic elements (square and bilinear terms) */
3108  int nquadlinterms; /* number of linear terms using variables that are in quadratic terms */
3109  SCIP_VAR** quadlinvars; /* variables of linear terms using variables that are in quadratic terms */
3110  SCIP_Real* quadlincoefs; /* coefficients of linear terms using variables that are in quadratic terms */
3111  int i;
3112  int idx1;
3113  int idx2;
3114  int lincnt;
3115  int elcnt;
3116  SCIP_VAR* lastvar;
3117  int lastvaridx;
3118 
3119  assert(scip != NULL);
3120  assert(cons != NULL);
3121 
3122  consdata = SCIPconsGetData(cons);
3123  assert(consdata != NULL);
3124 
3125  if( consdata->nlrow != NULL )
3126  {
3127  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3128  }
3129 
3130  nquadvars = consdata->nquadvars;
3131  nquadelems = consdata->nbilinterms;
3132  nquadlinterms = 0;
3133  for( i = 0; i < nquadvars; ++i )
3134  {
3135  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3136  ++nquadelems;
3137  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3138  ++nquadlinterms;
3139  }
3140 
3141  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, nquadvars) );
3142  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
3143  SCIP_CALL( SCIPallocBufferArray(scip, &quadlinvars, nquadlinterms) );
3144  SCIP_CALL( SCIPallocBufferArray(scip, &quadlincoefs, nquadlinterms) );
3145 
3146  lincnt = 0;
3147  elcnt = 0;
3148  for( i = 0; i < nquadvars; ++i )
3149  {
3150  quadvars[i] = consdata->quadvarterms[i].var;
3151 
3152  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3153  {
3154  assert(elcnt < nquadelems);
3155  quadelems[elcnt].idx1 = i;
3156  quadelems[elcnt].idx2 = i;
3157  quadelems[elcnt].coef = consdata->quadvarterms[i].sqrcoef;
3158  ++elcnt;
3159  }
3160 
3161  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3162  {
3163  assert(lincnt < nquadlinterms);
3164  quadlinvars [lincnt] = consdata->quadvarterms[i].var;
3165  quadlincoefs[lincnt] = consdata->quadvarterms[i].lincoef;
3166  ++lincnt;
3167  }
3168  }
3169  assert(lincnt == nquadlinterms);
3170 
3171  /* bilinear terms are sorted first by first variable, then by second variable
3172  * 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 */
3173  lastvar = NULL;
3174  lastvaridx = -1;
3175  for( i = 0; i < consdata->nbilinterms; ++i )
3176  {
3177  if( lastvar == consdata->bilinterms[i].var1 )
3178  {
3179  assert(lastvaridx >= 0);
3180  assert(consdata->quadvarterms[lastvaridx].var == consdata->bilinterms[i].var1);
3181  }
3182  else
3183  {
3184  lastvar = consdata->bilinterms[i].var1;
3185  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, lastvar, &lastvaridx) );
3186  }
3187  idx1 = lastvaridx;
3188 
3189  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &idx2) );
3190 
3191  assert(elcnt < nquadelems);
3192  quadelems[elcnt].idx1 = MIN(idx1, idx2);
3193  quadelems[elcnt].idx2 = MAX(idx1, idx2);
3194  quadelems[elcnt].coef = consdata->bilinterms[i].coef;
3195  ++elcnt;
3196  }
3197  assert(elcnt == nquadelems);
3198 
3199  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3200  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
3201  nquadvars, quadvars, nquadelems, quadelems,
3202  NULL, consdata->lhs, consdata->rhs) );
3203 
3204  SCIP_CALL( SCIPaddLinearCoefsToNlRow(scip, consdata->nlrow, nquadlinterms, quadlinvars, quadlincoefs) );
3205 
3206  SCIPfreeBufferArray(scip, &quadvars);
3207  SCIPfreeBufferArray(scip, &quadelems);
3208  SCIPfreeBufferArray(scip, &quadlinvars);
3209  SCIPfreeBufferArray(scip, &quadlincoefs);
3210 
3211  return SCIP_OKAY;
3212 }
3213 
3214 /** solve constraint as presolving */
3215 static
3217  SCIP* scip, /**< SCIP data structure */
3218  SCIP_CONS* cons, /**< constraint */
3219  SCIP_RESULT* result, /**< to store result of solve: cutoff, success, or do-not-find */
3220  SCIP_Bool* redundant, /**< to store whether constraint is redundant now (should be deleted) */
3221  int* naggrvars /**< counter on number of variable aggregations */
3222  )
3223 {
3224  SCIP_CONSDATA* consdata;
3225 
3226  assert(scip != NULL);
3227  assert(cons != NULL);
3228  assert(result != NULL);
3229  assert(redundant != NULL);
3230 
3231  *result = SCIP_DIDNOTFIND;
3232  *redundant = FALSE;
3233 
3234  consdata = SCIPconsGetData(cons);
3235  assert(consdata != NULL);
3236 
3237  /* if constraint is an equality with two variables, at least one of them binary,
3238  * and linear after fixing the binary, then we can aggregate the variables */
3239  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && consdata->nlinvars == 0 && consdata->nquadvars == 2 &&
3240  ((SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ||
3241  (SCIPvarIsBinary(consdata->quadvarterms[1].var) && consdata->quadvarterms[0].sqrcoef == 0.0)) )
3242  {
3243  SCIP_Bool infeasible;
3244  SCIP_Bool aggregated;
3245  SCIP_Real a;
3246  SCIP_Real b;
3247  SCIP_Real c;
3248  SCIP_VAR* x;
3249  SCIP_VAR* y;
3250  int binvaridx;
3251 
3252  /* constraint is a*(x+x^2) + b*y + c*x*y = rhs, with x binary variable
3253  * x = 0 -> b*y == rhs
3254  * x = 1 -> (b+c)*y == rhs - a
3255  *
3256  * 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
3257  */
3258 
3259  binvaridx = (SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ? 0 : 1;
3260 
3261  x = consdata->quadvarterms[binvaridx].var;
3262  a = consdata->quadvarterms[binvaridx].sqrcoef + consdata->quadvarterms[binvaridx].lincoef;
3263 
3264  y = consdata->quadvarterms[1-binvaridx].var;
3265  b = consdata->quadvarterms[1-binvaridx].lincoef;
3266 
3267  assert(consdata->nbilinterms <= 1); /* should actually be 1, since constraint is otherwise linear */
3268  c = (consdata->nbilinterms == 1) ? consdata->bilinterms[0].coef : 0.0;
3269 
3270  if( !SCIPisZero(scip, b) && !SCIPisZero(scip, b+c) )
3271  {
3272  SCIPdebugMessage("<%s> = 0 -> %g*<%s> = %g and <%s> = 1 -> %g*<%s> = %g\n", SCIPvarGetName(x), b, SCIPvarGetName(y), consdata->rhs,
3273  SCIPvarGetName(x), b+c, SCIPvarGetName(y), consdata->rhs - a);
3274  SCIPdebugMessage("=> attempt aggregation <%s> = %g*<%s> + %g\n", SCIPvarGetName(y), (consdata->rhs-a)/(b+c) - consdata->rhs/b,
3275  SCIPvarGetName(x), consdata->rhs/b);
3276 
3277  SCIP_CALL( SCIPaggregateVars(scip, x, y, (consdata->rhs-a)/(b+c) - consdata->rhs/b, -1.0, -consdata->rhs/b, &infeasible, redundant, &aggregated) );
3278  if( infeasible )
3279  *result = SCIP_CUTOFF;
3280  else if( *redundant || aggregated )
3281  {
3282  /* aggregated (or were already aggregated), so constraint is now redundant */
3283  *result = SCIP_SUCCESS;
3284  *redundant = TRUE;
3285 
3286  if( aggregated )
3287  ++*naggrvars;
3288  }
3289  }
3290 
3291  /* @todo if b is 0 or b+c is 0, or lhs != rhs, then could replace by varbound constraint */
3292  }
3293 
3294  return SCIP_OKAY;
3295 }
3296 
3297 
3298 /** reformulates products of binary variables as AND constraint
3299  *
3300  * 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.
3301  */
3302 static
3304  SCIP* scip, /**< SCIP data structure */
3305  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3306  SCIP_CONS* cons, /**< constraint */
3307  int* naddconss /**< buffer where to add the number of AND constraints added */
3308  )
3309 {
3310  SCIP_CONSHDLRDATA* conshdlrdata;
3311  SCIP_CONSDATA* consdata;
3312  char name[SCIP_MAXSTRLEN];
3313  SCIP_VAR* vars[2];
3314  SCIP_VAR* auxvar;
3315  SCIP_CONS* andcons;
3316  int i;
3317  int ntodelete;
3318  int* todelete;
3319 
3320  assert(scip != NULL);
3321  assert(conshdlr != NULL);
3322  assert(cons != NULL);
3323  assert(naddconss != NULL);
3324 
3325  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3326  assert(conshdlrdata != NULL);
3327 
3328  /* if user does not like AND very much, then return */
3329  if( conshdlrdata->empathy4and < 2 )
3330  return SCIP_OKAY;
3331 
3332  consdata = SCIPconsGetData(cons);
3333  assert(consdata != NULL);
3334 
3335  if( consdata->nbilinterms == 0 )
3336  return SCIP_OKAY;
3337 
3338  /* get array to store indices of bilinear terms that shall be deleted */
3339  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
3340  ntodelete = 0;
3341 
3342  for( i = 0; i < consdata->nbilinterms; ++i )
3343  {
3344  vars[0] = consdata->bilinterms[i].var1;
3345  if( !SCIPvarIsBinary(vars[0]) )
3346  continue;
3347 
3348  vars[1] = consdata->bilinterms[i].var2;
3349  if( !SCIPvarIsBinary(vars[1]) )
3350  continue;
3351 
3352  /* create auxiliary variable */
3353  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]), SCIPconsGetName(cons));
3354  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
3355  SCIPvarIsInitial(vars[0]) || SCIPvarIsInitial(vars[1]), SCIPvarIsRemovable(vars[0]) && SCIPvarIsRemovable(vars[1]), NULL, NULL, NULL, NULL, NULL) );
3356  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3357 #ifdef SCIP_DEBUG_SOLUTION
3358  if( SCIPdebugIsMainscip(scip) )
3359  {
3360  SCIP_Real var0val;
3361  SCIP_Real var1val;
3362  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[0], &var0val) );
3363  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[1], &var1val) );
3364  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3365  }
3366 #endif
3367 
3368  /* create AND-constraint auxvar = x and y, need to be enforced as not redundant */
3369  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3370  SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, auxvar, 2, vars,
3371  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3372  SCIPconsIsSeparated(cons), TRUE, TRUE,
3375  SCIP_CALL( SCIPaddCons(scip, andcons) );
3376  SCIPdebugMessage("added AND constraint: ");
3377  SCIPdebugPrintCons(scip, andcons, NULL);
3378  SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
3379  ++*naddconss;
3380 
3381  /* add bilincoef * auxvar to linear terms */
3382  SCIP_CALL( addLinearCoef(scip, cons, auxvar, consdata->bilinterms[i].coef) );
3383  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3384 
3385  /* remember that we have to delete this bilinear term */
3386  assert(ntodelete < consdata->nbilinterms);
3387  todelete[ntodelete++] = i;
3388  }
3389 
3390  /* remove bilinear terms that have been replaced */
3391  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3392  SCIPfreeBufferArray(scip, &todelete);
3393 
3394  return SCIP_OKAY;
3395 }
3396 
3397 /** gets bounds of variable y if x takes a certain value; checks whether x = xval has implications on y */
3398 static
3400  SCIP* scip, /**< SCIP data structure */
3401  SCIP_VAR* x, /**< variable which implications to check */
3402  SCIP_Bool xval, /**< value of x to check for (TRUE for 1, FALSE for 0) */
3403  SCIP_VAR* y, /**< variable to check if bounds can be reduced */
3404  SCIP_INTERVAL* resultant /**< buffer to store bounds on y */
3405  )
3406 {
3407  SCIP_VAR** implvars;
3408  SCIP_BOUNDTYPE* impltypes;
3409  SCIP_Real* implbounds;
3410  int nimpls;
3411  int pos;
3412 
3413  assert(scip != NULL);
3414  assert(x != NULL);
3415  assert(y != NULL);
3416  assert(resultant != NULL);
3417 
3419 
3420  if( !SCIPvarIsBinary(x) || !SCIPvarIsActive(x) )
3421  return SCIP_OKAY;
3422 
3423  /* check in cliques for binary to binary implications */
3424  if( SCIPvarIsBinary(y) )
3425  {
3426  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 0.0));
3427  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 1.0));
3428 
3429  if( SCIPhaveVarsCommonClique(scip, x, xval, y, TRUE, FALSE) )
3430  {
3431  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 0.0));
3432  }
3433  else if( SCIPhaveVarsCommonClique(scip, x, xval, y, FALSE, FALSE) )
3434  {
3435  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 1.0));
3436  }
3437 
3438  return SCIP_OKAY;
3439  }
3440 
3441  /* analyze implications for x = xval */
3442  nimpls = SCIPvarGetNImpls(x, xval);
3443  if( nimpls == 0 )
3444  return SCIP_OKAY;
3445 
3446  implvars = SCIPvarGetImplVars (x, xval);
3447  impltypes = SCIPvarGetImplTypes (x, xval);
3448  implbounds = SCIPvarGetImplBounds(x, xval);
3449 
3450  assert(implvars != NULL);
3451  assert(impltypes != NULL);
3452  assert(implbounds != NULL);
3453 
3454  /* find implications */
3455  if( !SCIPsortedvecFindPtr((void**)implvars, SCIPvarComp, (void*)y, nimpls, &pos) )
3456  return SCIP_OKAY;
3457 
3458  /* if there are several implications on y, go to the first one */
3459  while( pos > 0 && implvars[pos-1] == y )
3460  --pos;
3461 
3462  /* update implied lower and upper bounds on y
3463  * but make sure that resultant will not be empty, due to tolerances
3464  */
3465  while( pos < nimpls && implvars[pos] == y )
3466  {
3467  if( impltypes[pos] == SCIP_BOUNDTYPE_LOWER )
3468  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, implbounds[pos]));
3469  else
3470  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, implbounds[pos]));
3471  ++pos;
3472  }
3473 
3474  assert(resultant->sup >= resultant->inf);
3475 
3476  return SCIP_OKAY;
3477 }
3478 
3479 /** Reformulates products of binary times bounded continuous variables as system of linear inequalities (plus auxiliary variable).
3480  *
3481  * For a product x*y, with y a binary variable and x a continous variable with finite bounds,
3482  * 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.
3483  *
3484  * 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.
3485  * For each product of linear term of length at most maxnrvar with y, an auxiliary z and linear inequalities are added.
3486  *
3487  * If y is a binary variable, the AND constraint \f$ z = x \wedge y \f$ may be added instead of linear constraints.
3488  */
3489 static
3491  SCIP* scip, /**< SCIP data structure */
3492  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3493  SCIP_CONS* cons, /**< constraint */
3494  int* naddconss /**< buffer where to add the number of auxiliary constraints added */
3495  )
3496 { /*lint --e{666} */
3497  SCIP_CONSHDLRDATA* conshdlrdata;
3498  SCIP_CONSDATA* consdata;
3499  SCIP_VAR** xvars;
3500  SCIP_Real* xcoef;
3501  SCIP_INTERVAL xbndszero;
3502  SCIP_INTERVAL xbndsone;
3503  SCIP_INTERVAL act0;
3504  SCIP_INTERVAL act1;
3505  int nxvars;
3506  SCIP_VAR* y;
3507  SCIP_VAR* bvar;
3508  char name[SCIP_MAXSTRLEN];
3509  int nbilinterms;
3510  SCIP_VAR* auxvar;
3511  SCIP_CONS* auxcons;
3512  int i;
3513  int j;
3514  int k;
3515  int bilinidx;
3516  SCIP_Real bilincoef;
3517  SCIP_Real mincoef;
3518  SCIP_Real maxcoef;
3519  int* todelete;
3520  int ntodelete;
3521  int maxnrvar;
3522  SCIP_Bool integral;
3523  SCIP_Longint gcd;
3524  SCIP_Bool auxvarinitial;
3525  SCIP_Bool auxvarremovable;
3526 
3527  assert(scip != NULL);
3528  assert(conshdlr != NULL);
3529  assert(cons != NULL);
3530  assert(naddconss != NULL);
3531 
3532  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3533  assert(conshdlrdata != NULL);
3534 
3535  maxnrvar = conshdlrdata->replacebinaryprodlength;
3536  if( maxnrvar == 0 )
3537  return SCIP_OKAY;
3538 
3539  consdata = SCIPconsGetData(cons);
3540  assert(consdata != NULL);
3541 
3542  xvars = NULL;
3543  xcoef = NULL;
3544  todelete = NULL;
3545  gcd = 0;
3546 
3547  for( i = 0; i < consdata->nquadvars; ++i )
3548  {
3549  y = consdata->quadvarterms[i].var;
3550  if( !SCIPvarIsBinary(y) )
3551  continue;
3552 
3553  nbilinterms = consdata->quadvarterms[i].nadjbilin;
3554  if( nbilinterms == 0 )
3555  continue;
3556 
3557  SCIP_CALL( SCIPreallocBufferArray(scip, &xvars, MIN(maxnrvar, nbilinterms)+2) ); /* add 2 for later use when creating linear constraints */
3558  SCIP_CALL( SCIPreallocBufferArray(scip, &xcoef, MIN(maxnrvar, nbilinterms)+2) );
3559 
3560  /* alloc array to store indices of bilinear terms that shall be deleted */
3561  SCIP_CALL( SCIPreallocBufferArray(scip, &todelete, nbilinterms) );
3562  ntodelete = 0;
3563 
3564  auxvarinitial = SCIPvarIsInitial(y);
3565  auxvarremovable = SCIPvarIsRemovable(y);
3566 
3567  /* 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)
3568  * and compute range of sum_i a_i*x_i for the cases y = 0 and y = 1
3569  * we may need several rounds of maxnrvar < nbilinterms
3570  */
3571  j = 0;
3572  do
3573  {
3574  nxvars = 0;
3575  SCIPintervalSet(&xbndszero, 0.0);
3576  SCIPintervalSet(&xbndsone, 0.0);
3577 
3578  mincoef = SCIPinfinity(scip);
3579  maxcoef = 0.0;
3580  integral = TRUE;
3581 
3582  /* collect at most maxnrvar variables for x term */
3583  for( ; j < nbilinterms && nxvars < maxnrvar; ++j )
3584  {
3585  bilinidx = consdata->quadvarterms[i].adjbilin[j];
3586  assert(bilinidx >= 0);
3587  assert(bilinidx < consdata->nbilinterms);
3588 
3589  bvar = consdata->bilinterms[bilinidx].var1;
3590  if( bvar == y )
3591  bvar = consdata->bilinterms[bilinidx].var2;
3592  assert(bvar != y);
3593 
3594  /* skip products with unbounded variables */
3595  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(bvar)) || SCIPisInfinity(scip, SCIPvarGetUbGlobal(bvar)) )
3596  {
3597  SCIPdebugMessage("skip reform of <%s><%s> due to unbounded second variable [%g,%g]\n",
3599  continue;
3600  }
3601 
3602  bilincoef = consdata->bilinterms[bilinidx].coef;
3603  assert(bilincoef != 0.0);
3604 
3605  /* get activity of bilincoef * x if y = 0 */
3606  SCIP_CALL( getImpliedBounds(scip, y, FALSE, bvar, &act0) );
3607  SCIPintervalMulScalar(SCIPinfinity(scip), &act0, act0, bilincoef);
3608 
3609  /* get activity of bilincoef * x if y = 1 */
3610  SCIP_CALL( getImpliedBounds(scip, y, TRUE, bvar, &act1) );
3611  SCIPintervalMulScalar(SCIPinfinity(scip), &act1, act1, bilincoef);
3612 
3613  /* skip products that give rise to very large coefficients (big big-M's) */
3614  if( SCIPfeastol(scip) * REALABS(act0.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act0.sup) >= conshdlrdata->binreformmaxcoef )
3615  {
3616  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 0.0\n",
3617  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act0), SCIPintervalGetSup(act0), SCIPvarGetName(y));
3618  continue;
3619  }
3620  if( SCIPfeastol(scip) * REALABS(act1.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act1.sup) >= conshdlrdata->binreformmaxcoef )
3621  {
3622  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 1.0\n",
3623  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act1), SCIPintervalGetSup(act1), SCIPvarGetName(y));
3624  continue;
3625  }
3626  if( !SCIPisZero(scip, MIN(REALABS(act0.inf), REALABS(act0.sup))) &&
3627  SCIPfeastol(scip) * MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)) >= conshdlrdata->binreformmaxcoef )
3628  {
3629  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3630  MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)), SCIPvarGetName(y));
3631  continue;
3632  }
3633  if( !SCIPisZero(scip, MIN(REALABS(act1.inf), REALABS(act1.sup))) &&
3634  SCIPfeastol(scip) * MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)) >= conshdlrdata->binreformmaxcoef )
3635  {
3636  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3637  MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)), SCIPvarGetName(y));
3638  continue;
3639  }
3640 
3641  /* add bvar to x term */
3642  xvars[nxvars] = bvar;
3643  xcoef[nxvars] = bilincoef;
3644  ++nxvars;
3645 
3646  /* update bounds on x term */
3647  SCIPintervalAdd(SCIPinfinity(scip), &xbndszero, xbndszero, act0);
3648  SCIPintervalAdd(SCIPinfinity(scip), &xbndsone, xbndsone, act1);
3649 
3650  if( REALABS(bilincoef) < mincoef )
3651  mincoef = ABS(bilincoef);
3652  if( REALABS(bilincoef) > maxcoef )
3653  maxcoef = ABS(bilincoef);
3654 
3655  /* update whether all coefficients will be integral and if so, compute their gcd */
3656  integral &= (SCIPvarGetType(bvar) < SCIP_VARTYPE_CONTINUOUS) && SCIPisIntegral(scip, bilincoef); /*lint !e514 */
3657  if( integral )
3658  {
3659  if( nxvars == 1 )
3660  gcd = (SCIP_Longint)SCIPround(scip, REALABS(bilincoef));
3661  else
3662  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)SCIPround(scip, REALABS(bilincoef)));
3663  }
3664 
3665  /* if bvar is initial, then also the auxiliary variable should be initial
3666  * if bvar is not removable, then also the auxiliary variable should not be removable
3667  */
3668  auxvarinitial |= SCIPvarIsInitial(bvar);
3669  auxvarremovable &= SCIPvarIsRemovable(bvar);
3670 
3671  /* remember that we have to remove this bilinear term later */
3672  assert(ntodelete < nbilinterms);
3673  todelete[ntodelete++] = bilinidx;
3674  }
3675 
3676  if( nxvars == 0 ) /* all (remaining) x_j seem to be unbounded */
3677  break;
3678 
3679  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndszero)));
3680  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndszero)));
3681  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndsone)));
3682  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndsone)));
3683 
3684 #ifdef SCIP_DEBUG
3685  if( SCIPintervalGetInf(xbndszero) != SCIPintervalGetInf(xbndsone) || /*lint !e777*/
3686  +SCIPintervalGetSup(xbndszero) != SCIPintervalGetSup(xbndsone) ) /*lint !e777*/
3687  {
3688  SCIPdebugMessage("got different bounds for y = 0: [%g, %g] and y = 1: [%g, %g]\n", xbndszero.inf, xbndszero.sup, xbndsone.inf, xbndsone.sup);
3689  }
3690 #endif
3691 
3692  if( nxvars == 1 && conshdlrdata->empathy4and >= 1 && SCIPvarIsBinary(xvars[0]) )
3693  {
3694  /* product of two binary variables, replace by auxvar and AND constraint */
3695  /* add auxiliary variable z */
3696  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3697  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT,
3698  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3699  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3700 
3701 #ifdef SCIP_DEBUG_SOLUTION
3702  if( SCIPdebugIsMainscip(scip) )
3703  {
3704  SCIP_Real var0val;
3705  SCIP_Real var1val;
3706  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[0], &var0val) );
3707  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &var1val) );
3708  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3709  }
3710 #endif
3711 
3712  /* add constraint z = x and y; need to be enforced, as it is not redundant w.r.t. existing constraints */
3713  xvars[1] = y;
3714  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3715  SCIP_CALL( SCIPcreateConsAnd(scip, &auxcons, name, auxvar, 2, xvars,
3716  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3717  SCIPconsIsSeparated(cons), TRUE, TRUE,
3720  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3721  SCIPdebugMessage("added AND constraint: ");
3722  SCIPdebugPrintCons(scip, auxcons, NULL);
3723  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3724  ++*naddconss;
3725 
3726  /* add linear term coef*auxvar */
3727  SCIP_CALL( addLinearCoef(scip, cons, auxvar, xcoef[0]) );
3728 
3729  /* forget about auxvar */
3730  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3731  }
3732  else
3733  {
3734  /* product of binary variable with more than one binary or with continuous variables or with binary and user
3735  * did not like AND -> replace by auxvar and linear constraints */
3736  SCIP_Real scale;
3737 
3738  /* scale auxiliary constraint by some nice value,
3739  * if all coefficients are integral, take a value that preserves integrality (-> gcd), so we can make the auxiliary variable impl. integer
3740  */
3741  if( integral )
3742  {
3743  scale = (SCIP_Real)gcd;
3744  assert(scale >= 1.0);
3745  }
3746  else if( nxvars == 1 )
3747  {
3748  /* scaling by the only coefficient gives auxiliary variable = x * y, which thus will be implicit integral provided y is not continuous */
3749  assert(mincoef == maxcoef); /*lint !e777 */
3750  scale = mincoef;
3751  integral = SCIPvarGetType(xvars[0]) < SCIP_VARTYPE_CONTINUOUS;
3752  }
3753  else
3754  {
3755  scale = 1.0;
3756  if( maxcoef < 0.5 )
3757  scale = maxcoef;
3758  if( mincoef > 2.0 )
3759  scale = mincoef;
3760  if( scale != 1.0 )
3761  scale = SCIPselectSimpleValue(scale / 2.0, 1.5 * scale, MAXDNOM);
3762  }
3763  assert(scale > 0.0);
3764  assert(!SCIPisInfinity(scip, scale));
3765 
3766  /* if x-term is always negative for y = 1, negate scale so we get a positive auxiliary variable; maybe this is better sometimes? */
3767  if( !SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3768  scale = -scale;
3769 
3770  SCIPdebugMessage("binary reformulation using scale %g, nxvars = %d, integral = %u\n", scale, nxvars, integral);
3771  if( scale != 1.0 )
3772  {
3773  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndszero, xbndszero, scale);
3774  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndsone, xbndsone, scale);
3775  for( k = 0; k < nxvars; ++k )
3776  xcoef[k] /= scale;
3777  }
3778 
3779  /* add auxiliary variable z */
3780  if( nxvars == 1 )
3781  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3782  else
3783  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_more_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3784  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, MIN(0., SCIPintervalGetInf(xbndsone)), MAX(0., SCIPintervalGetSup(xbndsone)),
3786  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3787  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3788 
3789  /* compute value of auxvar in debug solution */
3790 #ifdef SCIP_DEBUG_SOLUTION
3791  if( SCIPdebugIsMainscip(scip) )
3792  {
3793  SCIP_Real debugval;
3794  SCIP_Real varval;
3795 
3796  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &varval) );
3797  if( SCIPisZero(scip, varval) )
3798  {
3799  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, 0.0) );
3800  }
3801  else
3802  {
3803  assert(SCIPisEQ(scip, varval, 1.0));
3804 
3805  debugval = 0.0;
3806  for( k = 0; k < nxvars; ++k )
3807  {
3808  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[k], &varval) );
3809  debugval += xcoef[k] * varval;
3810  }
3811  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
3812  }
3813  }
3814 #endif
3815 
3816  /* add auxiliary constraints
3817  * it seems to be advantageous to make the varbound constraints initial and the linear constraints not initial
3818  * maybe because it is more likely that a binary variable takes value 0 instead of 1, and thus the varbound constraints
3819  * are more often active, compared to the linear constraints added below
3820  * also, the varbound constraints are more sparse than the linear cons
3821  */
3822  if( SCIPisNegative(scip, SCIPintervalGetInf(xbndsone)) )
3823  {
3824  /* add 0 <= z - xbndsone.inf * y constraint (as varbound constraint), need to be enforced as not redundant */
3825  if( nxvars == 1 )
3826  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3827  else
3828  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3829  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetInf(xbndsone), 0.0, SCIPinfinity(scip),
3830  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3831  SCIPconsIsSeparated(cons), TRUE, TRUE,
3834  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3835  SCIPdebugMessage("added varbound constraint: ");
3836  SCIPdebugPrintCons(scip, auxcons, NULL);
3837  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3838  ++*naddconss;
3839  }
3840  if( SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3841  {
3842  /* add z - xbndsone.sup * y <= 0 constraint (as varbound constraint), need to be enforced as not redundant */
3843  if( nxvars == 1 )
3844  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3845  else
3846  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3847  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetSup(xbndsone), -SCIPinfinity(scip), 0.0,
3848  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3849  SCIPconsIsSeparated(cons), TRUE, TRUE,
3852  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3853  SCIPdebugMessage("added varbound constraint: ");
3854  SCIPdebugPrintCons(scip, auxcons, NULL);
3855  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3856  ++*naddconss;
3857  }
3858 
3859  /* add xbndszero.inf <= sum_i a_i*x_i + xbndszero.inf * y - z constraint, need to be enforced as not redundant */
3860  xvars[nxvars] = y;
3861  xvars[nxvars+1] = auxvar;
3862  xcoef[nxvars] = SCIPintervalGetInf(xbndszero);
3863  xcoef[nxvars+1] = -1;
3864 
3865  if( nxvars == 1 )
3866  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3867  else
3868  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3869  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, SCIPintervalGetInf(xbndszero), SCIPinfinity(scip),
3870  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3871  SCIPconsIsSeparated(cons), TRUE, TRUE,
3874  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3875  SCIPdebugMessage("added linear constraint: ");
3876  SCIPdebugPrintCons(scip, auxcons, NULL);
3877  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3878  ++*naddconss;
3879 
3880  /* add sum_i a_i*x_i + xbndszero.sup * y - z <= xbndszero.sup constraint, need to be enforced as not redundant */
3881  xcoef[nxvars] = SCIPintervalGetSup(xbndszero);
3882 
3883  if( nxvars == 1 )
3884  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3885  else
3886  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3887  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, -SCIPinfinity(scip), SCIPintervalGetSup(xbndszero),
3888  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3889  SCIPconsIsSeparated(cons), TRUE, TRUE,
3892  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3893  SCIPdebugMessage("added linear constraint: ");
3894  SCIPdebugPrintCons(scip, auxcons, NULL);
3895  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3896  ++*naddconss;
3897 
3898  /* add linear term scale*auxvar to this constraint */
3899  SCIP_CALL( addLinearCoef(scip, cons, auxvar, scale) );
3900 
3901  /* forget about auxvar */
3902  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3903  }
3904  }
3905  while( j < nbilinterms );
3906 
3907  /* remove bilinear terms that have been replaced */
3908  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3909  }
3910  SCIPdebugMessage("resulting quadratic constraint: ");
3911  SCIPdebugPrintCons(scip, cons, NULL);
3912 
3913  SCIPfreeBufferArrayNull(scip, &xvars);
3914  SCIPfreeBufferArrayNull(scip, &xcoef);
3915  SCIPfreeBufferArrayNull(scip, &todelete);
3916 
3917  return SCIP_OKAY;
3918 }
3919 
3920 /** tries to automatically convert a quadratic constraint (or a part of it) into a more specific and more specialized constraint */
3921 static
3923  SCIP* scip, /**< SCIP data structure */
3924  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
3925  SCIP_CONS* cons, /**< source constraint to try to convert */
3926  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
3927  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
3928  int* naddconss, /**< buffer to increase with number of additional constraints created during upgrade */
3929  SCIP_PRESOLTIMING presoltiming /**< current presolving timing */
3930  )
3931 {
3932  SCIP_CONSHDLRDATA* conshdlrdata;
3933  SCIP_CONSDATA* consdata;
3934  SCIP_VAR* var;
3935  SCIP_Real lincoef;
3936  SCIP_Real quadcoef;
3937  SCIP_Real lb;
3938  SCIP_Real ub;
3939  int nbinlin;
3940  int nbinquad;
3941  int nintlin;
3942  int nintquad;
3943  int nimpllin;
3944  int nimplquad;
3945  int ncontlin;
3946  int ncontquad;
3947  SCIP_Bool integral;
3948  int i;
3949  int j;
3950  SCIP_CONS** upgdconss;
3951  int upgdconsssize;
3952  int nupgdconss_;
3953 
3954  assert(scip != NULL);
3955  assert(conshdlr != NULL);
3956  assert(cons != NULL);
3957  assert(!SCIPconsIsModifiable(cons));
3958  assert(upgraded != NULL);
3959  assert(nupgdconss != NULL);
3960  assert(naddconss != NULL);
3961 
3962  *upgraded = FALSE;
3963 
3964  nupgdconss_ = 0;
3965 
3966  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3967  assert(conshdlrdata != NULL);
3968 
3969  /* if there are no upgrade methods, we can also stop */
3970  if( conshdlrdata->nquadconsupgrades == 0 )
3971  return SCIP_OKAY;
3972 
3973  upgdconsssize = 2;
3974  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
3975 
3976  consdata = SCIPconsGetData(cons);
3977  assert(consdata != NULL);
3978 
3979  /* calculate some statistics on quadratic constraint */
3980  nbinlin = 0;
3981  nbinquad = 0;
3982  nintlin = 0;
3983  nintquad = 0;
3984  nimpllin = 0;
3985  nimplquad = 0;
3986  ncontlin = 0;
3987  ncontquad = 0;
3988  integral = TRUE;
3989  for( i = 0; i < consdata->nlinvars; ++i )
3990  {
3991  var = consdata->linvars[i];
3992  lincoef = consdata->lincoefs[i];
3993  lb = SCIPvarGetLbLocal(var);
3994  ub = SCIPvarGetUbLocal(var);
3995  assert(!SCIPisZero(scip, lincoef));
3996 
3997  switch( SCIPvarGetType(var) )
3998  {
3999  case SCIP_VARTYPE_BINARY:
4000  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4001  integral = integral && SCIPisIntegral(scip, lincoef);
4002  nbinlin++;
4003  break;
4004  case SCIP_VARTYPE_INTEGER:
4005  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4006  integral = integral && SCIPisIntegral(scip, lincoef);
4007  nintlin++;
4008  break;
4009  case SCIP_VARTYPE_IMPLINT:
4010  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4011  integral = integral && SCIPisIntegral(scip, lincoef);
4012  nimpllin++;
4013  break;
4015  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb);
4016  ncontlin++;
4017  break;
4018  default:
4019  SCIPerrorMessage("unknown variable type\n");
4020  return SCIP_INVALIDDATA;
4021  }
4022  }
4023 
4024  for( i = 0; i < consdata->nquadvars; ++i )
4025  {
4026  var = consdata->quadvarterms[i].var;
4027  lincoef = consdata->quadvarterms[i].lincoef;
4028  quadcoef = consdata->quadvarterms[i].sqrcoef;
4029  lb = SCIPvarGetLbLocal(var);
4030  ub = SCIPvarGetUbLocal(var);
4031 
4032  switch( SCIPvarGetType(var) )
4033  {
4034  case SCIP_VARTYPE_BINARY:
4035  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4036  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4037  nbinquad++;
4038  break;
4039  case SCIP_VARTYPE_INTEGER:
4040  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4041  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4042  nintquad++;
4043  break;
4044  case SCIP_VARTYPE_IMPLINT:
4045  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4046  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4047  nimplquad++;
4048  break;
4050  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb + quadcoef * lb * lb);
4051  ncontquad++;
4052  break;
4053  default:
4054  SCIPerrorMessage("unknown variable type\n");
4055  return SCIP_INVALIDDATA;
4056  }
4057  }
4058 
4059  if( integral )
4060  {
4061  for( i = 0; i < consdata->nbilinterms && integral; ++i )
4062  {
4063  if( SCIPvarGetType(consdata->bilinterms[i].var1) < SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->bilinterms[i].var2) < SCIP_VARTYPE_CONTINUOUS )
4064  integral = integral && SCIPisIntegral(scip, consdata->bilinterms[i].coef);
4065  else
4066  integral = FALSE;
4067  }
4068  }
4069 
4070  /* call the upgrading methods */
4071 
4072  SCIPdebugMessage("upgrading quadratic constraint <%s> (%d upgrade methods):\n",
4073  SCIPconsGetName(cons), conshdlrdata->nquadconsupgrades);
4074  SCIPdebugMessage(" binlin=%d binquad=%d intlin=%d intquad=%d impllin=%d implquad=%d contlin=%d contquad=%d integral=%u\n",
4075  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral);
4076  SCIPdebugPrintCons(scip, cons, NULL);
4077 
4078  /* try all upgrading methods in priority order in case the upgrading step is enable */
4079  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
4080  {
4081  if( !conshdlrdata->quadconsupgrades[i]->active )
4082  continue;
4083 
4084  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4085  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4086  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4087 
4088  while( nupgdconss_ < 0 )
4089  {
4090  /* upgrade function requires more memory: resize upgdconss and call again */
4091  assert(-nupgdconss_ > upgdconsssize);
4092  upgdconsssize = -nupgdconss_;
4093  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
4094 
4095  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4096  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4097  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4098 
4099  assert(nupgdconss_ != 0);
4100  }
4101 
4102  if( nupgdconss_ > 0 )
4103  {
4104  /* got upgrade */
4105  SCIPdebugPrintCons(scip, cons, NULL);
4106  SCIPdebugMessage(" -> upgraded to %d constraints:\n", nupgdconss_);
4107 
4108  /* add the upgraded constraints to the problem and forget them */
4109  for( j = 0; j < nupgdconss_; ++j )
4110  {
4111  SCIPdebugPrintf("\t");
4112  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
4113 
4114  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
4115  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
4116  }
4117 
4118  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
4119  *nupgdconss += 1;
4120  *naddconss += nupgdconss_ - 1;
4121  *upgraded = TRUE;
4122 
4123  /* delete upgraded constraint */
4124  SCIPdebugMessage("delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
4125  SCIP_CALL( SCIPdelCons(scip, cons) );
4126 
4127  break;
4128  }
4129  }
4130 
4131  SCIPfreeBufferArray(scip, &upgdconss);
4132 
4133  return SCIP_OKAY;
4134 }
4135 
4136 /** helper function for presolveDisaggregate */
4137 static
4139  SCIP* scip, /**< SCIP data structure */
4140  SCIP_CONSDATA* consdata, /**< constraint data */
4141  int quadvaridx, /**< index of quadratic variable to mark */
4142  SCIP_HASHMAP* var2component, /**< variables to components mapping */
4143  int componentnr /**< the component number to mark to */
4144  )
4145 {
4146  SCIP_QUADVARTERM* quadvarterm;
4147  SCIP_VAR* othervar;
4148  int othervaridx;
4149  int i;
4150 
4151  assert(consdata != NULL);
4152  assert(quadvaridx >= 0);
4153  assert(quadvaridx < consdata->nquadvars);
4154  assert(var2component != NULL);
4155  assert(componentnr >= 0);
4156 
4157  quadvarterm = &consdata->quadvarterms[quadvaridx];
4158 
4159  if( SCIPhashmapExists(var2component, quadvarterm->var) )
4160  {
4161  /* if we saw the variable before, then it should have the same component number */
4162  assert((int)(size_t)SCIPhashmapGetImage(var2component, quadvarterm->var) == componentnr);
4163  return SCIP_OKAY;
4164  }
4165 
4166  /* assign component number to variable */
4167  SCIP_CALL( SCIPhashmapInsert(var2component, quadvarterm->var, (void*)(size_t)componentnr) );
4168 
4169  /* assign same component number to all variables this variable is multiplied with */
4170  for( i = 0; i < quadvarterm->nadjbilin; ++i )
4171  {
4172  othervar = consdata->bilinterms[quadvarterm->adjbilin[i]].var1 == quadvarterm->var ?
4173  consdata->bilinterms[quadvarterm->adjbilin[i]].var2 : consdata->bilinterms[quadvarterm->adjbilin[i]].var1;
4174  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, othervar, &othervaridx) );
4175  assert(othervaridx >= 0);
4176  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, othervaridx, var2component, componentnr) );
4177  }
4178 
4179  return SCIP_OKAY;
4180 }
4181 
4182 /** for quadratic constraints that consists of a sum of quadratic terms, disaggregates the sum into a set of constraints by introducing auxiliary variables */
4183 static
4185  SCIP* scip, /**< SCIP data structure */
4186  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4187  SCIP_CONS* cons, /**< source constraint to try to convert */
4188  int* naddconss /**< pointer to counter of added constraints */
4189  )
4190 {
4191  SCIP_CONSDATA* consdata;
4192  SCIP_HASHMAP* var2component;
4193  int ncomponents;
4194  int i;
4195  int comp;
4196  SCIP_CONS** auxconss;
4197  SCIP_VAR** auxvars;
4198  SCIP_Real* auxcoefs;
4199  char name[SCIP_MAXSTRLEN];
4200 
4201  assert(scip != NULL);
4202  assert(conshdlr != NULL);
4203  assert(cons != NULL);
4204  assert(naddconss != NULL);
4205 
4206  consdata = SCIPconsGetData(cons);
4207  assert(consdata != NULL);
4208 
4209  /* make sure there are no quadratic variables without coefficients */
4210  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4211  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
4212 
4213  if( consdata->nquadvars <= 1 )
4214  return SCIP_OKAY;
4215 
4216  /* sort quadratic variable terms here, so we can later search in it without reordering the array */
4217  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4218 
4219  /* check how many quadratic terms with non-overlapping variables we have
4220  * in other words, the number of components in the sparsity graph of the quadratic term matrix */
4221  ncomponents = 0;
4222  SCIP_CALL( SCIPhashmapCreate(&var2component, SCIPblkmem(scip), SCIPcalcHashtableSize(consdata->nquadvars)) );
4223  for( i = 0; i < consdata->nquadvars; ++i )
4224  {
4225  /* if variable was marked already, skip it */
4226  if( SCIPhashmapExists(var2component, (void*)consdata->quadvarterms[i].var) )
4227  continue;
4228 
4229  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, i, var2component, ncomponents) );
4230  ++ncomponents;
4231  }
4232  assert(ncomponents >= 1);
4233 
4234  /* if there is only one component, we cannot disaggregate
4235  * @todo we could still split the constraint into several while keeping the number of variables sharing several constraints as small as possible
4236  */
4237  if( ncomponents == 1 )
4238  {
4239  SCIPhashmapFree(&var2component);
4240  return SCIP_OKAY;
4241  }
4242 
4243  SCIP_CALL( SCIPallocBufferArray(scip, &auxconss, ncomponents) );
4244  SCIP_CALL( SCIPallocBufferArray(scip, &auxvars, ncomponents) );
4245  SCIP_CALL( SCIPallocBufferArray(scip, &auxcoefs, ncomponents) );
4246 
4247  /* create auxiliary variables and empty constraints for each component */
4248  for( comp = 0; comp < ncomponents; ++comp )
4249  {
4250  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp%d", SCIPconsGetName(cons), comp);
4251 
4252  SCIP_CALL( SCIPcreateVar(scip, &auxvars[comp], name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
4254 
4255  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &auxconss[comp], name, 0, NULL, NULL, 0, NULL, 0, NULL,
4256  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : 0.0),
4257  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : 0.0),
4260  SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons)) );
4261 
4262  auxcoefs[comp] = SCIPinfinity(scip);
4263  }
4264 
4265  /* add quadratic variables to each component constraint
4266  * delete adjacency information */
4267  for( i = 0; i < consdata->nquadvars; ++i )
4268  {
4269  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->quadvarterms[i].var);
4270  assert(comp >= 0);
4271  assert(comp < ncomponents);
4272 
4273  /* add variable term to corresponding constraint */
4274  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, auxconss[comp], consdata->quadvarterms[i].var, consdata->quadvarterms[i].lincoef, consdata->quadvarterms[i].sqrcoef) );
4275 
4276  /* reduce coefficient of aux variable */
4277  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) && ABS(consdata->quadvarterms[i].lincoef) < auxcoefs[comp] )
4278  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].lincoef);
4279  if( !SCIPisZero(scip, consdata->quadvarterms[i].sqrcoef) && ABS(consdata->quadvarterms[i].sqrcoef) < auxcoefs[comp] )
4280  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].sqrcoef);
4281 
4282  SCIPfreeBlockMemoryArray(scip, &consdata->quadvarterms[i].adjbilin, consdata->quadvarterms[i].adjbilinsize);
4283  consdata->quadvarterms[i].nadjbilin = 0;
4284  consdata->quadvarterms[i].adjbilinsize = 0;
4285  }
4286 
4287  /* add bilinear terms to each component constraint */
4288  for( i = 0; i < consdata->nbilinterms; ++i )
4289  {
4290  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var1);
4291  assert(comp == (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var2));
4292  assert(!SCIPisZero(scip, consdata->bilinterms[i].coef));
4293 
4294  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, auxconss[comp],
4295  consdata->bilinterms[i].var1, consdata->bilinterms[i].var2, consdata->bilinterms[i].coef) );
4296 
4297  if( ABS(consdata->bilinterms[i].coef) < auxcoefs[comp] )
4298  auxcoefs[comp] = ABS(consdata->bilinterms[i].coef);
4299  }
4300 
4301  /* forget about bilinear terms in cons */
4302  SCIPfreeBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize);
4303  consdata->nbilinterms = 0;
4304  consdata->bilintermssize = 0;
4305 
4306  /* remove quadratic variable terms from cons */
4307  for( i = consdata->nquadvars - 1; i >= 0; --i )
4308  {
4309  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
4310  }
4311  assert(consdata->nquadvars == 0);
4312 
4313  /* add auxiliary variables to auxiliary constraints
4314  * add aux vars and constraints to SCIP
4315  * add aux vars to this constraint
4316  * @todo compute debug solution values and set for auxvars
4317  */
4318  SCIPdebugMessage("add %d constraints for disaggregation of quadratic constraint <%s>\n", ncomponents, SCIPconsGetName(cons));
4319  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + ncomponents) );
4320  for( comp = 0; comp < ncomponents; ++comp )
4321  {
4322  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, auxconss[comp], auxvars[comp], -auxcoefs[comp]) );
4323 
4324  SCIP_CALL( SCIPaddVar(scip, auxvars[comp]) );
4325 
4326  SCIP_CALL( SCIPaddCons(scip, auxconss[comp]) );
4327  SCIPdebugPrintCons(scip, auxconss[comp], NULL);
4328 
4329  SCIP_CALL( addLinearCoef(scip, cons, auxvars[comp], auxcoefs[comp]) );
4330 
4331  SCIP_CALL( SCIPreleaseCons(scip, &auxconss[comp]) );
4332  SCIP_CALL( SCIPreleaseVar(scip, &auxvars[comp]) );
4333  }
4334  *naddconss += ncomponents;
4335 
4336  SCIPdebugPrintCons(scip, cons, NULL);
4337 
4338  SCIPfreeBufferArray(scip, &auxconss);
4339  SCIPfreeBufferArray(scip, &auxvars);
4340  SCIPfreeBufferArray(scip, &auxcoefs);
4341  SCIPhashmapFree(&var2component);
4342 
4343  return SCIP_OKAY;
4344 }
4345 
4346 #ifdef CHECKIMPLINBILINEAR
4347 /** checks if there are bilinear terms x*y with a binary variable x and an implication x = {0,1} -> y = 0
4348  *
4349  * In this case, the bilinear term can be removed (x=0 case) or replaced by y (x=1 case).
4350  */
4351 static
4352 SCIP_RETCODE presolveApplyImplications(
4353  SCIP* scip, /**< SCIP data structure */
4354  SCIP_CONS* cons, /**< quadratic constraint */
4355  int* nbilinremoved /**< buffer to store number of removed bilinear terms */
4356  )
4357 {
4358  SCIP_CONSDATA* consdata;
4359  SCIP_VAR* x;
4360  SCIP_VAR* y;
4361  SCIP_INTERVAL implbnds;
4362  int i;
4363  int j;
4364  int k;
4365 
4366  assert(scip != NULL);
4367  assert(cons != NULL);
4368  assert(nbilinremoved != NULL);
4369 
4370  *nbilinremoved = 0;
4371 
4372  consdata = SCIPconsGetData(cons);
4373  assert(consdata != NULL);
4374 
4375  SCIPdebugMessage("apply implications in <%s>\n", SCIPconsGetName(cons));
4376 
4377  /* sort quadvarterms in case we need to search */
4378  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4379 
4380  for( i = 0; i < consdata->nquadvars; ++i )
4381  {
4382  x = consdata->quadvarterms[i].var;
4383  assert(x != NULL);
4384 
4385  if( consdata->quadvarterms[i].nadjbilin == 0 )
4386  continue;
4387 
4388  if( !SCIPvarIsBinary(x) )
4389  continue;
4390 
4391  if( !SCIPvarIsActive(x) )
4392  continue;
4393 
4394  if( SCIPvarGetNImpls(x, TRUE) == 0 && SCIPvarGetNImpls(x, FALSE) == 0 )
4395  continue;
4396 
4397  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4398  {
4399  k = consdata->quadvarterms[i].adjbilin[j];
4400  assert(k >= 0);
4401  assert(k < consdata->nbilinterms);
4402 
4403  if( consdata->bilinterms[k].coef == 0.0 )
4404  continue;
4405 
4406  y = consdata->bilinterms[k].var1 == x ? consdata->bilinterms[k].var2 : consdata->bilinterms[k].var1;
4407  assert(x != y);
4408 
4409  SCIP_CALL( getImpliedBounds(scip, x, TRUE, y, &implbnds) );
4410  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4411  {
4412  /* if x = 1 implies y = 0, then we can remove the bilinear term x*y, since it is always 0
4413  * we only set the coefficient to 0.0 here and mark the bilinterms as not merged */
4414  SCIPdebugMessage("remove bilinear term %g<%s><%s> from <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), SCIPconsGetName(cons));
4415  consdata->bilinterms[k].coef = 0.0;
4416  consdata->bilinmerged = FALSE;
4417  ++*nbilinremoved;
4418  continue;
4419  }
4420 
4421  SCIP_CALL( getImpliedBounds(scip, x, FALSE, y, &implbnds) );
4422  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4423  {
4424  /* if x = 0 implies y = 0, then we can replace the bilinear term x*y by y
4425  * we only move the coefficient to the linear coef of y here and mark the bilinterms as not merged */
4426  SCIPdebugMessage("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));
4427  assert(consdata->quadvarssorted);
4428  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, cons, y, consdata->bilinterms[k].coef) );
4429  consdata->bilinterms[k].coef = 0.0;
4430  consdata->bilinmerged = FALSE;
4431  ++*nbilinremoved;
4432  }
4433  }
4434  }
4435 
4436  if( *nbilinremoved > 0 )
4437  {
4438  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4439 
4440  /* invalidate nonlinear row */
4441  if( consdata->nlrow != NULL )
4442  {
4443  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4444  }
4445 
4446  consdata->ispropagated = FALSE;
4447  consdata->ispresolved = FALSE;
4448  consdata->iscurvchecked = FALSE;
4449  }
4450 
4451  consdata->isimpladded = FALSE;
4452 
4453  return SCIP_OKAY;
4454 }
4455 #endif
4456 
4457 /** checks a quadratic constraint for convexity and/or concavity without checking multivariate functions */
4458 static
4459 void checkCurvatureEasy(
4460  SCIP* scip, /**< SCIP data structure */
4461  SCIP_CONS* cons, /**< quadratic constraint */
4462  SCIP_Bool* determined, /**< pointer to store whether the curvature could be determined */
4463  SCIP_Bool checkmultivariate /**< whether curvature will be checked later on for multivariate functions */
4464  )
4465 {
4466  SCIP_CONSDATA* consdata;
4467  int nquadvars;
4468 
4469  assert(scip != NULL);
4470  assert(cons != NULL);
4471  assert(determined != NULL);
4472 
4473  consdata = SCIPconsGetData(cons);
4474  assert(consdata != NULL);
4475 
4476  nquadvars = consdata->nquadvars;
4477  *determined = TRUE;
4478 
4479  if( consdata->iscurvchecked )
4480  return;
4481 
4482  SCIPdebugMessage("Checking curvature of constraint <%s> without multivariate functions\n", SCIPconsGetName(cons));
4483 
4484  if( nquadvars == 1 )
4485  {
4486  assert(consdata->nbilinterms == 0);
4487  consdata->isconvex = !SCIPisNegative(scip, consdata->quadvarterms[0].sqrcoef);
4488  consdata->isconcave = !SCIPisPositive(scip, consdata->quadvarterms[0].sqrcoef);
4489  consdata->iscurvchecked = TRUE;
4490  }
4491  else if( nquadvars == 0 )
4492  {
4493  consdata->isconvex = TRUE;
4494  consdata->isconcave = TRUE;
4495  consdata->iscurvchecked = TRUE;
4496  }
4497  else if( consdata->nbilinterms == 0 )
4498  {
4499  int v;
4500 
4501  consdata->isconvex = TRUE;
4502  consdata->isconcave = TRUE;
4503 
4504  for( v = nquadvars - 1; v >= 0; --v )
4505  {
4506  consdata->isconvex = consdata->isconvex && !SCIPisNegative(scip, consdata->quadvarterms[v].sqrcoef);
4507  consdata->isconcave = consdata->isconcave && !SCIPisPositive(scip, consdata->quadvarterms[v].sqrcoef);
4508  }
4509 
4510  consdata->iscurvchecked = TRUE;
4511  }
4512  else if( !checkmultivariate )
4513  {
4514  consdata->isconvex = FALSE;
4515  consdata->isconcave = FALSE;
4516  consdata->iscurvchecked = TRUE;
4517  }
4518  else
4519  *determined = FALSE;
4520 }
4521 
4522 /** checks a quadratic constraint for convexity and/or concavity */
4523 static
4525  SCIP* scip, /**< SCIP data structure */
4526  SCIP_CONS* cons, /**< quadratic constraint */
4527  SCIP_Bool checkmultivariate /**< whether curvature should also be checked for multivariate functions */
4528  )
4529 {
4530  SCIP_CONSDATA* consdata;
4531  double* matrix;
4532  SCIP_HASHMAP* var2index;
4533  int i;
4534  int n;
4535  int nn;
4536  int row;
4537  int col;
4538  double* alleigval;
4539  SCIP_Bool determined;
4540 
4541  assert(scip != NULL);
4542  assert(cons != NULL);
4543 
4544  consdata = SCIPconsGetData(cons);
4545  assert(consdata != NULL);
4546 
4547  n = consdata->nquadvars;
4548 
4549  if( consdata->iscurvchecked )
4550  return SCIP_OKAY;
4551 
4552  /* easy checks for curvature detection */
4553  checkCurvatureEasy(scip, cons, &determined, checkmultivariate);
4554 
4555  /* if curvature was already detected stop */
4556  if( determined )
4557  {
4558  return SCIP_OKAY;
4559  }
4560 
4561  SCIPdebugMessage("Checking curvature of constraint <%s> with multivariate functions\n", SCIPconsGetName(cons));
4562 
4563  if( n == 2 )
4564  {
4565  /* compute eigenvalues by hand */
4566  assert(consdata->nbilinterms == 1);
4567  consdata->isconvex =
4568  consdata->quadvarterms[0].sqrcoef >= 0 &&
4569  consdata->quadvarterms[1].sqrcoef >= 0 &&
4570  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4571  consdata->isconcave =
4572  consdata->quadvarterms[0].sqrcoef <= 0 &&
4573  consdata->quadvarterms[1].sqrcoef <= 0 &&
4574  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4575 
4576  consdata->iscurvchecked = TRUE;
4577  return SCIP_OKAY;
4578  }
4579 
4580  /* do not check curvature if n is too large */
4581  nn = n * n;
4582  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
4583  {
4584  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "cons_quadratic - n is too large to check the curvature\n");
4585  consdata->isconvex = FALSE;
4586  consdata->isconcave = FALSE;
4587  consdata->iscurvchecked = TRUE;
4588  return SCIP_OKAY;
4589  }
4590 
4591  /* lower triangular of quadratic term matrix */
4592  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, nn) );
4593  BMSclearMemoryArray(matrix, nn);
4594 
4595  consdata->isconvex = TRUE;
4596  consdata->isconcave = TRUE;
4597 
4598  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * n)) );
4599  for( i = 0; i < n; ++i )
4600  {
4601  if( consdata->quadvarterms[i].nadjbilin > 0 )
4602  {
4603  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
4604  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4605  }
4606  /* nonzero elements on diagonal tell a lot about convexity/concavity */
4607  if( SCIPisNegative(scip, consdata->quadvarterms[i].sqrcoef) )
4608  consdata->isconvex = FALSE;
4609  if( SCIPisPositive(scip, consdata->quadvarterms[i].sqrcoef) )
4610  consdata->isconcave = FALSE;
4611  }
4612 
4613  if( !consdata->isconvex && !consdata->isconcave )
4614  {
4615  SCIPfreeBufferArray(scip, &matrix);
4616  SCIPhashmapFree(&var2index);
4617  consdata->iscurvchecked = TRUE;
4618  return SCIP_OKAY;
4619  }
4620 
4622  {
4623  for( i = 0; i < consdata->nbilinterms; ++i )
4624  {
4625  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
4626  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
4627  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
4628  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
4629  if( row < col )
4630  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
4631  else
4632  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
4633  }
4634 
4635  SCIP_CALL( SCIPallocBufferArray(scip, &alleigval, n) );
4636  /* @todo Can we compute only min and max eigen value?
4637  * @todo Can we estimate the numerical error?
4638  * @todo Trying a cholesky factorization may be much faster.
4639  */
4640  if( LapackDsyev(FALSE, n, matrix, alleigval) != SCIP_OKAY )
4641  {
4642  SCIPwarningMessage(scip, "Failed to compute eigenvalues of quadratic coefficient matrix of constraint %s. Assuming matrix is indefinite.\n", SCIPconsGetName(cons));
4643  consdata->isconvex = FALSE;
4644  consdata->isconcave = FALSE;
4645  }
4646  else
4647  {
4648  /* deconvexification reformulates a stricly convex quadratic function in binaries such that it becomes not-strictly convex
4649  * by adding the -lambda*(x^2-x) terms for lambda the smallest eigenvalue of the matrix
4650  * 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
4651  */
4652 #ifdef DECONVEXIFY
4653  SCIP_Bool allbinary;
4654  printf("cons <%s>[%g,%g] spectrum = [%g,%g]\n", SCIPconsGetName(cons), consdata->lhs, consdata->rhs, alleigval[0], alleigval[n-1]);
4655 #endif
4656  consdata->isconvex &= !SCIPisNegative(scip, alleigval[0]); /*lint !e514*/
4657  consdata->isconcave &= !SCIPisPositive(scip, alleigval[n-1]); /*lint !e514*/
4658  consdata->iscurvchecked = TRUE;
4659 #ifdef DECONVEXIFY
4660  for( i = 0; i < consdata->nquadvars; ++i )
4661  if( !SCIPvarIsBinary(consdata->quadvarterms[i].var) )
4662  break;
4663  allbinary = i == consdata->nquadvars;
4664 
4665  if( !SCIPisInfinity(scip, consdata->rhs) && alleigval[0] > 0.1 && allbinary )
4666  {
4667  printf("deconvexify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[0]);
4668  for( i = 0; i < consdata->nquadvars; ++i )
4669  {
4670  consdata->quadvarterms[i].sqrcoef -= alleigval[0];
4671  consdata->quadvarterms[i].lincoef += alleigval[0];
4672  }
4673  }
4674 
4675  if( !SCIPisInfinity(scip, consdata->lhs) && alleigval[n-1] < -0.1 && allbinary )
4676  {
4677  printf("deconcavify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[n-1]);
4678  for( i = 0; i < consdata->nquadvars; ++i )
4679  {
4680  consdata->quadvarterms[i].sqrcoef -= alleigval[n-1];
4681  consdata->quadvarterms[i].lincoef += alleigval[n-1];
4682  }
4683  }
4684 #endif
4685  }
4686 
4687  SCIPfreeBufferArray(scip, &alleigval);
4688  }
4689  else
4690  {
4691  consdata->isconvex = FALSE;
4692  consdata->isconcave = FALSE;
4693  consdata->iscurvchecked = TRUE; /* set to TRUE since it does not help to repeat this procedure again and again (that will not bring Ipopt in) */
4694  }
4695 
4696  SCIPhashmapFree(&var2index);
4697  SCIPfreeBufferArray(scip, &matrix);
4698 
4699  return SCIP_OKAY;
4700 }
4701 
4702 /** check whether indefinite constraint function is factorable and store corresponding coefficients */
4703 static
4705  SCIP* scip, /**< SCIP data structure */
4706  SCIP_CONS* cons /**< constraint */
4707  )
4708 {
4709  SCIP_BILINTERM* bilinterm;
4710  SCIP_CONSDATA* consdata;
4711  SCIP_Real* a;
4712  SCIP_Real* eigvals;
4713  SCIP_Real sigma1;
4714  SCIP_Real sigma2;
4715  SCIP_Bool success;
4716  int n;
4717  int i;
4718  int idx1;
4719  int idx2;
4720  int posidx;
4721  int negidx;
4722 
4723  assert(scip != NULL);
4724  assert(cons != NULL);
4725 
4726  consdata = SCIPconsGetData(cons);
4727  assert(consdata != NULL);
4728  assert(consdata->factorleft == NULL);
4729  assert(consdata->factorright == NULL);
4730 
4731  /* we don't need this if there are no bilinear terms */
4732  if( consdata->nbilinterms == 0 )
4733  return SCIP_OKAY;
4734 
4735  /* write constraint as lhs <= linear + x'^T A x' <= rhs where x' = (x,1) and
4736  * A = ( Q b/2 )
4737  * ( b^T/2 0 )
4738  * compute an eigenvalue factorization of A and check if there are one positive and one negative eigenvalue
4739  * 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
4740  * thus, x'^T A x' = sigma1^2 (v1^T x')^2 - sigma2^2 (v2^T x')^2
4741  * = (sigma1 (v1^T x') - sigma2 (v2^T x')) * (sigma1 (v1^T x') + sigma2 (v2^T x'))
4742  * we then store sigma1 v1^T - sigma2 v2^T as left factor coef, and sigma1 v1^T + sigma2 v2^T as right factor coef
4743  */
4744 
4745  /* if we already know that there are only positive or only negative eigenvalues, then don't try */
4746  if( consdata->iscurvchecked && (consdata->isconvex || consdata->isconcave) )
4747  return SCIP_OKAY;
4748 
4749  n = consdata->nquadvars + 1;
4750 
4751  /* @todo handle case n=3 explicitly */
4752 
4753  /* skip too large matrices */
4754  if( n > 50 )
4755  return SCIP_OKAY;
4756 
4757  /* need routine to compute eigenvalues/eigenvectors */
4758  if( !SCIPisIpoptAvailableIpopt() )
4759  return SCIP_OKAY;
4760 
4761  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4762 
4763  SCIP_CALL( SCIPallocBufferArray(scip, &a, n*n) );
4764  BMSclearMemoryArray(a, n*n);
4765 
4766  /* set lower triangular entries of A corresponding to bilinear terms */
4767  for( i = 0; i < consdata->nbilinterms; ++i )
4768  {
4769  bilinterm = &consdata->bilinterms[i];
4770 
4771  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4772  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4773  assert(idx1 >= 0);
4774  assert(idx2 >= 0);
4775  assert(idx1 != idx2);
4776 
4777  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
4778  }
4779 
4780  /* set lower triangular entries of A corresponding to square and linear terms */
4781  for( i = 0; i < consdata->nquadvars; ++i )
4782  {
4783  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4784  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
4785  }
4786 
4787  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, n) );
4788  if( LapackDsyev(TRUE, n, a, eigvals) != SCIP_OKAY )
4789  {
4790  SCIPdebugMessage("Failed to compute eigenvalues and eigenvectors of augmented quadratic form matrix for constraint <%s>.\n", SCIPconsGetName(cons));
4791  goto CLEANUP;
4792  }
4793 
4794  /* check if there is exactly one positive and one negative eigenvalue */
4795  posidx = -1;
4796  negidx = -1;
4797  for( i = 0; i < n; ++i )
4798  {
4799  if( SCIPisPositive(scip, eigvals[i]) )
4800  {
4801  if( posidx == -1 )
4802  posidx = i;
4803  else
4804  break;
4805  }
4806  else if( SCIPisNegative(scip, eigvals[i]) )
4807  {
4808  if( negidx == -1 )
4809  negidx = i;
4810  else
4811  break;
4812  }
4813  }
4814  if( i < n || posidx == -1 || negidx == -1 )
4815  {
4816  SCIPdebugMessage("Augmented quadratic form of constraint <%s> is not factorable.\n", SCIPconsGetName(cons));
4817  goto CLEANUP;
4818  }
4819  assert(SCIPisPositive(scip, eigvals[posidx]));
4820  assert(SCIPisNegative(scip, eigvals[negidx]));
4821 
4822  /* compute factorleft and factorright */
4823  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1) );
4824  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1) );
4825 
4826  /* eigenvectors are stored in a, inverse eigenvector matrix is transposed of a
4827  * it seems that v1 and v2 are at &a[posidx*n] and &a[negidx*n]
4828  */
4829  sigma1 = sqrt( eigvals[posidx]);
4830  sigma2 = sqrt(-eigvals[negidx]);
4831  for( i = 0; i < n; ++i )
4832  {
4833  consdata->factorleft[i] = sigma1 * a[posidx * n + i] - sigma2 * a[negidx * n + i];
4834  consdata->factorright[i] = sigma1 * a[posidx * n + i] + sigma2 * a[negidx * n + i];
4835  /* set almost-zero elements to zero */
4836  if( SCIPisZero(scip, consdata->factorleft[i]) )
4837  consdata->factorleft[i] = 0.0;
4838  if( SCIPisZero(scip, consdata->factorright[i]) )
4839  consdata->factorright[i] = 0.0;
4840  }
4841 
4842 #ifdef SCIP_DEBUG
4843  SCIPdebugMessage("constraint <%s> has factorable quadratic form: (%g", SCIPconsGetName(cons), consdata->factorleft[n-1]);
4844  for( i = 0; i < consdata->nquadvars; ++i )
4845  {
4846  if( consdata->factorleft[i] != 0.0 )
4847  SCIPdebugPrintf(" %+g<%s>", consdata->factorleft[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4848  }
4849  SCIPdebugPrintf(") * (%g", consdata->factorright[n-1]);
4850  for( i = 0; i < consdata->nquadvars; ++i )
4851  {
4852  if( consdata->factorright[i] != 0.0 )
4853  SCIPdebugPrintf(" %+g<%s>", consdata->factorright[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4854  }
4855  SCIPdebugPrintf(")\n");
4856 #endif
4857 
4858  /* check whether factorleft * factorright^T is matrix of augmented quadratic form
4859  * we check here only the nonzero entries from the quadratic form
4860  */
4861  success = TRUE;
4862 
4863  /* check 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 
4871  if( !SCIPisRelEQ(scip, consdata->factorleft[idx1] * consdata->factorright[idx2] + consdata->factorleft[idx2] * consdata->factorright[idx1], bilinterm->coef) )
4872  {
4873  success = FALSE;
4874  break;
4875  }
4876  }
4877 
4878  /* set lower triangular entries of A corresponding to square and linear terms */
4879  for( i = 0; i < consdata->nquadvars; ++i )
4880  {
4881  if( !SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[i], consdata->quadvarterms[i].sqrcoef) )
4882  {
4883  success = FALSE;
4884  break;
4885  }
4886 
4887  if( !SCIPisRelEQ(scip, consdata->factorleft[n-1] * consdata->factorright[i] + consdata->factorleft[i] * consdata->factorright[n-1], consdata->quadvarterms[i].lincoef) )
4888  {
4889  success = FALSE;
4890  break;
4891  }
4892  }
4893 
4894  if( !success )
4895  {
4896  SCIPdebugMessage("Factorization not accurate enough. Dropping it.\n");
4897  SCIPfreeBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1);
4898  SCIPfreeBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1);
4899  }
4900 
4901  CLEANUP:
4902  SCIPfreeBufferArray(scip, &a);
4903  SCIPfreeBufferArray(scip, &eigvals);
4904 
4905  return SCIP_OKAY;
4906 }
4907 
4908 /** gets maximal absolute value in gradient of quadratic function */
4909 static
4911  SCIP* scip, /**< SCIP data structure */
4912  SCIP_CONS* cons, /**< constraint */
4913  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
4914  )
4915 {
4916  SCIP_CONSDATA* consdata;
4917  SCIP_Real maxelem;
4918  SCIP_Real g;
4919  int i, j, k;
4920  SCIP_VAR* var;
4921 
4922  assert(scip != NULL);
4923  assert(cons != NULL);
4924 
4925  consdata = SCIPconsGetData(cons);
4926  assert(consdata != NULL);
4927 
4928  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
4929  {
4930  maxelem = 0.0;
4931  for( i = 0; i < consdata->nlinvars; ++i )
4932  if( REALABS(consdata->lincoefs[i]) > maxelem )
4933  maxelem = REALABS(consdata->lincoefs[i]);
4934  }
4935  else
4936  maxelem = consdata->lincoefsmax;
4937 
4938  for( i = 0; i < consdata->nquadvars; ++i )
4939  {
4940  var = consdata->quadvarterms[i].var;
4941  assert(!SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)));
4942  assert(!SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)));
4943  g = consdata->quadvarterms[i].lincoef;
4944  g += 2.0 * consdata->quadvarterms[i].sqrcoef * SCIPgetSolVal(scip, sol, var);
4945  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4946  {
4947  k = consdata->quadvarterms[i].adjbilin[j];
4948  if( consdata->bilinterms[k].var1 == var )
4949  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var2);
4950  else
4951  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var1);
4952  }
4953  if( REALABS(g) > maxelem )
4954  maxelem = REALABS(g);
4955  }
4956 
4957  return maxelem;
4958 }
4959 
4960 /** computes activity and violation of a constraint */
4961 static
4963  SCIP* scip, /**< SCIP data structure */
4964  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4965  SCIP_CONS* cons, /**< constraint */
4966  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
4967  )
4968 { /*lint --e{666}*/
4969  SCIP_CONSHDLRDATA* conshdlrdata;
4970  SCIP_CONSDATA* consdata;
4971  SCIP_Real varval;
4972  SCIP_Real varval2;
4973  SCIP_VAR* var;
4974  SCIP_VAR* var2;
4975  int i;
4976  int j;
4977 
4978  assert(scip != NULL);
4979  assert(cons != NULL);
4980 
4981  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4982  assert(conshdlrdata != NULL);
4983 
4984  consdata = SCIPconsGetData(cons);
4985  assert(consdata != NULL);
4986 
4987  consdata->activity = 0.0;
4988  varval = 0.0;
4989 
4990  /* @todo Take better care of variables at +/- infinity: e.g., run instance waste in debug mode with a short timelimit (30s). */
4991  for( i = 0; i < consdata->nlinvars; ++i )
4992  {
4993  var = consdata->linvars[i];
4994  varval = SCIPgetSolVal(scip, sol, var);
4995 
4996  if( SCIPisInfinity(scip, REALABS(varval)) )
4997  {
4998  consdata->activity = SCIPinfinity(scip);
4999  if( !SCIPisInfinity(scip, -consdata->lhs) )
5000  consdata->lhsviol = SCIPinfinity(scip);
5001  if( !SCIPisInfinity(scip, consdata->rhs) )
5002  consdata->rhsviol = SCIPinfinity(scip);
5003  return SCIP_OKAY;
5004  }
5005 
5006  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5007  if( sol == NULL )
5008  {
5009  /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case
5010  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
5011  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
5012  */
5013  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5014  }
5015 
5016  consdata->activity += consdata->lincoefs[i] * varval;
5017  }
5018 
5019  for( j = 0; j < consdata->nquadvars; ++j )
5020  {
5021  var = consdata->quadvarterms[j].var;
5022  varval = SCIPgetSolVal(scip, sol, var);
5023  if( SCIPisInfinity(scip, REALABS(varval)) )
5024  {
5025  consdata->activity = SCIPinfinity(scip);
5026  if( !SCIPisInfinity(scip, -consdata->lhs) )
5027  consdata->lhsviol = SCIPinfinity(scip);
5028  if( !SCIPisInfinity(scip, consdata->rhs) )
5029  consdata->rhsviol = SCIPinfinity(scip);
5030  return SCIP_OKAY;
5031  }
5032 
5033  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5034  if( sol == NULL )
5035  {
5036  /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case
5037  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
5038  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
5039  */
5040  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5041  }
5042 
5043  consdata->activity += (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5044  }
5045 
5046  for( j = 0; j < consdata->nbilinterms; ++j )
5047  {
5048  var = consdata->bilinterms[j].var1;
5049  var2 = consdata->bilinterms[j].var2;
5050  varval = SCIPgetSolVal(scip, sol, var);
5051  varval2 = SCIPgetSolVal(scip, sol, var2);
5052 
5053  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5054  if( sol == NULL )
5055  {
5056 #if 0 /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case */
5057  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
5058  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
5059 #endif
5060  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5061 
5062 #if 0 /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case */
5063  assert(SCIPisFeasGE(scip, varval2, SCIPvarGetLbLocal(var2)));
5064  assert(SCIPisFeasLE(scip, varval2, SCIPvarGetUbLocal(var2)));
5065 #endif
5066  varval2 = MAX(SCIPvarGetLbLocal(var2), MIN(SCIPvarGetUbLocal(var2), varval2));
5067  }
5068 
5069  consdata->activity += consdata->bilinterms[j].coef * varval * varval2;
5070  }
5071 
5072  /* compute absolute violation left hand side */
5073  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
5074  consdata->lhsviol = consdata->lhs - consdata->activity;
5075  else
5076  consdata->lhsviol = 0.0;
5077 
5078  /* compute absolute violation right hand side */
5079  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
5080  consdata->rhsviol = consdata->activity - consdata->rhs;
5081  else
5082  consdata->rhsviol = 0.0;
5083 
5084  switch( conshdlrdata->scaling )
5085  {
5086  case 'o' :
5087  /* no scaling */
5088  break;
5089 
5090  case 'g' :
5091  /* scale by sup-norm of gradient in current point */
5092  if( consdata->lhsviol > 0.0 || consdata->rhsviol > 0.0 )
5093  {
5094  SCIP_Real norm;
5095  norm = getGradientMaxElement(scip, cons, sol);
5096  if( norm > 1.0 )
5097  {
5098  consdata->lhsviol /= norm;
5099  consdata->rhsviol /= norm;
5100  }
5101  }
5102  break;
5103 
5104  case 's' :
5105  /* scale by left/right hand side of constraint */
5106  if( consdata->lhsviol > 0.0 )
5107  consdata->lhsviol /= MAX(1.0, REALABS(consdata->lhs));
5108 
5109  if( consdata->rhsviol > 0.0 )
5110  consdata->rhsviol /= MAX(1.0, REALABS(consdata->rhs));
5111 
5112  break;
5113 
5114  default :
5115  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
5116  SCIPABORT();
5117  return SCIP_INVALIDDATA; /*lint !e527*/
5118  }
5119 
5120  return SCIP_OKAY;
5121 }
5122 
5123 /** computes violation of a set of constraints */
5124 static
5126  SCIP* scip, /**< SCIP data structure */
5127  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5128  SCIP_CONS** conss, /**< constraints */
5129  int nconss, /**< number of constraints */
5130  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5131  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
5132  )
5133 {
5134  SCIP_CONSDATA* consdata;
5135  SCIP_Real viol;
5136  SCIP_Real maxviol;
5137  int c;
5138 
5139  assert(scip != NULL);
5140  assert(conss != NULL || nconss == 0);
5141  assert(maxviolcon != NULL);
5142 
5143  *maxviolcon = NULL;
5144 
5145  maxviol = 0.0;
5146 
5147  for( c = 0; c < nconss; ++c )
5148  {
5149  assert(conss != NULL);
5150  assert(conss[c] != NULL);
5151 
5152  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
5153 
5154  consdata = SCIPconsGetData(conss[c]);
5155  assert(consdata != NULL);
5156 
5157  viol = MAX(consdata->lhsviol, consdata->rhsviol);
5158  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
5159  {
5160  maxviol = viol;
5161  *maxviolcon = conss[c];
5162  }
5163  }
5164 
5165  return SCIP_OKAY;
5166 }
5167 
5168 /** tries to compute cut for multleft * <coefleft, x'> * multright <= rhs / (multright * <coefright, x'>) where x'=(x,1) */
5169 static
5171  SCIP* scip, /**< SCIP data structure */
5172  SCIP_CONS* cons, /**< constraint */
5173  SCIP_Real* ref, /**< reference solution where to generate the cut */
5174  SCIP_Real multleft, /**< multiplicator on lhs */
5175  SCIP_Real* coefleft, /**< coefficient for factor on lhs */
5176  SCIP_Real multright, /**< multiplicator on both sides */
5177  SCIP_Real* coefright, /**< coefficient for factor that goes to rhs */
5178  SCIP_Real rightminactivity, /**< minimal activity of <coefright, x> */
5179  SCIP_Real rightmaxactivity, /**< maximal activity of <coefright, x> */
5180  SCIP_Real rhs, /**< denominator on rhs */
5181  SCIP_Real* cutcoef, /**< array to store cut coefficients for quadratic variables */
5182  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5183  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5184  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5185  char* name /**< buffer to store name of cut */
5186  )
5187 {
5188  SCIP_CONSDATA* consdata;
5189  SCIP_Real constant;
5190  int i;
5191 
5192  assert(cutcoef != NULL);
5193  assert(rightminactivity * multright > 0.0);
5194  assert(rightmaxactivity * multright > 0.0);
5195  assert(multright == 1.0 || multright == -1.0);
5196 
5197  consdata = SCIPconsGetData(cons);
5198  assert(consdata != NULL);
5199 
5200  if( rhs > 0.0 )
5201  {
5202  /* if rhs > 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need secant:
5203  * 1 / multright*<coefright, x'> <= 1/minact + 1/maxact - 1/(minact * maxact) multright*<coefright, x'>
5204  * where [minact, maxact] = multright * [rightminactivity, rightmaxactivity]
5205  *
5206  * assuming multright is either -1 or 1, and substituting gives
5207  * multright/rightminactivity + multright/rightmaxactivity - multright/(rightminactivity * rightmaxactivity) *<coefright, x'>
5208  *
5209  * multiplying by rhs, gives the estimate
5210  * rhs / (multright * <coefright, x'>) <= rhs * multright * (1/rightminactivity + 1/rightmaxactivity - 1/(rightminactivity * rightmaxactivity) * <coefright, x'>)
5211  */
5212 
5213  /* cannot do if unbounded */
5214  if( SCIPisInfinity(scip, rightmaxactivity * multright) )
5215  {
5216  *success = FALSE;
5217  return;
5218  }
5219 
5220  assert(SCIPisFeasLE(scip, rightminactivity, rightmaxactivity));
5221 
5222  constant = multleft * multright * coefleft[consdata->nquadvars];
5223  constant -= rhs * multright * (1.0 / rightminactivity + 1.0 / rightmaxactivity);
5224  constant += rhs * multright * coefright[consdata->nquadvars] / (rightminactivity * rightmaxactivity);
5225 
5226  for( i = 0; i < consdata->nquadvars; ++i )
5227  {
5228  cutcoef[i] = multleft * multright * coefleft[i];
5229  cutcoef[i] += rhs * multright / (rightminactivity * rightmaxactivity) * coefright[i];
5230  }
5231 
5232  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_factorablesecant_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5233  }
5234  else
5235  {
5236  SCIP_Real refvalue;
5237 
5238  /* if rhs < 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need linearization:
5239  * rhs / (multright * <coefright, x'>)
5240  * <= rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'> - multright * <coefright, ref'>)
5241  * = 2*rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'>)
5242  *
5243  * where ref' = (ref, 1)
5244  */
5245 
5246  /* compute <coefright, ref'> */
5247  refvalue = coefright[consdata->nquadvars];
5248  for( i = 0; i < consdata->nquadvars; ++i )
5249  refvalue += coefright[i] * ref[i];
5250 
5251  /* should not happen, since we checked activity of <coefright,x> before, and assume ref within bounds */
5252  assert(!SCIPisZero(scip, refvalue));
5253 
5254  constant = multleft * multright * coefleft[consdata->nquadvars];
5255  constant -= 2.0 * rhs / (multright * refvalue);
5256  constant += rhs / (refvalue * refvalue) * multright * coefright[consdata->nquadvars];
5257 
5258  for( i = 0; i < consdata->nquadvars; ++i )
5259  {
5260  cutcoef[i] = multleft * multright * coefleft[i];
5261  cutcoef[i] += rhs / (refvalue * refvalue) * multright * coefright[i];
5262  }
5263 
5264  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_factorablelinearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5265  }
5266 
5267  *cutrhs = -constant;
5268 
5269  /* @todo does not always need to be local */
5270  *islocal = TRUE;
5271  *success = TRUE;
5272 }
5273 
5274 /** tries to generate a cut if constraint quadratic function is factorable and there are no linear variables
5275  * (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
5276  */
5277 static
5279  SCIP* scip, /**< SCIP data structure */
5280  SCIP_CONS* cons, /**< constraint */
5281  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
5282  SCIP_Real* ref, /**< reference solution where to generate the cut */
5283  SCIP_Real* cutcoef, /**< array to store cut coefficients for quadratic variables */
5284  SCIP_Real* cutlhs, /**< buffer to store cut lhs */
5285  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5286  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5287  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5288  char* name /**< buffer to store name of cut */
5289  )
5290 {
5291  SCIP_CONSDATA* consdata;
5292  SCIP_Real leftminactivity;
5293  SCIP_Real leftmaxactivity;
5294  SCIP_Real rightminactivity;
5295  SCIP_Real rightmaxactivity;
5296  SCIP_Real multleft;
5297  SCIP_Real multright;
5298  SCIP_Real rhs;
5299  int i;
5300 
5301  assert(scip != NULL);
5302  assert(cons != NULL);
5303  assert(ref != NULL);
5304  assert(cutcoef != NULL);
5305  assert(cutlhs != NULL);
5306  assert(cutrhs != NULL);
5307  assert(islocal != NULL);
5308  assert(success != NULL);
5309  assert(name != NULL);
5310 
5311  consdata = SCIPconsGetData(cons);
5312  assert(consdata != NULL);
5313  assert(consdata->nlinvars == 0);
5314  assert(consdata->factorleft != NULL);
5315  assert(consdata->factorright != NULL);
5316 
5317  *success = FALSE;
5318  *cutlhs = -SCIPinfinity(scip);
5319 
5320  leftminactivity = consdata->factorleft[consdata->nquadvars];
5321  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
5322  rightminactivity = consdata->factorright[consdata->nquadvars];
5323  rightmaxactivity = consdata->factorright[consdata->nquadvars];
5324  for( i = 0; i < consdata->nquadvars; ++i )
5325  {
5326  if( !SCIPisInfinity(scip, -leftminactivity) )
5327  {
5328  if( consdata->factorleft[i] > 0.0 )
5329  {
5330  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5331  leftminactivity = -SCIPinfinity(scip);
5332  else
5333  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5334  }
5335  else if( consdata->factorleft[i] < 0.0 )
5336  {
5337  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5338  leftminactivity = -SCIPinfinity(scip);
5339  else
5340  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5341  }
5342  }
5343  if( !SCIPisInfinity(scip, leftmaxactivity) )
5344  {
5345  if( consdata->factorleft[i] > 0.0 )
5346  {
5347  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5348  leftmaxactivity = SCIPinfinity(scip);
5349  else
5350  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5351  }
5352  else if( consdata->factorleft[i] < 0.0 )
5353  {
5354  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5355  leftmaxactivity = SCIPinfinity(scip);
5356  else
5357  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5358  }
5359  }
5360 
5361  if( !SCIPisInfinity(scip, -rightminactivity) )
5362  {
5363  if( consdata->factorright[i] > 0.0 )
5364  {
5365  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5366  rightminactivity = -SCIPinfinity(scip);
5367  else
5368  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5369  }
5370  else if( consdata->factorright[i] < 0.0 )
5371  {
5372  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5373  rightminactivity = -SCIPinfinity(scip);
5374  else
5375  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5376  }
5377  }
5378  if( !SCIPisInfinity(scip, rightmaxactivity) )
5379  {
5380  if( consdata->factorright[i] > 0.0 )
5381  {
5382  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5383  rightmaxactivity = SCIPinfinity(scip);
5384  else
5385  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5386  }
5387  else if( consdata->factorright[i] < 0.0 )
5388  {
5389  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5390  rightmaxactivity = SCIPinfinity(scip);
5391  else
5392  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5393  }
5394  }
5395  }
5396 
5397  /* write violated constraints as multleft * factorleft * factorright <= rhs */
5398  if( violside == SCIP_SIDETYPE_RIGHT )
5399  {
5400  rhs = consdata->rhs;
5401  multleft = 1.0;
5402  }
5403  else
5404  {
5405  rhs = -consdata->lhs;
5406  multleft = -1.0;
5407  }
5408 
5409  if( SCIPisZero(scip, rhs) )
5410  {
5411  /* @todo do something for rhs == 0.0? */
5412  return SCIP_OKAY;
5413  }
5414 
5415  if( !SCIPisFeasPositive(scip, leftminactivity) && !SCIPisFeasNegative(scip, leftmaxactivity) )
5416  {
5417  /* left factor has 0 within activity bounds, or is very close, at least */
5418  if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5419  {
5420  /* right factor also has 0 within activity bounds, or is very close, at least
5421  * -> cannot separate
5422  */
5423  return SCIP_OKAY;
5424  }
5425 
5426  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5427  * such that multright * factorright > 0.0
5428  */
5429  if( rightminactivity < 0.0 )
5430  multright = -1.0;
5431  else
5432  multright = 1.0;
5433 
5434  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5435  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5436  }
5437  else if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5438  {
5439  /* left factor is bounded away from 0
5440  * right factor has 0 within activity bounds, or is very close, at least
5441  * -> so divide by left factor
5442  */
5443 
5444  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5445  * such that multright * factorleft > 0.0
5446  */
5447  if( leftminactivity < 0.0 )
5448  multright = -1.0;
5449  else
5450  multright = 1.0;
5451 
5452  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5453  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5454  }
5455  else if( SCIPisInfinity(scip, -leftminactivity) || SCIPisInfinity(scip, leftmaxactivity) ||
5456  (!SCIPisInfinity(scip, -rightminactivity) && !SCIPisInfinity(scip, rightmaxactivity) && rightmaxactivity - rightminactivity < leftmaxactivity - leftminactivity) )
5457  {
5458  /* both factors are bounded away from 0, but the right one has a smaller activity range, so divide by that one */
5459 
5460  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5461  * such that multright * factorright > 0.0
5462  */
5463  if( rightminactivity < 0.0 )
5464  multright = -1.0;
5465  else
5466  multright = 1.0;
5467 
5468  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5469  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5470  }
5471  else
5472  {
5473  /* both factors are bounded away from 0, but the left one has a smaller activity range, so divide by that one */
5474 
5475  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5476  * such that multright * factorleft > 0.0
5477  */
5478  if( leftminactivity < 0.0 )
5479  multright = -1.0;
5480  else
5481  multright = 1.0;
5482 
5483  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5484  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5485  }
5486 
5487  return SCIP_OKAY;
5488 }
5489 
5490 /* finds intersections of a parametric line (x,y) = (x0,y0) + t [(x1,y1) - (x0,y0)] on curves x*y = wl and x*y = wu;
5491  * returns TRUE if unsuccessful and FALSE otherwise
5492  */
5493 static
5495  SCIP* scip,
5496  SCIP_Real x0,
5497  SCIP_Real y0_,
5498  SCIP_Real x1,
5499  SCIP_Real y1_,
5500  SCIP_Real wl,
5501  SCIP_Real wu,
5502  SCIP_Real* xl,
5503  SCIP_Real* yl,
5504  SCIP_Real* xu,
5505  SCIP_Real* yu
5506  )
5507 {
5508  SCIP_Real a;
5509  SCIP_Real b;
5510  SCIP_Real c;
5511  SCIP_Real tl;
5512  SCIP_Real tu;
5513 
5514  assert(wl == SCIP_INVALID || (xl != NULL && yl != NULL)); /*lint !e777 */
5515  assert(wu == SCIP_INVALID || (xu != NULL && yu != NULL)); /*lint !e777 */
5516 
5517  /* The parametric line is of the form
5518  *
5519  * x = x0 + t (x1-x0)
5520  * y = y0 + t (y1-y0)
5521  *
5522  * and for that to satisfy xy = wl and xy = wu we must have
5523  *
5524  * x0 y0 + t [x0 (y1-y0) + y0 (x1-x0)] + t^2 (x1-x0) (y1-y0) = wl
5525  * = wu
5526  *
5527  * or a t^2 + b t + c - wl = 0 for proper values of a,b,c.
5528  * a t^2 + b t + c - wu = 0
5529  *
5530  * Because of the way this procedure will be used, one of the two
5531  * solutions found we must always use the minimum nonnegative one
5532  */
5533 
5534  a = (x1 - x0) * (y1_ - y0_);
5535  c = x0 * y0_;
5536  b = x0 * y1_ + y0_ * x1 - 2.0 * c;
5537 
5538  tl = 0.0;
5539  tu = 0.0;
5540 
5541  if( !SCIPisZero(scip, (SCIP_Real)a) )
5542  {
5543  if( wl != SCIP_INVALID ) /*lint !e777 */
5544  {
5545  SCIP_Real tl1;
5546  SCIP_Real tl2;
5547  SCIP_Real denom;
5548 
5549  assert(b * b - 4.0 * a * (c - wl) >= 0.0);
5550  denom = sqrt(b * b - 4.0 * a * (c - wl));
5551  tl1 = (-b - denom) / (2.0 * a);
5552  tl2 = (-b + denom) / (2.0 * a);
5553  tl = (tl1 < 0.0) ? tl2 : tl1;
5554  }
5555 
5556  if( wu != SCIP_INVALID ) /*lint !e777 */
5557  {
5558  SCIP_Real tu1;
5559  SCIP_Real tu2;
5560  SCIP_Real denom;
5561 
5562  assert(b * b - 4.0 * a * (c - wu) >= 0.0);
5563  denom = sqrt(b * b - 4.0 * a * (c - wu));
5564  tu1 = (-b - denom) / (2.0 * a);
5565  tu2 = (-b + denom) / (2.0 * a);
5566  tu = (tu1 < 0.0) ? tu2 : tu1;
5567  }
5568  }
5569  else if( !SCIPisZero(scip, (SCIP_Real)b) )
5570  {
5571  if( wl != SCIP_INVALID ) /*lint !e777 */
5572  tl = (wl - c) / b;
5573  if( wu != SCIP_INVALID ) /*lint !e777 */
5574  tu = (wu - c) / b;
5575  }
5576  else
5577  {
5578  /* no or infinitely many solutions */
5579  return TRUE;
5580  }
5581 
5582  if( wl != SCIP_INVALID ) /*lint !e777 */
5583  {
5584  *xl = (SCIP_Real)(x0 + tl * (x1 - x0 ));
5585  *yl = (SCIP_Real)(y0_ + tl * (y1_ - y0_));
5586 
5587  if( !SCIPisRelEQ(scip, *xl * *yl, wl) )
5588  {
5589  SCIPdebugMessage("probable numerical difficulties, give up\n");
5590  return TRUE;
5591  }
5592  }
5593 
5594  if( wu != SCIP_INVALID ) /*lint !e777 */
5595  {
5596  *xu = (SCIP_Real)(x0 + tu * (x1 - x0));
5597  *yu = (SCIP_Real)(y0_ + tu * (y1_ - y0_));
5598 
5599  if( !SCIPisRelEQ(scip, *xu * *yu, wu) )
5600  {
5601  SCIPdebugMessage("probable numerical difficulties, give up\n");
5602  return TRUE;
5603  }
5604  }
5605 
5606  /* do not use the computed points if one of the components is infinite */
5607  if( (xu != NULL && SCIPisInfinity(scip, *xu)) || (xl != NULL && SCIPisInfinity(scip, -*xl)) ||
5608  (yu != NULL && SCIPisInfinity(scip, *yu)) || (yl != NULL && SCIPisInfinity(scip, -*yl)) )
5609  {
5610  SCIPdebugMessage("probable numerical difficulties, give up\n");
5611  return TRUE;
5612  }
5613 
5614  return FALSE;
5615 }
5616 
5617 /** generate coefficients for a plane through points (x1, y1_, x1*y1) and (x2, y2, x2*y2)
5618  * such that intersecting it with one of them (the first if whichuse is FALSE, the second otherwise)
5619  * gives a tangent to the curve x*y = k
5620  *
5621  * Returns TRUE on error and FALSE on success.
5622  */
5623 static
5625  SCIP* scip,
5626  SCIP_Real x1,
5627  SCIP_Real y1_,
5628  SCIP_Real x2,
5629  SCIP_Real y2,
5630  SCIP_Bool whichuse,
5631  SCIP_Real* cx,
5632  SCIP_Real* cy,
5633  SCIP_Real* cw
5634  )
5635 {
5636  SCIP_Real xd;
5637  SCIP_Real yd;
5638  SCIP_Real xo;
5639  SCIP_Real yo;
5640 
5641  assert(cx != NULL);
5642  assert(cy != NULL);
5643  assert(cw != NULL);
5644 
5645  /* the x-y slope of this constraint must be tangent to a curve x*y = k at (xD,yD) */
5646  if( !whichuse )
5647  {
5648  xd = x1;
5649  xo = x2;
5650  yd = y1_;
5651  yo = y2;
5652  }
5653  else
5654  {
5655  xd = x2;
5656  xo = x1;
5657  yd = y2;
5658  yo = y1_;
5659  }
5660 
5661  *cx = yd;
5662  *cy = xd;
5663 
5664  /* lift it so that it touches the other curve */
5665 
5666  /* if the two points are on the same curve, then no cut */
5667  if( SCIPisZero(scip, xo * yo - xd * yd) )
5668  return TRUE;
5669 
5670  /* should ALWAYS be negative */
5671  *cw = (2.0 * xd * yd - (*cx * xo + *cy * yo)) / (xo * yo - xd * yd);
5672 
5673  return FALSE;
5674 }
5675 
5676 /** computes coefficients of a lifted-tangent inequality for x*y = w
5677  *
5678  * The code is an adaptation of the methods in exprMul-upperHull.cpp in Couenne/stable/0.4 rev773,
5679  * written by P. Belotti and licensed under Eclipse Public License.
5680  */
5681 static
5683  SCIP* scip, /**< SCIP data structure */
5684  SCIP_Real xl, /**< lower bound on x */
5685  SCIP_Real xu, /**< upper bound on x */
5686  SCIP_Real x0, /**< reference point for x */
5687  SCIP_Real yl, /**< lower bound on y */
5688  SCIP_Real yu, /**< upper bound on y */
5689  SCIP_Real y0_, /**< reference point for y */
5690  SCIP_Real wl, /**< lower bound on w */
5691  SCIP_Real wu, /**< upper bound on w */
5692  SCIP_Real w0, /**< reference point for w */
5693  SCIP_Real* cx, /**< buffer where to store cut coefficient for x */
5694  SCIP_Real* cy, /**< buffer where to store cut coefficient for y */
5695  SCIP_Real* cw, /**< buffer where to store cut coefficient for w */
5696  SCIP_Real* c0, /**< buffer where to store cut left-hand-side */
5697  SCIP_Bool* success /**< buffer where to indicate whether cut coefficients were computed */
5698  )
5699 {
5700  SCIP_Bool flipx;
5701  SCIP_Bool flipy;
5702  SCIP_Bool flipw;
5703  SCIP_Real tmp;
5704  SCIP_Real xlow;
5705  SCIP_Real ylow;
5706  SCIP_Real xupp;
5707  SCIP_Real yupp;
5708  SCIP_Real c0x;
5709  SCIP_Real c0y;
5710  SCIP_Real c0w;
5711 
5712  assert(scip != NULL);
5713  assert(cx != NULL);
5714  assert(cy != NULL);
5715  assert(cw != NULL);
5716  assert(c0 != NULL);
5717  assert(success != NULL);
5718 
5719  *success = FALSE;
5720  *cx = 0.0;
5721  *cy = 0.0;
5722  *cw = 0.0;
5723  *c0 = 0.0;
5724 
5725  SCIPdebugMessage("entering points:\n");
5726  SCIPdebugMessage("x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5727  SCIPdebugMessage("y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5728  SCIPdebugMessage("w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5729 
5730  /* generateCutLTI should have recognized these */
5731  assert(wl >= 0.0 || wu <= 0.0);
5732  assert(!SCIPisInfinity(scip, -wl));
5733  assert(!SCIPisInfinity(scip, wu));
5734 
5735  assert(SCIPisFeasGE(scip, x0, xl));
5736  assert(SCIPisFeasLE(scip, x0, xu));
5737  assert(SCIPisFeasGE(scip, y0_, yl));
5738  assert(SCIPisFeasLE(scip, y0_, yu));
5739 
5740  /* preliminary bound tightening */
5741  if( wl >= 0.0 )
5742  {
5743  if( xl >= 0.0 || yl >= 0.0 || SCIPisLT(scip, xl * yl, wl) )
5744  {
5745  xl = MAX(xl, 0.0);
5746  yl = MAX(yl, 0.0);
5747  }
5748  else if( xu <= 0.0 || yu <= 0.0 || SCIPisLT(scip, xu * yu, wl) )
5749  {
5750  xu = MIN(xu, 0.0);
5751  yu = MIN(yu, 0.0);
5752  }
5753  else
5754  {
5755  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yl and xu*yu are feasible
5756  * cannot generate cut for this
5757  */
5758  return;
5759  }
5760  }
5761  else
5762  {
5763  if( xl >= 0.0 || yu <= 0.0 || SCIPisGT(scip, xl * yu, wu) )
5764  {
5765  xl = MAX(xl, 0.0);
5766  yu = MIN(yu, 0.0);
5767  }
5768  else if( xu <= 0.0 || yl >= 0.0 || SCIPisGT(scip, xu * yl, wu))
5769  {
5770  xu = MIN(xu, 0.0);
5771  yl = MAX(yl, 0.0);
5772  }
5773  else
5774  {
5775  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yu and xu*yl are feasible
5776  * cannot generate cut for this
5777  */
5778  return;
5779  }
5780  }
5781 
5782  /* if x or y is fixed now or even infeasible, then do not think about a cut */
5783  if( SCIPisGE(scip, xl, xu) || SCIPisGE(scip, yl, yu) )
5784  return;
5785 
5786  /* reduce to positive orthant by flipping variables */
5787  if( xl < 0.0 )
5788  {
5789  flipx = TRUE;
5790  tmp = xu;
5791  xu = -xl;
5792  xl = -tmp;
5793  x0 = -x0;
5794  }
5795  else
5796  flipx = FALSE;
5797 
5798  if( yl < 0.0 )
5799  {
5800  flipy = TRUE;
5801  tmp = yu;
5802  yu = -yl;
5803  yl = -tmp;
5804  y0_ = -y0_;
5805  }
5806  else
5807  flipy = FALSE;
5808 
5809  if( flipx ^ flipy )
5810  {
5811  flipw = TRUE;
5812  tmp = wu;
5813  wu = -wl;
5814  wl = -tmp;
5815  w0 = -w0;
5816  }
5817  else
5818  flipw = FALSE;
5819 
5820  /* project refpoint into box not only for numerical reasons, but also due to preliminary bound tightening above */
5821  x0 = MIN(xu, MAX(x0, xl));
5822  y0_ = MIN(yu, MAX(y0_, yl));
5823  w0 = MIN(wu, MAX(w0, wl));
5824 
5825  SCIPdebugMessage("reduced points:\n");
5826  SCIPdebugMessage("x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5827  SCIPdebugMessage("y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5828  SCIPdebugMessage("w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5829 
5830  if( SCIPisGE(scip, xl * yl, wl) && SCIPisLE(scip, xu * yu, wu) )
5831  {
5832  SCIPdebugMessage("box for x and y inside feasible region -> nothing to separate\n");
5833  return;
5834  }
5835  if( SCIPisGE(scip, x0 * y0_, w0) )
5836  {
5837  SCIPdebugMessage("point to separate not below curve -> cannot separate\n");
5838  return;
5839  }
5840 
5841  /* find intersections of halfline from origin
5842  * return if no proper point could be found
5843  */
5844  if( generateCutLTIfindIntersection(scip, 0.0, 0.0, x0, y0_, wl, wu, &xlow, &ylow, &xupp, &yupp) )
5845  return;
5846 
5847  SCIPdebugMessage("intersections:\n");
5848  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5849  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5850 
5851  /* Case 1: If both are outside of bounding box, either NW or SE, then McCormick is sufficient, so return */
5852  if( (xlow <= xl && yupp >= yu) || (ylow <= yl && xupp >= xu) )
5853  return;
5854 
5855  /* There will be at least one cut. Define coefficients and rhs ---will have to change them back if (flipX || flipY) */
5856  if( xlow >= xl && xupp <= xu && ylow >= yl && yupp <= yu )
5857  {
5858  /* Case 2: both are inside. Easy lifting... */
5859  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5860  return;
5861 
5862  c0x = *cx * xlow;
5863  c0y = *cy * ylow;
5864  c0w = *cw * wl;
5865  }
5866  else if( xlow >= xl && ylow >= yl && (xupp > xu || yupp > yu) )
5867  {
5868  /* Case 3a and 3b: through lower curve, but not upper. */
5869  if( yupp > yu )
5870  {
5871  /* upper intersect is North; place it within box */
5872  assert(!SCIPisInfinity(scip, yu));
5873  yupp = yu;
5874  xupp = wu / yu;
5875  }
5876  else
5877  {
5878  /* upper intersect is East; place it within box */
5879  assert(!SCIPisInfinity(scip, xu));
5880  xupp = xu;
5881  yupp = wu / xu;
5882  }
5883 
5884  /* find intersection on low curve on half line through new point and (x0,y0_) */
5885  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow, &ylow, NULL, NULL) )
5886  return;
5887 
5888  /* check whether McCormick is sufficient */
5889  if( xlow < xl || ylow < yl )
5890  return;
5891 
5892  /* lift inequality on lower point */
5893  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5894  return;
5895 
5896  c0x = *cx * xlow;
5897  c0y = *cy * ylow;
5898  c0w = *cw * wl;
5899  }
5900  else if( xupp <= xu && yupp <= yu && (xlow < xl || ylow < yl) )
5901  {
5902  /* Case 4a and 4b: viceversa (lift for validity) */
5903  if( ylow < yl )
5904  {
5905  /* upper intersect is South; place it within box */
5906  assert(!SCIPisZero(scip, yl));
5907  ylow = yl;
5908  xlow = wl / yl;
5909  }
5910  else
5911  {
5912  /* upper intersect is West; place it within box */
5913  assert(!SCIPisZero(scip, xl));
5914  xlow = xl;
5915  ylow = wl / xl;
5916  }
5917 
5918  /* find intersection on low curve on half line through new point and (x0,y0) */
5919  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp, &yupp) )
5920  return;
5921 
5922  /* check whether McCormick is sufficient */
5923  if( xupp > xu || yupp > yu )
5924  return;
5925 
5926  /* lift inequality on UPPER point */
5927  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
5928  return;
5929 
5930  c0x = *cx * xupp;
5931  c0y = *cy * yupp;
5932  c0w = *cw * wu;
5933  }
5934  else if( (xlow < xl && xupp > xu) || (ylow < yl && yupp > yu) )
5935  {
5936  /* Case 5: both outside of bounding box, N and S or W and E. */
5937 #if 0
5938  SCIP_Real xlow2;
5939  SCIP_Real ylow2;
5940  SCIP_Real xupp2;
5941  SCIP_Real yupp2;
5942 #endif
5943 
5944  if( ylow < yl )
5945  {
5946  /* upper intersect is South; place it within box */
5947  assert(!SCIPisZero(scip, yl));
5948  assert(!SCIPisZero(scip, yu));
5949  ylow = yl;
5950  yupp = yu;
5951  xlow = wl / yl;
5952  xupp = wu / yu;
5953  }
5954  else
5955  {
5956  /* upper intersect is West; place it within box */
5957  assert(!SCIPisZero(scip, xl));
5958  assert(!SCIPisZero(scip, xu));
5959  xlow = xl;
5960  xupp = xu;
5961  ylow = wl / xl;
5962  yupp = wu / xu;
5963  }
5964 
5965  SCIPdebugMessage("New intersections:\n");
5966  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5967  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5968 
5969 #if 1
5970  /* Nothing to find. Just separate two inequalities at the same point, just using different support */
5971  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5972  {
5973  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
5974  return;
5975 
5976  c0x = *cx * xupp;
5977  c0y = *cy * yupp;
5978  c0w = *cw * wu;
5979  }
5980  else
5981  {
5982  c0x = *cx * xlow;
5983  c0y = *cy * ylow;
5984  c0w = *cw * wl;
5985  }
5986 
5987 #else
5988  /* find the intersection on the lower (upper) curve on the line through xLP and the upper (lower) point
5989  * this does not seem to work (cuts off solution at nous2), so it is disabled for now
5990  */
5991  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp2, &yupp2) ||
5992  generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp2, yupp2, FALSE, cx, cx, cw) )
5993  {
5994  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow2, &ylow2, NULL, NULL) ||
5995  generateCutLTIgenMulCoeff(scip, xlow2, ylow2, xupp, yupp, TRUE, cx, cy, cw) )
5996  return;
5997 
5998  c0x = *cx * xupp;
5999  c0y = *cy * yupp;
6000  c0w = *cw * wu;
6001  }
6002  else
6003  {
6004  c0x = *cx * xlow;
6005  c0y = *cy * ylow;
6006  c0w = *cw * wl;
6007  }
6008 #endif
6009  }
6010  else
6011  {
6012  SCIPdebugMessage("points are in a weird position:\n");
6013  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6014  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6015 
6016  return;
6017  }
6018 
6019  SCIPdebugMessage("cut w.r.t. reduced points: %gx-%g %+gy-%g %+gw-%g >= 0\n",
6020  *cx, c0x, *cy, c0y, *cw, c0w);
6021 
6022  /* re-transform back into original variables */
6023  if( flipx )
6024  *cx = -*cx;
6025  if( flipy )
6026  *cy = -*cy;
6027  if( flipw )
6028  *cw = -*cw;
6029 
6030  *c0 = c0x + c0y + c0w;
6031 
6032  *success = TRUE;
6033 }
6034 
6035 /** tries to generate a cut if constraint quadratic function is factorable and there are linear variables
6036  *
6037  * Computes what is called a lifted tangent inequality described in@n
6038  * Belotti, Miller, Namazifar, Lifted inequalities for bounded products of variables, SIAG/OPT Views-and-News 22:1, 2011
6039  */
6040 static
6042  SCIP* scip, /**< SCIP data structure */
6043  SCIP_CONS* cons, /**< constraint */
6044  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6045  SCIP_Real* ref, /**< reference solution where to generate the cut */
6046  SCIP_SOL* sol, /**< solution that shall be cutoff, NULL for LP solution */
6047  SCIP_Real** cutcoeflin, /**< buffer to store pointer to array with coefficients for linear variables */
6048  SCIP_Real* cutcoefquad, /**< array to store cut coefficients for quadratic variables */
6049  SCIP_Real* cutlhs, /**< buffer to store cut lhs */
6050  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
6051  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
6052  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6053  char* name /**< buffer to store name of cut */
6054  )
6055 {
6056  SCIP_CONSDATA* consdata;
6057  SCIP_Real leftminactivity;
6058  SCIP_Real leftmaxactivity;
6059  SCIP_Real leftrefactivity;
6060  SCIP_Real rightminactivity;
6061  SCIP_Real rightmaxactivity;
6062  SCIP_Real rightrefactivity;
6063  SCIP_Real rhsminactivity;
6064  SCIP_Real rhsmaxactivity;
6065  SCIP_Real rhsrefactivity;
6066  SCIP_Real coefleft;
6067  SCIP_Real coefright;
6068  SCIP_Real coefrhs;
6069  int i;
6070 
6071  assert(scip != NULL);
6072  assert(cons != NULL);
6073  assert(ref != NULL);
6074  assert(cutcoeflin != NULL);
6075  assert(cutcoefquad != NULL);
6076  assert(cutlhs != NULL);
6077  assert(cutrhs != NULL);
6078  assert(islocal != NULL);
6079  assert(success != NULL);
6080  assert(name != NULL);
6081  /* currently only separate LP solution or solutions given as SCIP_SOL, i.e., no cutgeneration during initlp */
6082  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
6083 
6084  consdata = SCIPconsGetData(cons);
6085  assert(consdata != NULL);
6086  assert(consdata->nlinvars > 0);
6087  assert(consdata->factorleft != NULL);
6088  assert(consdata->factorright != NULL);
6089 
6090  *success = FALSE;
6091  *cutlhs = -SCIPinfinity(scip); /* for compiler */
6092 
6093  /* write violated constraints as factorleft * factorright '==' rhs
6094  * where rhs are constraint sides - activity bound of linear part
6095  */
6096  rhsminactivity = consdata->lhs;
6097  rhsmaxactivity = consdata->rhs;
6098  rhsrefactivity = (violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
6099 
6100  for( i = 0; i < consdata->nlinvars; ++i )
6101  {
6102  if( !SCIPisInfinity(scip, -rhsminactivity) )
6103  {
6104  if( consdata->lincoefs[i] < 0.0 )
6105  {
6106  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6107  rhsminactivity = -SCIPinfinity(scip);
6108  else
6109  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6110  }
6111  else
6112  {
6113  assert(consdata->lincoefs[i] > 0.0);
6114  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6115  rhsminactivity = -SCIPinfinity(scip);
6116  else
6117  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6118  }
6119  }
6120  if( !SCIPisInfinity(scip, rhsmaxactivity) )
6121  {
6122  if( consdata->lincoefs[i] < 0.0 )
6123  {
6124  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6125  rhsmaxactivity = SCIPinfinity(scip);
6126  else
6127  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6128  }
6129  else
6130  {
6131  assert(consdata->lincoefs[i] > 0.0);
6132  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6133  rhsmaxactivity = SCIPinfinity(scip);
6134  else
6135  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6136  }
6137  }
6138  rhsrefactivity -= consdata->lincoefs[i] * SCIPgetSolVal(scip, sol, consdata->linvars[i]);
6139  }
6140 
6141  if( SCIPisInfinity(scip, -rhsminactivity) || SCIPisInfinity(scip, rhsmaxactivity) )
6142  {
6143  /* if right hand side is unbounded, then cannot do LTI */
6144  return SCIP_OKAY;
6145  }
6146 
6147  if( !SCIPisFeasPositive(scip, rhsminactivity) && !SCIPisFeasNegative(scip, rhsmaxactivity) )
6148  {
6149  /* if right hand side has 0 inside activity, then cannot do anything
6150  * if it has 0.0 as min or max activity, then a usual McCormick should be sufficient, too
6151  */
6152  return SCIP_OKAY;
6153  }
6154 
6155  leftminactivity = consdata->factorleft[consdata->nquadvars];
6156  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
6157  leftrefactivity = consdata->factorleft[consdata->nquadvars];
6158  rightminactivity = consdata->factorright[consdata->nquadvars];
6159  rightmaxactivity = consdata->factorright[consdata->nquadvars];
6160  rightrefactivity = consdata->factorright[consdata->nquadvars];
6161  for( i = 0; i < consdata->nquadvars; ++i )
6162  {
6163  if( !SCIPisInfinity(scip, -leftminactivity) )
6164  {
6165  if( consdata->factorleft[i] > 0.0 )
6166  {
6167  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6168  leftminactivity = -SCIPinfinity(scip);
6169  else
6170  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6171  }
6172  else if( consdata->factorleft[i] < 0.0 )
6173  {
6174  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6175  leftminactivity = -SCIPinfinity(scip);
6176  else
6177  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6178  }
6179  }
6180  if( !SCIPisInfinity(scip, leftmaxactivity) )
6181  {
6182  if( consdata->factorleft[i] > 0.0 )
6183  {
6184  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6185  leftmaxactivity = SCIPinfinity(scip);
6186  else
6187  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6188  }
6189  else if( consdata->factorleft[i] < 0.0 )
6190  {
6191  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6192  leftmaxactivity = SCIPinfinity(scip);
6193  else
6194  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6195  }
6196  }
6197  leftrefactivity += consdata->factorleft[i] * ref[i];
6198 
6199  if( !SCIPisInfinity(scip, -rightminactivity) )
6200  {
6201  if( consdata->factorright[i] > 0.0 )
6202  {
6203  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6204  rightminactivity = -SCIPinfinity(scip);
6205  else
6206  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6207  }
6208  else if( consdata->factorright[i] < 0.0 )
6209  {
6210  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6211  rightminactivity = -SCIPinfinity(scip);
6212  else
6213  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6214  }
6215  }
6216  if( !SCIPisInfinity(scip, rightmaxactivity) )
6217  {
6218  if( consdata->factorright[i] > 0.0 )
6219  {
6220  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6221  rightmaxactivity = SCIPinfinity(scip);
6222  else
6223  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6224  }
6225  else if( consdata->factorright[i] < 0.0 )
6226  {
6227  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6228  rightmaxactivity = SCIPinfinity(scip);
6229  else
6230  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6231  }
6232  }
6233  rightrefactivity += consdata->factorright[i] * ref[i];
6234  }
6235 
6236  /* if activities exceed "opposite" infinity, huge bounds seem to be involved, for which the below method is not prepared */
6237  if( SCIPisInfinity(scip, leftminactivity) || SCIPisInfinity(scip, -leftmaxactivity) ||
6238  SCIPisInfinity(scip, rightminactivity) || SCIPisInfinity(scip, -rightmaxactivity) )
6239  return SCIP_OKAY;
6240 
6241  /* if any of the factors is essentially fixed, give up and do usual method (numerically less sensitive, I hope) */
6242  if( SCIPisRelEQ(scip, leftminactivity, leftmaxactivity) || SCIPisRelEQ(scip, rightminactivity, rightmaxactivity) )
6243  return SCIP_OKAY;
6244 
6245  /* success can only be expected for separation of violated x*y <= w, assuming x>=0, y>=0
6246  * @todo we should check this early? */
6247 
6248  /* call Couenne magic */
6250  leftminactivity, leftmaxactivity, leftrefactivity,
6251  rightminactivity, rightmaxactivity, rightrefactivity,
6252  rhsminactivity, rhsmaxactivity, rhsrefactivity,
6253  &coefleft, &coefright, &coefrhs, cutlhs,
6254  success);
6255 
6256  if( !*success )
6257  return SCIP_OKAY;
6258 
6259  SCIPdebugMessage("LTI for x[%g,%g] * y[%g,%g] = w[%g,%g]: %gx %+gy %+gw >= %g; feas: %g\n",
6260  leftminactivity, leftmaxactivity, rightminactivity, rightmaxactivity, rhsminactivity, rhsmaxactivity,
6261  coefleft, coefright, coefrhs, *cutlhs,
6262  coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity - *cutlhs
6263  );
6264 
6265  if( coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity >= *cutlhs )
6266  {
6267  SCIPdebugMessage("does not cutoff point? :-(\n");
6268  *success = FALSE;
6269  return SCIP_OKAY;
6270  }
6271 
6272  /* setup cut coefs for
6273  * coefleft * leftfactor + coefright * rightfactor + coefrhs * w >= cutlhs, where conslhs - lincoefs <= w <= consrhs - lincoefs
6274  */
6275  for( i = 0; i < consdata->nquadvars; ++i )
6276  cutcoefquad[i] = coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i];
6277  assert(i == consdata->nquadvars);
6278  *cutlhs -= coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i];
6279 
6280  SCIP_CALL( SCIPallocBufferArray(scip, cutcoeflin, consdata->nlinvars) );
6281  for( i = 0; i < consdata->nlinvars; ++i )
6282  (*cutcoeflin)[i] = -coefrhs * consdata->lincoefs[i];
6283  if( coefrhs > 0.0 )
6284  {
6285  /* use coefrhs * w <= coefrhs * (consrhs - lincoefs) */
6286  assert(!SCIPisInfinity(scip, consdata->rhs));
6287  *cutlhs -= coefrhs * consdata->rhs;
6288  }
6289  else
6290  {
6291  /* use coefrhs * w <= coeflhs * (conslhs - lincoefs) */
6292  assert(!SCIPisInfinity(scip, -consdata->lhs));
6293  *cutlhs -= coefrhs * consdata->lhs;
6294  }
6295 
6296  *cutrhs = SCIPinfinity(scip);
6297  *islocal = TRUE;
6298 
6299  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_lti_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6300 
6301  *success = TRUE;
6302 
6303  return SCIP_OKAY;
6304 }
6305 
6306 /** computes cut coefficients by linearizing a quadratic function */
6307 static
6309  SCIP* scip, /**< SCIP data structure */
6310  SCIP_CONS* cons, /**< constraint */
6311  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6312  SCIP_Real* ref, /**< reference solution where to generate the cut */
6313  SCIP_Real* coef, /**< array to store cut coefficients w.r.t. quadratic variables */
6314  SCIP_Real* lhs, /**< buffer to store left-hand-side of cut */
6315  SCIP_Real* rhs, /**< buffer to store right-hand-side of cut */
6316  SCIP_Bool* islocal, /**< buffer to set to TRUE if local bounds were used */
6317  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6318  char* name /**< buffer to store name for cut */
6319  )
6320 {
6321  SCIP_CONSDATA* consdata;
6322  SCIP_BILINTERM* bilinterm;
6323  SCIP_Real constant;
6324  SCIP_VAR* var;
6325  int var2pos;
6326  int j;
6327  int k;
6328 
6329  assert(scip != NULL);
6330  assert(cons != NULL);
6331  assert(ref != NULL);
6332  assert(coef != NULL);
6333  assert(lhs != NULL);
6334  assert(rhs != NULL);
6335  assert(islocal != NULL);
6336  assert(success != NULL);
6337 
6338  consdata = SCIPconsGetData(cons);
6339  assert(consdata != NULL);
6340 
6341  constant = 0.0;
6342  BMSclearMemoryArray(coef, consdata->nquadvars);
6343  *success = TRUE;
6344 
6345  /* do first-order Taylor for each term */
6346  for( j = 0; j < consdata->nquadvars && *success; ++j )
6347  {
6348  /* initialize coefficients to linear coefficients of quadratic variables */
6349  coef[j] += consdata->quadvarterms[j].lincoef;
6350 
6351  /* add linearization of square term */
6352  var = consdata->quadvarterms[j].var;
6353  SCIPaddSquareLinearization(scip, consdata->quadvarterms[j].sqrcoef, ref[j],
6354  consdata->quadvarterms[j].nadjbilin == 0 && SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef[j], &constant, success);
6355 
6356  /* add linearization of bilinear terms that have var as first variable */
6357  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6358  {
6359  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6360  if( bilinterm->var1 != var )
6361  continue;
6362  assert(bilinterm->var2 != var);
6363  assert(consdata->sepabilinvar2pos != NULL);
6364 
6365  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6366  assert(var2pos >= 0);
6367  assert(var2pos < consdata->nquadvars);
6368  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6369 
6370  SCIPaddBilinLinearization(scip, bilinterm->coef, ref[j], ref[var2pos], &coef[j], &coef[var2pos], &constant, success);
6371  }
6372  }
6373 
6374  if( !*success )
6375  {
6376  SCIPdebugMessage("no success in linearization of <%s> in reference point\n", SCIPconsGetName(cons));
6377  return SCIP_OKAY;
6378  }
6379 
6380  if( violside == SCIP_SIDETYPE_LEFT )
6381  {
6382  *lhs = consdata->lhs - constant;
6383  *rhs = SCIPinfinity(scip);
6384  }
6385  else
6386  {
6387  *lhs = -SCIPinfinity(scip);
6388  *rhs = consdata->rhs - constant;
6389  }
6390 
6391  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_side%d_linearization_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6392 
6393  return SCIP_OKAY;
6394 }
6395 
6396 /** computes cut coefficients for a nonconvex quadratic function */
6397 static
6399  SCIP* scip, /**< SCIP data structure */
6400  SCIP_CONS* cons, /**< constraint */
6401  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6402  SCIP_Real* ref, /**< reference solution where to generate the cut */
6403  SCIP_Real* coef, /**< array to store cut coefficients w.r.t. quadratic variables */
6404  SCIP_Real* lhs, /**< buffer to store left-hand-side of cut */
6405  SCIP_Real* rhs, /**< buffer to store right-hand-side of cut */
6406  SCIP_Bool* islocal, /**< buffer to set to TRUE if local bounds were used */
6407  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6408  char* name /**< buffer to store name for cut */
6409  )
6410 {
6411  SCIP_CONSDATA* consdata;
6412  SCIP_BILINTERM* bilinterm;
6413  SCIP_Real constant;
6414  SCIP_Real sqrcoef;
6415  SCIP_VAR* var;
6416  int var2pos;
6417  int j;
6418  int k;
6419 
6420  assert(scip != NULL);
6421  assert(cons != NULL);
6422  assert(ref != NULL);
6423  assert(coef != NULL);
6424  assert(lhs != NULL);
6425  assert(rhs != NULL);
6426  assert(islocal != NULL);
6427  assert(success != NULL);
6428 
6429  consdata = SCIPconsGetData(cons);
6430  assert(consdata != NULL);
6431 
6432  *islocal = TRUE;
6433  constant = 0.0;
6434  BMSclearMemoryArray(coef, consdata->nquadvars);
6435  *success = TRUE;
6436 
6437  /* underestimate (secant, McCormick) or linearize each term separately */
6438  for( j = 0; j < consdata->nquadvars && *success; ++j )
6439  {
6440  /* initialize coefficients to linear coefficients of quadratic variables */
6441  coef[j] += consdata->quadvarterms[j].lincoef;
6442 
6443  var = consdata->quadvarterms[j].var;
6444 
6445  sqrcoef = consdata->quadvarterms[j].sqrcoef;
6446  if( sqrcoef != 0.0 )
6447  {
6448  if( (violside == SCIP_SIDETYPE_LEFT && sqrcoef <= 0.0) || (violside == SCIP_SIDETYPE_RIGHT && sqrcoef > 0.0) )
6449  {
6450  /* convex -> linearize */
6451  SCIPaddSquareLinearization(scip, sqrcoef, ref[j], SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef[j],
6452  &constant, success);
6453  }
6454  else
6455  {
6456  /* not convex -> secant approximation */
6457  SCIPaddSquareSecant(scip, sqrcoef, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j], &coef[j],
6458  &constant, success);
6459  }
6460  }
6461 
6462  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6463  {
6464  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6465  if( bilinterm->var1 != var )
6466  continue;
6467  assert(bilinterm->var2 != var);
6468  assert(consdata->sepabilinvar2pos != NULL);
6469 
6470  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6471  assert(var2pos >= 0);
6472  assert(var2pos < consdata->nquadvars);
6473  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6474 
6475  SCIPaddBilinMcCormick(scip, bilinterm->coef,
6476  SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j],
6477  SCIPvarGetLbLocal(bilinterm->var2), SCIPvarGetUbLocal(bilinterm->var2), ref[var2pos],
6478  violside == SCIP_SIDETYPE_LEFT, &coef[j], &coef[var2pos], &constant, success);
6479  }
6480  }
6481 
6482  if( !*success )
6483  {
6484  SCIPdebugMessage("no success to find estimator for nonconvex <%s>\n", SCIPconsGetName(cons));
6485  return SCIP_OKAY;
6486  }
6487 
6488  if( violside == SCIP_SIDETYPE_LEFT )
6489  {
6490  *lhs = consdata->lhs - constant;
6491  *rhs = SCIPinfinity(scip);
6492  }
6493  else
6494  {
6495  *lhs = -SCIPinfinity(scip);
6496  *rhs = consdata->rhs - constant;
6497  }
6498 
6499  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_side%d_estimation_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6500 
6501  return SCIP_OKAY;
6502 }
6503 
6504 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a given reference point */
6505 static
6507  SCIP* scip, /**< SCIP data structure */
6508  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6509  SCIP_CONS* cons, /**< constraint */
6510  SCIP_Real* ref, /**< reference solution where to generate the cut */
6511  SCIP_SOL* sol, /**< point that we aim to separate, or NULL for LP solution */
6512  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6513  SCIP_ROW** row, /**< storage for cut */
6514  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
6515  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
6516  SCIP_Real minefficacy /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
6517  )
6518 {
6519  SCIP_CONSHDLRDATA* conshdlrdata;
6520  SCIP_CONSDATA* consdata;
6521  SCIP_Bool islocal;
6522  char cutname[SCIP_MAXSTRLEN];
6523  SCIP_Real* lincoefs;
6524  SCIP_Real* coef;
6525  SCIP_Real lhs;
6526  SCIP_Real rhs;
6527  SCIP_Bool success;
6528  SCIP_Real mincoef;
6529  SCIP_Real maxcoef;
6530  SCIP_Real lincoefsmax;
6531  SCIP_Real lincoefsmin;
6532  SCIP_Real viol;
6533  SCIP_Real rowefficacy;
6534  SCIP_VAR* var;
6535  int j;
6536 
6537  assert(scip != NULL);
6538  assert(conshdlr != NULL);
6539  assert(cons != NULL);
6540  assert(ref != NULL);
6541  assert(row != NULL);
6542 
6543  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6544  assert(conshdlrdata != NULL);
6545 
6546  consdata = SCIPconsGetData(cons);
6547  assert(consdata != NULL);
6548  assert(violside != SCIP_SIDETYPE_LEFT || !SCIPisInfinity(scip, -consdata->lhs));
6549  assert(violside != SCIP_SIDETYPE_RIGHT || !SCIPisInfinity(scip, consdata->rhs));
6550 
6551  *row = NULL;
6552  SCIP_CALL( SCIPallocBufferArray(scip, &coef, consdata->nquadvars) );
6553  lincoefs = consdata->lincoefs;
6554  lincoefsmax = consdata->lincoefsmax;
6555  lincoefsmin = consdata->lincoefsmin;
6556  islocal = SCIPconsIsLocal(cons);
6557  success = FALSE;
6558  lhs = -SCIPinfinity(scip);
6559  rhs = SCIPinfinity(scip);
6560  cutname[0] = '\0';
6561  rowefficacy = 0.0;
6562 
6563  /* if constraint function is factorable, then try to use factorable form to generate cut */
6564  if( consdata->factorleft != NULL )
6565  {
6566  if( consdata->nlinvars == 0 )
6567  {
6568  SCIP_CALL( generateCutFactorable(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6569  }
6570  else if( sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
6571  {
6572  int i;
6573 
6574  /* generateCutLTI needs reference values also for the linear variables, which we only have if sol is given or LP has been solved */
6575  SCIP_CALL( generateCutLTI(scip, cons, violside, ref, sol, &lincoefs, coef, &lhs, &rhs, &islocal, &success, cutname) );
6576 
6577  /* in case of LTI cuts, we have to recompute the min and max of lincoefs, since they may have been modified */
6578  for( i = 0; i < consdata->nlinvars; ++i )
6579  {
6580  if( REALABS(lincoefs[i]) > lincoefsmax )
6581  lincoefsmax = REALABS(lincoefs[i]);
6582  if( REALABS(lincoefs[i]) < lincoefsmin )
6583  lincoefsmin = REALABS(lincoefs[i]);
6584  }
6585  }
6586  }
6587 
6588  /* if constraint is not factorable or failed to generate cut, try default method */
6589  if( !success )
6590  {
6591  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
6592 
6593  if( (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave) || (violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex) )
6594  {
6595  SCIP_CALL( generateCutConvex(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6596  }
6597  else
6598  {
6599  SCIP_CALL( generateCutNonConvex(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6600  }
6601  }
6602 
6603  /* cut should be one-sided, if any found */
6604  assert(!success || SCIPisInfinity(scip, -lhs) || SCIPisInfinity(scip, rhs));
6605 
6606  /* check if range of cut coefficients is ok
6607  * compute cut activity and violation in sol
6608  */
6609  mincoef = 0.0; /* only for lint */
6610  maxcoef = 0.0; /* only for compiler */
6611  viol = 0.0; /* only for compiler */
6612  if( success )
6613  {
6614  SCIP_Real constant;
6615  SCIP_Real abscoef;
6616  SCIP_Real roundcoef;
6617  int mincoefidx;
6618  SCIP_Real refactivity;
6619  SCIP_Real refactivitylinpart;
6620 
6621  /* compute activity of linear part in sol, if required
6622  * it is required if we need to check or return cut efficacy, for some debug output below, and some assert
6623  * round almost integral coefficients in integers, since this will happen when adding coefs to row (see comments below)
6624  */
6625  refactivitylinpart = 0.0;
6626 #if !defined(SCIP_DEBUG)
6627  if( !SCIPisInfinity(scip, -minefficacy) || efficacy != NULL )
6628 #endif
6629  for( j = 0; j < consdata->nlinvars; ++j )
6630  /* Loose variable have the best bound as LP solution value.
6631  * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
6632  * When this happens, their LP solution value changes to 0.0!
6633  * So when calculating the row activity, we treat loose variable as if they were already column variables.
6634  */
6635  if( SCIPvarGetStatus(consdata->linvars[j]) != SCIP_VARSTATUS_LOOSE )
6636  refactivitylinpart += (SCIPisIntegral(scip, lincoefs[j]) ? SCIPround(scip, lincoefs[j]) : lincoefs[j]) * SCIPgetSolVal(scip, sol, consdata->linvars[j]);
6637 
6638  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
6639 
6640  constant = 0.0;
6641  do
6642  {
6643  refactivity = refactivitylinpart;
6644  mincoefidx = -1;
6645  mincoef = lincoefsmin;
6646  maxcoef = lincoefsmax;
6647 
6648  for( j = 0; j < consdata->nquadvars; ++j )
6649  {
6650  /* coefficients smaller than epsilon are rounded to 0.0 when added to row
6651  * further, coefficients very close to integral values are rounded to integers when added to LP
6652  * both cases can be problematic if variable value is very large (bad numerics)
6653  * thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible)
6654  * i.e., estimate coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x)
6655  * if required bound of x is not finite, then do nothing
6656  */
6657  roundcoef = SCIPround(scip, coef[j]);
6658  if( SCIPisEQ(scip, coef[j], roundcoef) && coef[j] != roundcoef ) /*lint !e777*/
6659  {
6660  SCIP_Real xbnd;
6661 
6662  var = consdata->quadvarterms[j].var;
6663  if( !SCIPisInfinity(scip, rhs) )
6664  if( islocal )
6665  xbnd = coef[j] > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
6666  else
6667  xbnd = coef[j] > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
6668  else
6669  if( islocal )
6670  xbnd = coef[j] > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
6671  else
6672  xbnd = coef[j] > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
6673 
6674  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
6675  {
6676  SCIPdebugMessage("var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g and add constant %g\n",
6677  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef[j], roundcoef, (coef[j]-roundcoef) * xbnd);
6678  constant += (coef[j]-roundcoef) * xbnd;
6679  coef[j] = roundcoef;
6680  }
6681  }
6682 
6683  if( coef[j] == 0.0 )
6684  continue;
6685 
6686  /* As above: When calculating the row activity, we treat loose variable as if they were already column variables. */
6687  if( SCIPvarGetStatus(consdata->quadvarterms[j].var) != SCIP_VARSTATUS_LOOSE )
6688  refactivity += coef[j] * SCIPgetSolVal(scip, sol, consdata->quadvarterms[j].var);
6689 
6690  abscoef = REALABS(coef[j]);
6691  if( abscoef < mincoef )
6692  {
6693  mincoef = abscoef;
6694  mincoefidx = j;
6695  }
6696  if( abscoef > maxcoef )
6697  maxcoef = abscoef;
6698  }
6699 
6700  if( maxcoef < mincoef )
6701  {
6702  /* if all coefficients are zero, then mincoef and maxcoef are still at their initial values
6703  * thus, skip cut generation if its boring
6704  */
6705  assert(maxcoef == 0.0); /*lint !e777 */
6706  assert(mincoef == SCIPinfinity(scip)); /*lint !e777 */
6707 
6708  if( !SCIPisFeasPositive(scip, lhs) && !SCIPisFeasNegative(scip, rhs) )
6709  {
6710  SCIPdebugMessage("skip cut for constraint <%s> since all coefficients are zero and it's always satisfied\n", SCIPconsGetName(cons));
6711  success = FALSE;
6712  }
6713  else
6714  {
6715  /* cut will cutoff node */
6716  }
6717 
6718  break;
6719  }
6720 
6721  if( maxcoef / mincoef > conshdlrdata->cutmaxrange )
6722  {
6723  SCIPdebugMessage("cut coefficients for constraint <%s> have very large range: mincoef = %g maxcoef = %g\n", SCIPconsGetName(cons), mincoef, maxcoef);
6724  if( mincoefidx >= 0 )
6725  {
6726  var = consdata->quadvarterms[mincoefidx].var;
6727  /* try to eliminate coefficient with minimal absolute value by weakening cut and try again
6728  * since we use local bounds, we need to make the row local if they are different from their global counterpart
6729  */
6730  if( ((coef[mincoefidx] > 0.0 && !SCIPisInfinity(scip, rhs)) || (coef[mincoefidx] < 0.0 && !SCIPisInfinity(scip, -lhs))) &&
6731  !SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
6732  {
6733  SCIPdebugMessage("eliminate coefficient %g for <%s> [%g, %g]\n", coef[mincoefidx], SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6734  constant += coef[mincoefidx] * SCIPvarGetLbLocal(var);
6735  coef[mincoefidx] = 0.0;
6736  islocal |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
6737  continue;
6738  }
6739  else if( ((coef[mincoefidx] < 0.0 && !SCIPisInfinity(scip, rhs)) || (coef[mincoefidx] > 0.0 && !SCIPisInfinity(scip, -lhs))) &&
6740  !SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6741  {
6742  SCIPdebugMessage("eliminate coefficient %g for <%s> [%g, %g]\n", coef[mincoefidx], SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6743  constant += coef[mincoefidx] * SCIPvarGetUbLocal(var);
6744  coef[mincoefidx] = 0.0;
6745  islocal |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
6746  continue;
6747  }
6748  }
6749 
6750  SCIPdebugMessage("skip cut\n");
6751  success = FALSE;
6752  }
6753  break;
6754  }
6755  while( TRUE ); /*lint !e506 */
6756 
6757  if( !SCIPisInfinity(scip, -lhs) )
6758  {
6759  lhs -= constant;
6760  viol = lhs - refactivity;
6761  }
6762  if( !SCIPisInfinity(scip, rhs) )
6763  {
6764  rhs -= constant;
6765  viol = refactivity - rhs;
6766  }
6767  }
6768 
6769  if( success && SCIPisInfinity(scip, REALABS(lhs)) && SCIPisInfinity(scip, REALABS(rhs)) )
6770  {
6771  SCIPdebugMessage("skip cut for constraint <%s> because both sides are not finite: lhs = %g, rhs = %g\n", SCIPconsGetName(cons), lhs, rhs);
6772  success = FALSE;
6773  }
6774 
6775  /* check if reference point violates cut sufficiently */
6776  if( success )
6777  {
6778  rowefficacy = viol;
6779  switch( conshdlrdata->scaling )
6780  {
6781  case 'o' :
6782  break;
6783 
6784  case 'g' :
6785  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
6786  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too also we
6787  * use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium scaling) */
6788  rowefficacy /= MAX(1.0, maxcoef);
6789  break;
6790 
6791  case 's' :
6792  {
6793  SCIP_Real abslhs = REALABS(lhs);
6794 
6795  if( !SCIPisInfinity(scip, abslhs) )
6796  rowefficacy /= MAX(1.0, abslhs);
6797  else
6798  {
6799  SCIP_Real absrhs = REALABS(rhs);
6800 
6801  rowefficacy /= MAX(1.0, absrhs);
6802  }
6803 
6804  break;
6805  }
6806 
6807  default:
6808  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
6809  SCIPABORT();
6810  return SCIP_INVALIDDATA; /*lint !e527*/
6811  }
6812  }
6813 
6814  if( success && !SCIPisInfinity(scip, -minefficacy) && rowefficacy < minefficacy ) /*lint !e644*/
6815  {
6816  SCIPdebugMessage("skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), rowefficacy, minefficacy);
6817  success = FALSE;
6818  }
6819 
6820  /* generate row */
6821  if( success )
6822  {
6823  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, lhs, rhs, islocal && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
6824 
6825  /* add coefficients from linear part */
6826  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nlinvars, consdata->linvars, lincoefs) );
6827 
6828  /* add coefficients from quadratic part */
6829  assert(consdata->sepaquadvars != NULL || consdata->nquadvars == 0);
6830  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nquadvars, consdata->sepaquadvars, coef) );
6831 
6832  SCIPdebugMessage("found cut <%s>, lhs=%g, rhs=%g, mincoef=%g, maxcoef=%g, range=%g, nnz=%d, violation=%g, efficacy=%g\n",
6833  SCIProwGetName(*row), lhs, rhs,
6834  mincoef, maxcoef, maxcoef/mincoef,
6835  SCIProwGetNNonz(*row), viol, rowefficacy); /*lint !e414 */
6836 
6837  if( efficacy != NULL )
6838  {
6839  *efficacy = rowefficacy;
6840 
6841  /* check that our computed efficacy is > feastol, iff efficacy computed by row is > feastol
6842  * computing efficacy w.r.t. the LP solution makes only sense if the LP was solved to optimality (see bug 612)
6843  *
6844  * disabled these asserts as they can fail due to numerical reasons (cancelation when substracting big numbers),
6845  * as the order in which we add up the activity for the single terms can be different than the one that lp.c uses
6846  */
6847  /*
6848  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
6849  assert((conshdlrdata->scaling != 'g') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol)/MAX(1.0,SCIPgetRowMaxCoef(scip, *row)))));
6850  assert((conshdlrdata->scaling != 's') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol)/MAX(1.0,MIN(REALABS(lhs),REALABS(rhs))))));
6851  assert((conshdlrdata->scaling != 'o') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol))));
6852  */
6853  }
6854  }
6855 
6856  SCIPfreeBufferArray(scip, &coef);
6857 
6858  /* if coefficients for linear variables are different than those in constraint, then free array */
6859  if( lincoefs != consdata->lincoefs )
6860  {
6861  SCIPfreeBufferArray(scip, &lincoefs);
6862  }
6863 
6864  return SCIP_OKAY;
6865 }
6866 
6867 
6868 /** computes an interior point for the quadratic part of the convex constraint
6869  *
6870  * There are different methods for computing the interior point
6871  * - 'a'ny: solves min 0, f(x) <= rhs, x in bounds
6872  * - 'm'ost interior: solves min f(x), x in bounds
6873  *
6874  * @todo: other methods for computing an interior point?
6875  */
6876 static
6878  SCIP* scip, /**< SCIP data structure */
6879  SCIP_CONS* cons, /**< constraint */
6880  char method, /**< method for computing interior point ('a' any point, 'm'ost interior) */
6881  SCIP_Bool* success /**< buffer to store if an interior point was found */
6882  )
6883 {
6884  SCIP_CONSDATA* consdata;
6885  SCIP_QUADELEM* nlrowquadelems;
6886  SCIP_NLPIPROBLEM* prob;
6887  SCIP_NLPI* nlpi;
6888  SCIP_Real* interiorpoint;
6889  SCIP_Real* lbs;
6890  SCIP_Real* ubs;
6891  SCIP_Real* lincoefs;
6892  SCIP_Real nlpiside;
6893  char probname[SCIP_MAXSTRLEN];
6894  int* lininds;
6895  int nlrownquadelems;
6896  int nquadvars;
6897  int i;
6898 
6899  assert(scip != NULL);
6900  assert(cons != NULL);
6901 
6902  assert(success != NULL);
6903  *success = FALSE;
6904 
6905  consdata = SCIPconsGetData(cons);
6906  assert(consdata != NULL);
6907 
6908  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
6909  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
6910 
6911  /* need an NLP solver */
6912  if( SCIPgetNNlpis(scip) == 0 )
6913  return SCIP_OKAY;
6914 
6915  nlpi = NULL;
6916  prob = NULL;
6917  lbs = NULL;
6918  ubs = NULL;
6919  lincoefs = NULL;
6920  lininds = NULL;
6921 
6922 #ifdef SCIP_DEBUG_INT
6923  SCIPinfoMessage(scip, NULL, "Computing interior point for\n");
6924  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
6925  SCIPinfoMessage(scip, NULL, ";\n");
6926 #endif
6927 
6928  /* in the convex case, we try to find an interior point of x^T A x + b^T x <= rhs - maximum activity linear part
6929  * in the concave case: lhs - minimum activity linear part <= x^T A x + b^T x; we compute activities ourselves,
6930  * since consdata->max(min)linactivity are only computed when lhs (rhs) is finite and this not always holds
6931  */
6932  if( consdata->isconvex )
6933  {
6934  /* compute maximum activity */
6935  nlpiside = 0;
6936  for( i = 0; i < consdata->nlinvars; ++i )
6937  {
6938  if( consdata->lincoefs[i] >= 0.0 )
6939  {
6940  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i]) ) )
6941  nlpiside = SCIPinfinity(scip);
6942  else
6943  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6944  }
6945  else
6946  {
6947  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i]) ) )
6948  nlpiside = SCIPinfinity(scip);
6949  else
6950  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6951  }
6952 
6953  if( SCIPisInfinity(scip, nlpiside) )
6954  {
6955  SCIPdebugMessage("maximum activity is infinity: there is no interior point for fun <= rhs - maxlinactivity!\n");
6956  return SCIP_OKAY;
6957  }
6958  }
6959 
6960  if( consdata->nlinvars == 0 )
6961  nlpiside = INTERIOR_EPS;
6962 
6963  nlpiside = consdata->rhs - nlpiside;
6964  }
6965  else
6966  {
6967  /* compute minimum activity */
6968  nlpiside = 0;
6969  for( i = 0; i < consdata->nlinvars; ++i )
6970  {
6971  if( consdata->lincoefs[i] >= 0.0 )
6972  {
6973  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6974  nlpiside = -SCIPinfinity(scip);
6975  else
6976  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6977  }
6978  else
6979  {
6980  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6981  nlpiside = -SCIPinfinity(scip);
6982  else
6983  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6984  }
6985 
6986  if( SCIPisInfinity(scip, -nlpiside) )
6987  {
6988  SCIPdebugMessage("minimum activity is -infinity: there is no interior point for fun >= lhs - minlinactivity!\n");
6989  return SCIP_OKAY;
6990  }
6991  }
6992 
6993  if( consdata->nlinvars == 0 )
6994  nlpiside = INTERIOR_EPS;
6995 
6996  nlpiside = consdata->lhs - nlpiside;
6997  }
6998 
6999  nquadvars = consdata->nquadvars;
7000 
7001  /* if we are looking for any interior point and the 0 is one, then use it */
7002  if( method == 'a' && ((consdata->isconvex && SCIPisGE(scip, nlpiside, 0.0))
7003  || (consdata->isconcave && SCIPisLE(scip, nlpiside, 0.0))) )
7004  {
7005  SCIP_CALL( SCIPallocClearMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
7006 
7007  *success = TRUE;
7008  goto TERMINATE;
7009  }
7010 
7011  /* build nlrow */
7012  if( consdata->nlrow == NULL )
7013  {
7014  SCIP_CALL( createNlRow(scip, cons) );
7015  assert(consdata->nlrow != NULL);
7016  }
7017 
7018  nlpi = SCIPgetNlpis(scip)[0];
7019  assert(nlpi != NULL);
7020 
7021  /* initializing the subproblem */
7022  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_subquad", SCIPgetProbName(scip));
7023  SCIP_CALL( SCIPnlpiCreateProblem(nlpi, &prob, probname) );
7024  assert(prob != NULL);
7025 
7026 #ifdef SCIP_DEBUG_INT
7028 #endif
7029  /* TODO: maybe one should set some generous iteration limit and/or a timelimit (remaining scip solve time)? */
7030 
7031  /* ask for memory to store data needed to create vars and linear coefficients */
7032  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nquadvars) );
7033  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nquadvars) );
7034  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nquadvars) );
7035  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nquadvars) );
7036 
7037  /* get bounds and linear coefficients */
7038  for( i = 0; i < nquadvars; i++ )
7039  {
7040  lbs[i] = SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
7041  ubs[i] = SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
7042 
7043  lincoefs[i] = consdata->quadvarterms[i].lincoef;
7044  lininds[i] = i;
7045  }
7046 
7047  /* add vars */
7048  SCIP_CALL( SCIPnlpiAddVars(nlpi, prob, nquadvars, lbs, ubs, NULL) );
7049 
7050  /* get nlrow info */
7051  nlrownquadelems = SCIPnlrowGetNQuadElems(consdata->nlrow);
7052  nlrowquadelems = SCIPnlrowGetQuadElems(consdata->nlrow);
7053 
7054 #ifndef NDEBUG
7055  {
7056  SCIP_VAR** nlrowquadvars;
7057 
7058  nlrowquadvars = SCIPnlrowGetQuadVars(consdata->nlrow);
7059  for( i = 0; i < nlrownquadelems; i++ )
7060  {
7061  assert(nlrowquadvars[nlrowquadelems[i].idx1] == consdata->quadvarterms[nlrowquadelems[i].idx1].var);
7062  assert(nlrowquadvars[nlrowquadelems[i].idx2] == consdata->quadvarterms[nlrowquadelems[i].idx2].var);
7063  }
7064  }
7065 #endif
7066 
7067  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
7068 
7069  switch( method )
7070  {
7071  case 'a':
7072  /* add constraint */
7073  if( consdata->isconvex )
7074  {
7075  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, NULL, &nlpiside, &nquadvars, &lininds, &lincoefs,
7076  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
7077  }
7078  else
7079  {
7080  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, &nlpiside, NULL, &nquadvars, &lininds, &lincoefs,
7081  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
7082  }
7083  break;
7084 
7085  case 'm':
7086  /* add objective */
7087  if( consdata->isconvex )
7088  {
7089  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
7090  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
7091  }
7092  else
7093  {
7094  /* NLPI assumes minimization: change signs */
7095  for( i = 0; i < nquadvars; i++ )
7096  lincoefs[i] *= -1;
7097 
7098  /* WARNING: this pointer is not ours, information should be restored! */
7099  for( i = 0; i < nlrownquadelems; i++ )
7100  nlrowquadelems->coef *= -1;
7101 
7102  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
7103  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
7104 
7105  /* WARNING: restore information! */
7106  for( i = 0; i < nlrownquadelems; i++ )
7107  nlrowquadelems->coef *= -1;
7108  }
7109  break;
7110 
7111  default:
7112  SCIPerrorMessage("undefined method for computing interior point: %c\n", method);
7113  return SCIP_INVALIDDATA;
7114  }
7115 
7116  /* solve NLP problem */
7117  SCIP_CALL( SCIPnlpiSolve(nlpi, prob) );
7118 
7119  /* check termination status */
7120  if( SCIPnlpiGetTermstat(nlpi, prob) != SCIP_NLPTERMSTAT_OKAY )
7121  {
7122  SCIPdebugMessage("cons <%s>: NLP Solver termination status not okay: %d\n",
7123  SCIPconsGetName(cons), SCIPnlpiGetTermstat(nlpi, prob));
7124  *success = FALSE;
7125  goto TERMINATE;
7126  }
7127 
7128  /* check solution status */
7129  switch( SCIPnlpiGetSolstat(nlpi, prob) )
7130  {
7134  /* fallthrough */
7135  SCIPdebugMessage("cons <%s>: found an interior point. solution status: %d, termination status: %d\n",
7136  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7137  break;
7138 
7141  /* fallthrough */
7142  /* TODO: we could still use the point, and let evaluateGauge decide whether the point is interior or not */
7143  SCIPdebugMessage("cons <%s>: failed to find an interior point. solution status: %d, termination status: %d\n",
7144  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7145  goto TERMINATE;
7146 
7149  default:
7150  /* fallthrough */
7151  SCIPerrorMessage("cons <%s>: undefined behaviour of NLP Solver. solution status: %d, termination status: %d\n",
7152  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7153  SCIPABORT();
7154  goto TERMINATE; /*lint !e527*/
7155  }
7156 
7157  /* fetch solution
7158  * note: nlpiGetSolution (at least for IPOPT) makes interiorpoint point to the internal solution stored in the
7159  * nlpi problem data structure; we need to copy it here because it will be destroyed once the problem is free'd
7160  */
7161  SCIP_CALL( SCIPnlpiGetSolution(nlpi, prob, &interiorpoint, NULL, NULL, NULL) );
7162 
7163  SCIP_CALL( SCIPallocMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
7164 
7165  for( i = 0; i < nquadvars; i++ )
7166  {
7167  if( SCIPisFeasZero(scip, interiorpoint[i]) )
7168  consdata->interiorpoint[i] = 0.0;
7169  else
7170  consdata->interiorpoint[i] = interiorpoint[i];
7171  }
7172 
7173  *success = TRUE;
7174 
7175 TERMINATE:
7176 
7177 #ifdef SCIP_DEBUG_INT
7178  printf("Computation of interior point for cons <%s>:\n", SCIPconsGetName(cons));
7179  printf(" - has %d linear variables\n", consdata->nlinvars);
7180  if( consdata->isconvex )
7181  {
7182  printf(" - is convex. rhs: %g maximum activity of linear variables: %g\n", consdata->rhs, consdata->rhs - nlpiside);
7183  printf(" - searched for point whose quadratic part is <= %g\n", nlpiside);
7184  }
7185  else
7186  {
7187  printf(" - is concave. lhs: %g minimum activity of linear variables: %g\n", consdata->lhs, consdata->lhs - nlpiside);
7188  printf(" - searched for point whose quadratic part is >= %g\n", nlpiside);
7189  }
7190 
7191  if( *success )
7192  {
7193  if( prob == NULL )
7194  {
7195  printf("Computation successful, 0 is interior point.\n");
7196  for( i = 0; i < nquadvars; i++ )
7197  {
7198  assert(consdata->interiorpoint[i] == 0.0);
7199  }
7200  }
7201  else
7202  {
7203  printf("Computation successful, NLP soltat: %d, termstat: %d\nPoint found:\n",
7204  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7205  for( i = 0; i < nquadvars; i++ )
7206  {
7207  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[i].var), consdata->interiorpoint[i]);
7208  }
7209  }
7210  }
7211  else
7212  {
7213  printf("Computation failed. NLP soltat: %d, termstat: %d\n",
7214  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7215  printf("run with SCIP_DEBUG for more info\n");
7216  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7217  SCIPinfoMessage(scip, NULL, ";\n");
7218  /* FIXME: instance camshape100 says that there is no interior point (interior empty)
7219  * is there something intelligent that can be said?
7220  */
7221  }
7222 #endif
7223 
7224  /* free memory */
7225  SCIPfreeBufferArrayNull(scip, &lbs);
7226  SCIPfreeBufferArrayNull(scip, &ubs);
7227  SCIPfreeBufferArrayNull(scip, &lininds);
7228  SCIPfreeBufferArrayNull(scip, &lincoefs);
7229 
7230  if( prob != NULL )
7231  {
7232  SCIP_CALL( SCIPnlpiFreeProblem(nlpi, &prob) );
7233  }
7234 
7235  return SCIP_OKAY;
7236 }
7237 
7238 /** 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$.
7239  *
7240  * Here, \f$ f(x) \f$ is a purely quadratic (i.e, all \f$x\f$ variables appear in a bilinear or quadratic term).
7241  * Explicitly, \f$ f(x) = \pm x^T A x \pm b^T x \f$ depending whether \f$A\f$
7242  * is positive semidefinite (+) or negative semidefinite (-).
7243  * The constant \f$c\f$ is rhs - maximum activity of the purely linear part of the constraint
7244  * if \f$A \succeq 0\f$ and minimum activity - lhs if \f$A \preceq 0\f$.
7245  * This is computed only at INITSOL.
7246  *
7247  * The method does:
7248  * 1. compute interior point
7249  * 2. compute gauge function
7250  */
7251 static
7253  SCIP* scip, /**< SCIP data structure */
7254  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7255  SCIP_CONS* cons /**< constraint */
7256  )
7257 {
7258  SCIP_CONSHDLRDATA* conshdlrdata;
7259  SCIP_CONSDATA* consdata;
7260  SCIP_QUADVARTERM* quadvarterm;
7261  SCIP_BILINTERM* bilinterm;
7262  SCIP_Bool success;
7263  SCIP_Bool convex;
7264  int i;
7265  int j;
7266 
7267  assert(scip != NULL);
7268  assert(conshdlr != NULL);
7269  assert(cons != NULL);
7270 
7271  consdata = SCIPconsGetData(cons);
7272  assert(consdata != NULL);
7273  assert(consdata->sepabilinvar2pos != NULL || consdata->nbilinterms == 0); /* this should have been computed in INITSOL */
7274 
7275  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7276  assert(conshdlrdata != NULL);
7277  assert(conshdlrdata->gaugecuts);
7278 
7279  /* function has to be convex with finite rhs or concave with finite lhs */
7280  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
7281  assert(convex || (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7282 
7283  SCIPdebugMessage("cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
7284 
7285  /* 1. */
7286  SCIP_CALL( computeInteriorPoint(scip, cons, conshdlrdata->interiorcomputation, &success) );
7287 
7288  /* if success, compute gaugecoefs (b_gauge) and gaugeconst (c_gauge) */
7289  if( !success )
7290  {
7291  SCIPdebugMessage("failed to compute gauge function\n");
7292  consdata->isgaugeavailable = FALSE;
7293  return SCIP_OKAY;
7294  }
7295 
7296  /* 2.
7297  * we are going to evaluate the function at interiorpoint; so, we need to compute interiorpoint^T A interiorpoint;
7298  * therefore, we need a mechanism that for a given variable, it returns its interior point value
7299  * fortunately, sepabilinvar2pos in consdata gives us all the information that we need
7300  */
7301 
7302  SCIP_CALL( SCIPallocClearMemoryArray(scip, &(consdata->gaugecoefs), consdata->nquadvars) );
7303 
7304  /* compute value of quadratic part at interior point, build map and compute gaugeconst (c_gauge) */
7305  consdata->interiorpointval = 0;
7306  consdata->gaugeconst = 0;
7307  for( i = 0; i < consdata->nquadvars; i++ )
7308  {
7309  SCIP_Real val;
7310  SCIP_Real val2;
7311 
7312  val = consdata->interiorpoint[i];
7313  quadvarterm = &consdata->quadvarterms[i];
7314 
7315  consdata->interiorpointval += (quadvarterm->lincoef + quadvarterm->sqrcoef * val) * val;
7316  consdata->gaugeconst += quadvarterm->sqrcoef * val * val;
7317 
7318  for( j = 0; j < quadvarterm->nadjbilin; ++j )
7319  {
7320  int bilintermidx;
7321 
7322  bilintermidx = quadvarterm->adjbilin[j];
7323  bilinterm = &consdata->bilinterms[bilintermidx];
7324 
7325  if( bilinterm->var1 != quadvarterm->var )
7326  continue;
7327 
7328  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
7329  assert(consdata->quadvarterms[consdata->sepabilinvar2pos[bilintermidx]].var == bilinterm->var2);
7330 
7331  val2 = consdata->interiorpoint[consdata->sepabilinvar2pos[bilintermidx]];
7332 
7333  consdata->interiorpointval += bilinterm->coef * val * val2;
7334  consdata->gaugeconst += bilinterm->coef * val * val2;
7335  }
7336  }
7337 
7338  /* compute gaugecoefs (b_gauge = b + 2 * A * interiorpoint) */
7339  for( i = 0; i < consdata->nquadvars; i++ )
7340  {
7341  quadvarterm = &consdata->quadvarterms[i];
7342  consdata->gaugecoefs[i] += quadvarterm->lincoef + 2.0 * quadvarterm->sqrcoef * consdata->interiorpoint[i];
7343 
7344  for( j = 0; j < quadvarterm->nadjbilin; j++ )
7345  {
7346  int varpos;
7347  int bilintermidx;
7348 
7349  bilintermidx = quadvarterm->adjbilin[j];
7350  bilinterm = &consdata->bilinterms[bilintermidx];
7351 
7352  if( bilinterm->var1 == quadvarterm->var )
7353  {
7354  varpos = consdata->sepabilinvar2pos[bilintermidx];
7355 
7356  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
7357  assert(consdata->quadvarterms[varpos].var == bilinterm->var2);
7358 
7359  consdata->gaugecoefs[i] += bilinterm->coef * consdata->interiorpoint[varpos];
7360  consdata->gaugecoefs[varpos] += bilinterm->coef * consdata->interiorpoint[i];
7361  }
7362  }
7363  }
7364 
7365 #ifdef SCIP_DEBUG_INT
7366  printf("quadratic part at interior point: %g\n", consdata->interiorpointval);
7367 
7368  for( j = 0; j < consdata->nquadvars; j++ )
7369  {
7370  printf("b_gauge[%s] = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), consdata->gaugecoefs[j]);
7371  }
7372  printf("c_gauge = %g\n", consdata->gaugeconst);
7373 #endif
7374 
7375  SCIPdebugMessage("gauge function computed successfully\n");
7376  consdata->isgaugeavailable = TRUE;
7377 
7378  return SCIP_OKAY;
7379 }
7380 
7381 /** 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$.
7382  *
7383  * \f$ S = \{ x : f(x) \le c \}\f$ at \f$sol - s_0\f$;
7384  * see computeGauge() for more details
7385  *
7386  * @todo Think about if user should tell that function is convex or ...
7387  */
7388 static
7390  SCIP* scip, /**< SCIP data structure */
7391  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7392  SCIP_CONS* cons, /**< constraint */
7393  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
7394  SCIP_Real* gaugeval, /**< buffer to store the value of the gauge function */
7395  SCIP_Bool* success /**< buffer to store if evaluation was successful */
7396  )
7397 {
7398  SCIP_CONSDATA* consdata;
7399  SCIP_Real side;
7400  SCIP_Real aterm;
7401  SCIP_Real bterm;
7402  SCIP_Real cterm;
7403  SCIP_Bool convex;
7404  int i;
7405 
7406  assert(scip != NULL);
7407  assert(conshdlr != NULL);
7408  assert(cons != NULL);
7409 
7410  consdata = SCIPconsGetData(cons);
7411  assert(consdata != NULL);
7412  assert(consdata->isgaugeavailable);
7413 
7414  *success = FALSE;
7415 
7416  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
7417 
7418  SCIPdebugMessage("cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
7419 
7420  /* evaluate gauge function at x0 = (refsol - interior point)
7421  *
7422  * compute aterm = side - function(interior point)
7423  */
7424  if( convex )
7425  {
7426  side = consdata->rhs;
7427  for( i = 0; i < consdata->nlinvars; i++ )
7428  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
7429 
7430  aterm = side - consdata->interiorpointval;
7431 
7432  /* it can happen that the interior point is not really interior, since we are not so strict at the moment of
7433  * computing the interior point, which makes sense in the case that the constraint is quadratic <= linear expr,
7434  * since we compute a point in quadratic <= min linear expr and it might be that this set consists of a single
7435  * point which will not be interior. furthermore, if this set is empty, we could just take any point and it could
7436  * happen that for some value of linear expr, the point is actually interior, but for many it could not be.
7437  * also, if min linear expr = -infinity, we might have computed an interior point using some finite value.
7438  * the point will not be an interior point, if and only if aterm is negative.
7439  */
7440 #ifdef SCIP_DEBUG_GAUGE
7441  if( SCIPisLE(scip, aterm, 0.0) )
7442  {
7443  printf("For current level, there is no interior point. ");
7444  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
7445  if( consdata->nlinvars == 1 )
7446  {
7447  SCIP_VAR* var;
7448 
7449  var = consdata->linvars[0];
7450  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
7451  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7452  }
7453  }
7454  else
7455  {
7456  printf("For current level, there is interior point. ");
7457  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
7458  }
7459 #endif
7460  if( !SCIPisPositive(scip, aterm) )
7461  {
7462  *gaugeval = -1.0;
7463  return SCIP_OKAY;
7464  }
7465  }
7466  else
7467  {
7468  side = consdata->lhs;
7469  for( i = 0; i < consdata->nlinvars; i++ )
7470  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
7471 
7472  aterm = side - consdata->interiorpointval;
7473 
7474 #ifdef SCIP_DEBUG_GAUGE
7475  if( SCIPisGE(scip, aterm, 0.0) )
7476  {
7477  printf("For current level, there is no interior point. ");
7478  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
7479  if( consdata->nlinvars == 1 )
7480  {
7481  SCIP_VAR* var;
7482 
7483  var = consdata->linvars[0];
7484  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
7485  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7486  }
7487  }
7488  else
7489  {
7490  printf("For current level, there is interior point. ");
7491  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
7492  }
7493 #endif
7494  if( !SCIPisNegative(scip, aterm) )
7495  {
7496  *gaugeval = -1.0;
7497  return SCIP_OKAY;
7498  }
7499  }
7500 
7501  /* compute bterm = b_gauge^T * refsol - f(interiorpoint) - c_gauge
7502  * compute cterm = f(refsol) - b_gauge^T * refsol + c_gauge */
7503  bterm = -consdata->interiorpointval - consdata->gaugeconst;
7504  cterm = consdata->gaugeconst;
7505  for( i = 0; i < consdata->nquadvars; i++ )
7506  {
7507  SCIP_Real val;
7508 
7509  val = SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var);
7510  bterm += consdata->gaugecoefs[i] * val;
7511  cterm -= consdata->gaugecoefs[i] * val;
7512  cterm += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val) * val;
7513  }
7514 
7515  for( i = 0; i < consdata->nbilinterms; i++ )
7516  {
7517  SCIP_VAR* var1;
7518  SCIP_VAR* var2;
7519 
7520  var1 = consdata->bilinterms[i].var1;
7521  var2 = consdata->bilinterms[i].var2;
7522  cterm += consdata->bilinterms[i].coef * SCIPgetSolVal(scip, refsol, var1) * SCIPgetSolVal(scip, refsol, var2);
7523  }
7524 
7525  /* now compute gauge */
7526  if( convex && cterm < 0.0 )
7527  {
7528  assert(SCIPisZero(scip, cterm));
7529  cterm = 0.0;
7530  }
7531  else if( !convex && cterm > 0.0 )
7532  {
7533  assert(SCIPisZero(scip, cterm));
7534  cterm = 0.0;
7535  }
7536  assert(bterm*bterm + 4*aterm*cterm >= 0);
7537 
7538  if( convex )
7539  {
7540  *gaugeval = bterm + sqrt(bterm*bterm + 4 * aterm * cterm);
7541  *gaugeval = *gaugeval / (2 * aterm);
7542  }
7543  else
7544  {
7545  *gaugeval = bterm - sqrt(bterm*bterm + 4 * aterm * cterm);
7546  *gaugeval = *gaugeval / (2 * aterm);
7547  }
7548  assert(!SCIPisNegative(scip, *gaugeval));
7549  *success = TRUE;
7550 
7551 #ifdef SCIP_DEBUG_GAUGE
7552  printf("Gauge's aterm = %g, bterm = %g, cterm = %g\n", aterm, bterm, cterm);
7553 #endif
7554  return SCIP_OKAY;
7555 }
7556 
7557 /** compute reference point suggested by gauge function
7558  *
7559  * @todo Should we modify a point in the interior? Currently we do not.
7560  */
7561 static
7563  SCIP* scip, /**< SCIP data structure */
7564  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7565  SCIP_CONS* cons, /**< constraint */
7566  SCIP_SOL* refsol, /**< reference point where to compute gauge, or NULL if LP solution should be used */
7567  SCIP_Real** ref, /**< pointer to store reference point */
7568  SCIP_Bool* success /**< buffer to store whether we succeeded computing reference point */
7569  )
7570 {
7571  SCIP_CONSDATA* consdata;
7572  SCIP_Real gaugeval;
7573  SCIP_Real intpoint;
7574  SCIP_Real lb;
7575  SCIP_Real ub;
7576  SCIP_VAR* var;
7577  int j;
7578 
7579  assert(scip != NULL);
7580  assert(conshdlr != NULL);
7581  assert(cons != NULL);
7582 
7583  consdata = SCIPconsGetData(cons);
7584  assert(consdata != NULL);
7585  assert(consdata->isgaugeavailable);
7586 
7587  SCIPdebugMessage("evaluating gauge\n");
7588  SCIP_CALL( evaluateGauge(scip, conshdlr, cons, refsol, &gaugeval, success) );
7589 
7590  if( !(*success) )
7591  {
7592 #ifdef SCIP_DEBUG_GAUGE
7593  printf("Couldn't evaluate gauge!\n");
7594 #endif
7595  return SCIP_OKAY;
7596  }
7597 
7598 #ifdef SCIP_DEBUG_GAUGE
7599  {
7600  SCIP_Real level;
7601 
7602  level = consdata->rhs;
7603  for( j = 0; j < consdata->nlinvars; j++ )
7604  level -= SCIPgetSolVal(scip, refsol, consdata->linvars[j]) * consdata->lincoefs[j];
7605 
7606  printf("Summary:\n");
7607  printf("For cons <%s>: gauge at level %g evaluated at (refsol - intpoint) is %.10f\n",
7608  SCIPconsGetName(cons), level, gaugeval);
7609  printf("refsol - intpoint:\n");
7610 
7611  for( j = 0; j < consdata->nquadvars; ++j )
7612  {
7613  SCIP_VAR* vvar;
7614  vvar = consdata->quadvarterms[j].var;
7615  printf("%s: % 20.15g - %g = %g\n", SCIPvarGetName(vvar), SCIPgetSolVal(scip, refsol, vvar),
7616  consdata->interiorpoint[j], SCIPgetSolVal(scip, refsol, vvar) - consdata->interiorpoint[j]);
7617  }
7618  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
7619  printf("refsol is in the closure of the region (gaugeval <= 1), don't modify reference point\n");
7620  }
7621 #endif
7622 
7623  /* scale gauge value so that point is close to the boundary, but not on the boundary */
7624  gaugeval *= GAUGESCALE;
7625 
7626  /* when a new solution is found, this method is called from addLinearizationCuts.
7627  * in this case, since the solution is feasible, gaugeval <= 1
7628  * is it a good idea to modify the point if it is interior?
7629  */
7630  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
7631  {
7632  *success = FALSE;
7633 
7634  return SCIP_OKAY;
7635  }
7636 
7637  /* set reference to (refsol - interior point)/gaugeval + interior point and project into bounds
7638  * this is important for some cut generation methods such as generateCutLTI
7639  */
7640  for( j = 0; j < consdata->nquadvars; ++j )
7641  {
7642  var = consdata->quadvarterms[j].var;
7643  lb = SCIPvarGetLbLocal(var);
7644  ub = SCIPvarGetUbLocal(var);
7645  /* do not like variables at infinity */
7646  assert(!SCIPisInfinity(scip, lb));
7647  assert(!SCIPisInfinity(scip, -ub));
7648 
7649  intpoint = consdata->interiorpoint[j];
7650  (*ref)[j] = (SCIPgetSolVal(scip, refsol, var) - intpoint) / gaugeval + intpoint;
7651  (*ref)[j] = MIN(ub, MAX(lb, (*ref)[j])); /* project value into bounds */
7652  }
7653 
7654 #ifdef SCIP_DEBUG_GAUGE
7655  printf("successful application of guage: %g\n", gaugeval);
7656  printf("modified reference point:\n");
7657  for( j = 0; j < consdata->nquadvars; ++j )
7658  {
7659  printf("%s = % 20.15g\n", SCIPvarGetName(consdata->quadvarterms[j].var), (*ref)[j]);
7660  }
7661 #endif
7662 
7663  return SCIP_OKAY;
7664 }
7665 
7666 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a solution */
7667 static
7669  SCIP* scip, /**< SCIP data structure */
7670  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7671  SCIP_CONS* cons, /**< constraint */
7672  SCIP_SOL* sol, /**< solution where to generate cut, or NULL if LP solution should be used */
7673  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
7674  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7675  SCIP_ROW** row, /**< storage for cut */
7676  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
7677  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7678  SCIP_Real minefficacy /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
7679  )
7680 {
7681  SCIP_CONSHDLRDATA* conshdlrdata;
7682  SCIP_CONSDATA* consdata;
7683  SCIP_VAR* var;
7684  SCIP_Real lb;
7685  SCIP_Real ub;
7686  SCIP_Real* ref;
7687  SCIP_Bool success;
7688  int j;
7689 
7690  assert(scip != NULL);
7691  assert(conshdlr != NULL);
7692  assert(cons != NULL);
7693 
7694  consdata = SCIPconsGetData(cons);
7695  assert(consdata != NULL);
7696 
7697  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7698  assert(conshdlrdata != NULL);
7699 
7700  if( refsol == NULL )
7701  refsol = sol;
7702 
7703  /* get reference point */
7704  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
7705  success = FALSE;
7706 
7707  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable &&
7708  ((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
7709  (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT)) )
7710  {
7711  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, &ref, &success) );
7712  }
7713 
7714  if( success )
7715  {
7716  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
7717 
7718  /* if cut fails, try again without modifying reference point via gauge */
7719  if( *row == NULL || (efficacy != NULL && !SCIPisGT(scip, *efficacy, minefficacy)) || !SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
7720  {
7721  SCIPdebugMessage("gauge cut fail, try without modifying\n");
7722  success = FALSE;
7723  }
7724  }
7725 
7726  if( !success )
7727  {
7728  for( j = 0; j < consdata->nquadvars; ++j )
7729  {
7730  var = consdata->quadvarterms[j].var;
7731  lb = SCIPvarGetLbLocal(var);
7732  ub = SCIPvarGetUbLocal(var);
7733  /* do not like variables at infinity */
7734  assert(!SCIPisInfinity(scip, lb));
7735  assert(!SCIPisInfinity(scip, -ub));
7736 
7737  ref[j] = SCIPgetSolVal(scip, refsol, var);
7738  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
7739  }
7740 
7741  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
7742  }
7743 
7744  SCIPfreeBufferArray(scip, &ref);
7745 
7746  return SCIP_OKAY;
7747 }
7748 
7749 /** tries to find a cut that intersects with an unbounded ray of the LP
7750  *
7751  * For convex functions, we do this by linearizing in the feasible solution of the LPI.
7752  * For nonconvex functions, we just call generateCutSol with the unbounded solution as reference point.
7753  */
7754 static
7756  SCIP* scip, /**< SCIP data structure */
7757  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7758  SCIP_CONS* cons, /**< constraint */
7759  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7760  SCIP_ROW** row, /**< storage for cut */
7761  SCIP_Real* rowrayprod, /**< buffer to store product of ray with row coefficients, or NULL if not of interest */
7762  SCIP_Bool checkcurvmultivar /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7763  )
7764 {
7765  SCIP_CONSDATA* consdata;
7766  SCIP_BILINTERM* bilinterm;
7767  SCIP_VAR* var;
7768  SCIP_Real* ref;
7769  SCIP_Real matrixrayprod;
7770  SCIP_Real linrayprod;
7771  SCIP_Real quadrayprod;
7772  SCIP_Real rayval;
7773  int i;
7774  int j;
7775 
7776  assert(scip != NULL);
7777  assert(conshdlr != NULL);
7778  assert(cons != NULL);
7779  assert(row != NULL);
7781 
7782  consdata = SCIPconsGetData(cons);
7783  assert(consdata != NULL);
7784 
7785  *row = NULL;
7786 
7787  if( !SCIPhasPrimalRay(scip) )
7788  {
7789  SCIPdebugMessage("do not have primal ray, thus cannot resolve unboundedness\n");
7790  return SCIP_OKAY;
7791  }
7792 
7793  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
7794  if( (!consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
7795  (!consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
7796  {
7797  /* if not convex, just call generateCut and hope it's getting something useful */
7798  SCIP_CALL( generateCutSol(scip, conshdlr, cons, NULL, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
7799 
7800  /* compute product of cut coefficients with ray, if required */
7801  if( *row != NULL && rowrayprod != NULL )
7802  {
7803  *rowrayprod = 0.0;
7804  for( i = 0; i < SCIProwGetNNonz(*row); ++i )
7805  {
7806  assert(SCIProwGetCols(*row)[i] != NULL);
7807  var = SCIPcolGetVar(SCIProwGetCols(*row)[i]);
7808  assert(var != NULL);
7809 
7810  *rowrayprod += SCIProwGetVals(*row)[i] * SCIPgetPrimalRayVal(scip, var);
7811  }
7812  }
7813 
7814  return SCIP_OKAY;
7815  }
7816 
7817  /* we seek for a linearization of the quadratic function such that it intersects with the unbounded ray
7818  * that is, we need a reference point ref such that for the gradient g of xAx+bx in ref, we have
7819  * <g, ray> > 0.0 if rhs is finite and <g, ray> < 0.0 if lhs is finite
7820  * Since g = 2*A*ref + b, we have <g, ray> = <2*A*ref + b, ray> = <ref, 2*A*ray> + <b,ray>
7821  * 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)
7822  * <ref, 2*A*ray> + <b,ray> is sufficiently larger 0.0, we call generateCut for this point, otherwise, we scale up ref
7823  */
7824 
7825  quadrayprod = 0.0; /* <ref, 2*A*ray> */
7826  linrayprod = 0.0; /* <b, ray> */
7827  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
7828  for( i = 0; i < consdata->nquadvars; ++i )
7829  {
7830  var = consdata->quadvarterms[i].var;
7831  rayval = SCIPgetPrimalRayVal(scip, var);
7832 
7833  /* compute i-th entry of (2*A*ray) */
7834  matrixrayprod = 2.0 * consdata->quadvarterms[i].sqrcoef * rayval;
7835  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
7836  {
7837  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
7838  matrixrayprod += bilinterm->coef * SCIPgetPrimalRayVal(scip, bilinterm->var1 == var ? bilinterm->var2 : bilinterm->var1);
7839  }
7840 
7841  if( SCIPisPositive(scip, matrixrayprod) )
7842  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? 1.0 : -1.0);
7843  else if( SCIPisNegative(scip, matrixrayprod) )
7844  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? -1.0 : 1.0);
7845  else
7846  ref[i] = 0.0;
7847 
7848  quadrayprod += matrixrayprod * ref[i];
7849  linrayprod += consdata->quadvarterms[i].lincoef * rayval;
7850  }
7851  assert((violside == SCIP_SIDETYPE_RIGHT && quadrayprod >= 0.0) || (violside == SCIP_SIDETYPE_LEFT && quadrayprod <= 0.0));
7852 
7853  if( SCIPisZero(scip, quadrayprod) )
7854  {
7855  SCIPdebugMessage("ray is zero along cons <%s>\n", SCIPconsGetName(cons));
7856  SCIPfreeBufferArray(scip, &ref);
7857  return SCIP_OKAY;
7858  }
7859 
7860  /* add linear part to linrayprod */
7861  for( i = 0; i < consdata->nlinvars; ++i )
7862  linrayprod += consdata->lincoefs[i] * SCIPgetPrimalRayVal(scip, consdata->linvars[i]);
7863 
7864  SCIPdebugMessage("initially have <b,ray> = %g and <ref, 2*A*ref> = %g\n", linrayprod, quadrayprod);
7865 
7866  /* 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
7867  * if <b,ray> is zero, then we scale refpoint up if |<ref, 2*A*ray>| < 1.0
7868  */
7869  if( (!SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_RIGHT && quadrayprod < -2*linrayprod) ||
7870  ( !SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_LEFT && quadrayprod > -2*linrayprod) ||
7871  (SCIPisZero(scip, linrayprod) && REALABS(quadrayprod) < 1.0) )
7872  {
7873  SCIP_Real scale;
7874 
7875  if( !SCIPisZero(scip, linrayprod) )
7876  scale = 2*REALABS(linrayprod/quadrayprod); /*lint !e795 */
7877  else
7878  scale = 1.0/REALABS(quadrayprod);
7879 
7880  SCIPdebugMessage("scale refpoint by %g\n", scale);
7881  for( i = 0; i < consdata->nquadvars; ++i )
7882  ref[i] *= scale;
7883  quadrayprod *= scale;
7884  }
7885 
7886  if( rowrayprod != NULL )
7887  *rowrayprod = quadrayprod + linrayprod;
7888 
7889  SCIPdebugMessage("calling generateCut, expecting ray product %g\n", quadrayprod + linrayprod);
7890  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
7891 
7892  SCIPfreeBufferArray(scip, &ref);
7893 
7894  return SCIP_OKAY;
7895 }
7896 
7897 /** tries to separate solution or LP solution by a linear cut
7898  *
7899  * assumes that constraint violations have been computed
7900  */
7901 static
7903  SCIP* scip, /**< SCIP data structure */
7904  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
7905  SCIP_CONS** conss, /**< constraints */
7906  int nconss, /**< number of constraints */
7907  int nusefulconss, /**< number of constraints that seem to be useful */
7908  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7909  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
7910  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
7911  SCIP_RESULT* result, /**< result of separation */
7912  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 */
7913  )
7914 {
7915  SCIP_CONSHDLRDATA* conshdlrdata;
7916  SCIP_CONSDATA* consdata;
7917  SCIP_Real efficacy;
7918  SCIP_Real actminefficacy;
7919  SCIP_SIDETYPE violside;
7920  int c;
7921  SCIP_ROW* row;
7922 
7923  assert(scip != NULL);
7924  assert(conshdlr != NULL);
7925  assert(conss != NULL || nconss == 0);
7926  assert(nusefulconss <= nconss);
7927  assert(result != NULL);
7928 
7929  *result = SCIP_FEASIBLE;
7930 
7931  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7932  assert(conshdlrdata != NULL);
7933 
7934  if( bestefficacy != NULL )
7935  *bestefficacy = 0.0;
7936 
7937  for( c = 0; c < nconss; ++c )
7938  {
7939  assert(conss != NULL);
7940  consdata = SCIPconsGetData(conss[c]);
7941  assert(consdata != NULL);
7942 
7943  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7944  {
7945  /* we are not feasible anymore */
7946  if( *result == SCIP_FEASIBLE )
7947  *result = SCIP_DIDNOTFIND;
7948 
7949  violside = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT;
7950 
7951  /* actual minimal efficacy */
7952  actminefficacy = inenforcement && ((violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex ) || (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave))
7953  ? (SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip))
7954  : minefficacy;
7955 
7956  /* generate cut */
7957  if( sol == NULL && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
7958  {
7959  /* if the LP is unbounded, then we need a cut that cuts into the direction of a hopefully existing primal ray
7960  * 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
7961  * given a cut lhs <= <c,x> <= rhs, we check whether it imposes an upper bound on t and thus bounds the ray
7962  * 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>
7963  * similar, lhs > -infinity and <c,r> < 0 is good
7964  */
7965  SCIP_Real rayprod;
7966  SCIP_Real norm;
7967 
7968  rayprod = 0.0; /* for compiler */
7969  SCIP_CALL( generateCutUnboundedLP(scip, conshdlr, conss[c], violside, &row, &rayprod, conshdlrdata->checkcurvature) );
7970 
7971  if( row != NULL )
7972  {
7973  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) && SCIPisPositive(scip, rayprod) )
7974  efficacy = rayprod;
7975  else if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) && SCIPisNegative(scip, rayprod) )
7976  efficacy = -rayprod;
7977  else
7978  efficacy = 0.0;
7979 
7980  switch( conshdlrdata->scaling )
7981  {
7982  case 'o' :
7983  break;
7984 
7985  case 'g' :
7986  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding
7987  * cuts efficient which are only very slightly violated CPLEX does not seem to scale row
7988  * coefficients up too also we use infinity norm, since that seem to be the usual scaling strategy
7989  * in LP solvers (equilibrium scaling) */
7990  norm = SCIPgetRowMaxCoef(scip, row);
7991  efficacy /= MAX(1.0, norm);
7992  break;
7993 
7994  case 's' :
7995  {
7996  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
7997  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
7998  SCIP_Real minval = MIN(abslhs, absrhs);
7999 
8000  efficacy /= MAX(1.0, minval);
8001  break;
8002  }
8003 
8004  default:
8005  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
8006  SCIPABORT();
8007  return SCIP_INVALIDDATA; /*lint !e527*/
8008  }
8009  }
8010  }
8011  else
8012  {
8013  /* @todo If convex, can we easily move the refpoint closer to the feasible region to get a stronger cut?
8014  * E.g., use bisection on the line between LP solution and best primal (or LP interior)
8015  */
8016  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], sol, NULL, violside, &row, &efficacy, conshdlrdata->checkcurvature, actminefficacy) );
8017  /* @todo If generation failed not because of low efficacy, then probably because of numerical issues;
8018  * if the constraint is convex and we are desperate to get a cut, then we may try again with a better chosen reference point
8019  */
8020  }
8021 
8022  if( row == NULL ) /* failed to generate cut */
8023  continue;
8024 
8025  if( SCIPisGT(scip, efficacy, actminefficacy) && SCIPisCutApplicable(scip, row) ) /*lint !e644 */
8026  {
8027  SCIP_Bool infeasible;
8028 
8029  /* cut cuts off solution */
8030  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE /* forcecut */, &infeasible) );
8031  if( infeasible )
8032  {
8033  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(conss[c]));
8034  *result = SCIP_CUTOFF;
8035  }
8036  else
8037  {
8038  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy,
8039  SCIPconsGetName(conss[c]), consdata->lhsviol+consdata->rhsviol);
8040  *result = SCIP_SEPARATED;
8041  }
8042  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
8043 
8044  /* mark row as not removable from LP for current node, if in enforcement */
8045  if( inenforcement && !conshdlrdata->enfocutsremovable )
8046  SCIPmarkRowNotRemovableLocal(scip, row);
8047  }
8048  if( bestefficacy != NULL && efficacy > *bestefficacy )
8049  *bestefficacy = efficacy;
8050 
8051  SCIP_CALL( SCIPreleaseRow (scip, &row) );
8052  }
8053 
8054  if( *result == SCIP_CUTOFF )
8055  break;
8056 
8057  /* enforce only useful constraints
8058  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
8059  */
8060  if( c >= nusefulconss && *result == SCIP_SEPARATED )
8061  break;
8062  }
8063 
8064  return SCIP_OKAY;
8065 }
8066 
8067 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
8068  *
8069  * - 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.
8070  * - If separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only.
8071  * - If separatedlpsol is NULL, then cut is added to cutpool only.
8072  */
8073 static
8075  SCIP* scip, /**< SCIP data structure */
8076  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
8077  SCIP_CONS** conss, /**< constraints */
8078  int nconss, /**< number of constraints */
8079  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
8080  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP,
8081  * or NULL if adding to cutpool only */
8082  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
8083  )
8084 {
8085  SCIP_CONSHDLRDATA* conshdlrdata;
8086  SCIP_CONSDATA* consdata;
8087  SCIP_Bool addedtolp;
8088  SCIP_ROW* row;
8089  int c;
8090 
8091  assert(scip != NULL);
8092  assert(conshdlr != NULL);
8093  assert(conss != NULL || nconss == 0);
8094 
8095  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8096  assert(conshdlrdata != NULL);
8097 
8098  if( separatedlpsol != NULL )
8099  *separatedlpsol = FALSE;
8100 
8101  for( c = 0; c < nconss; ++c )
8102  {
8103  assert(conss[c] != NULL); /*lint !e613 */
8104 
8105  if( SCIPconsIsLocal(conss[c]) || !SCIPconsIsEnabled(conss[c]) ) /*lint !e613 */
8106  continue;
8107 
8108  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
8109 
8110  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
8111  assert(consdata != NULL);
8112 
8113  if( consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
8114  {
8115  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_RIGHT, &row, NULL,
8116  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
8117  }
8118  else if( consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
8119  {
8120  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_LEFT, &row, NULL,
8121  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
8122  }
8123  else
8124  continue;
8125 
8126  if( row == NULL )
8127  continue;
8128 
8129  addedtolp = FALSE;
8130 
8131  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
8132  if( separatedlpsol != NULL )
8133  {
8134  SCIP_Real efficacy;
8135  SCIP_Real norm;
8136 
8137  efficacy = -SCIPgetRowLPFeasibility(scip, row);
8138  switch( conshdlrdata->scaling )
8139  {
8140  case 'o' :
8141  break;
8142 
8143  case 'g' :
8144  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
8145  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too
8146  * also we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
8147  * scaling) */
8148  norm = SCIPgetRowMaxCoef(scip, row);
8149  efficacy /= MAX(1.0, norm);
8150  break;
8151 
8152  case 's' :
8153  {
8154  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
8155  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
8156  SCIP_Real minval = MIN(abslhs, absrhs);
8157 
8158  efficacy /= MAX(1.0, minval);
8159  break;
8160  }
8161 
8162  default:
8163  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
8164  SCIPABORT();
8165  return SCIP_INVALIDDATA; /*lint !e527*/
8166  }
8167 
8168  if( efficacy >= minefficacy )
8169  {
8170  SCIP_Bool infeasible;
8171 
8172  *separatedlpsol = TRUE;
8173  addedtolp = TRUE;
8174  SCIP_CALL( SCIPaddCut(scip, NULL, row, TRUE, &infeasible) );
8175  assert( ! infeasible );
8176  SCIPdebugMessage("added linearization cut <%s> to LP, efficacy = %g\n", SCIProwGetName(row), efficacy);
8177  }
8178  }
8179 
8180  if( !SCIProwIsLocal(row) && !addedtolp )
8181  {
8182  SCIP_CALL( SCIPaddPoolCut(scip, row) );
8183  SCIPdebugMessage("added linearization cut <%s> to cutpool\n", SCIProwGetName(row));
8184  }
8185 
8186  SCIP_CALL( SCIPreleaseRow(scip, &row) );
8187  }
8188 
8189  return SCIP_OKAY;
8190 }
8191 
8192 /** processes the event that a new primal solution has been found */
8193 static
8194 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
8196  SCIP_CONSHDLRDATA* conshdlrdata;
8197  SCIP_CONSHDLR* conshdlr;
8198  SCIP_CONS** conss;
8199  int nconss;
8200  SCIP_SOL* sol;
8201 
8202  assert(scip != NULL);
8203  assert(event != NULL);
8204  assert(eventdata != NULL);
8205  assert(eventhdlr != NULL);
8206 
8207  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
8208 
8209  conshdlr = (SCIP_CONSHDLR*)eventdata;
8210 
8211  nconss = SCIPconshdlrGetNConss(conshdlr);
8212 
8213  if( nconss == 0 )
8214  return SCIP_OKAY;
8215 
8216  sol = SCIPeventGetSol(event);
8217  assert(sol != NULL);
8218 
8219  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8220  assert(conshdlrdata != NULL);
8221 
8222  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
8223  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
8224  * or are from the tree, but postprocessed via proposeFeasibleSolution
8225  */
8226  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
8227  return SCIP_OKAY;
8228 
8229  conss = SCIPconshdlrGetConss(conshdlr);
8230  assert(conss != NULL);
8231 
8232  SCIPdebugMessage("caught new sol event %x from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
8233 
8234  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
8235 
8236  return SCIP_OKAY;
8237 }
8238 
8239 /** registers branching candidates according to convexification gap rule
8240  *
8241  * That is, computes for every nonconvex term the gap between the terms value in the LP solution and the value of the underestimator
8242  * as it would be (and maybe has been) constructed by the separation routines of this constraint handler. Then it registers all
8243  * variables occurring in each term with the computed gap. If variables appear in more than one term, they are registered several times.
8244  */
8245 static
8247  SCIP* scip, /**< SCIP data structure */
8248  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8249  SCIP_CONS** conss, /**< constraints to check */
8250  int nconss, /**< number of constraints to check */
8251  int* nnotify /**< counter for number of notifications performed */
8252  )
8253 {
8254  SCIP_CONSDATA* consdata;
8255  int c;
8256  int j;
8257  SCIP_Bool xbinary;
8258  SCIP_Bool ybinary;
8259  SCIP_Bool xunbounded;
8260  SCIP_Bool yunbounded;
8261  SCIP_VAR* x;
8262  SCIP_VAR* y;
8263  SCIP_Real xlb;
8264  SCIP_Real xub;
8265  SCIP_Real xval;
8266  SCIP_Real ylb;
8267  SCIP_Real yub;
8268  SCIP_Real yval;
8269  SCIP_Real gap;
8270  SCIP_Real coef_;
8271 
8272  assert(scip != NULL);
8273  assert(conshdlr != NULL);
8274  assert(conss != NULL || nconss == 0);
8275 
8276  *nnotify = 0;
8277  yval = SCIP_INVALID;
8278  xval = SCIP_INVALID;
8279 
8280  for( c = 0; c < nconss; ++c )
8281  {
8282  assert(conss != NULL);
8283  consdata = SCIPconsGetData(conss[c]);
8284  assert(consdata != NULL);
8285 
8286  if( !consdata->nquadvars )
8287  continue;
8288 
8289  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
8290  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
8291  continue;
8292  SCIPdebugMessage("cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
8293 
8294  /* square terms */
8295  for( j = 0; j < consdata->nquadvars; ++j )
8296  {
8297  x = consdata->quadvarterms[j].var;
8298  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef < 0) ||
8299  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef > 0) )
8300  {
8301  xlb = SCIPvarGetLbLocal(x);
8302  xub = SCIPvarGetUbLocal(x);
8303  if( SCIPisRelEQ(scip, xlb, xub) )
8304  {
8305  SCIPdebugMessage("ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
8306  continue;
8307  }
8308 
8309  xval = SCIPgetSolVal(scip, NULL, x);
8310 
8311  /* if variable is at bounds, then no need to branch, since secant is exact there */
8312  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
8313  continue;
8314 
8315  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
8316  gap = SCIPinfinity(scip);
8317  else
8318  gap = (xval-xlb)*(xub-xval)/(1+2*ABS(xval));
8319  assert(!SCIPisFeasNegative(scip, gap));
8320  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(gap, 0.0), SCIP_INVALID) );
8321  ++*nnotify;
8322  }
8323  }
8324 
8325  /* bilinear terms */
8326  for( j = 0; j < consdata->nbilinterms; ++j )
8327  {
8328  /* if any of the variables if fixed, then it actually behaves like a linear term, so we don't need to branch on it */
8329  x = consdata->bilinterms[j].var1;
8330  xlb = SCIPvarGetLbLocal(x);
8331  xub = SCIPvarGetUbLocal(x);
8332  if( SCIPisRelEQ(scip, xlb, xub) )
8333  continue;
8334 
8335  y = consdata->bilinterms[j].var2;
8336  ylb = SCIPvarGetLbLocal(y);
8337  yub = SCIPvarGetUbLocal(y);
8338  if( SCIPisRelEQ(scip, ylb, yub) )
8339  continue;
8340 
8341  xunbounded = SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub);
8342  yunbounded = SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub);
8343 
8344  /* compute gap, if both variable are bounded */
8345  gap = SCIPinfinity(scip);
8346  if( !xunbounded && !yunbounded )
8347  {
8348  xval = SCIPgetSolVal(scip, NULL, x);
8349  yval = SCIPgetSolVal(scip, NULL, y);
8350 
8351  /* if both variables are at one of its bounds, then no need to branch, since McCormick is exact there */
8352  if( (SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub)) &&
8353  ( SCIPisLE(scip, yval, ylb) || SCIPisGE(scip, yval, yub)) )
8354  continue;
8355 
8356  xval = MAX(xlb, MIN(xval, xub));
8357  yval = MAX(ylb, MIN(yval, yub));
8358 
8359  coef_ = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? -consdata->bilinterms[j].coef : consdata->bilinterms[j].coef;
8360  if( coef_ > 0.0 )
8361  {
8362  if( (xub-xlb)*yval + (yub-ylb)*xval <= xub*yub - xlb*ylb )
8363  gap = (xval*yval - xlb*yval - ylb*xval + xlb*ylb) / (1+sqrt(xval*xval + yval*yval));
8364  else
8365  gap = (xval*yval - xval*yub - yval*xub + xub*yub) / (1+sqrt(xval*xval + yval*yval));
8366  }
8367  else
8368  { /* coef_ < 0 */
8369  if( (xub-xlb)*yval - (yub-ylb)*xval <= xub*ylb - xlb*yub )
8370  gap = -(xval*yval - xval*ylb - yval*xub + xub*ylb) / (1+sqrt(xval*xval + yval*yval));
8371  else
8372  gap = -(xval*yval - xval*yub - yval*xlb + xlb*yub) / (1+sqrt(xval*xval + yval*yval));
8373  }
8374 
8375  assert(!SCIPisNegative(scip, gap / MAX3(MAX(REALABS(xlb), REALABS(xub)), MAX(REALABS(ylb), REALABS(yub)), 1.0))); /*lint !e666*/
8376  if( gap < 0.0 )
8377  gap = 0.0;
8378  }
8379 
8380  /* if one of the variables is binary or integral with domain width 1, then branching on this makes the term linear, so prefer this */
8381  xbinary = SCIPvarIsBinary(x) || (SCIPvarIsIntegral(x) && xub - xlb < 1.5);
8382  ybinary = SCIPvarIsBinary(y) || (SCIPvarIsIntegral(y) && yub - ylb < 1.5);
8383  if( xbinary )
8384  {
8386  ++*nnotify;
8387  }
8388  if( ybinary )
8389  {
8391  ++*nnotify;
8392  }
8393  if( xbinary || ybinary )
8394  continue;
8395 
8396  /* if one of the variables is unbounded, then branch on it first */
8397  if( xunbounded )
8398  {
8400  ++*nnotify;
8401  }
8402  if( yunbounded )
8403  {
8405  ++*nnotify;
8406  }
8407  if( xunbounded || yunbounded )
8408  continue;
8409 
8410  /* if both variables are integral, prefer the one with the smaller domain, so variable gets fixed soon
8411  * does not seem to work well on tln instances, so disable for now and may look at it later again
8412  */
8413 #ifdef BRANCHTOLINEARITY
8414  if( SCIPvarIsIntegral(x) && SCIPvarIsIntegral(y) )
8415  {
8416  if( SCIPisLT(scip, xub-xlb, yub-ylb) )
8417  {
8419  ++*nnotify;
8420  continue;
8421  }
8422  if( SCIPisGT(scip, xub-xlb, yub-ylb) )
8423  {
8425  ++*nnotify;
8426  continue;
8427  }
8428  }
8429 #endif
8430 
8431  /* in the regular case, suggest those variables which are not at its bounds for branching
8432  * this is, because after branching both variables will be one the bounds, and McCormick will be exact then */
8433  if( !SCIPisLE(scip, xval, xlb) && !SCIPisGE(scip, xval, xub) )
8434  {
8436  ++*nnotify;
8437  }
8438  if( !SCIPisLE(scip, yval, ylb) && !SCIPisGE(scip, yval, yub) )
8439  {
8441  ++*nnotify;
8442  }
8443  }
8444  }
8445 
8446  SCIPdebugMessage("registered %d branching candidates\n", *nnotify);
8447 
8448  return SCIP_OKAY;
8449 }
8450 
8451 /** registers branching candidates according to constraint violation rule
8452  *
8453  * That is, registers all variables appearing in nonconvex terms^1 with a score that is the violation of the constraint.
8454  * This is the same rule as is applied in cons_nonlinear and other nonlinear constraint handlers.
8455  *
8456  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
8457  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
8458  */
8459 static
8461  SCIP* scip, /**< SCIP data structure */
8462  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8463  SCIP_CONS** conss, /**< constraints to check */
8464  int nconss, /**< number of constraints to check */
8465  int* nnotify /**< counter for number of notifications performed */
8466  )
8467 {
8468  SCIP_CONSDATA* consdata;
8469  SCIP_QUADVARTERM* quadvarterm;
8470  int c;
8471  int j;
8472  SCIP_VAR* x;
8473  SCIP_Real xlb;
8474  SCIP_Real xub;
8475  SCIP_Real xval;
8476 
8477  assert(scip != NULL);
8478  assert(conshdlr != NULL);
8479  assert(conss != NULL || nconss == 0);
8480 
8481  *nnotify = 0;
8482 
8483  for( c = 0; c < nconss; ++c )
8484  {
8485  assert(conss != NULL);
8486  consdata = SCIPconsGetData(conss[c]);
8487  assert(consdata != NULL);
8488 
8489  if( !consdata->nquadvars )
8490  continue;
8491 
8492  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
8493  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
8494  continue;
8495  SCIPdebugMessage("cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
8496 
8497  for( j = 0; j < consdata->nquadvars; ++j )
8498  {
8499  quadvarterm = &consdata->quadvarterms[j];
8500  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
8501  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
8502  quadvarterm->nadjbilin > 0 )
8503  {
8504  x = quadvarterm->var;
8505  xlb = SCIPvarGetLbLocal(x);
8506  xub = SCIPvarGetUbLocal(x);
8507 
8508  if( quadvarterm->nadjbilin == 0 )
8509  {
8510  xval = SCIPgetSolVal(scip, NULL, x);
8511 
8512  /* if variable is at bounds and only in a nonconvex square term, then no need to branch, since secant is exact there */
8513  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
8514  continue;
8515  }
8516 
8517  if( SCIPisRelEQ(scip, xlb, xub) )
8518  {
8519  SCIPdebugMessage("ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
8520  continue;
8521  }
8522 
8523  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
8524  ++*nnotify;
8525  }
8526  }
8527  }
8528 
8529  SCIPdebugMessage("registered %d branching candidates\n", *nnotify);
8530 
8531  return SCIP_OKAY;
8532 }
8533 
8534 /** registers branching candidates according to centrality rule
8535  *
8536  * That is, registers all variables appearing in nonconvex terms^1 with a score that is given by the distance of the
8537  * variable value from its bounds. This rule should not make sense, as the distance to the bounds is also (often) considered
8538  * by the branching rule later on.
8539  *
8540  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
8541  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
8542  */
8543 static
8545  SCIP* scip, /**< SCIP data structure */
8546  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8547  SCIP_CONS** conss, /**< constraints to check */
8548  int nconss, /**< number of constraints to check */
8549  int* nnotify /**< counter for number of notifications performed */
8550  )
8551 {
8552  SCIP_CONSDATA* consdata;
8553  SCIP_QUADVARTERM* quadvarterm;
8554  int c;
8555  int j;
8556  SCIP_VAR* x;
8557  SCIP_Real xlb;
8558  SCIP_Real xub;
8559  SCIP_Real xval;
8560  SCIP_Real score;
8561 
8562  assert(scip != NULL);
8563  assert(conshdlr != NULL);
8564  assert(conss != NULL || nconss == 0);
8565 
8566  *nnotify = 0;
8567 
8568  for( c = 0; c < nconss; ++c )
8569  {
8570  assert(conss != NULL);
8571  consdata = SCIPconsGetData(conss[c]);
8572  assert(consdata != NULL);
8573 
8574  if( !consdata->nquadvars )
8575  continue;
8576 
8577  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
8578  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
8579  continue;
8580  SCIPdebugMessage("cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
8581 
8582  for( j = 0; j < consdata->nquadvars; ++j )
8583  {
8584  quadvarterm = &consdata->quadvarterms[j];
8585  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
8586  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
8587  quadvarterm->nadjbilin > 0 )
8588  {
8589  x = quadvarterm->var;
8590  xlb = SCIPvarGetLbLocal(x);
8591  xub = SCIPvarGetUbLocal(x);
8592 
8593  if( SCIPisRelEQ(scip, xlb, xub) )
8594  {
8595  SCIPdebugMessage("ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
8596  continue;
8597  }
8598 
8599  xval = SCIPgetSolVal(scip, NULL, x);
8600  xval = MAX(xlb, MIN(xub, xval));
8601 
8602  /* compute relative difference of xval to each of its bounds
8603  * and scale such that if xval were in the middle, we get a score of 1
8604  * and if xval is on one its bounds, the score is 0
8605  */
8606  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
8607  {
8608  if( (!SCIPisInfinity(scip, -xlb) && SCIPisEQ(scip, xval, xlb)) || (!SCIPisInfinity(scip, xub) && SCIPisEQ(scip, xval, xub)) )
8609  score = 0.0;
8610  else
8611  score = 1.0;
8612  }
8613  else
8614  {
8615  score = 4.0 * (xval - xlb) * (xub - xval) / ((xub - xlb) * (xub - xlb));
8616  }
8617 
8618  SCIP_CALL( SCIPaddExternBranchCand(scip, x, score, SCIP_INVALID) );
8619  ++*nnotify;
8620  }
8621  }
8622  }
8623 
8624  SCIPdebugMessage("registered %d branching candidates\n", *nnotify);
8625 
8626  return SCIP_OKAY;
8627 }
8628 
8629 /** registers branching candidates */
8630 static
8632  SCIP* scip, /**< SCIP data structure */
8633  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8634  SCIP_CONS** conss, /**< constraints to check */
8635  int nconss, /**< number of constraints to check */
8636  int* nnotify /**< counter for number of notifications performed */
8637  )
8638 {
8639  SCIP_CONSHDLRDATA* conshdlrdata;
8640 
8641  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8642  assert(conshdlrdata != NULL);
8643 
8644  switch( conshdlrdata->branchscoring )
8645  {
8646  case 'g' :
8647  SCIP_CALL( registerBranchingCandidatesGap(scip, conshdlr, conss, nconss, nnotify) );
8648  break;
8649 
8650  case 'v' :
8651  SCIP_CALL( registerBranchingCandidatesViolation(scip, conshdlr, conss, nconss, nnotify) );
8652  break;
8653 
8654  case 'c' :
8655  SCIP_CALL( registerBranchingCandidatesCentrality(scip, conshdlr, conss, nconss, nnotify) );
8656  break;
8657 
8658  default :
8659  SCIPerrorMessage("invalid branchscoring selection");
8660  SCIPABORT();
8661  return SCIP_ERROR; /*lint !e527*/
8662  }
8663 
8664  return SCIP_OKAY;
8665 }
8666 
8667 
8668 /** registers a quadratic variable from a violated constraint as branching candidate that has a large absolute value in the LP relaxation */
8669 static
8671  SCIP* scip, /**< SCIP data structure */
8672  SCIP_CONS** conss, /**< constraints */
8673  int nconss, /**< number of constraints */
8674  SCIP_VAR** brvar /**< buffer to store branching variable */
8675  )
8676 {
8677  SCIP_CONSDATA* consdata;
8678  SCIP_Real val;
8679  SCIP_Real brvarval;
8680  int i;
8681  int c;
8682 
8683  assert(scip != NULL);
8684  assert(conss != NULL || nconss == 0);
8685 
8686  *brvar = NULL;
8687  brvarval = -1.0;
8688 
8689  for( c = 0; c < nconss; ++c )
8690  {
8691  assert(conss != NULL);
8692  consdata = SCIPconsGetData(conss[c]);
8693  assert(consdata != NULL);
8694 
8695  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
8696  continue;
8697 
8698  for( i = 0; i < consdata->nquadvars; ++i )
8699  {
8700  /* do not propose fixed variables */
8701  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
8702  continue;
8703  val = SCIPgetSolVal(scip, NULL, consdata->quadvarterms[i].var);
8704  if( ABS(val) > brvarval )
8705  {
8706  brvarval = ABS(val);
8707  *brvar = consdata->quadvarterms[i].var;
8708  }
8709  }
8710  }
8711 
8712  if( *brvar != NULL )
8713  {
8714  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
8715  }
8716 
8717  return SCIP_OKAY;
8718 }
8719 
8720 /** replaces violated quadratic constraints where all quadratic variables are fixed by linear constraints */
8721 static
8723  SCIP* scip, /**< SCIP data structure */
8724  SCIP_CONS** conss, /**< constraints */
8725  int nconss, /**< number of constraints */
8726  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
8727  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
8728  SCIP_Bool* infeasible /**< whether we detected infeasibility */
8729  )
8730 {
8731  SCIP_CONS* cons;
8732  SCIP_CONSDATA* consdata;
8733  SCIP_RESULT checkresult;
8734  SCIP_Real constant;
8735  SCIP_Real val1;
8736  SCIP_Real val2;
8737  int i;
8738  int c;
8739 
8740  assert(scip != NULL);
8741  assert(conss != NULL || nconss == 0);
8742  assert(addedcons != NULL);
8743  assert(reduceddom != NULL);
8744  assert(infeasible != NULL);
8745 
8746  *addedcons = FALSE;
8747  *reduceddom = FALSE;
8748  *infeasible = FALSE;
8749 
8750  for( c = 0; c < nconss; ++c )
8751  {
8752  assert(conss != NULL);
8753  consdata = SCIPconsGetData(conss[c]);
8754  assert(consdata != NULL);
8755 
8756  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
8757  continue;
8758 
8759  constant = 0.0;
8760 
8761  for( i = 0; i < consdata->nquadvars; ++i )
8762  {
8763  /* variables should be fixed if constraint is violated */
8764  assert(SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
8765 
8766  val1 = (SCIPvarGetUbLocal(consdata->quadvarterms[i].var) + SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) / 2.0;
8767  constant += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val1) * val1;
8768  }
8769 
8770  for( i = 0; i < consdata->nbilinterms; ++i )
8771  {
8772  val1 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var1) + SCIPvarGetLbLocal(consdata->bilinterms[i].var1)) / 2.0;
8773  val2 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var2) + SCIPvarGetLbLocal(consdata->bilinterms[i].var2)) / 2.0;
8774  constant += consdata->bilinterms[i].coef * val1 * val2;
8775  }
8776 
8777  /* check if we have a bound change */
8778  if ( consdata->nlinvars == 1 )
8779  {
8780  SCIP_Bool tightened;
8781  SCIP_Real coef;
8782  SCIP_Real lhs;
8783  SCIP_Real rhs;
8784 
8785  coef = *consdata->lincoefs;
8786 
8787  /* compute lhs/rhs */
8788  if ( SCIPisInfinity(scip, -consdata->lhs) )
8789  lhs = -SCIPinfinity(scip);
8790  else
8791  lhs = consdata->lhs - constant;
8792 
8793  if ( SCIPisInfinity(scip, consdata->rhs) )
8794  rhs = SCIPinfinity(scip);
8795  else
8796  rhs = consdata->rhs - constant;
8797 
8798  SCIPdebugMessage("Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(*consdata->linvars), rhs);
8799 
8800  /* possibly correct lhs/rhs */
8801  assert( ! SCIPisZero(scip, coef) );
8802  if ( coef >= 0.0 )
8803  {
8804  if ( ! SCIPisInfinity(scip, -lhs) )
8805  lhs /= coef;
8806  if ( ! SCIPisInfinity(scip, rhs) )
8807  rhs /= coef;
8808  }
8809  else
8810  {
8811  SCIP_Real h;
8812  h = rhs;
8813  if ( ! SCIPisInfinity(scip, -lhs) )
8814  rhs = lhs/coef;
8815  else
8816  rhs = SCIPinfinity(scip);
8817 
8818  if ( ! SCIPisInfinity(scip, h) )
8819  lhs = h/coef;
8820  else
8821  lhs = -SCIPinfinity(scip);
8822  }
8823  SCIPdebugMessage("Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(*consdata->linvars), rhs);
8824 
8825  if( SCIPisInfinity(scip, -rhs) || SCIPisInfinity(scip, lhs) )
8826  {
8827  SCIPdebugMessage("node will marked as infeasible since lb/ub of %s is +/-infinity\n",
8828  SCIPvarGetName(consdata->linvars[0]));
8829 
8830  *infeasible = TRUE;
8831  return SCIP_OKAY;
8832  }
8833 
8834  if ( ! SCIPisInfinity(scip, -lhs) )
8835  {
8836  SCIP_CALL( SCIPtightenVarLb(scip, *consdata->linvars, lhs, TRUE, infeasible, &tightened) );
8837  if ( *infeasible )
8838  {
8839  SCIPdebugMessage("Lower bound leads to infeasibility.\n");
8840  return SCIP_OKAY;
8841  }
8842  if ( tightened )
8843  {
8844  SCIPdebugMessage("Lower boundx changed.\n");
8845  *reduceddom = TRUE;
8846  return SCIP_OKAY;
8847  }
8848  }
8849 
8850  if ( ! SCIPisInfinity(scip, rhs) )
8851  {
8852  SCIP_CALL( SCIPtightenVarUb(scip, *consdata->linvars, rhs, TRUE, infeasible, &tightened) );
8853  if ( *infeasible )
8854  {
8855  SCIPdebugMessage("Upper bound leads to infeasibility.\n");
8856  return SCIP_OKAY;
8857  }
8858  if ( tightened )
8859  {
8860  SCIPdebugMessage("Upper bound changed.\n");
8861  *reduceddom = TRUE;
8862  return SCIP_OKAY;
8863  }
8864  }
8865  }
8866  else
8867  {
8868  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
8869  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
8870  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : (consdata->lhs - constant)),
8871  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : (consdata->rhs - constant)),
8872  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
8873  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
8874  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
8875  SCIPconsIsStickingAtNode(conss[c])) );
8876 
8877  SCIPdebugMessage("replace quadratic constraint <%s> by linear constraint after all quadratic vars have been fixed\n", SCIPconsGetName(conss[c]) );
8878  SCIPdebugPrintCons(scip, cons, NULL);
8879 
8880  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
8881 
8882  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
8883  {
8884  SCIPdebugMessage("linear constraint is feasible and LP optimal, thus do not add\n");
8885  }
8886  else
8887  {
8888  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
8889  *addedcons = TRUE;
8890  }
8891  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
8892  }
8893  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
8894  }
8895 
8896  return SCIP_OKAY;
8897 }
8898 
8899 /** tightens a lower bound on a variable and checks the result */
8900 static
8902  SCIP* scip, /**< SCIP data structure */
8903  SCIP_CONS* cons, /**< constraint where we currently propagate */
8904  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8905  SCIP_VAR* var, /**< variable which domain we might reduce */
8906  SCIP_Real bnd, /**< new lower bound for variable */
8907  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
8908  int* nchgbds /**< counter to increase if a bound was tightened */
8909  )
8910 {
8911  SCIP_Bool infeas;
8912  SCIP_Bool tightened;
8913 
8914  assert(scip != NULL);
8915  assert(cons != NULL);
8916  assert(intervalinfty > 0.0);
8917  assert(bnd > -intervalinfty);
8918  assert(var != NULL);
8919  assert(result != NULL);
8920  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
8921  assert(nchgbds != NULL);
8922 
8923  /* new bound is no improvement */
8924  if( SCIPisHugeValue(scip, -bnd) || SCIPisLE(scip, bnd, SCIPvarGetLbLocal(var)) )
8925  return SCIP_OKAY;
8926 
8927  if( SCIPisInfinity(scip, bnd) )
8928  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
8929  *result = SCIP_CUTOFF;
8930  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8931  return SCIP_OKAY;
8932  }
8933 
8934  /* new lower bound is very low (between -intervalinfty and -SCIPinfinity()) */
8935  if( SCIPisInfinity(scip, -bnd) )
8936  return SCIP_OKAY;
8937 
8938  bnd = SCIPadjustedVarLb(scip, var, bnd);
8939  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
8940  if( infeas )
8941  {
8942  SCIPdebugMessage("%s found constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n",
8943  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
8944  *result = SCIP_CUTOFF;
8945  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8946  return SCIP_OKAY;
8947  }
8948  if( tightened )
8949  {
8950  SCIPdebugMessage("%s tightened lower bound of variable <%s> in constraint <%s> to %g\n",
8951  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
8952  ++*nchgbds;
8953  *result = SCIP_REDUCEDDOM;
8954  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8955  }
8956 
8957  return SCIP_OKAY;
8958 }
8959 
8960 /** tightens an upper bound on a variable and checks the result */
8961 static
8963  SCIP* scip, /**< SCIP data structure */
8964  SCIP_CONS* cons, /**< constraint where we currently propagate */
8965  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8966  SCIP_VAR* var, /**< variable which domain we might reduce */
8967  SCIP_Real bnd, /**< new upper bound for variable */
8968  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
8969  int* nchgbds /**< counter to increase if a bound was tightened */
8970  )
8971 {
8972  SCIP_Bool infeas;
8973  SCIP_Bool tightened;
8974 
8975  assert(scip != NULL);
8976  assert(cons != NULL);
8977  assert(intervalinfty > 0.0);
8978  assert(bnd < intervalinfty);
8979  assert(var != NULL);
8980  assert(result != NULL);
8981  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
8982  assert(nchgbds != NULL);
8983 
8984  /* new bound is no improvement */
8985  if( SCIPisHugeValue(scip, bnd) || SCIPisGE(scip, bnd, SCIPvarGetUbLocal(var)) )
8986  return SCIP_OKAY;
8987 
8988  if( SCIPisInfinity(scip, -bnd) )
8989  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
8990  *result = SCIP_CUTOFF;
8991  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8992  return SCIP_OKAY;
8993  }
8994 
8995  /* new upper bound is very high (between SCIPinfinity() and intervalinfty) */
8996  if( SCIPisInfinity(scip, bnd) )
8997  return SCIP_OKAY;
8998 
8999  bnd = SCIPadjustedVarUb(scip, var, bnd);
9000  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
9001  if( infeas )
9002  {
9003  SCIPdebugMessage("%s found constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n",
9004  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
9005  *result = SCIP_CUTOFF;
9006  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9007  return SCIP_OKAY;
9008  }
9009  if( tightened )
9010  {
9011  SCIPdebugMessage("%s tightened upper bound of variable <%s> in constraint <%s> to %g\n",
9012  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
9013  ++*nchgbds;
9014  *result = SCIP_REDUCEDDOM;
9015  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9016  }
9017 
9018  return SCIP_OKAY;
9019 }
9020 
9021 /** 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 */
9022 static
9024  SCIP* scip, /**< SCIP data structure */
9025  SCIP_CONS* cons, /**< constraint where we currently propagate */
9026  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9027  SCIP_VAR* var, /**< variable which bounds with might tighten */
9028  SCIP_Real a, /**< coefficient in square term */
9029  SCIP_INTERVAL b, /**< coefficient in linear term */
9030  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9031  SCIP_RESULT* result, /**< result of propagation */
9032  int* nchgbds /**< buffer where to add number of tightened bounds */
9033  )
9034 {
9035  SCIP_INTERVAL newrange;
9036 
9037  assert(scip != NULL);
9038  assert(cons != NULL);
9039  assert(var != NULL);
9040  assert(result != NULL);
9041  assert(nchgbds != NULL);
9042 
9043  /* compute solution of a*x^2 + b*x \in rhs */
9044  if( a == 0.0 && SCIPintervalGetInf(b) == 0.0 && SCIPintervalGetSup(b) == 0.0 )
9045  {
9046  /* relatively easy case: 0.0 \in rhs, thus check if infeasible or just redundant */
9047  if( SCIPintervalGetInf(rhs) > 0.0 || SCIPintervalGetSup(rhs) < 0.0 )
9048  {
9049  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9050  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9051  *result = SCIP_CUTOFF;
9052  }
9053  return SCIP_OKAY;
9054  }
9055  else if( SCIPvarGetLbLocal(var) >= 0.0 )
9056  {
9057  SCIP_INTERVAL a_;
9058 
9059  /* need only positive solutions */
9060  SCIPintervalSet(&a_, a);
9061  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &newrange, a_, b, rhs);
9062  }
9063  else if( SCIPvarGetUbLocal(var) <= 0.0 )
9064  {
9065  /* need only negative solutions */
9066  SCIP_INTERVAL a_;
9067  SCIP_INTERVAL tmp;
9068  SCIPintervalSet(&a_, a);
9070  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &tmp, a_, tmp, rhs);
9071  if( SCIPintervalIsEmpty(intervalinfty, tmp) )
9072  {
9073  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9074  *result = SCIP_CUTOFF;
9075  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9076  return SCIP_OKAY;
9077  }
9079  }
9080  else
9081  {
9082  /* need both positive and negative solution */
9083  SCIP_INTERVAL a_;
9084  SCIPintervalSet(&a_, a);
9085  SCIPintervalSolveUnivariateQuadExpression(intervalinfty, &newrange, a_, b, rhs);
9086  }
9087 
9088  /* SCIPdebugMessage("%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); */
9089 
9090  if( SCIPisInfinity(scip, SCIPintervalGetInf(newrange)) || SCIPisInfinity(scip, -SCIPintervalGetSup(newrange)) )
9091  {
9092  /* domain outside [-infty, +infty] -> declare node infeasible */
9093  SCIPdebugMessage("found <%s> infeasible because propagated domain of quadratic variable <%s> is outside of (-infty, +infty)\n",
9094  SCIPconsGetName(cons), SCIPvarGetName(var));
9095  *result = SCIP_CUTOFF;
9096  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9097  return SCIP_OKAY;
9098  }
9099 
9100  if( SCIPintervalIsEmpty(intervalinfty, newrange) )
9101  {
9102  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9103  *result = SCIP_CUTOFF;
9104  return SCIP_OKAY;
9105  }
9106 
9107  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(newrange)) )
9108  {
9109  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, SCIPintervalGetInf(newrange), result, nchgbds) );
9110  if( *result == SCIP_CUTOFF )
9111  return SCIP_OKAY;
9112  }
9113 
9114  if( !SCIPisInfinity(scip, SCIPintervalGetSup(newrange)) )
9115  {
9116  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, SCIPintervalGetSup(newrange), result, nchgbds) );
9117  if( *result == SCIP_CUTOFF )
9118  return SCIP_OKAY;
9119  }
9120 
9121  return SCIP_OKAY;
9122 }
9123 
9124 /* The new version below computes potentially tighter bounds, but also always adds a small safety area since it is not implemented roundingsafe.
9125  * This may be a reason why it gives worse results on one of two instances.
9126  * Further, I have only very few instances where one can expect a difference.
9127  */
9128 #ifndef PROPBILINNEW
9129 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
9130  *
9131  * @note Domain reductions for y are not deduced.
9132  */
9133 static
9135  SCIP* scip, /**< SCIP data structure */
9136  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
9137  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9138  SCIP_VAR* x, /**< first variable */
9139  SCIP_Real xsqrcoef, /**< square coefficient of x */
9140  SCIP_Real xlincoef, /**< linear coefficient of x */
9141  SCIP_VAR* y, /**< second variable */
9142  SCIP_Real ysqrcoef, /**< square coefficient of y */
9143  SCIP_Real ylincoef, /**< linear coefficient of y */
9144  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
9145  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9146  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
9147  int* nchgbds /**< counter to increment if domain reductions are found */
9148  )
9149 {
9150  SCIP_INTERVAL myrhs;
9151  SCIP_INTERVAL varbnds;
9152  SCIP_INTERVAL lincoef;
9153 
9154  assert(scip != NULL);
9155  assert(cons != NULL);
9156  assert(x != NULL);
9157  assert(y != NULL);
9158  assert(x != y);
9159  assert(result != NULL);
9160  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9161  assert(nchgbds != NULL);
9162  assert(bilincoef != 0.0);
9163 
9164  if( SCIPintervalIsEntire(intervalinfty, rhs) )
9165  return SCIP_OKAY;
9166 
9167  /* try to find domain reductions for x */
9169 
9170  /* put ysqrcoef*y^2 + ylincoef * y into rhs */
9171  if( SCIPintervalGetSup(rhs) >= intervalinfty )
9172  {
9173  /* if rhs is unbounded by above, it is sufficient to get an upper bound on ysqrcoef*y^2 + ylincoef * y */
9174  SCIP_ROUNDMODE roundmode;
9175  SCIP_Real tmp;
9176 
9177  SCIPintervalSet(&lincoef, ylincoef);
9178  tmp = SCIPintervalQuadUpperBound(intervalinfty, ysqrcoef, lincoef, varbnds);
9179  roundmode = SCIPintervalGetRoundingMode();
9181  SCIPintervalSetBounds(&myrhs, SCIPintervalGetInf(rhs) - tmp, intervalinfty);
9182  SCIPintervalSetRoundingMode(roundmode);
9183  }
9184  else if( SCIPintervalGetInf(rhs) <= -intervalinfty )
9185  {
9186  /* if rhs is unbounded by below, it is sufficient to get a lower bound on ysqrcoef*y^2 + ylincoef * y */
9187  SCIP_ROUNDMODE roundmode;
9188  SCIP_Real tmp;
9189 
9190  SCIPintervalSet(&lincoef, -ylincoef);
9191  tmp = -SCIPintervalQuadUpperBound(intervalinfty, -ysqrcoef, lincoef, varbnds);
9192  roundmode = SCIPintervalGetRoundingMode();
9194  SCIPintervalSetBounds(&myrhs, -intervalinfty, SCIPintervalGetSup(rhs) - tmp);
9195  SCIPintervalSetRoundingMode(roundmode);
9196  }
9197  else
9198  {
9199  /* if rhs is bounded, we need both bounds on ysqrcoef*y^2 + ylincoef * y */
9200  SCIP_INTERVAL tmp;
9201 
9202  SCIPintervalSet(&lincoef, ylincoef);
9203  SCIPintervalQuad(intervalinfty, &tmp, ysqrcoef, lincoef, varbnds);
9204  SCIPintervalSub(intervalinfty, &myrhs, rhs, tmp);
9205  }
9206 
9207  /* create equation xsqrcoef * x^2 + (xlincoef + bilincoef * [ylb, yub]) * x \in myrhs */
9208  SCIPintervalMulScalar(intervalinfty, &lincoef, varbnds, bilincoef);
9209  SCIPintervalAddScalar(intervalinfty, &lincoef, lincoef, xlincoef);
9210 
9211  /* propagate bounds on x */
9212  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, x, xsqrcoef, lincoef, myrhs, result, nchgbds) );
9213 
9214  return SCIP_OKAY;
9215 }
9216 #else
9217 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
9218  *
9219  * @note Domain reductions for y are not deduced.
9220  */
9221 static
9223  SCIP* scip, /**< SCIP data structure */
9224  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
9225  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9226  SCIP_VAR* x, /**< first variable */
9227  SCIP_Real xsqrcoef, /**< square coefficient of x */
9228  SCIP_Real xlincoef, /**< linear coefficient of x */
9229  SCIP_VAR* y, /**< second variable */
9230  SCIP_Real ysqrcoef, /**< square coefficient of y */
9231  SCIP_Real ylincoef, /**< linear coefficient of y */
9232  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
9233  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9234  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
9235  int* nchgbds /**< counter to increment if domain reductions are found */
9236  )
9237 {
9238  SCIP_INTERVAL xbnds;
9239  SCIP_INTERVAL ybnds;
9240 
9241  assert(scip != NULL);
9242  assert(cons != NULL);
9243  assert(x != NULL);
9244  assert(y != NULL);
9245  assert(x != y);
9246  assert(result != NULL);
9247  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9248  assert(nchgbds != NULL);
9249  assert(bilincoef != 0.0);
9250 
9251  if( SCIPintervalIsEntire(intervalinfty, rhs) )
9252  return SCIP_OKAY;
9253 
9254  SCIPintervalSetBounds(&xbnds,
9255  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x))), /*lint !e666*/
9256  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)))); /*lint !e666*/
9257  SCIPintervalSetBounds(&ybnds,
9258  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))), /*lint !e666*/
9259  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))); /*lint !e666*/
9260 
9261  /* try to find domain reductions for x */
9262  SCIPintervalSolveBivariateQuadExpressionAllScalar(intervalinfty, &xbnds, xsqrcoef, ysqrcoef, bilincoef, xlincoef, ylincoef, rhs, xbnds, ybnds);
9263 
9264  if( SCIPintervalIsEmpty(intervalinfty, xbnds) )
9265  {
9266  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(x));
9267  *result = SCIP_CUTOFF;
9268  return SCIP_OKAY;
9269  }
9270 
9271  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(xbnds)) )
9272  {
9273  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, x, SCIPintervalGetInf(xbnds), result, nchgbds) );
9274  if( *result == SCIP_CUTOFF )
9275  return SCIP_OKAY;
9276  }
9277 
9278  if( !SCIPisInfinity(scip, SCIPintervalGetSup(xbnds)) )
9279  {
9280  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, x, SCIPintervalGetSup(xbnds), result, nchgbds) );
9281  if( *result == SCIP_CUTOFF )
9282  return SCIP_OKAY;
9283  }
9284 
9285  return SCIP_OKAY;
9286 }
9287 #endif
9288 
9289 /** computes the minimal and maximal activity for the quadratic part in a constraint data
9290  *
9291  * Only sums up terms that contribute finite values.
9292  * Gives the number of terms that contribute infinite values.
9293  * Only computes those activities where the corresponding side of the constraint is finite.
9294  */
9295 static
9297  SCIP* scip, /**< SCIP data structure */
9298  SCIP_CONSDATA* consdata, /**< constraint data */
9299  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9300  SCIP_Real* minquadactivity, /**< minimal activity of quadratic variable terms where only terms with finite minimal activity contribute */
9301  SCIP_Real* maxquadactivity, /**< maximal activity of quadratic variable terms where only terms with finite maximal activity contribute */
9302  int* minactivityinf, /**< number of quadratic variables that contribute -infinity to minimal activity */
9303  int* maxactivityinf, /**< number of quadratic variables that contribute +infinity to maximal activity */
9304  SCIP_INTERVAL* quadactcontr /**< contribution of each quadratic variables to quadactivity */
9305  )
9306 { /*lint --e{666}*/
9307  SCIP_ROUNDMODE prevroundmode;
9308  int i;
9309  int j;
9310  int k;
9311  SCIP_INTERVAL tmp;
9312  SCIP_Real bnd;
9313  SCIP_INTERVAL xrng;
9314  SCIP_INTERVAL lincoef;
9315 
9316  assert(scip != NULL);
9317  assert(consdata != NULL);
9318  assert(minquadactivity != NULL);
9319  assert(maxquadactivity != NULL);
9320  assert(minactivityinf != NULL);
9321  assert(maxactivityinf != NULL);
9322  assert(quadactcontr != NULL);
9323 
9324  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
9325  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
9326  */
9327  *minquadactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
9328  *maxquadactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
9329 
9330  *minactivityinf = 0;
9331  *maxactivityinf = 0;
9332 
9333  if( consdata->nquadvars == 0 )
9334  {
9335  SCIPintervalSet(&consdata->quadactivitybounds, 0.0);
9336  return;
9337  }
9338 
9339  for( i = 0; i < consdata->nquadvars; ++i )
9340  {
9341  /* there should be no quadratic variables fixed at -/+ infinity due to our locks */
9342  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var)));
9343  assert(!SCIPisInfinity(scip, -SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
9344 
9345  SCIPintervalSetBounds(&quadactcontr[i], -intervalinfty, intervalinfty);
9346 
9347  SCIPintervalSetBounds(&xrng,
9348  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))),
9349  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))));
9350 
9351  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
9352  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
9353  {
9354  k = consdata->quadvarterms[i].adjbilin[j];
9355  if( consdata->bilinterms[k].var1 != consdata->quadvarterms[i].var )
9356  continue; /* handle this term later */
9357 
9358  SCIPintervalSetBounds(&tmp,
9359  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9360  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9361  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9362  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9363  }
9364 
9365  if( !SCIPisInfinity(scip, -consdata->lhs) )
9366  {
9367  /* compute maximal activity only if there is a finite left hand side */
9368  bnd = SCIPintervalQuadUpperBound(intervalinfty, consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
9369  if( SCIPisInfinity(scip, bnd) )
9370  {
9371  ++*maxactivityinf;
9372  }
9373  else if( SCIPisInfinity(scip, -bnd) )
9374  {
9375  /* if maximal activity is below value for -infinity, let's take -1e10 as upper bound on maximal activity
9376  * @todo Something better?
9377  */
9378  bnd = -sqrt(SCIPinfinity(scip));
9379  *maxquadactivity += bnd;
9380  quadactcontr[i].sup = bnd;
9381  }
9382  else
9383  {
9384  prevroundmode = SCIPintervalGetRoundingMode();
9386  *maxquadactivity += bnd;
9387  SCIPintervalSetRoundingMode(prevroundmode);
9388  quadactcontr[i].sup = bnd;
9389  }
9390  }
9391 
9392  if( !SCIPisInfinity(scip, consdata->rhs) )
9393  {
9394  /* compute minimal activity only if there is a finite right hand side */
9395  SCIPintervalSetBounds(&lincoef, -SCIPintervalGetSup(lincoef), -SCIPintervalGetInf(lincoef));
9396  bnd = -SCIPintervalQuadUpperBound(intervalinfty, -consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
9397 
9398  if( SCIPisInfinity(scip, -bnd) )
9399  {
9400  ++*minactivityinf;
9401  }
9402  else if( SCIPisInfinity(scip, bnd) )
9403  {
9404  /* if minimal activity is above value for infinity, let's take 1e10 as lower bound on minimal activity
9405  * @todo Something better?
9406  */
9407  bnd = sqrt(SCIPinfinity(scip));
9408  *minquadactivity += bnd;
9409  quadactcontr[i].inf = bnd;
9410  }
9411  else
9412  {
9413  prevroundmode = SCIPintervalGetRoundingMode();
9415  *minquadactivity += bnd;
9416  SCIPintervalSetRoundingMode(prevroundmode);
9417  quadactcontr[i].inf = bnd;
9418  }
9419  }
9420 
9421  }
9422 
9423  SCIPintervalSetBounds(&consdata->quadactivitybounds,
9424  (*minactivityinf > 0 ? -intervalinfty : *minquadactivity),
9425  (*maxactivityinf > 0 ? intervalinfty : *maxquadactivity));
9426  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
9427 }
9428 
9429 /** propagates bounds on a quadratic constraint */
9430 static
9432  SCIP* scip, /**< SCIP data structure */
9433  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9434  SCIP_CONS* cons, /**< constraint to process */
9435  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
9436  int* nchgbds, /**< buffer where to add the the number of changed bounds */
9437  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
9438  )
9439 { /*lint --e{666}*/
9440  SCIP_CONSDATA* consdata;
9441  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
9442  SCIP_INTERVAL consactivity; /* activity of linear plus quadratic part */
9443  SCIP_Real intervalinfty; /* infinity used for interval computation */
9444  SCIP_Real minquadactivity; /* lower bound on finite activities of quadratic part */
9445  SCIP_Real maxquadactivity; /* upper bound on finite activities of quadratic part */
9446  int quadminactinf; /* number of quadratic variables that contribute -infinity to minimal activity of quadratic term */
9447  int quadmaxactinf; /* number of quadratic variables that contribute +infinity to maximal activity of quadratic term */
9448  SCIP_INTERVAL* quadactcontr; /* contribution of each quadratic variable term to quadactivity */
9449 
9450  SCIP_VAR* var;
9451  SCIP_INTERVAL rhs; /* right hand side of quadratic equation */
9452  SCIP_INTERVAL tmp;
9453  SCIP_ROUNDMODE roundmode;
9454  SCIP_Real bnd;
9455  int i;
9456 
9457  assert(scip != NULL);
9458  assert(conshdlr != NULL);
9459  assert(cons != NULL);
9460  assert(result != NULL);
9461  assert(nchgbds != NULL);
9462  assert(redundant != NULL);
9463 
9464  consdata = SCIPconsGetData(cons);
9465  assert(consdata != NULL);
9466 
9467  *result = SCIP_DIDNOTRUN;
9468  *redundant = FALSE;
9469 
9470  if( consdata->ispropagated )
9471  return SCIP_OKAY;
9472 
9473  *result = SCIP_DIDNOTFIND;
9474 
9475  intervalinfty = 1000 * SCIPinfinity(scip) * SCIPinfinity(scip);
9476 
9477  quadactcontr = NULL;
9478  quadminactinf = -1;
9479  quadmaxactinf = -1;
9480 
9481  SCIPdebugMessage("start domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
9482 
9483  consdata->ispropagated = TRUE;
9484 
9485  /* make sure we have activity of linear term and that they are consistent */
9486  consdataUpdateLinearActivity(scip, consdata, intervalinfty);
9487  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
9488  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
9489  assert(consdata->minlinactivityinf >= 0);
9490  assert(consdata->maxlinactivityinf >= 0);
9491 
9492  /* sort quadratic variable terms, in case we need to search for terms occuring in bilinear terms later
9493  * we sort here already, since we rely on a constant variable order during this method
9494  */
9495  if( consdata->nbilinterms > 0 )
9496  {
9497  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
9498  }
9499 
9500  /* compute activity of quad term part, if not up to date
9501  * in that case, we also collect the contribution of each quad var term for later */
9502  if( SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds) )
9503  {
9504  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
9505  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
9506  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
9507  }
9508 
9509  SCIPdebugMessage("linear activity: [%g, %g] quadratic activity: [%g, %g]\n",
9510  (consdata->minlinactivityinf > 0 ? -SCIPinfinity(scip) : consdata->minlinactivity),
9511  (consdata->maxlinactivityinf > 0 ? SCIPinfinity(scip) : consdata->maxlinactivity),
9512  consdata->quadactivitybounds.inf, consdata->quadactivitybounds.sup);
9513 
9514  /* extend constraint bounds by epsilon to avoid some numerical difficulties */
9515  SCIPintervalSetBounds(&consbounds,
9516  -infty2infty(SCIPinfinity(scip), intervalinfty, -consdata->lhs+SCIPepsilon(scip)),
9517  +infty2infty(SCIPinfinity(scip), intervalinfty, consdata->rhs+SCIPepsilon(scip)));
9518 
9519  /* check redundancy and infeasibility */
9520  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity,
9521  consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity);
9522  SCIPintervalAdd(intervalinfty, &consactivity, consactivity, consdata->quadactivitybounds);
9523  if( SCIPintervalIsSubsetEQ(intervalinfty, consactivity, consbounds) )
9524  {
9525  SCIPdebugMessage("found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
9526  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
9527  *redundant = TRUE;
9528  goto CLEANUP;
9529  }
9530 
9531  /* was SCIPintervalAreDisjoint(consbounds, consactivity), but that would allow violations up to eps only
9532  * we need to decide feasibility w.r.t. feastol (but still want to propagate w.r.t. eps)
9533  */
9534  if( SCIPisFeasGT(scip, consbounds.inf, consactivity.sup) || SCIPisFeasLT(scip, consbounds.sup, consactivity.inf) )
9535  {
9536  SCIPdebugMessage("found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
9537  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
9538  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
9539  *result = SCIP_CUTOFF;
9540  goto CLEANUP;
9541  }
9542 
9543  /* propagate linear part \in rhs = consbounds - quadactivity (use the one from consdata, since that includes infinities) */
9544  SCIPintervalSub(intervalinfty, &rhs, consbounds, consdata->quadactivitybounds);
9545  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
9546  {
9547  SCIP_Real coef;
9548 
9549  for( i = 0; i < consdata->nlinvars; ++i )
9550  {
9551  coef = consdata->lincoefs[i];
9552  var = consdata->linvars[i];
9553 
9554  /* skip fixed variables
9555  * @todo is that a good or a bad idea?
9556  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
9557  */
9558  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
9559  continue;
9560 
9561  if( coef > 0.0 )
9562  {
9563  if( SCIPintervalGetSup(rhs) < intervalinfty )
9564  {
9565  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
9566  /* try to tighten the upper bound on var x */
9567  if( consdata->minlinactivityinf == 0 )
9568  {
9569  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
9570  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
9571  roundmode = SCIPintervalGetRoundingMode();
9573  bnd = SCIPintervalGetSup(rhs);
9574  bnd -= consdata->minlinactivity;
9575  bnd += coef * SCIPvarGetLbLocal(var);
9576  bnd /= coef;
9577  SCIPintervalSetRoundingMode(roundmode);
9578  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9579  if( *result == SCIP_CUTOFF )
9580  break;
9581  }
9582  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
9583  {
9584  /* x was the variable that made the minimal linear activity equal -infinity, so
9585  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
9586  roundmode = SCIPintervalGetRoundingMode();
9588  bnd = SCIPintervalGetSup(rhs);
9589  bnd -= consdata->minlinactivity;
9590  bnd /= coef;
9591  SCIPintervalSetRoundingMode(roundmode);
9592  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9593  if( *result == SCIP_CUTOFF )
9594  break;
9595  }
9596  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
9597  }
9598 
9599  if( SCIPintervalGetInf(rhs) > -intervalinfty )
9600  {
9601  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
9602  /* try to tighten the lower bound on var x */
9603  if( consdata->maxlinactivityinf == 0 )
9604  {
9605  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
9606  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
9607  roundmode = SCIPintervalGetRoundingMode();
9609  bnd = SCIPintervalGetInf(rhs);
9610  bnd -= consdata->maxlinactivity;
9611  bnd += coef * SCIPvarGetUbLocal(var);
9612  bnd /= coef;
9613  SCIPintervalSetRoundingMode(roundmode);
9614  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9615  if( *result == SCIP_CUTOFF )
9616  break;
9617  }
9618  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
9619  {
9620  /* x was the variable that made the maximal linear activity equal infinity, so
9621  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
9622  roundmode = SCIPintervalGetRoundingMode();
9624  bnd = SCIPintervalGetInf(rhs);
9625  bnd -= consdata->maxlinactivity;
9626  bnd /= coef;
9627  SCIPintervalSetRoundingMode(roundmode);
9628  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9629  if( *result == SCIP_CUTOFF )
9630  break;
9631  }
9632  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
9633  }
9634  }
9635  else
9636  {
9637  assert(coef < 0.0 );
9638  if( SCIPintervalGetInf(rhs) > -intervalinfty )
9639  {
9640  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
9641  /* try to tighten the upper bound on var x */
9642  if( consdata->maxlinactivityinf == 0 )
9643  {
9644  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
9645  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
9646  roundmode = SCIPintervalGetRoundingMode();
9648  bnd = consdata->maxlinactivity;
9649  bnd += (-coef) * SCIPvarGetLbLocal(var);
9650  bnd -= SCIPintervalGetInf(rhs);
9651  bnd /= (-coef);
9652  SCIPintervalSetRoundingMode(roundmode);
9653  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9654  if( *result == SCIP_CUTOFF )
9655  break;
9656  }
9657  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
9658  {
9659  /* x was the variable that made the maximal linear activity equal infinity, so
9660  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
9661  roundmode = SCIPintervalGetRoundingMode();
9663  bnd = consdata->maxlinactivity;
9664  bnd -= SCIPintervalGetInf(rhs);
9665  bnd /= (-coef);
9666  SCIPintervalSetRoundingMode(roundmode);
9667  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9668  if( *result == SCIP_CUTOFF )
9669  break;
9670  }
9671  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
9672  }
9673 
9674  if( SCIPintervalGetSup(rhs) < intervalinfty )
9675  {
9676  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
9677  /* try to tighten the lower bound on var x */
9678  if( consdata->minlinactivityinf == 0 )
9679  {
9680  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
9681  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
9682  roundmode = SCIPintervalGetRoundingMode();
9684  bnd = consdata->minlinactivity;
9685  bnd += (-coef) * SCIPvarGetUbLocal(var);
9686  bnd -= SCIPintervalGetSup(rhs);
9687  bnd /= (-coef);
9688  SCIPintervalSetRoundingMode(roundmode);
9689  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9690  if( *result == SCIP_CUTOFF )
9691  break;
9692  }
9693  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
9694  {
9695  /* x was the variable that made the maximal linear activity equal -infinity, so
9696  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
9697  roundmode = SCIPintervalGetRoundingMode();
9699  bnd = consdata->minlinactivity;
9700  bnd -= SCIPintervalGetSup(rhs);
9701  bnd /= (-coef);
9702  SCIPintervalSetRoundingMode(roundmode);
9703  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9704  if( *result == SCIP_CUTOFF )
9705  break;
9706  }
9707  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
9708  }
9709  }
9710  }
9711  if( *result == SCIP_CUTOFF )
9712  goto CLEANUP;
9713  }
9714 
9715  /* propagate quadratic part \in rhs = consbounds - linactivity */
9716  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
9717  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
9718  consdataUpdateLinearActivity(scip, consdata, intervalinfty); /* make sure, activities of linear part did not become invalid by above bound changes, if any */
9719  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
9720  SCIPintervalSetBounds(&tmp,
9721  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
9722  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity));
9723  SCIPintervalSub(intervalinfty, &rhs, consbounds, tmp);
9724  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
9725  {
9726  if( consdata->nquadvars == 1 )
9727  {
9728  /* quadratic part is just a*x^2+b*x -> a common case that we treat directly */
9729  SCIP_INTERVAL lincoef; /* linear coefficient of quadratic equation */
9730 
9731  assert(consdata->nbilinterms == 0);
9732 
9733  var = consdata->quadvarterms[0].var;
9734  SCIPintervalSet(&lincoef, consdata->quadvarterms[0].lincoef);
9735 
9736  /* propagate a*x^2 + b*x \in rhs */
9737  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[0].sqrcoef, lincoef, rhs, result, nchgbds) );
9738  }
9739  else if( consdata->nbilinterms == 1 && consdata->nquadvars == 2 )
9740  {
9741  /* quadratic part is just ax*x^2+bx*x + ay*y^2+by*y + c*xy -> a common case that we treat directly */
9742  assert(consdata->bilinterms[0].var1 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var1 == consdata->quadvarterms[1].var);
9743  assert(consdata->bilinterms[0].var2 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var2 == consdata->quadvarterms[1].var);
9744 
9745  /* 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 */
9746  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
9747  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
9748  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
9749  consdata->bilinterms[0].coef,
9750  rhs, result, nchgbds) );
9751  if( *result != SCIP_CUTOFF )
9752  {
9753  /* 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 */
9754  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
9755  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
9756  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
9757  consdata->bilinterms[0].coef,
9758  rhs, result, nchgbds) );
9759  }
9760  }
9761  else
9762  {
9763  /* general case */
9764 
9765  /* compute "advanced" information on quad var term activities, if not up-to-date */
9766  if( quadminactinf == -1 )
9767  {
9768  assert(quadactcontr == NULL);
9769  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
9770  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
9771  }
9772  assert(quadactcontr != NULL);
9773  assert(quadminactinf >= 0);
9774  assert(quadmaxactinf >= 0);
9775 
9776  /* if the quad activities are not hopelessly unbounded on useful sides, try to deduce domain reductions on quad vars */
9777  if( (SCIPintervalGetSup(rhs) < intervalinfty && quadminactinf <= 1) ||
9778  ( SCIPintervalGetInf(rhs) > -intervalinfty && quadmaxactinf <= 1) )
9779  {
9780  SCIP_INTERVAL lincoef;
9781  SCIP_INTERVAL rhs2;
9782  int j;
9783  int k;
9784 
9785  for( i = 0; i < consdata->nquadvars; ++i )
9786  {
9787  var = consdata->quadvarterms[i].var;
9788 
9789  /* skip fixed variables
9790  * @todo is that a good or a bad idea?
9791  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
9792  */
9793  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
9794  continue;
9795 
9796  /* compute rhs2 such that we can propagate quadvarterm(x_i) \in rhs2 */
9797 
9798  /* setup rhs2.sup = rhs.sup - (quadactivity.inf - quadactcontr[i].inf), if everything were finite
9799  * if only quadactcontr[i].inf is infinite (i.e., the other i are all finite), we just get rhs2.sup = rhs.sup
9800  * otherwise we get rhs2.sup = infinity */
9801  if( SCIPintervalGetSup(rhs) < intervalinfty )
9802  {
9803  if( quadminactinf == 0 || (quadminactinf == 1 && SCIPintervalGetInf(quadactcontr[i]) <= -intervalinfty) )
9804  {
9805  roundmode = SCIPintervalGetRoundingMode();
9807  rhs2.sup = rhs.sup - minquadactivity; /*lint !e644*/
9808  /* if the residual quad min activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
9809  if( quadminactinf == 0 && SCIPintervalGetInf(quadactcontr[i]) != 0.0 )
9810  rhs2.sup += SCIPintervalGetInf(quadactcontr[i]);
9811  SCIPintervalSetRoundingMode(roundmode);
9812  }
9813  else
9814  {
9815  /* there are either >= 2 quad var terms contributing -infinity, or there is one which is not i */
9816  rhs2.sup = intervalinfty;
9817  }
9818  }
9819  else
9820  {
9821  rhs2.sup = intervalinfty;
9822  }
9823 
9824  /* setup rhs2.inf = rhs.inf - (quadactivity.sup - quadactcontr[i].sup), see also above */
9825  if( SCIPintervalGetInf(rhs) > -intervalinfty )
9826  {
9827  if( quadmaxactinf == 0 || (quadmaxactinf == 1 && SCIPintervalGetSup(quadactcontr[i]) >= intervalinfty) )
9828  {
9829  roundmode = SCIPintervalGetRoundingMode();
9831  rhs2.inf = rhs.inf - maxquadactivity; /*lint !e644*/
9832  /* if the residual quad max activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
9833  if( quadmaxactinf == 0 && SCIPintervalGetSup(quadactcontr[i]) != 0.0 )
9834  rhs2.inf += SCIPintervalGetSup(quadactcontr[i]);
9835  SCIPintervalSetRoundingMode(roundmode);
9836  }
9837  else
9838  {
9839  /* there are either >= 2 quad var terms contributing infinity, or there is one which is not i */
9840  rhs2.inf = -intervalinfty;
9841  }
9842  }
9843  else
9844  {
9845  rhs2.inf = -intervalinfty;
9846  }
9847  assert(!SCIPintervalIsEmpty(intervalinfty, rhs2));
9848 
9849  /* if rhs2 is entire, then there is nothing we could propagate */
9850  if( SCIPintervalIsEntire(intervalinfty, rhs2) )
9851  continue;
9852 
9853  /* assemble linear coefficient for quad equation a*x^2 + b*x \in rhs2 */
9854  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
9855  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
9856  {
9857  k = consdata->quadvarterms[i].adjbilin[j];
9858 #if 1
9859  if( consdata->bilinterms[k].var1 == var )
9860  {
9861  /* bilinear term k contributes to the activity of quad var term i, so just add bounds to linear coef */
9862  SCIPintervalSetBounds(&tmp,
9863  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9864  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9865  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9866  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9867  }
9868  else
9869  {
9870  /* bilinear term k does not contribute to the activity of quad var term i
9871  * so bounds on term k are contained in rhs2
9872  * if they are finite, we try to remove them from rhs2 and update lincoef instead
9873  * 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
9874  * HOWEVER: when computing rhs2, we may not just have added the bounds for the bilinear term, but for the associated quadratic term
9875  * for this complete term, we used SCIPintervalQuad to compute the bounds
9876  * since we do not want to repeat a call to SCIPintervalQuad for that quadratic term with bilinear term k removed,
9877  * we only remove the bounds for the bilinear term k from rhs2 if the associated quadratic term consists only of this bilinear term,
9878  * i.e., the quadratic term corresponding to var1 should be only var1*var2, but have no square or linear coefs or other bilinear terms
9879  * (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)
9880  */
9881  SCIP_INTERVAL me;
9882  SCIP_INTERVAL bilinbounds;
9883  int otherpos;
9884 
9885  assert(consdata->bilinterms[k].var2 == var);
9886 
9887  assert(consdata->quadvarssorted);
9888  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[k].var1, &otherpos) );
9889  assert(otherpos >= 0);
9890  assert(consdata->quadvarterms[otherpos].var == consdata->bilinterms[k].var1);
9891 
9892  if( (consdata->quadvarterms[otherpos].sqrcoef != 0.0) || consdata->quadvarterms[otherpos].lincoef != 0.0 ||
9893  consdata->quadvarterms[otherpos].nadjbilin > 1 )
9894  continue;
9895 
9896  /* set tmp to bounds of other variable and multiply with bilin coef */
9897  SCIPintervalSetBounds(&tmp,
9898  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))),
9899  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))));
9900  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9901 
9902  /* set me to bounds of i'th variable */
9904  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9905  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9906 
9907  /* remove me*tmp from rhs2 */
9908 
9909  roundmode = SCIPintervalGetRoundingMode();
9910 
9911  if( rhs2.inf > -intervalinfty )
9912  {
9913  /* need upward rounding for SCIPintervalMulSup */
9915  SCIPintervalMulSup(intervalinfty, &bilinbounds, me, tmp);
9916  /* rhs2.inf += bilinbounds.sup, but we are in upward rounding */
9917  if( bilinbounds.sup < intervalinfty )
9918  rhs2.inf = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.inf) - bilinbounds.sup);
9919  }
9920 
9921  if( rhs2.sup < intervalinfty )
9922  {
9923  /* need downward rounding for SCIPintervalMulInf */
9925  SCIPintervalMulInf(intervalinfty, &bilinbounds, me, tmp);
9926  /* rhs2.sup += bilinbounds.inf, but we are in downward rounding */
9927  if( bilinbounds.inf > -intervalinfty )
9928  rhs2.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.sup) - bilinbounds.inf);
9929  }
9930 
9931  SCIPintervalSetRoundingMode(roundmode);
9932 
9933  /* add tmp to lincoef */
9934  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9935  }
9936 #else
9937  if( consdata->bilinterms[k].var1 != var )
9938  continue; /* this term does not contribute to the activity of quad var term i */
9939 
9940  SCIPintervalSetBounds(&tmp,
9941  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9942  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9943  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9944  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9945 #endif
9946  }
9947 
9948  /* deduce domain reductions for x_i */
9949  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[i].sqrcoef, lincoef, rhs2, result, nchgbds) );
9950  if( *result == SCIP_CUTOFF )
9951  goto CLEANUP;
9952  }
9953  }
9954  }
9955  }
9956 
9957  CLEANUP:
9958  SCIPfreeBufferArrayNull(scip, &quadactcontr);
9959 
9960  return SCIP_OKAY;
9961 }
9962 
9963 /** calls domain propagation for a set of constraints */
9964 static
9966  SCIP* scip, /**< SCIP data structure */
9967  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9968  SCIP_CONS** conss, /**< constraints to process */
9969  int nconss, /**< number of constraints */
9970  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
9971  int* nchgbds /**< buffer where to add the the number of changed bounds */
9972  )
9973 {
9974  SCIP_CONSHDLRDATA* conshdlrdata;
9975  SCIP_RESULT propresult;
9976  SCIP_Bool redundant;
9977  int c;
9978  int roundnr;
9979  SCIP_Bool success;
9980  int maxproprounds;
9981 
9982  assert(scip != NULL);
9983  assert(conshdlr != NULL);
9984  assert(conss != NULL || nconss == 0);
9985  assert(result != NULL);
9986  assert(nchgbds != NULL);
9987 
9989 
9990  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9991  assert(conshdlrdata != NULL);
9992 
9993  *result = SCIP_DIDNOTFIND;
9994  roundnr = 0;
9995  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
9996  maxproprounds = conshdlrdata->maxproproundspresolve;
9997  else
9998  maxproprounds = conshdlrdata->maxproprounds;
9999 
10000  do
10001  {
10002  success = FALSE;
10003  ++roundnr;
10004 
10005  SCIPdebugMessage("starting domain propagation round %d of %d for %d constraints\n", roundnr, maxproprounds, nconss);
10006 
10007  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
10008  {
10009  assert(conss != NULL);
10010  if( !SCIPconsIsEnabled(conss[c]) )
10011  continue;
10012 
10013  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
10014  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
10015  {
10016  *result = propresult;
10017  success = TRUE;
10018  }
10019  if( redundant )
10020  {
10021  SCIPdebugMessage("deleting constraint <%s> locally\n", SCIPconsGetName(conss[c]));
10022  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
10023  }
10024  }
10025 
10026  }
10027  while( success && *result != SCIP_CUTOFF && roundnr < maxproprounds );
10028 
10029  return SCIP_OKAY;
10030 }
10031 
10032 /** checks for a linear variable that can be increase or decreased without harming feasibility */
10033 static
10035  SCIP* scip, /**< SCIP data structure */
10036  SCIP_CONSDATA* consdata /**< constraint data */
10037  )
10038 {
10039  int i;
10040  int poslock;
10041  int neglock;
10042 
10043  consdata->linvar_maydecrease = -1;
10044  consdata->linvar_mayincrease = -1;
10045 
10046  /* check for a linear variable that can be increase or decreased without harming feasibility */
10047  for( i = 0; i < consdata->nlinvars; ++i )
10048  {
10049  /* compute locks of i'th linear variable */
10050  assert(consdata->lincoefs[i] != 0.0);
10051  if( consdata->lincoefs[i] > 0.0 )
10052  {
10053  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
10054  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
10055  }
10056  else
10057  {
10058  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
10059  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
10060  }
10061 
10062  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - neglock == 0 )
10063  {
10064  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
10065  /* if we have already one candidate, then take the one where the loss in the objective function is less */
10066  if( (consdata->linvar_maydecrease < 0) ||
10067  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
10068  consdata->linvar_maydecrease = i;
10069  }
10070 
10071  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - poslock == 0 )
10072  {
10073  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
10074  /* if we have already one candidate, then take the one where the loss in the objective function is less */
10075  if( (consdata->linvar_mayincrease < 0) ||
10076  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
10077  consdata->linvar_mayincrease = i;
10078  }
10079  }
10080 
10081 #ifdef SCIP_DEBUG
10082  if( consdata->linvar_mayincrease >= 0 )
10083  {
10084  SCIPdebugMessage("may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
10085  }
10086  if( consdata->linvar_maydecrease >= 0 )
10087  {
10088  SCIPdebugMessage("may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
10089  }
10090 #endif
10091 }
10092 
10093 /** Given a solution where every quadratic constraint is either feasible or can be made feasible by
10094  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
10095  *
10096  * The method assumes that this is always possible and that not all constraints are feasible already.
10097  */
10098 static
10100  SCIP* scip, /**< SCIP data structure */
10101  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10102  SCIP_CONS** conss, /**< constraints to process */
10103  int nconss, /**< number of constraints */
10104  SCIP_SOL* sol, /**< solution to process */
10105  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
10106  )
10107 {
10108  SCIP_CONSHDLRDATA* conshdlrdata;
10109  SCIP_CONSDATA* consdata;
10110  char origscaling;
10111  SCIP_SOL* newsol;
10112  SCIP_VAR* var;
10113  int c;
10114  SCIP_Real viol;
10115  SCIP_Real delta;
10116  SCIP_Real gap;
10117 
10118  assert(scip != NULL);
10119  assert(conshdlr != NULL);
10120  assert(conss != NULL || nconss == 0);
10121  assert(success != NULL);
10122 
10123  *success = FALSE;
10124 
10125  /* don't propose new solutions if not in presolve or solving */
10127  return SCIP_OKAY;
10128 
10129  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10130  assert(conshdlrdata != NULL);
10131 
10132  if( sol != NULL )
10133  {
10134  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
10135  }
10136  else
10137  {
10138  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
10139  }
10140  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
10141  SCIPdebugMessage("attempt to make solution from <%s> feasible by shifting linear variable\n",
10142  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
10143 
10144  origscaling = conshdlrdata->scaling;
10145  for( c = 0; c < nconss; ++c )
10146  {
10147  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
10148  assert(consdata != NULL);
10149 
10150  /* recompute violation of solution in case solution has changed
10151  * get absolution violation and sign
10152  * @todo avoid doing it this way
10153  */
10154  conshdlrdata->scaling = 'o';
10155  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
10156  {
10157  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
10158  viol = consdata->lhs - consdata->activity;
10159  }
10160  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10161  {
10162  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
10163  viol = consdata->rhs - consdata->activity;
10164  }
10165  else
10166  continue; /* constraint is satisfied */
10167 
10168  assert(viol != 0.0);
10169  if( consdata->linvar_mayincrease >= 0 &&
10170  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
10171  {
10172  /* have variable where increasing makes the constraint less violated */
10173  var = consdata->linvars[consdata->linvar_mayincrease];
10174  /* compute how much we would like to increase var */
10175  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
10176  assert(delta > 0.0);
10177  /* if var has an upper bound, may need to reduce delta */
10178  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
10179  {
10180  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
10181  delta = MIN(MAX(0.0, gap), delta);
10182  }
10183  if( SCIPisPositive(scip, delta) )
10184  {
10185  /* if variable is integral, round delta up so that it will still have an integer value */
10186  if( SCIPvarIsIntegral(var) )
10187  delta = SCIPceil(scip, delta);
10188 
10189  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
10190  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
10191 
10192  /* adjust constraint violation, if satisfied go on to next constraint */
10193  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
10194  if( SCIPisZero(scip, viol) )
10195  continue;
10196  }
10197  }
10198 
10199  assert(viol != 0.0);
10200  if( consdata->linvar_maydecrease >= 0 &&
10201  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
10202  {
10203  /* have variable where decreasing makes constraint less violated */
10204  var = consdata->linvars[consdata->linvar_maydecrease];
10205  /* compute how much we would like to decrease var */
10206  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
10207  assert(delta < 0.0);
10208  /* if var has a lower bound, may need to reduce delta */
10209  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
10210  {
10211  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
10212  delta = MAX(MIN(0.0, gap), delta);
10213  }
10214  if( SCIPisNegative(scip, delta) )
10215  {
10216  /* if variable is integral, round delta down so that it will still have an integer value */
10217  if( SCIPvarIsIntegral(var) )
10218  delta = SCIPfloor(scip, delta);
10219  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
10220  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
10221 
10222  /* adjust constraint violation, if satisfied go on to next constraint */
10223  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
10224  if( SCIPisZero(scip, viol) )
10225  continue;
10226  }
10227  }
10228 
10229  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
10230  break;
10231  }
10232  conshdlrdata->scaling = origscaling;
10233 
10234  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
10235  * then pass it to the trysol heuristic
10236  */
10237  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
10238  {
10239  SCIPdebugMessage("pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
10240 
10241  assert(conshdlrdata->trysolheur != NULL);
10242  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
10243 
10244  *success = TRUE;
10245  }
10246 
10247  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
10248 
10249  return SCIP_OKAY;
10250 }
10251 
10252 /** tries to upgrade a nonlinear constraint into a quadratic constraint */
10253 static
10254 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
10256  SCIP_EXPRGRAPH* exprgraph;
10257  SCIP_EXPRGRAPHNODE* node;
10258  int i;
10259 
10260  assert(nupgdconss != NULL);
10261  assert(upgdconss != NULL);
10262 
10263  *nupgdconss = 0;
10264 
10265  node = SCIPgetExprgraphNodeNonlinear(scip, cons);
10266 
10267  /* no interest in linear constraints */
10268  if( node == NULL )
10269  return SCIP_OKAY;
10270 
10271  /* if a quadratic expression has been simplified, then all children of the node should be variables */
10273  return SCIP_OKAY;
10274 
10275  switch( SCIPexprgraphGetNodeOperator(node) )
10276  {
10277  case SCIP_EXPR_VARIDX:
10278  case SCIP_EXPR_CONST:
10279  case SCIP_EXPR_PLUS:
10280  case SCIP_EXPR_MINUS:
10281  case SCIP_EXPR_SUM:
10282  case SCIP_EXPR_LINEAR:
10283  /* these should not appear as exprgraphnodes after constraint presolving */
10284  return SCIP_OKAY;
10285 
10286  case SCIP_EXPR_DIV:
10287  case SCIP_EXPR_SQRT:
10288  case SCIP_EXPR_REALPOWER:
10289  case SCIP_EXPR_INTPOWER:
10290  case SCIP_EXPR_SIGNPOWER:
10291  case SCIP_EXPR_EXP:
10292  case SCIP_EXPR_LOG:
10293  case SCIP_EXPR_SIN:
10294  case SCIP_EXPR_COS:
10295  case SCIP_EXPR_TAN:
10296  /* case SCIP_EXPR_ERF: */
10297  /* case SCIP_EXPR_ERFI: */
10298  case SCIP_EXPR_MIN:
10299  case SCIP_EXPR_MAX:
10300  case SCIP_EXPR_ABS:
10301  case SCIP_EXPR_SIGN:
10302  case SCIP_EXPR_PRODUCT:
10303  case SCIP_EXPR_POLYNOMIAL:
10304  case SCIP_EXPR_USER:
10305  /* these do not look like an quadratic expression (assuming the expression graph simplifier did run) */
10306  return SCIP_OKAY;
10307 
10308  case SCIP_EXPR_MUL:
10309  case SCIP_EXPR_SQUARE:
10310  case SCIP_EXPR_QUADRATIC:
10311  /* these mean that we have something quadratic */
10312  break;
10313 
10314  case SCIP_EXPR_PARAM:
10315  case SCIP_EXPR_LAST:
10316  default:
10317  SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
10318  return SCIP_OKAY;
10319  }
10320 
10321  /* setup a quadratic constraint */
10322 
10323  if( upgdconsssize < 1 )
10324  {
10325  /* request larger upgdconss array */
10326  *nupgdconss = -1;
10327  return SCIP_OKAY;
10328  }
10329 
10330  *nupgdconss = 1;
10331  SCIP_CALL( SCIPcreateConsQuadratic(scip, &upgdconss[0], SCIPconsGetName(cons),
10333  0, NULL, 0, NULL,
10334  SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
10338  assert(!SCIPconsIsStickingAtNode(cons));
10339 
10340  exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
10341 
10342  /* add variables from expression tree as "quadratic" variables to quadratic constraint */
10343  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
10344  {
10345  assert(SCIPexprgraphGetNodeChildren(node)[i] != NULL);
10346  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, upgdconss[0], (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[i]), 0.0, 0.0) );
10347  }
10348 
10349  switch( SCIPexprgraphGetNodeOperator(node) )
10350  {
10351  case SCIP_EXPR_MUL:
10352  /* expression is product of two variables, so add bilinear term to constraint */
10353  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
10354 
10355  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
10358  1.0) );
10359 
10360  break;
10361 
10362  case SCIP_EXPR_SQUARE:
10363  /* expression is square of a variable, so change square coefficient of quadratic variable */
10364  assert(SCIPexprgraphGetNodeNChildren(node) == 1);
10365 
10366  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
10368  1.0) );
10369 
10370  break;
10371 
10372  case SCIP_EXPR_QUADRATIC:
10373  {
10374  /* expression is quadratic */
10375  SCIP_QUADELEM* quadelems;
10376  int nquadelems;
10377  SCIP_Real* lincoefs;
10378 
10380  nquadelems = SCIPexprgraphGetNodeQuadraticNQuadElements(node);
10382 
10384 
10385  if( lincoefs != NULL )
10386  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
10387  if( lincoefs[i] != 0.0 )
10388  {
10389  /* linear term */
10390  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, upgdconss[0],
10392  lincoefs[i]) );
10393  }
10394 
10395  for( i = 0; i < nquadelems; ++i )
10396  {
10397  assert(quadelems[i].idx1 < SCIPexprgraphGetNodeNChildren(node));
10398  assert(quadelems[i].idx2 < SCIPexprgraphGetNodeNChildren(node));
10399 
10400  if( quadelems[i].idx1 == quadelems[i].idx2 )
10401  {
10402  /* square term */
10403  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
10404  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
10405  quadelems[i].coef) );
10406  }
10407  else
10408  {
10409  /* bilinear term */
10410  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
10411  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
10412  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx2]),
10413  quadelems[i].coef) );
10414  }
10415  }
10416 
10417  break;
10418  }
10419 
10420  default:
10421  SCIPerrorMessage("you should not be here\n");
10422  return SCIP_ERROR;
10423  } /*lint !e788 */
10424 
10425  return SCIP_OKAY;
10426 }
10427 
10428 /*
10429  * Callback methods of constraint handler
10430  */
10431 
10432 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
10433 static
10434 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
10435 { /*lint --e{715}*/
10436  assert(scip != NULL);
10437  assert(conshdlr != NULL);
10438  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
10439 
10440  /* call inclusion method of constraint handler */
10442 
10443  *valid = TRUE;
10444 
10445  return SCIP_OKAY;
10446 }
10447 
10448 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
10449 static
10450 SCIP_DECL_CONSFREE(consFreeQuadratic)
10452  SCIP_CONSHDLRDATA* conshdlrdata;
10453  int i;
10454 
10455  assert(scip != NULL);
10456  assert(conshdlr != NULL);
10457 
10458  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10459  assert(conshdlrdata != NULL);
10460 
10461  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
10462  {
10463  assert(conshdlrdata->quadconsupgrades[i] != NULL);
10464  SCIPfreeMemory(scip, &conshdlrdata->quadconsupgrades[i]);
10465  }
10466  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->quadconsupgrades);
10467 
10468  SCIPfreeMemory(scip, &conshdlrdata);
10469 
10470  return SCIP_OKAY;
10471 }
10472 
10473 /** initialization method of constraint handler (called after problem was transformed) */
10474 static
10475 SCIP_DECL_CONSINIT(consInitQuadratic)
10476 { /*lint --e{715} */
10477  SCIP_CONSHDLRDATA* conshdlrdata;
10478 
10479  assert(scip != NULL);
10480  assert(conshdlr != NULL);
10481 
10482  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10483  assert(conshdlrdata != NULL);
10484 
10485  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
10486  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
10487 
10488  return SCIP_OKAY;
10489 }
10490 
10491 
10492 /** deinitialization method of constraint handler (called before transformed problem is freed) */
10493 static
10494 SCIP_DECL_CONSEXIT(consExitQuadratic)
10495 { /*lint --e{715} */
10496  SCIP_CONSHDLRDATA* conshdlrdata;
10497 
10498  assert(scip != NULL);
10499  assert(conshdlr != NULL);
10500 
10501  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10502  assert(conshdlrdata != NULL);
10503 
10504  conshdlrdata->subnlpheur = NULL;
10505  conshdlrdata->trysolheur = NULL;
10506 
10507  return SCIP_OKAY;
10508 }
10509 
10510 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
10511 #if 0
10512 static
10513 SCIP_DECL_CONSINITPRE(consInitpreQuadratic)
10514 { /*lint --e{715}*/
10515  SCIP_CONSHDLRDATA* conshdlrdata;
10516  SCIP_CONSDATA* consdata;
10517  int c;
10518 
10519  assert(scip != NULL);
10520  assert(conshdlr != NULL);
10521  assert(conss != NULL || nconss == 0);
10522 
10523  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10524  assert(conshdlrdata != NULL);
10525 
10526  return SCIP_OKAY;
10527 }
10528 #endif
10529 
10530 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
10531 static
10532 SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
10533 { /*lint --e{715}*/
10534  SCIP_CONSDATA* consdata;
10535  int c;
10536 #ifndef NDEBUG
10537  int i;
10538 #endif
10539 
10540  assert(scip != NULL);
10541  assert(conshdlr != NULL);
10542  assert(conss != NULL || nconss == 0);
10543 
10544  for( c = 0; c < nconss; ++c )
10545  {
10546  assert(conss != NULL);
10547  consdata = SCIPconsGetData(conss[c]);
10548  assert(consdata != NULL);
10549 
10550  if( !consdata->isremovedfixings )
10551  {
10552  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
10553  }
10554 
10555  /* make sure we do not have duplicate bilinear terms, quad var terms, or linear vars */
10556  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
10557  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
10558  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
10559 
10560  assert(consdata->isremovedfixings);
10561  assert(consdata->linvarsmerged);
10562  assert(consdata->quadvarsmerged);
10563  assert(consdata->bilinmerged);
10564 
10565 #ifndef NDEBUG
10566  for( i = 0; i < consdata->nlinvars; ++i )
10567  assert(SCIPvarIsActive(consdata->linvars[i]));
10568 
10569  for( i = 0; i < consdata->nquadvars; ++i )
10570  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
10571 #endif
10572 
10573  /* tell SCIP that we have something nonlinear */
10574  if( SCIPconsIsAdded(conss[c]) && consdata->nquadvars > 0 )
10575  SCIPenableNLP(scip);
10576  }
10577 
10578  return SCIP_OKAY;
10579 }
10580 
10581 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin)
10582  *
10583  * @note Also called from consEnableQuadratic during solving stage.
10584  */
10585 static
10586 SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
10588  SCIP_CONSHDLRDATA* conshdlrdata;
10589  SCIP_CONSDATA* consdata;
10590  int c;
10591  int i;
10592 
10593  assert(scip != NULL);
10594  assert(conshdlr != NULL);
10595  assert(conss != NULL || nconss == 0);
10596 
10597  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10598  assert(conshdlrdata != NULL);
10599 
10600  for( c = 0; c < nconss; ++c )
10601  {
10602  assert(conss != NULL);
10603  consdata = SCIPconsGetData(conss[c]);
10604  assert(consdata != NULL);
10605 
10606  /* check for a linear variable that can be increase or decreased without harming feasibility */
10607  consdataFindUnlockedLinearVar(scip, consdata);
10608 
10609  /* setup lincoefsmin, lincoefsmax */
10610  consdata->lincoefsmin = SCIPinfinity(scip);
10611  consdata->lincoefsmax = 0.0;
10612  for( i = 0; i < consdata->nlinvars; ++i )
10613  {
10614  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666 */
10615  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666 */
10616  }
10617 
10618  /* add nlrow representation to NLP, if NLP had been constructed */
10619  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
10620  {
10621  if( consdata->nlrow == NULL )
10622  {
10623  SCIP_CALL( createNlRow(scip, conss[c]) );
10624  assert(consdata->nlrow != NULL);
10625  }
10626  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
10627  }
10628 
10629  /* setup sepaquadvars and sepabilinvar2pos */
10630  assert(consdata->sepaquadvars == NULL);
10631  assert(consdata->sepabilinvar2pos == NULL);
10632  if( consdata->nquadvars > 0 )
10633  {
10634  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepaquadvars, consdata->nquadvars) );
10635  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms) );
10636 
10637  /* make sure, quadratic variable terms are sorted */
10638  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
10639 
10640  for( i = 0; i < consdata->nquadvars; ++i )
10641  consdata->sepaquadvars[i] = consdata->quadvarterms[i].var;
10642 
10643  for( i = 0; i < consdata->nbilinterms; ++i )
10644  {
10645  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &consdata->sepabilinvar2pos[i]) );
10646  }
10647  }
10648 
10649  if( conshdlrdata->checkfactorable )
10650  {
10651  /* check if constraint function is factorable, i.e., can be written as product of two linear functions */
10652  SCIP_CALL( checkFactorable(scip, conss[c]) );
10653  }
10654 
10655  /* compute gauge function using interior points per constraint, only when there are quadratic variables */
10656  if( conshdlrdata->gaugecuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
10657  {
10658  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
10659  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
10660  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
10661  {
10662  SCIP_CALL( computeGauge(scip, conshdlr, conss[c]) );
10663  }
10664 
10665  }
10666  }
10667 
10668  if( SCIPgetStage(scip) != SCIP_STAGE_INITSOLVE )
10669  {
10670  /* if called from consEnableQuadratic, then don't do below */
10671  return SCIP_OKAY;
10672  }
10673 
10674  conshdlrdata->newsoleventfilterpos = -1;
10675  if( nconss != 0 && conshdlrdata->linearizeheursol )
10676  {
10677  SCIP_EVENTHDLR* eventhdlr;
10678 
10679  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
10680  assert(eventhdlr != NULL);
10681 
10682  /* @todo Should we catch every new solution or only new *best* solutions */
10683  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
10684  }
10685 
10686  if( nconss != 0 && !SCIPisIpoptAvailableIpopt() && !SCIPisInRestart(scip) )
10687  {
10688  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");
10689  }
10690 
10691  /* reset flags and counters */
10692  conshdlrdata->sepanlp = FALSE;
10693  conshdlrdata->lastenfolpnode = NULL;
10694  conshdlrdata->nenfolprounds = 0;
10695 
10696  return SCIP_OKAY;
10697 }
10698 
10699 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed)
10700  *
10701  * @note Also called from consDisableQuadratic during solving stage.
10702  */
10703 static
10704 SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
10705 { /*lint --e{715}*/
10706  SCIP_CONSHDLRDATA* conshdlrdata;
10707  SCIP_CONSDATA* consdata;
10708  int c;
10709 
10710  assert(scip != NULL);
10711  assert(conshdlr != NULL);
10712  assert(conss != NULL || nconss == 0);
10713 
10714  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10715  assert(conshdlrdata != NULL);
10716 
10717  for( c = 0; c < nconss; ++c )
10718  {
10719  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
10720  assert(consdata != NULL);
10721 
10722  /* free nonlinear row representation */
10723  if( consdata->nlrow != NULL )
10724  {
10725  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
10726  }
10727 
10728  assert(consdata->sepaquadvars != NULL || consdata->nquadvars == 0);
10729  assert(consdata->sepabilinvar2pos != NULL || consdata->nquadvars == 0);
10730  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepaquadvars, consdata->nquadvars);
10731  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms);
10732 
10733  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorleft, consdata->nquadvars + 1);
10734  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorright, consdata->nquadvars + 1);
10735 
10736  SCIPfreeMemoryArrayNull(scip, &consdata->interiorpoint);
10737  SCIPfreeMemoryArrayNull(scip, &consdata->gaugecoefs);
10738  }
10739 
10740  if( SCIPgetStage(scip) != SCIP_STAGE_EXITSOLVE )
10741  {
10742  /* if called from consDisableQuadratic, then don't do below */
10743  return SCIP_OKAY;
10744  }
10745 
10746  if( conshdlrdata->newsoleventfilterpos >= 0 )
10747  {
10748  SCIP_EVENTHDLR* eventhdlr;
10749 
10750  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
10751  assert(eventhdlr != NULL);
10752 
10753  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
10754  conshdlrdata->newsoleventfilterpos = -1;
10755  }
10756 
10757  return SCIP_OKAY;
10758 }
10759 
10760 /** frees specific constraint data */
10761 static
10762 SCIP_DECL_CONSDELETE(consDeleteQuadratic)
10764  assert(scip != NULL);
10765  assert(conshdlr != NULL);
10766  assert(cons != NULL);
10767  assert(consdata != NULL);
10768  assert(SCIPconsGetData(cons) == *consdata);
10769 
10770  SCIP_CALL( consdataFree(scip, consdata) );
10771 
10772  assert(*consdata == NULL);
10773 
10774  return SCIP_OKAY;
10775 }
10776 
10777 /** transforms constraint data into data belonging to the transformed problem */
10778 static
10779 SCIP_DECL_CONSTRANS(consTransQuadratic)
10780 {
10781  SCIP_CONSDATA* sourcedata;
10782  SCIP_CONSDATA* targetdata;
10783  int i;
10784 
10785  sourcedata = SCIPconsGetData(sourcecons);
10786  assert(sourcedata != NULL);
10787 
10788  SCIP_CALL( consdataCreate(scip, &targetdata,
10789  sourcedata->lhs, sourcedata->rhs,
10790  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
10791  sourcedata->nquadvars, sourcedata->quadvarterms,
10792  sourcedata->nbilinterms, sourcedata->bilinterms,
10793  FALSE) );
10794 
10795  for( i = 0; i < targetdata->nlinvars; ++i )
10796  {
10797  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
10798  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
10799  }
10800 
10801  for( i = 0; i < targetdata->nquadvars; ++i )
10802  {
10803  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->quadvarterms[i].var, &targetdata->quadvarterms[i].var) );
10804  SCIP_CALL( SCIPcaptureVar(scip, targetdata->quadvarterms[i].var) );
10805  }
10806 
10807  for( i = 0; i < targetdata->nbilinterms; ++i )
10808  {
10809  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var1, &targetdata->bilinterms[i].var1) );
10810  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var2, &targetdata->bilinterms[i].var2) );
10811 
10812  if( SCIPvarCompare(targetdata->bilinterms[i].var1, targetdata->bilinterms[i].var2) > 0 )
10813  {
10814  SCIP_VAR* tmp;
10815  tmp = targetdata->bilinterms[i].var2;
10816  targetdata->bilinterms[i].var2 = targetdata->bilinterms[i].var1;
10817  targetdata->bilinterms[i].var1 = tmp;
10818  }
10819  }
10820 
10821  /* create target constraint */
10822  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
10823  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
10824  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
10825  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
10826  SCIPconsIsStickingAtNode(sourcecons)) );
10827 
10828  SCIPdebugMessage("created transformed quadratic constraint ");
10829  SCIPdebugPrintCons(scip, *targetcons, NULL);
10830 
10831  return SCIP_OKAY;
10832 }
10833 
10834 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
10835 static
10836 SCIP_DECL_CONSINITLP(consInitlpQuadratic)
10838  SCIP_CONSHDLRDATA* conshdlrdata;
10839  SCIP_CONSDATA* consdata;
10840  SCIP_VAR* var;
10841  SCIP_ROW* row;
10842  SCIP_Real* x;
10843  int c;
10844  int i;
10845 
10846  assert(scip != NULL);
10847  assert(conshdlr != NULL);
10848  assert(conss != NULL || nconss == 0);
10849 
10850  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10851  assert(conshdlrdata != NULL);
10852 
10853  for( c = 0; c < nconss; ++c )
10854  {
10855  assert(conss[c] != NULL); /*lint !e613 */
10856 
10857  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
10858 
10859  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
10860  assert(consdata != NULL);
10861 
10862  row = NULL;
10863 
10864  if( consdata->nquadvars == 0 )
10865  {
10866  SCIP_Bool infeasible;
10867 
10868  /* if we are actually linear, add the constraint as row to the LP */
10869  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
10870  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613 */
10871  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
10872  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
10873 #ifdef ASSERT_INITLP_FEASCUT
10874  assert( ! infeasible );
10875 #endif
10876  SCIP_CALL( SCIPreleaseRow (scip, &row) );
10877  continue;
10878  }
10879 
10880  /* alloc memory for reference point */
10881  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nquadvars) );
10882 
10883  /* for convex parts, add linearizations in 5 points */
10884  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
10885  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
10886  {
10887  SCIP_Real lb;
10888  SCIP_Real ub;
10889  SCIP_Real lambda;
10890  int k;
10891 
10892  for( k = 0; k < 5; ++k )
10893  {
10894  lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
10895  for( i = 0; i < consdata->nquadvars; ++i )
10896  {
10897  var = consdata->quadvarterms[i].var;
10898  lb = SCIPvarGetLbGlobal(var);
10899  ub = SCIPvarGetUbGlobal(var);
10900 
10901  if( ub > -INITLPMAXVARVAL )
10902  lb = MAX(lb, -INITLPMAXVARVAL);
10903  if( lb < INITLPMAXVARVAL )
10904  ub = MIN(ub, INITLPMAXVARVAL);
10905 
10906  /* make bounds finite */
10907  if( SCIPisInfinity(scip, -lb) )
10908  lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
10909  if( SCIPisInfinity(scip, ub) )
10910  ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
10911 
10913  x[i] = lambda * ub + (1.0 - lambda) * lb;
10914  else
10915  x[i] = lambda * lb + (1.0 - lambda) * ub;
10916  }
10917 
10918  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, consdata->isconvex ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT, &row, NULL,
10919  FALSE, -SCIPinfinity(scip)) ); /*lint !e613 */
10920  if( row != NULL )
10921  {
10922  SCIP_Bool infeasible;
10923 
10924  SCIPdebugMessage("initlp adds row <%s> for lambda = %g of conss <%s>\n", SCIProwGetName(row), lambda, SCIPconsGetName(conss[c])); /*lint !e613 */
10925  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
10926 
10927  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
10928 #ifdef ASSERT_INITLP_FEASCUT
10929  assert( ! infeasible );
10930 #endif
10931 
10932  SCIP_CALL( SCIPreleaseRow (scip, &row) );
10933  }
10934  }
10935  }
10936 
10937  /* for concave parts, add underestimator w.r.t. at most 2 reference points */
10938  if( (! consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) || (! consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
10939  {
10940  SCIP_Bool unbounded;
10941  SCIP_Bool possquare;
10942  SCIP_Bool negsquare;
10943  SCIP_Real lb;
10944  SCIP_Real ub;
10945  SCIP_Real lambda;
10946  int k;
10947 
10948  unbounded = FALSE; /* whether there are unbounded variables */
10949  possquare = FALSE; /* whether there is a positive square term */
10950  negsquare = FALSE; /* whether there is a negative square term */
10951  for( k = 0; k < 2; ++k )
10952  {
10953  /* Set reference point to 0 projected on bounds for unbounded variables or in between lower and upper bound
10954  * for bounded variables in the first round, we set it closer to the best bound for one part of the
10955  * variables, in the second closer to the best bound for the other part of the variables.
10956  * Additionally, we use slightly different weights for each variable.
10957  * The reason for the latter is, that for a bilinear term with bounded variables, there are always two linear underestimators
10958  * if the same weight is used for both variables of a product, then rounding and luck decides which underestimator is chosen
10959  * of course, the possible number of cuts is something in the order of 2^nquadvars, and we choose two of them here.
10960  */
10961  for( i = 0; i < consdata->nquadvars; ++i )
10962  {
10963  var = consdata->quadvarterms[i].var;
10964  lb = SCIPvarGetLbGlobal(var);
10965  ub = SCIPvarGetUbGlobal(var);
10966 
10967  if( SCIPisInfinity(scip, -lb) )
10968  {
10969  if( SCIPisInfinity(scip, ub) )
10970  x[i] = 0.0;
10971  else
10972  x[i] = MIN(0.0, ub);
10973  unbounded = TRUE;
10974  }
10975  else
10976  {
10977  if( SCIPisInfinity(scip, ub) )
10978  {
10979  x[i] = MAX(0.0, lb);
10980  unbounded = TRUE;
10981  }
10982  else
10983  {
10984  lambda = 0.4 + 0.2 * ((i+k)%2) + 0.01 * i / (double)consdata->nquadvars;
10985  x[i] = lambda * SCIPvarGetBestBoundLocal(var) + (1.0-lambda) * SCIPvarGetWorstBoundLocal(var);
10986  }
10987  }
10988 
10989  possquare |= consdata->quadvarterms[i].sqrcoef > 0.0; /*lint !e514 */
10990  negsquare |= consdata->quadvarterms[i].sqrcoef < 0.0; /*lint !e514 */
10991  }
10992 
10993  if( !consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
10994  {
10995  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_RIGHT, &row, NULL,
10996  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
10997  if( row != NULL )
10998  {
10999  SCIP_Bool infeasible;
11000 
11001  SCIPdebugMessage("initlp adds row <%s> for rhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
11002  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11003 
11004  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
11005 #ifdef ASSERT_INITLP_FEASCUT
11006  assert( ! infeasible );
11007 #endif
11008 
11009  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11010  }
11011  }
11012  if( !consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
11013  {
11014  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_LEFT, &row, NULL,
11015  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
11016  if( row != NULL )
11017  {
11018  SCIP_Bool infeasible;
11019 
11020  SCIPdebugMessage("initlp adds row <%s> for lhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
11021  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11022 
11023  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
11024 #ifdef ASSERT_INITLP_FEASCUT
11025  assert( ! infeasible );
11026 #endif
11027 
11028  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11029  }
11030  }
11031 
11032  /* if there are unbounded variables, then there is typically only at most one possible underestimator, so don't try another round
11033  * 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 */
11034  if( unbounded ||
11035  (consdata->nbilinterms == 0 && (!possquare || SCIPisInfinity(scip, consdata->rhs))) ||
11036  (consdata->nbilinterms == 0 && (!negsquare || SCIPisInfinity(scip, -consdata->lhs))) )
11037  break;
11038  }
11039  }
11040 
11041  SCIPfreeBufferArray(scip, &x);
11042  }
11043 
11044  return SCIP_OKAY;
11045 }
11046 
11047 /** separation method of constraint handler for LP solutions */
11048 static
11049 SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
11050 {
11051  SCIP_CONSHDLRDATA* conshdlrdata;
11052  SCIP_CONS* maxviolcon;
11053 
11054  assert(scip != NULL);
11055  assert(conshdlr != NULL);
11056  assert(conss != NULL || nconss == 0);
11057  assert(result != NULL);
11058 
11059  *result = SCIP_DIDNOTFIND;
11060 
11061  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11062  assert(conshdlrdata != NULL);
11063 
11064  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
11065  if( maxviolcon == NULL )
11066  return SCIP_OKAY;
11067 
11068  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
11069  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
11070  */
11071  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
11072  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) ||
11073  (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
11074  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
11075  {
11076  SCIP_CONSDATA* consdata;
11077  SCIP_NLPSOLSTAT solstat;
11078  SCIP_Bool solvednlp;
11079  int c;
11080 
11081  solstat = SCIPgetNLPSolstat(scip);
11082  solvednlp = FALSE;
11083  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
11084  {
11085  /* NLP is not solved yet, so we might want to do this
11086  * but first check whether there is a violated constraint side which corresponds to a convex function
11087  */
11088  for( c = 0; c < nconss; ++c )
11089  {
11090  assert(conss[c] != NULL); /*lint !e613 */
11091 
11092  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
11093  assert(consdata != NULL);
11094 
11095  /* skip feasible constraints */
11096  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11097  continue;
11098 
11099  /* make sure curvature has been checked */
11100  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11101 
11102  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->isconvex) ||
11103  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->isconcave) )
11104  break;
11105  }
11106 
11107  if( c < nconss )
11108  {
11109  /* try to solve NLP and update solstat */
11110 
11111  /* ensure linear conss are in NLP */
11112  if( conshdlrdata->subnlpheur != NULL )
11113  {
11114  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
11115  }
11116 
11117  /* set LP solution as starting values, if available */
11119  {
11121  }
11122 
11123  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
11124  SCIP_CALL( SCIPsolveNLP(scip) );
11125 
11126  solstat = SCIPgetNLPSolstat(scip);
11127  SCIPdebugMessage("solved NLP relax, solution status: %d\n", solstat);
11128 
11129  solvednlp = TRUE;
11130  }
11131  }
11132 
11133  conshdlrdata->sepanlp = TRUE;
11134 
11135  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
11136  {
11137  SCIPdebugMessage("NLP relaxation is globally infeasible, thus can cutoff node\n");
11138  *result = SCIP_CUTOFF;
11139  return SCIP_OKAY;
11140  }
11141 
11142  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
11143  {
11144  /* if we have feasible NLP solution, generate linearization cuts there */
11145  SCIP_Bool lpsolseparated;
11146  SCIP_SOL* nlpsol;
11147 
11148  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
11149  assert(nlpsol != NULL);
11150 
11151  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
11152  if( solvednlp && conshdlrdata->trysolheur != NULL )
11153  {
11154  int nfracvars;
11155 
11156  nfracvars = 0;
11157  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
11158  {
11159  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
11160  }
11161 
11162  if( nfracvars == 0 )
11163  {
11164  SCIPdebugMessage("pass solution with obj. value %g to trysol\n", SCIPgetSolOrigObj(scip, nlpsol));
11165  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
11166  }
11167  }
11168 
11169  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, conshdlrdata->mincutefficacysepa) );
11170 
11171  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
11172 
11173  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
11174  if( lpsolseparated )
11175  {
11176  SCIPdebugMessage("linearization cuts separate LP solution\n");
11177  *result = SCIP_SEPARATED;
11178 
11179  return SCIP_OKAY;
11180  }
11181  }
11182  }
11183  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
11184  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
11185  */
11186 
11187  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
11188 
11189  return SCIP_OKAY;
11190 }
11191 
11192 /** separation method of constraint handler for arbitrary primal solutions */
11193 static
11194 SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
11196  SCIP_CONSHDLRDATA* conshdlrdata;
11197  SCIP_CONS* maxviolcon;
11198 
11199  assert(scip != NULL);
11200  assert(conshdlr != NULL);
11201  assert(conss != NULL || nconss == 0);
11202  assert(sol != NULL);
11203  assert(result != NULL);
11204 
11205  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11206  assert(conshdlrdata != NULL);
11207 
11208  *result = SCIP_DIDNOTFIND;
11209 
11210  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &maxviolcon) );
11211  if( maxviolcon == NULL )
11212  return SCIP_OKAY;
11213 
11214  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
11215 
11216  return SCIP_OKAY;
11217 }
11218 
11219 /** constraint enforcing method of constraint handler for LP solutions */
11220 static
11221 SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
11222 { /*lint --e{715}*/
11223  SCIP_CONSHDLRDATA* conshdlrdata;
11224  SCIP_CONSDATA* consdata;
11225  SCIP_CONS* maxviolcon;
11226  SCIP_Real maxviol;
11227  SCIP_RESULT propresult;
11228  SCIP_RESULT separateresult;
11229  int nchgbds;
11230  int nnotify;
11231  SCIP_Real sepaefficacy;
11232  SCIP_Real minefficacy;
11233  SCIP_Real leastpossibleefficacy;
11234 
11235  assert(scip != NULL);
11236  assert(conshdlr != NULL);
11237  assert(conss != NULL || nconss == 0);
11238 
11239  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11240  assert(conshdlrdata != NULL);
11241 
11242  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
11243  if( maxviolcon == NULL )
11244  {
11245  *result = SCIP_FEASIBLE;
11246  return SCIP_OKAY;
11247  }
11248 
11249  *result = SCIP_INFEASIBLE;
11250 
11251  consdata = SCIPconsGetData(maxviolcon);
11252  assert(consdata != NULL);
11253  maxviol = consdata->lhsviol + consdata->rhsviol;
11254  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
11255 
11256  SCIPdebugMessage("enfolp with max violation %g in cons <%s>\n", maxviol, SCIPconsGetName(maxviolcon));
11257 
11258  /* if we are above the 100'th enforcement round for this node, something is strange
11259  * (maybe the LP does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
11260  * 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
11261  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
11262  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
11263  * we only increment nenfolprounds until 101 to avoid an overflow
11264  */
11265  if( conshdlrdata->lastenfolpnode == SCIPgetCurrentNode(scip) )
11266  {
11267  if( conshdlrdata->nenfolprounds > 100 )
11268  {
11269  if( SCIPisStopped(scip) )
11270  {
11271  SCIP_NODE* child;
11272 
11273  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
11274  *result = SCIP_BRANCHED;
11275 
11276  return SCIP_OKAY;
11277  }
11278  }
11279 
11280  ++conshdlrdata->nenfolprounds;
11281 
11282  /* cut off the current subtree, if a limit on the enforcement rounds should be applied. At this point, feasible
11283  * solutions might get cut off; the enfolplimit parameter should therefore only be set if SCIP is used as a
11284  * heuristic solver and when the returned result (infeasible, optimal, the gap) can be ignored
11285  */
11286  if( conshdlrdata->enfolplimit != -1 && conshdlrdata->nenfolprounds > conshdlrdata->enfolplimit )
11287  {
11289  "cut off subtree because enforcement limit was reached; this might lead to incorrect results\n");
11290  *result = SCIP_CUTOFF;
11291  return SCIP_OKAY;
11292  }
11293  }
11294  else
11295  {
11296  conshdlrdata->lastenfolpnode = SCIPgetCurrentNode(scip);
11297  conshdlrdata->nenfolprounds = 0;
11298  }
11299 
11300  /* run domain propagation */
11301  nchgbds = 0;
11302  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
11303  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
11304  {
11305  SCIPdebugMessage("propagation succeeded (%s)\n", propresult == SCIP_CUTOFF ? "cutoff" : "reduceddom");
11306  *result = propresult;
11307  return SCIP_OKAY;
11308  }
11309 
11310  /* we would like a cut that is efficient enough that it is not redundant in the LP (>feastol)
11311  * however, if the maximal violation is very small, also the best cut efficacy cannot be large
11312  * thus, in the latter case, we are also happy if the efficacy is at least, say, 75% of the maximal violation
11313  * but in any case we need an efficacy that is at least feastol
11314  */
11315  minefficacy = MIN(0.75*maxviol, conshdlrdata->mincutefficacyenfofac * SCIPfeastol(scip)); /*lint !e666 */
11316  minefficacy = MAX(minefficacy, SCIPfeastol(scip)); /*lint !e666 */
11317  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, minefficacy, TRUE, &separateresult, &sepaefficacy) );
11318  if( separateresult == SCIP_CUTOFF )
11319  {
11320  SCIPdebugMessage("separation found cutoff\n");
11321  *result = SCIP_CUTOFF;
11322  return SCIP_OKAY;
11323  }
11324  if( separateresult == SCIP_SEPARATED )
11325  {
11326  SCIPdebugMessage("separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, minefficacy);
11327  *result = SCIP_SEPARATED;
11328  return SCIP_OKAY;
11329  }
11330 
11331  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
11332  * -> collect variables for branching
11333  */
11334 
11335  SCIPdebugMessage("separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, minefficacy, maxviol);
11336 
11337  /* find branching candidates */
11338  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &nnotify) );
11339 
11340  /* if sepastore can decrease LP feasibility tolerance, we can add cuts with efficacy in [eps, feastol] */
11341  leastpossibleefficacy = SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip);
11342  if( nnotify == 0 && !solinfeasible && minefficacy > leastpossibleefficacy )
11343  {
11344  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
11345  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, leastpossibleefficacy, TRUE, &separateresult, &sepaefficacy) );
11346  if( separateresult == SCIP_CUTOFF )
11347  {
11348  SCIPdebugMessage("separation found cutoff\n");
11349  *result = SCIP_CUTOFF;
11350  return SCIP_OKAY;
11351  }
11352  if( separateresult == SCIP_SEPARATED )
11353  {
11354  SCIPdebugMessage("separation fallback succeeded, efficacy = %g\n", sepaefficacy);
11355  *result = SCIP_SEPARATED;
11356  return SCIP_OKAY;
11357  }
11358  }
11359 
11360  if( nnotify == 0 && !solinfeasible )
11361  {
11362  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
11363  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
11364  */
11365  SCIP_VAR* brvar = NULL;
11366  SCIP_CALL( registerLargeLPValueVariableForBranching(scip, conss, nconss, &brvar) );
11367  if( brvar == NULL )
11368  {
11369  /* fallback 3: all quadratic variables seem to be fixed -> replace by linear constraint */
11370  SCIP_Bool addedcons;
11371  SCIP_Bool reduceddom;
11372  SCIP_Bool infeasible;
11373 
11374  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
11375  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
11376  * when it enforces the new constraints again and nothing resolves the infeasiblity that we declare here thus,
11377  * we only add them if considered violated, and otherwise claim the solution is feasible (but print a
11378  * warning) */
11379  if ( infeasible )
11380  *result = SCIP_CUTOFF;
11381  else if ( addedcons )
11382  *result = SCIP_CONSADDED;
11383  else if ( reduceddom )
11384  *result = SCIP_REDUCEDDOM;
11385  else
11386  {
11387  *result = SCIP_FEASIBLE;
11388  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
11389  assert(!SCIPisInfinity(scip, maxviol));
11390  }
11391  return SCIP_OKAY;
11392  }
11393  else
11394  {
11395  SCIPdebugMessage("Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
11396  SCIPvarGetName(brvar), SCIPgetSolVal(scip, NULL, brvar));
11397  nnotify = 1;
11398  }
11399  }
11400 
11401  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
11402  return SCIP_OKAY;
11403 }
11404 
11405 
11406 /** constraint enforcing method of constraint handler for pseudo solutions */
11407 static
11408 SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
11409 { /*lint --e{715}*/
11410  SCIP_CONS* maxviolcon;
11411  SCIP_CONSDATA* consdata;
11412  SCIP_RESULT propresult;
11413  SCIP_VAR* var;
11414  int c;
11415  int i;
11416  int nchgbds;
11417  int nnotify;
11418 
11419  assert(scip != NULL);
11420  assert(conss != NULL || nconss == 0);
11421 
11422  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
11423  if( maxviolcon == NULL )
11424  {
11425  *result = SCIP_FEASIBLE;
11426  return SCIP_OKAY;
11427  }
11428 
11429  *result = SCIP_INFEASIBLE;
11430 
11431  SCIPdebugMessage("enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcon));
11432 
11433  /* run domain propagation */
11434  nchgbds = 0;
11435  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
11436  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
11437  {
11438  *result = propresult;
11439  return SCIP_OKAY;
11440  }
11441 
11442  /* we are not feasible and we cannot proof that the whole node is infeasible
11443  * -> collect all variables in violated constraints for branching
11444  */
11445  nnotify = 0;
11446  for( c = 0; c < nconss; ++c )
11447  {
11448  assert(conss != NULL);
11449  consdata = SCIPconsGetData(conss[c]);
11450  assert(consdata != NULL);
11451 
11452  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11453  continue;
11454 
11455  for( i = 0; i < consdata->nlinvars; ++i )
11456  {
11457  var = consdata->linvars[i];
11458  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11459  {
11460  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
11461  ++nnotify;
11462  }
11463  }
11464 
11465  for( i = 0; i < consdata->nquadvars; ++i )
11466  {
11467  var = consdata->quadvarterms[i].var;
11468  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11469  {
11470  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
11471  ++nnotify;
11472  }
11473  }
11474  }
11475 
11476  if( nnotify == 0 )
11477  {
11478  SCIPdebugMessage("All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
11479  *result = SCIP_SOLVELP;
11480  }
11481 
11482  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
11483  return SCIP_OKAY;
11484 }
11485 
11486 /** domain propagation method of constraint handler */
11487 static
11488 SCIP_DECL_CONSPROP(consPropQuadratic)
11490  int nchgbds;
11491 
11492  assert(scip != NULL);
11493  assert(conshdlr != NULL);
11494  assert(conss != NULL || nconss == 0);
11495  assert(result != NULL);
11496 
11497  nchgbds = 0;
11498  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, result, &nchgbds) );
11499 
11500  return SCIP_OKAY;
11501 } /*lint !e715 */
11502 
11503 /** presolving method of constraint handler */
11504 static
11505 SCIP_DECL_CONSPRESOL(consPresolQuadratic)
11506 { /*lint --e{715,788}*/
11507  SCIP_CONSHDLRDATA* conshdlrdata;
11508  SCIP_CONSDATA* consdata;
11509  SCIP_RESULT solveresult;
11510  SCIP_Bool redundant;
11511  SCIP_Bool havechange;
11512  SCIP_Bool doreformulations;
11513  int c;
11514  int i;
11515 
11516  assert(scip != NULL);
11517  assert(conshdlr != NULL);
11518  assert(conss != NULL || nconss == 0);
11519  assert(result != NULL);
11520 
11521  *result = SCIP_DIDNOTFIND;
11522 
11523  /* if other presolvers did not find enough changes for another presolving round,
11524  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
11525  * otherwise, we wait with these
11526  * @todo first do all usual presolving steps, then check SCIPisPresolveFinished(scip), and if true then do reformulations (and usual steps again)
11527  */
11528  doreformulations = nrounds > 0 && ((presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 || SCIPisPresolveFinished(scip));
11529  SCIPdebugMessage("presolving will %swait with reformulation\n", doreformulations ? "not " : "");
11530 
11531  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11532  assert(conshdlrdata != NULL);
11533 
11534  for( c = 0; c < nconss; ++c )
11535  {
11536  assert(conss != NULL);
11537  consdata = SCIPconsGetData(conss[c]);
11538  assert(consdata != NULL);
11539 
11540  SCIPdebugMessage("process constraint <%s>\n", SCIPconsGetName(conss[c]));
11541  SCIPdebugPrintCons(scip, conss[c], NULL);
11542 
11543  if( !consdata->initialmerge )
11544  {
11545  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
11546  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
11547  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
11548  consdata->initialmerge = TRUE;
11549  }
11550 
11551  havechange = FALSE;
11552 #ifdef CHECKIMPLINBILINEAR
11553  if( consdata->isimpladded && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
11554  {
11555  int nbilinremoved;
11556  SCIP_CALL( presolveApplyImplications(scip, conss[c], &nbilinremoved) );
11557  if( nbilinremoved > 0 )
11558  {
11559  *nchgcoefs += nbilinremoved;
11560  havechange = TRUE;
11561  *result = SCIP_SUCCESS;
11562  }
11563  assert(!consdata->isimpladded);
11564  }
11565 #endif
11566  /* 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
11567  * we want to do this before (multi)aggregated variables are replaced, since that may change structure, e.g., introduce bilinear terms
11568  */
11569  if( !consdata->ispresolved || !consdata->ispropagated || nnewchgvartypes > 0 )
11570  {
11571  SCIP_Bool upgraded;
11572 
11573  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
11574  if( upgraded )
11575  {
11576  *result = SCIP_SUCCESS;
11577  continue;
11578  }
11579  }
11580 
11581  if( !consdata->isremovedfixings )
11582  {
11583  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
11584  assert(consdata->isremovedfixings);
11585  havechange = TRUE;
11586  }
11587 
11588  /* try to "solve" the constraint, e.g., reduce to a variable aggregation */
11589  SCIP_CALL( presolveSolve(scip, conss[c], &solveresult, &redundant, naggrvars) );
11590  if( solveresult == SCIP_CUTOFF )
11591  {
11592  SCIPdebugMessage("solving constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
11593  *result = SCIP_CUTOFF;
11594  return SCIP_OKAY;
11595  }
11596  if( redundant )
11597  {
11598  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
11599  ++*ndelconss;
11600  *result = SCIP_SUCCESS;
11601  break;
11602  }
11603  if( solveresult == SCIP_SUCCESS )
11604  {
11605  *result = SCIP_SUCCESS;
11606  havechange = TRUE;
11607  }
11608 
11609  /* @todo divide constraint by gcd of coefficients if all are integral */
11610 
11611  if( doreformulations )
11612  {
11613  int naddconss_old;
11614 
11615  naddconss_old = *naddconss;
11616 
11617  SCIP_CALL( presolveTryAddAND(scip, conshdlr, conss[c], naddconss) );
11618  assert(*naddconss >= naddconss_old);
11619 
11620  if( *naddconss == naddconss_old )
11621  {
11622  /* user not so empathic about AND, or we don't have products of two binaries, so try this more general reformulation */
11623  SCIP_CALL( presolveTryAddLinearReform(scip, conshdlr, conss[c], naddconss) );
11624  assert(*naddconss >= naddconss_old);
11625  }
11626 
11627  if( conshdlrdata->disaggregate )
11628  {
11629  /* try disaggregation, if enabled */
11630  SCIP_CALL( presolveDisaggregate(scip, conshdlr, conss[c], naddconss) );
11631  }
11632 
11633  if( *naddconss > naddconss_old )
11634  {
11635  /* if something happened, report success and cleanup constraint */
11636  *result = SCIP_SUCCESS;
11637  havechange = TRUE;
11638  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
11639  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
11640  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
11641  }
11642  }
11643 
11644  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
11645  {
11646  /* all variables fixed or removed, constraint function is 0.0 now */
11647  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
11648  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
11649  { /* left hand side positive or right hand side negative */
11650  SCIPdebugMessage("constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
11651  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
11652  ++*ndelconss;
11653  *result = SCIP_CUTOFF;
11654  return SCIP_OKAY;
11655  }
11656 
11657  /* left and right hand side are consistent */
11658  SCIPdebugMessage("constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
11659  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
11660  ++*ndelconss;
11661  *result = SCIP_SUCCESS;
11662  continue;
11663  }
11664 
11665  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 && !consdata->ispropagated )
11666  {
11667  /* try domain propagation if there were bound changes or constraint has changed (in which case, processVarEvents may have set ispropagated to false) */
11668  SCIP_RESULT propresult;
11669  int roundnr;
11670 
11671  roundnr = 0;
11672  do
11673  {
11674  ++roundnr;
11675 
11676  SCIPdebugMessage("starting domain propagation round %d of %d\n", roundnr, conshdlrdata->maxproproundspresolve);
11677 
11678  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
11679 
11680  if( propresult == SCIP_CUTOFF )
11681  {
11682  SCIPdebugMessage("propagation on constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
11683  *result = SCIP_CUTOFF;
11684  return SCIP_OKAY;
11685  }
11686 
11687  /* delete constraint if found redundant by bound tightening */
11688  if( redundant )
11689  {
11690  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
11691  ++*ndelconss;
11692  *result = SCIP_SUCCESS;
11693  break;
11694  }
11695 
11696  if( propresult == SCIP_REDUCEDDOM )
11697  {
11698  *result = SCIP_SUCCESS;
11699  havechange = TRUE;
11700  }
11701 
11702  }
11703  while( !consdata->ispropagated && roundnr < conshdlrdata->maxproproundspresolve );
11704 
11705  if( redundant )
11706  continue;
11707  }
11708 
11709  /* check if we have a single linear continuous variable that we can make implicit integer */
11710  if( (nnewchgvartypes != 0 || havechange || !consdata->ispresolved)
11711  && (SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->lhs)) )
11712  {
11713  int ncontvar;
11714  SCIP_VAR* candidate;
11715  SCIP_Bool fail;
11716 
11717  fail = FALSE;
11718  candidate = NULL;
11719  ncontvar = 0;
11720 
11721  for( i = 0; !fail && i < consdata->nlinvars; ++i )
11722  {
11723  if( !SCIPisIntegral(scip, consdata->lincoefs[i]) )
11724  {
11725  fail = TRUE;
11726  }
11727  else if( SCIPvarGetType(consdata->linvars[i]) == SCIP_VARTYPE_CONTINUOUS )
11728  {
11729  if( ncontvar > 0 ) /* now at 2nd continuous variable */
11730  fail = TRUE;
11731  else if( SCIPisEQ(scip, ABS(consdata->lincoefs[i]), 1.0) )
11732  candidate = consdata->linvars[i];
11733  ++ncontvar;
11734  }
11735  }
11736  for( i = 0; !fail && i < consdata->nquadvars; ++i )
11737  fail = SCIPvarGetType(consdata->quadvarterms[i].var) == SCIP_VARTYPE_CONTINUOUS ||
11738  !SCIPisIntegral(scip, consdata->quadvarterms[i].lincoef) ||
11739  !SCIPisIntegral(scip, consdata->quadvarterms[i].sqrcoef);
11740  for( i = 0; !fail && i < consdata->nbilinterms; ++i )
11741  fail = !SCIPisIntegral(scip, consdata->bilinterms[i].coef);
11742 
11743  if( !fail && candidate != NULL )
11744  {
11745  SCIP_Bool infeasible;
11746 
11747  SCIPdebugMessage("make variable <%s> implicit integer due to constraint <%s>\n", SCIPvarGetName(candidate), SCIPconsGetName(conss[c]));
11748 
11749  SCIP_CALL( SCIPchgVarType(scip, candidate, SCIP_VARTYPE_IMPLINT, &infeasible) );
11750  if( infeasible )
11751  {
11752  SCIPdebugMessage("infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(candidate));
11753  *result = SCIP_CUTOFF;
11754 
11755  return SCIP_OKAY;
11756  }
11757 
11758  ++(*nchgvartypes);
11759  *result = SCIP_SUCCESS;
11760  havechange = TRUE;
11761  }
11762  }
11763 
11764  /* call upgrade methods again if constraint has been changed */
11765  if( havechange )
11766  {
11767  SCIP_Bool upgraded;
11768 
11769  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
11770  if( upgraded )
11771  {
11772  *result = SCIP_SUCCESS;
11773  continue;
11774  }
11775  }
11776 
11777  consdata->ispresolved = TRUE;
11778  }
11779 
11780  return SCIP_OKAY;
11781 }
11782 
11783 /** variable rounding lock method of constraint handler */
11784 static
11785 SCIP_DECL_CONSLOCK(consLockQuadratic)
11786 { /*lint --e{715}*/
11787  SCIP_CONSDATA* consdata;
11788  SCIP_Bool haslb;
11789  SCIP_Bool hasub;
11790  int i;
11791 
11792  assert(scip != NULL);
11793  assert(cons != NULL);
11794 
11795  consdata = SCIPconsGetData(cons);
11796  assert(consdata != NULL);
11797 
11798  haslb = !SCIPisInfinity(scip, -consdata->lhs);
11799  hasub = !SCIPisInfinity(scip, consdata->rhs);
11800 
11801  for( i = 0; i < consdata->nlinvars; ++i )
11802  {
11803  if( consdata->lincoefs[i] > 0 )
11804  {
11805  if( haslb )
11806  {
11807  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
11808  }
11809  if( hasub )
11810  {
11811  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
11812  }
11813  }
11814  else
11815  {
11816  if( haslb )
11817  {
11818  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
11819  }
11820  if( hasub )
11821  {
11822  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
11823  }
11824  }
11825  }
11826 
11827  for( i = 0; i < consdata->nquadvars; ++i )
11828  {
11829  /* @todo try to be more clever, but variable locks that depend on the bounds of other variables are not trival to maintain */
11830  SCIP_CALL( SCIPaddVarLocks(scip, consdata->quadvarterms[i].var, nlockspos+nlocksneg, nlockspos+nlocksneg) );
11831  }
11832 
11833  return SCIP_OKAY;
11834 }
11835 
11836 /** constraint enabling notification method of constraint handler */
11837 static
11838 SCIP_DECL_CONSENABLE(consEnableQuadratic)
11840  SCIP_CONSHDLRDATA* conshdlrdata;
11841 
11842  assert(scip != NULL);
11843  assert(conshdlr != NULL);
11844  assert(cons != NULL);
11845  assert(SCIPconsIsTransformed(cons));
11846  assert(SCIPconsIsActive(cons));
11847 
11848  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11849  assert(conshdlrdata != NULL);
11850 
11851  SCIPdebugMessage("enable cons <%s>\n", SCIPconsGetName(cons));
11852 
11853  if( SCIPgetStage(scip) >= SCIP_STAGE_EXITPRESOLVE )
11854  {
11855  /* merge duplicate bilinear terms, move quad terms that are linear to linear vars */
11856  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
11857  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
11858  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
11859  }
11860 
11861  /* catch variable events */
11862  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11863 
11864  /* initialize solving data */
11865  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
11866  {
11867  SCIP_CALL( consInitsolQuadratic(scip, conshdlr, &cons, 1) );
11868  }
11869 
11870  return SCIP_OKAY;
11871 }
11872 
11873 /** constraint disabling notification method of constraint handler */
11874 static
11875 SCIP_DECL_CONSDISABLE(consDisableQuadratic)
11876 { /*lint --e{715}*/
11877  SCIP_CONSHDLRDATA* conshdlrdata;
11878 
11879  assert(scip != NULL);
11880  assert(conshdlr != NULL);
11881  assert(cons != NULL);
11882  assert(SCIPconsIsTransformed(cons));
11883 
11884  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11885  assert(conshdlrdata != NULL);
11886 
11887  SCIPdebugMessage("disable cons <%s>\n", SCIPconsGetName(cons));
11888 
11889  /* free solving data */
11890  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
11891  {
11892  SCIP_CALL( consExitsolQuadratic(scip, conshdlr, &cons, 1, FALSE) );
11893  }
11894 
11895  /* drop variable events */
11896  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11897 
11898  return SCIP_OKAY;
11899 }
11900 
11901 /** constraint display method of constraint handler */
11902 static
11903 SCIP_DECL_CONSPRINT(consPrintQuadratic)
11904 { /*lint --e{715}*/
11905  SCIP_CONSDATA* consdata;
11906 
11907  assert(scip != NULL);
11908  assert(cons != NULL);
11909 
11910  consdata = SCIPconsGetData(cons);
11911  assert(consdata != NULL);
11912 
11913  /* print left hand side for ranged rows */
11914  if( !SCIPisInfinity(scip, -consdata->lhs)
11915  && !SCIPisInfinity(scip, consdata->rhs)
11916  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11917  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
11918 
11919  /* print coefficients and variables */
11920  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
11921  {
11922  SCIPinfoMessage(scip, file, "0 ");
11923  }
11924  else
11925  {
11926  SCIP_VAR*** monomialvars;
11927  SCIP_Real** monomialexps;
11928  SCIP_Real* monomialcoefs;
11929  int* monomialnvars;
11930  int nmonomials;
11931  int monomialssize;
11932  int j;
11933 
11934  monomialssize = consdata->nlinvars + 2 * consdata->nquadvars + consdata->nbilinterms;
11935  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, monomialssize) );
11936  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps, monomialssize) );
11937  SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, monomialssize) );
11938  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, monomialssize) );
11939 
11940  nmonomials = 0;
11941  for( j = 0; j < consdata->nlinvars; ++j )
11942  {
11943  assert(nmonomials < monomialssize);
11944 
11945  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
11946 
11947  monomialvars[nmonomials][0] = consdata->linvars[j];
11948  monomialexps[nmonomials] = NULL;
11949  monomialcoefs[nmonomials] = consdata->lincoefs[j];
11950  monomialnvars[nmonomials] = 1;
11951  ++nmonomials;
11952  }
11953 
11954  for( j = 0; j < consdata->nquadvars; ++j )
11955  {
11956  if( consdata->quadvarterms[j].lincoef != 0.0 )
11957  {
11958  assert(nmonomials < monomialssize);
11959 
11960  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
11961 
11962  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
11963  monomialexps[nmonomials] = NULL;
11964  monomialcoefs[nmonomials] = consdata->quadvarterms[j].lincoef;
11965  monomialnvars[nmonomials] = 1;
11966  ++nmonomials;
11967  }
11968 
11969  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
11970  {
11971  assert(nmonomials < monomialssize);
11972 
11973  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
11974  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps[nmonomials], 1) ); /*lint !e866 */
11975 
11976  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
11977  monomialexps[nmonomials][0] = 2.0;
11978  monomialcoefs[nmonomials] = consdata->quadvarterms[j].sqrcoef;
11979  monomialnvars[nmonomials] = 1;
11980  ++nmonomials;
11981  }
11982  }
11983 
11984  for( j = 0; j < consdata->nbilinterms; ++j )
11985  {
11986  assert(nmonomials < monomialssize);
11987 
11988  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 2) ); /*lint !e866 */
11989 
11990  monomialvars[nmonomials][0] = consdata->bilinterms[j].var1;
11991  monomialvars[nmonomials][1] = consdata->bilinterms[j].var2;
11992  monomialexps[nmonomials] = NULL;
11993  monomialcoefs[nmonomials] = consdata->bilinterms[j].coef;
11994  monomialnvars[nmonomials] = 2;
11995  ++nmonomials;
11996  }
11997 
11998  SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, monomialexps, monomialcoefs, monomialnvars, nmonomials, TRUE) );
11999 
12000  for( j = 0; j < nmonomials; ++j )
12001  {
12002  SCIPfreeBufferArray(scip, &monomialvars[j]);
12003  SCIPfreeBufferArrayNull(scip, &monomialexps[j]);
12004  }
12005 
12006  SCIPfreeBufferArray(scip, &monomialvars);
12007  SCIPfreeBufferArray(scip, &monomialexps);
12008  SCIPfreeBufferArray(scip, &monomialcoefs);
12009  SCIPfreeBufferArray(scip, &monomialnvars);
12010  }
12011 
12012  /* print right hand side */
12013  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12014  {
12015  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
12016  }
12017  else if( !SCIPisInfinity(scip, consdata->rhs) )
12018  {
12019  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
12020  }
12021  else if( !SCIPisInfinity(scip, -consdata->lhs) )
12022  {
12023  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
12024  }
12025  else
12026  {
12027  /* should be ignored by parser */
12028  SCIPinfoMessage(scip, file, " [free]");
12029  }
12030 
12031  return SCIP_OKAY;
12032 }
12033 
12034 /** feasibility check method of constraint handler for integral solutions */
12035 static
12036 SCIP_DECL_CONSCHECK(consCheckQuadratic)
12037 { /*lint --e{715}*/
12038  SCIP_CONSHDLRDATA* conshdlrdata;
12039  SCIP_CONSDATA* consdata;
12040  SCIP_Real maxviol;
12041  int c;
12042  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
12043 
12044  assert(scip != NULL);
12045  assert(conss != NULL || nconss == 0);
12046  assert(result != NULL);
12047 
12048  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12049  assert(conshdlrdata != NULL);
12050 
12051  *result = SCIP_FEASIBLE;
12052 
12053  maxviol = 0.0;
12054  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
12056  for( c = 0; c < nconss; ++c )
12057  {
12058  assert(conss != NULL);
12059  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
12060 
12061  consdata = SCIPconsGetData(conss[c]);
12062  assert(consdata != NULL);
12063 
12064  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12065  {
12066  *result = SCIP_INFEASIBLE;
12067  if( printreason )
12068  {
12069  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
12070  SCIPinfoMessage(scip, NULL, ";\n");
12071  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
12072  {
12073  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
12074  }
12075  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12076  {
12077  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
12078  }
12079  }
12080  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible )
12081  return SCIP_OKAY;
12082  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
12083  maxviol = consdata->lhsviol + consdata->rhsviol;
12084 
12085  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
12086  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
12087  maypropfeasible = FALSE;
12088 
12089  if( maypropfeasible )
12090  {
12091  /* update information on linear variables that may be in- or decreased, if initsolve has not done so yet */
12093  consdataFindUnlockedLinearVar(scip, consdata);
12094 
12095  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
12096  {
12097  /* check if there is a variable which may help to get the left hand side satisfied
12098  * if there is no such var, then we cannot get feasible */
12099  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
12100  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
12101  maypropfeasible = FALSE;
12102  }
12103  else
12104  {
12105  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
12106  /* check if there is a variable which may help to get the right hand side satisfied
12107  * if there is no such var, then we cannot get feasible */
12108  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
12109  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
12110  maypropfeasible = FALSE;
12111  }
12112  }
12113  }
12114  }
12115 
12116  if( *result == SCIP_INFEASIBLE && maypropfeasible )
12117  {
12118  SCIP_Bool success;
12119 
12120  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
12121 
12122  /* do not pass solution to NLP heuristic if we made it feasible this way */
12123  if( success )
12124  return SCIP_OKAY;
12125  }
12126 
12127  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL )
12128  {
12129  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
12130  }
12131 
12132  return SCIP_OKAY;
12133 }
12134 
12135 /** constraint copying method of constraint handler */
12136 static
12137 SCIP_DECL_CONSCOPY(consCopyQuadratic)
12139  SCIP_CONSDATA* consdata;
12140  SCIP_CONSDATA* targetconsdata;
12141  SCIP_VAR** linvars;
12142  SCIP_QUADVARTERM* quadvarterms;
12143  SCIP_BILINTERM* bilinterms;
12144  int i;
12145  int j;
12146  int k;
12147 
12148  assert(scip != NULL);
12149  assert(cons != NULL);
12150  assert(sourcescip != NULL);
12151  assert(sourceconshdlr != NULL);
12152  assert(sourcecons != NULL);
12153  assert(varmap != NULL);
12154  assert(valid != NULL);
12155 
12156  consdata = SCIPconsGetData(sourcecons);
12157  assert(consdata != NULL);
12158 
12159  linvars = NULL;
12160  quadvarterms = NULL;
12161  bilinterms = NULL;
12162 
12163  *valid = TRUE;
12164 
12165  if( consdata->nlinvars != 0 )
12166  {
12167  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
12168  for( i = 0; i < consdata->nlinvars; ++i )
12169  {
12170  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
12171  assert(!(*valid) || linvars[i] != NULL);
12172 
12173  /* we do not copy, if a variable is missing */
12174  if( !(*valid) )
12175  goto TERMINATE;
12176  }
12177  }
12178 
12179  if( consdata->nbilinterms != 0 )
12180  {
12181  SCIP_CALL( SCIPallocBufferArray(sourcescip, &bilinterms, consdata->nbilinterms) );
12182  }
12183 
12184  if( consdata->nquadvars != 0 )
12185  {
12186  SCIP_CALL( SCIPallocBufferArray(sourcescip, &quadvarterms, consdata->nquadvars) );
12187  for( i = 0; i < consdata->nquadvars; ++i )
12188  {
12189  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->quadvarterms[i].var, &quadvarterms[i].var, varmap, consmap, global, valid) );
12190  assert(!(*valid) || quadvarterms[i].var != NULL);
12191 
12192  /* we do not copy, if a variable is missing */
12193  if( !(*valid) )
12194  goto TERMINATE;
12195 
12196  quadvarterms[i].lincoef = consdata->quadvarterms[i].lincoef;
12197  quadvarterms[i].sqrcoef = consdata->quadvarterms[i].sqrcoef;
12198  quadvarterms[i].eventdata = NULL;
12199  quadvarterms[i].nadjbilin = consdata->quadvarterms[i].nadjbilin;
12200  quadvarterms[i].adjbilin = consdata->quadvarterms[i].adjbilin;
12201 
12202  assert(consdata->nbilinterms != 0 || consdata->quadvarterms[i].nadjbilin == 0);
12203 
12204  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
12205  {
12206  assert(bilinterms != NULL);
12207 
12208  k = consdata->quadvarterms[i].adjbilin[j];
12209  assert(consdata->bilinterms[k].var1 != NULL);
12210  assert(consdata->bilinterms[k].var2 != NULL);
12211  if( consdata->bilinterms[k].var1 == consdata->quadvarterms[i].var )
12212  {
12213  assert(consdata->bilinterms[k].var2 != consdata->quadvarterms[i].var);
12214  bilinterms[k].var1 = quadvarterms[i].var;
12215  }
12216  else
12217  {
12218  assert(consdata->bilinterms[k].var2 == consdata->quadvarterms[i].var);
12219  bilinterms[k].var2 = quadvarterms[i].var;
12220  }
12221  bilinterms[k].coef = consdata->bilinterms[k].coef;
12222  }
12223  }
12224  }
12225 
12226  assert(stickingatnode == FALSE);
12227  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name ? name : SCIPconsGetName(sourcecons),
12228  consdata->nlinvars, linvars, consdata->lincoefs,
12229  consdata->nquadvars, quadvarterms,
12230  consdata->nbilinterms, bilinterms,
12231  consdata->lhs, consdata->rhs,
12232  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12233 
12234  /* copy information on curvature */
12235  targetconsdata = SCIPconsGetData(*cons);
12236  targetconsdata->isconvex = consdata->isconvex;
12237  targetconsdata->isconcave = consdata->isconcave;
12238  targetconsdata->iscurvchecked = consdata->iscurvchecked;
12239 
12240  TERMINATE:
12241  SCIPfreeBufferArrayNull(sourcescip, &quadvarterms);
12242  SCIPfreeBufferArrayNull(sourcescip, &bilinterms);
12243  SCIPfreeBufferArrayNull(sourcescip, &linvars);
12244 
12245  return SCIP_OKAY;
12246 }
12247 
12248 /** constraint parsing method of constraint handler */
12249 static
12250 SCIP_DECL_CONSPARSE(consParseQuadratic)
12251 { /*lint --e{715}*/
12252  SCIP_VAR*** monomialvars;
12253  SCIP_Real** monomialexps;
12254  SCIP_Real* monomialcoefs;
12255  char* endptr;
12256  int* monomialnvars;
12257  int nmonomials;
12258 
12259  SCIP_Real lhs;
12260  SCIP_Real rhs;
12261 
12262  assert(scip != NULL);
12263  assert(success != NULL);
12264  assert(str != NULL);
12265  assert(name != NULL);
12266  assert(cons != NULL);
12267 
12268  /* set left and right hand side to their default values */
12269  lhs = -SCIPinfinity(scip);
12270  rhs = SCIPinfinity(scip);
12271 
12272  (*success) = FALSE;
12273 
12274  /* return of string empty */
12275  if( !*str )
12276  return SCIP_OKAY;
12277 
12278  /* ignore whitespace */
12279  while( isspace((unsigned char)*str) )
12280  ++str;
12281 
12282  /* check for left hand side */
12283  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
12284  {
12285  /* there is a number coming, maybe it is a left-hand-side */
12286  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
12287  {
12288  SCIPerrorMessage("error parsing number from <%s>\n", str);
12289  return SCIP_OKAY;
12290  }
12291 
12292  /* ignore whitespace */
12293  while( isspace((unsigned char)*endptr) )
12294  ++endptr;
12295 
12296  if( endptr[0] != '<' || endptr[1] != '=' )
12297  {
12298  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
12299  lhs = -SCIPinfinity(scip);
12300  }
12301  else
12302  {
12303  /* it was indeed a left-hand-side, so continue parsing after it */
12304  str = endptr + 2;
12305 
12306  /* ignore whitespace */
12307  while( isspace((unsigned char)*str) )
12308  ++str;
12309  }
12310  }
12311 
12312  SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, &endptr, success) );
12313 
12314  if( *success )
12315  {
12316  /* check for right hand side */
12317  str = endptr;
12318 
12319  /* ignore whitespace */
12320  while( isspace((unsigned char)*str) )
12321  ++str;
12322 
12323  if( *str && str[0] == '<' && str[1] == '=' )
12324  {
12325  /* we seem to get a right-hand-side */
12326  str += 2;
12327 
12328  if( !SCIPstrToRealValue(str, &rhs, &endptr) )
12329  {
12330  SCIPerrorMessage("error parsing right-hand-side from %s\n", str);
12331  *success = FALSE;
12332  }
12333  }
12334  else if( *str && str[0] == '>' && str[1] == '=' )
12335  {
12336  /* we seem to get a left-hand-side */
12337  str += 2;
12338 
12339  /* we should not have a left-hand-side already */
12340  assert(SCIPisInfinity(scip, -lhs));
12341 
12342  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
12343  {
12344  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
12345  *success = FALSE;
12346  }
12347  }
12348  else if( *str && str[0] == '=' && str[1] == '=' )
12349  {
12350  /* we seem to get a left- and right-hand-side */
12351  str += 2;
12352 
12353  /* we should not have a left-hand-side already */
12354  assert(SCIPisInfinity(scip, -lhs));
12355 
12356  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
12357  {
12358  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
12359  *success = FALSE;
12360  }
12361  else
12362  {
12363  rhs = lhs;
12364  }
12365  }
12366  }
12367 
12368  if( *success )
12369  {
12370  int i;
12371 
12372  /* setup constraint */
12373  assert(stickingatnode == FALSE);
12374  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL,
12375  0, NULL, NULL, NULL, lhs, rhs,
12376  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12377 
12378  for( i = 0; i < nmonomials; ++i )
12379  {
12380  if( monomialnvars[i] == 0 )
12381  {
12382  /* constant monomial */
12383  SCIPaddConstantQuadratic(scip, *cons, monomialcoefs[i]);
12384  }
12385  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 1.0 )
12386  {
12387  /* linear monomial */
12388  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, *cons, monomialvars[i][0], monomialcoefs[i]) );
12389  }
12390  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 2.0 )
12391  {
12392  /* square monomial */
12393  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, monomialvars[i][0], 0.0, monomialcoefs[i]) );
12394  }
12395  else if( monomialnvars[i] == 2 && monomialexps[i][0] == 1.0 && monomialexps[i][1] == 1.0 )
12396  {
12397  /* bilinear term */
12398  SCIP_VAR* var1;
12399  SCIP_VAR* var2;
12400  int pos;
12401 
12402  var1 = monomialvars[i][0];
12403  var2 = monomialvars[i][1];
12404  if( var1 == var2 )
12405  {
12406  /* actually a square term */
12407  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, monomialcoefs[i]) );
12408  }
12409  else
12410  {
12411  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var1, &pos) );
12412  if( pos == -1 )
12413  {
12414  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, 0.0) );
12415  }
12416 
12417  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var2, &pos) );
12418  if( pos == -1 )
12419  {
12420  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var2, 0.0, 0.0) );
12421  }
12422  }
12423 
12424  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, *cons, var1, var2, monomialcoefs[i]) );
12425  }
12426  else
12427  {
12428  SCIPerrorMessage("polynomial in quadratic constraint does not have degree at most 2\n");
12429  *success = FALSE;
12430  SCIP_CALL( SCIPreleaseCons(scip, cons) );
12431  break;
12432  }
12433  }
12434  }
12435 
12436  SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
12437 
12438  return SCIP_OKAY;
12439 }
12440 
12441 /** constraint method of constraint handler which returns the variables (if possible) */
12442 static
12443 SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
12444 { /*lint --e{715}*/
12445  SCIP_CONSDATA* consdata;
12446 
12447  assert(cons != NULL);
12448  assert(success != NULL);
12449 
12450  consdata = SCIPconsGetData(cons);
12451  assert(consdata != NULL);
12452 
12453  if( varssize < consdata->nlinvars + consdata->nquadvars )
12454  (*success) = FALSE;
12455  else
12456  {
12457  int i;
12458 
12459  assert(vars != NULL);
12460 
12461  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
12462 
12463  for( i = 0; i < consdata->nquadvars; ++i )
12464  vars[consdata->nlinvars+i] = consdata->quadvarterms[i].var;
12465 
12466  (*success) = TRUE;
12467  }
12468 
12469  return SCIP_OKAY;
12470 }
12471 
12472 /** constraint method of constraint handler which returns the number of variables (if possible) */
12473 static
12474 SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
12475 { /*lint --e{715}*/
12476  SCIP_CONSDATA* consdata;
12477 
12478  assert(cons != NULL);
12479  assert(success != NULL);
12480 
12481  consdata = SCIPconsGetData(cons);
12482  assert(consdata != NULL);
12483 
12484  (*nvars) = consdata->nlinvars + consdata->nquadvars;
12485  (*success) = TRUE;
12486 
12487  return SCIP_OKAY;
12488 }
12489 
12490 
12491 /*
12492  * constraint specific interface methods
12493  */
12494 
12495 /** creates the handler for quadratic constraints and includes it in SCIP */
12497  SCIP* scip /**< SCIP data structure */
12498  )
12499 {
12500  SCIP_CONSHDLRDATA* conshdlrdata;
12501  SCIP_CONSHDLR* conshdlr;
12502 
12503  /* create quadratic constraint handler data */
12504  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
12505  BMSclearMemory(conshdlrdata);
12506 
12507  /* include constraint handler */
12510  consEnfolpQuadratic, consEnfopsQuadratic, consCheckQuadratic, consLockQuadratic,
12511  conshdlrdata) );
12512  assert(conshdlr != NULL);
12513 
12514 
12515  /* set non-fundamental callbacks via specific setter functions */
12516  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyQuadratic, consCopyQuadratic) );
12517  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteQuadratic) );
12518  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableQuadratic) );
12519  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableQuadratic) );
12520  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitQuadratic) );
12521  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreQuadratic) );
12522  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolQuadratic) );
12523  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeQuadratic) );
12524  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsQuadratic) );
12525  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsQuadratic) );
12526  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitQuadratic) );
12527  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolQuadratic) );
12528  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpQuadratic) );
12529  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseQuadratic) );
12530  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolQuadratic, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
12531  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintQuadratic) );
12532  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropQuadratic, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
12534  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpQuadratic, consSepasolQuadratic, CONSHDLR_SEPAFREQ,
12536  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransQuadratic) );
12537 
12538  /* add quadratic constraint handler parameters */
12539  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/replacebinaryprod",
12540  "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)",
12541  &conshdlrdata->replacebinaryprodlength, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12542 
12543  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/empathy4and",
12544  "empathy level for using the AND constraint handler: 0 always avoid using AND; 1 use AND sometimes; 2 use AND as often as possible",
12545  &conshdlrdata->empathy4and, FALSE, 0, 0, 2, NULL, NULL) );
12546 
12547  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreforminitial",
12548  "whether to make non-varbound linear constraints added due to replacing products with binary variables initial",
12549  &conshdlrdata->binreforminitial, TRUE, FALSE, NULL, NULL) );
12550 
12551  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/binreformmaxcoef",
12552  "limit (as factor on 1/feastol) on coefficients and coef. range in linear constraints created when replacing products with binary variables",
12553  &conshdlrdata->binreformmaxcoef, TRUE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
12554 
12555  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacysepa",
12556  "minimal efficacy for a cut to be added to the LP during separation; overwrites separating/efficacy",
12557  &conshdlrdata->mincutefficacysepa, TRUE, 0.0001, 0.0, SCIPinfinity(scip), NULL, NULL) );
12558 
12559  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacyenfofac",
12560  "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)",
12561  &conshdlrdata->mincutefficacyenfofac, TRUE, 2.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12562 
12563  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/scaling",
12564  "whether scaling of infeasibility is 'o'ff, by sup-norm of function 'g'radient, or by left/right hand 's'ide",
12565  &conshdlrdata->scaling, TRUE, 'o', "ogs", NULL, NULL) );
12566 
12567  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
12568  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
12569  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
12570 
12571  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12572  "whether linearizations of convex quadratic constraints should be added to cutpool in a solution found by some heuristic",
12573  &conshdlrdata->linearizeheursol, TRUE, TRUE, NULL, NULL) );
12574 
12575  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkcurvature",
12576  "whether multivariate quadratic functions should be checked for convexity/concavity",
12577  &conshdlrdata->checkcurvature, FALSE, TRUE, NULL, NULL) );
12578 
12579  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkfactorable",
12580  "whether constraint functions should be checked to be factorable",
12581  &conshdlrdata->checkfactorable, TRUE, TRUE, NULL, NULL) );
12582 
12583  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
12584  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
12585  &conshdlrdata->linfeasshift, TRUE, TRUE, NULL, NULL) );
12586 
12587  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/disaggregate",
12588  "whether to disaggregate quadratic parts that decompose into a sum of non-overlapping quadratic terms",
12589  &conshdlrdata->disaggregate, TRUE, FALSE, NULL, NULL) );
12590 
12591  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12592  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve",
12593  &conshdlrdata->maxproprounds, TRUE, 1, 0, INT_MAX, NULL, NULL) );
12594 
12595  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproproundspresolve",
12596  "limit on number of propagation rounds for a single constraint within one round of SCIP presolve",
12597  &conshdlrdata->maxproproundspresolve, TRUE, 10, 0, INT_MAX, NULL, NULL) );
12598 
12599  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/enfolplimit",
12600  "maximum number of enforcement rounds before declaring the LP relaxation infeasible (-1: no limit); WARNING: changing this parameter might lead to incorrect results!",
12601  &conshdlrdata->enfolplimit, TRUE, -1, -1, INT_MAX, NULL, NULL) );
12602 
12603  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
12604  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
12605  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
12606 
12607  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
12608  "are cuts added during enforcement removable from the LP in the same node?",
12609  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
12610 
12611  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/gaugecuts",
12612  "should convex quadratics generated strong cuts via gauge function?",
12613  &conshdlrdata->gaugecuts, FALSE, TRUE, NULL, NULL) );
12614 
12615  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/interiorcomputation",
12616  "how the interior point should be computed: 'a'ny point per constraint, 'm'ost interior per constraint",
12617  &conshdlrdata->interiorcomputation, TRUE, 'a', "am", NULL, NULL) );
12618 
12619  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchscoring",
12620  "which score to give branching candidates: convexification 'g'ap, constraint 'v'iolation, 'c'entrality of variable value in domain",
12621  &conshdlrdata->branchscoring, TRUE, 'g', "cgv", NULL, NULL) );
12622 
12623  conshdlrdata->eventhdlr = NULL;
12624  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr),CONSHDLR_NAME"_boundchange", "signals a bound change to a quadratic constraint",
12625  processVarEvent, NULL) );
12626  assert(conshdlrdata->eventhdlr != NULL);
12627 
12628  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
12629  processNewSolutionEvent, NULL) );
12630 
12631  /* include the quadratic constraint upgrade in the nonlinear constraint handler */
12633 
12634  return SCIP_OKAY;
12635 }
12636 
12637 /** includes a quadratic constraint update method into the quadratic constraint handler */
12639  SCIP* scip, /**< SCIP data structure */
12640  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
12641  int priority, /**< priority of upgrading method */
12642  SCIP_Bool active, /**< should the upgrading method be active by default? */
12643  const char* conshdlrname /**< name of the constraint handler */
12644  )
12645 {
12646  SCIP_CONSHDLR* conshdlr;
12647  SCIP_CONSHDLRDATA* conshdlrdata;
12648  SCIP_QUADCONSUPGRADE* quadconsupgrade;
12649  char paramname[SCIP_MAXSTRLEN];
12650  char paramdesc[SCIP_MAXSTRLEN];
12651  int i;
12652 
12653  assert(quadconsupgd != NULL);
12654  assert(conshdlrname != NULL );
12655 
12656  /* find the quadratic constraint handler */
12657  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12658  if( conshdlr == NULL )
12659  {
12660  SCIPerrorMessage("quadratic constraint handler not found\n");
12661  return SCIP_PLUGINNOTFOUND;
12662  }
12663 
12664  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12665  assert(conshdlrdata != NULL);
12666 
12667  if( !conshdlrdataHasUpgrade(scip, conshdlrdata, quadconsupgd, conshdlrname) )
12668  {
12669  /* create a quadratic constraint upgrade data object */
12670  SCIP_CALL( SCIPallocMemory(scip, &quadconsupgrade) );
12671  quadconsupgrade->quadconsupgd = quadconsupgd;
12672  quadconsupgrade->priority = priority;
12673  quadconsupgrade->active = active;
12674 
12675  /* insert quadratic constraint upgrade method into constraint handler data */
12676  assert(conshdlrdata->nquadconsupgrades <= conshdlrdata->quadconsupgradessize);
12677  if( conshdlrdata->nquadconsupgrades+1 > conshdlrdata->quadconsupgradessize )
12678  {
12679  int newsize;
12680 
12681  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nquadconsupgrades+1);
12682  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->quadconsupgrades, newsize) );
12683  conshdlrdata->quadconsupgradessize = newsize;
12684  }
12685  assert(conshdlrdata->nquadconsupgrades+1 <= conshdlrdata->quadconsupgradessize);
12686 
12687  for( i = conshdlrdata->nquadconsupgrades; i > 0 && conshdlrdata->quadconsupgrades[i-1]->priority < quadconsupgrade->priority; --i )
12688  conshdlrdata->quadconsupgrades[i] = conshdlrdata->quadconsupgrades[i-1];
12689  assert(0 <= i && i <= conshdlrdata->nquadconsupgrades);
12690  conshdlrdata->quadconsupgrades[i] = quadconsupgrade;
12691  conshdlrdata->nquadconsupgrades++;
12692 
12693  /* adds parameter to turn on and off the upgrading step */
12694  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12695  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable quadratic upgrading for constraint handler <%s>", conshdlrname);
12697  paramname, paramdesc,
12698  &quadconsupgrade->active, FALSE, active, NULL, NULL) );
12699  }
12700 
12701  return SCIP_OKAY;
12702 }
12703 
12704 /** Creates and captures a quadratic constraint.
12705  *
12706  * The constraint should be given in the form
12707  * \f[
12708  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
12709  * \f]
12710  * where \f$x_i = y_j = z_k\f$ is possible.
12711  *
12712  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12713  */
12715  SCIP* scip, /**< SCIP data structure */
12716  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12717  const char* name, /**< name of constraint */
12718  int nlinvars, /**< number of linear terms (n) */
12719  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
12720  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
12721  int nquadterms, /**< number of quadratic terms (m) */
12722  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
12723  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
12724  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
12725  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
12726  SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
12727  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12728  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12729  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12730  * Usually set to TRUE. */
12731  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12732  * TRUE for model constraints, FALSE for additional, redundant constraints. */
12733  SCIP_Bool check, /**< should the constraint be checked for feasibility?
12734  * TRUE for model constraints, FALSE for additional, redundant constraints. */
12735  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12736  * Usually set to TRUE. */
12737  SCIP_Bool local, /**< is constraint only valid locally?
12738  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12739  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12740  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12741  * adds coefficients to this constraint. */
12742  SCIP_Bool dynamic, /**< is constraint subject to aging?
12743  * Usually set to FALSE. Set to TRUE for own cuts which
12744  * are separated as constraints. */
12745  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12746  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12747  )
12748 {
12749  SCIP_CONSHDLR* conshdlr;
12750  SCIP_CONSDATA* consdata;
12751  SCIP_HASHMAP* quadvaridxs;
12752  SCIP_Real sqrcoef;
12753  int i;
12754  int var1pos;
12755  int var2pos;
12756 
12757  int nbilinterms;
12758 
12759  assert(modifiable == FALSE); /* we do not support column generation */
12760 
12761  /* find the quadratic constraint handler */
12762  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12763  if( conshdlr == NULL )
12764  {
12765  SCIPerrorMessage("quadratic constraint handler not found\n");
12766  return SCIP_PLUGINNOTFOUND;
12767  }
12768 
12769  /* create constraint data and constraint */
12770  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
12771 
12772  consdata->lhs = lhs;
12773  consdata->rhs = rhs;
12774 
12775  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
12776  local, modifiable, dynamic, removable, FALSE) );
12777 
12778  /* add quadratic variables and remember their indices */
12779  SCIP_CALL( SCIPhashmapCreate(&quadvaridxs, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * nquadterms)) );
12780  nbilinterms = 0;
12781  for( i = 0; i < nquadterms; ++i )
12782  {
12783  if( SCIPisZero(scip, quadcoefs[i]) )
12784  continue;
12785 
12786  /* if it is actually a square term, remember it's coefficient */
12787  if( quadvars1[i] == quadvars2[i] )
12788  sqrcoef = quadcoefs[i];
12789  else
12790  sqrcoef = 0.0;
12791 
12792  /* add quadvars1[i], if not in there already */
12793  if( !SCIPhashmapExists(quadvaridxs, quadvars1[i]) )
12794  {
12795  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars1[i], 0.0, sqrcoef) );
12796  assert(consdata->nquadvars >= 0);
12797  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars1[i]);
12798 
12799  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars1[i], (void*)(size_t)(consdata->nquadvars-1)) );
12800  }
12801  else if( !SCIPisZero(scip, sqrcoef) )
12802  {
12803  /* if it's there already, but we got a square coefficient, add it to the previous one */
12804  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]);
12805  assert(consdata->quadvarterms[var1pos].var == quadvars1[i]);
12806  consdata->quadvarterms[var1pos].sqrcoef += sqrcoef;
12807  }
12808 
12809  if( quadvars1[i] == quadvars2[i] )
12810  continue;
12811 
12812  /* add quadvars2[i], if not in there already */
12813  if( !SCIPhashmapExists(quadvaridxs, quadvars2[i]) )
12814  {
12815  assert(sqrcoef == 0.0);
12816  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars2[i], 0.0, 0.0) );
12817  assert(consdata->nquadvars >= 0);
12818  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars2[i]);
12819 
12820  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars2[i], (void*)(size_t)(consdata->nquadvars-1)) );
12821  }
12822 
12823  ++nbilinterms;
12824  }
12825 
12826  /* add bilinear terms, if we saw any */
12827  if( nbilinterms > 0 )
12828  {
12829  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, nbilinterms) );
12830  for( i = 0; i < nquadterms; ++i )
12831  {
12832  if( SCIPisZero(scip, quadcoefs[i]) )
12833  continue;
12834 
12835  /* square terms have been taken care of already */
12836  if( quadvars1[i] == quadvars2[i] )
12837  continue;
12838 
12839  assert(SCIPhashmapExists(quadvaridxs, quadvars1[i]));
12840  assert(SCIPhashmapExists(quadvaridxs, quadvars2[i]));
12841 
12842  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]);
12843  var2pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars2[i]);
12844 
12845  SCIP_CALL( addBilinearTerm(scip, *cons, var1pos, var2pos, quadcoefs[i]) );
12846  }
12847  }
12848 
12849  /* add linear variables */
12850  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
12851  for( i = 0; i < nlinvars; ++i )
12852  {
12853  if( SCIPisZero(scip, lincoefs[i]) )
12854  continue;
12855 
12856  /* if it's a linear coefficient for a quadratic variable, add it there, otherwise add as linear variable */
12857  if( SCIPhashmapExists(quadvaridxs, linvars[i]) )
12858  {
12859  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, linvars[i]);
12860  assert(consdata->quadvarterms[var1pos].var == linvars[i]);
12861  consdata->quadvarterms[var1pos].lincoef += lincoefs[i];
12862  }
12863  else
12864  {
12865  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) );
12866  }
12867  }
12868 
12869  SCIPhashmapFree(&quadvaridxs);
12870 
12871  SCIPdebugMessage("created quadratic constraint ");
12872  SCIPdebugPrintCons(scip, *cons, NULL);
12873 
12874  return SCIP_OKAY;
12875 }
12876 
12877 /** creates and captures a quadratic constraint with all its
12878  * flags set to their default values.
12879  *
12880  * The constraint should be given in the form
12881  * \f[
12882  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
12883  * \f]
12884  * where \f$x_i = y_j = z_k\f$ is possible.
12885  *
12886  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12887  */
12889  SCIP* scip, /**< SCIP data structure */
12890  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12891  const char* name, /**< name of constraint */
12892  int nlinvars, /**< number of linear terms (n) */
12893  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
12894  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
12895  int nquadterms, /**< number of quadratic terms (m) */
12896  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
12897  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
12898  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
12899  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
12900  SCIP_Real rhs /**< right hand side of quadratic equation (u) */
12901  )
12902 {
12903  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, nlinvars, linvars, lincoefs,
12904  nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
12905  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
12906 
12907  return SCIP_OKAY;
12908 }
12909 
12910 /** Creates and captures a quadratic constraint.
12911  *
12912  * The constraint should be given in the form
12913  * \f[
12914  * \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.
12915  * \f]
12916  *
12917  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12918  */
12920  SCIP* scip, /**< SCIP data structure */
12921  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12922  const char* name, /**< name of constraint */
12923  int nlinvars, /**< number of linear terms (n) */
12924  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
12925  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
12926  int nquadvarterms, /**< number of quadratic terms (m) */
12927  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
12928  int nbilinterms, /**< number of bilinear terms (p) */
12929  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
12930  SCIP_Real lhs, /**< constraint left hand side (ell) */
12931  SCIP_Real rhs, /**< constraint right hand side (u) */
12932  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
12933  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
12934  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
12935  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
12936  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
12937  SCIP_Bool local, /**< is constraint only valid locally? */
12938  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
12939  SCIP_Bool dynamic, /**< is constraint dynamic? */
12940  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
12941  )
12942 {
12943  SCIP_CONSHDLR* conshdlr;
12944  SCIP_CONSDATA* consdata;
12945 
12946  assert(modifiable == FALSE); /* we do not support column generation */
12947  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12948  assert(nquadvarterms == 0 || quadvarterms != NULL);
12949  assert(nbilinterms == 0 || bilinterms != NULL);
12950 
12951  /* find the quadratic constraint handler */
12952  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12953  if( conshdlr == NULL )
12954  {
12955  SCIPerrorMessage("quadratic constraint handler not found\n");
12956  return SCIP_PLUGINNOTFOUND;
12957  }
12958 
12959  /* create constraint data */
12960  SCIP_CALL( consdataCreate(scip, &consdata, lhs, rhs,
12961  nlinvars, linvars, lincoefs, nquadvarterms, quadvarterms, nbilinterms, bilinterms,
12962  TRUE) );
12963 
12964  /* create constraint */
12965  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
12966  local, modifiable, dynamic, removable, FALSE) );
12967 
12968  return SCIP_OKAY;
12969 }
12970 
12971 /** creates and captures a quadratic constraint in its most basic version, i.e.,
12972  * all constraint flags are set to their default values.
12973  *
12974  * The constraint should be given in the form
12975  * \f[
12976  * \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.
12977  * \f]
12978  *
12979  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12980  */
12982  SCIP* scip, /**< SCIP data structure */
12983  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12984  const char* name, /**< name of constraint */
12985  int nlinvars, /**< number of linear terms (n) */
12986  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
12987  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
12988  int nquadvarterms, /**< number of quadratic terms (m) */
12989  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
12990  int nbilinterms, /**< number of bilinear terms (p) */
12991  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
12992  SCIP_Real lhs, /**< constraint left hand side (ell) */
12993  SCIP_Real rhs /**< constraint right hand side (u) */
12994  )
12995 {
12996  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name, nlinvars, linvars, lincoefs,
12997  nquadvarterms, quadvarterms, nbilinterms, bilinterms, lhs, rhs,
12998  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
12999 
13000  return SCIP_OKAY;
13001 }
13002 
13003 
13004 /** Adds a constant to the constraint function, that is, subtracts a constant from both sides */
13006  SCIP* scip, /**< SCIP data structure */
13007  SCIP_CONS* cons, /**< constraint */
13008  SCIP_Real constant /**< constant to subtract from both sides */
13009  )
13010 {
13011  SCIP_CONSDATA* consdata;
13012 
13013  assert(scip != NULL);
13014  assert(cons != NULL);
13015  assert(!SCIPisInfinity(scip, REALABS(constant)));
13016 
13017  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13018  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13019  {
13020  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13021  SCIPABORT();
13022  }
13023 
13024  consdata = SCIPconsGetData(cons);
13025  assert(consdata != NULL);
13026  assert(consdata->lhs <= consdata->rhs);
13027 
13028  if( !SCIPisInfinity(scip, -consdata->lhs) )
13029  consdata->lhs -= constant;
13030  if( !SCIPisInfinity(scip, consdata->rhs) )
13031  consdata->rhs -= constant;
13032 
13033  if( consdata->lhs > consdata->rhs )
13034  {
13035  assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
13036  consdata->lhs = consdata->rhs;
13037  }
13038 }
13039 
13040 /** Adds a linear variable with coefficient to a quadratic constraint. */
13042  SCIP* scip, /**< SCIP data structure */
13043  SCIP_CONS* cons, /**< constraint */
13044  SCIP_VAR* var, /**< variable */
13045  SCIP_Real coef /**< coefficient of variable */
13046  )
13047 {
13048  assert(scip != NULL);
13049  assert(cons != NULL);
13050  assert(var != NULL);
13051  assert(!SCIPisInfinity(scip, REALABS(coef)));
13052 
13053  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13054  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13055  {
13056  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13057  return SCIP_INVALIDCALL;
13058  }
13059 
13060  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
13061 
13062  return SCIP_OKAY;
13063 }
13064 
13065 /** Adds a quadratic variable with linear and square coefficient to a quadratic constraint. */
13067  SCIP* scip, /**< SCIP data structure */
13068  SCIP_CONS* cons, /**< constraint */
13069  SCIP_VAR* var, /**< variable */
13070  SCIP_Real lincoef, /**< linear coefficient of variable */
13071  SCIP_Real sqrcoef /**< square coefficient of variable */
13072  )
13073 {
13074  assert(scip != NULL);
13075  assert(cons != NULL);
13076  assert(var != NULL);
13077  assert(!SCIPisInfinity(scip, REALABS(lincoef)));
13078  assert(!SCIPisInfinity(scip, REALABS(sqrcoef)));
13079 
13080  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13081  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13082  {
13083  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13084  return SCIP_INVALIDCALL;
13085  }
13086 
13087  SCIP_CALL( addQuadVarTerm(scip, cons, var, lincoef, sqrcoef) );
13088 
13089  return SCIP_OKAY;
13090 }
13091 
13092 /** Adds a linear coefficient for a quadratic variable.
13093  *
13094  * Variable will be added with square coefficient 0.0 if not existing yet.
13095  */
13097  SCIP* scip, /**< SCIP data structure */
13098  SCIP_CONS* cons, /**< constraint */
13099  SCIP_VAR* var, /**< variable */
13100  SCIP_Real coef /**< value to add to linear coefficient of variable */
13101  )
13102 {
13103  SCIP_CONSDATA* consdata;
13104  int pos;
13105 
13106  assert(scip != NULL);
13107  assert(cons != NULL);
13108  assert(var != NULL);
13109  assert(!SCIPisInfinity(scip, REALABS(coef)));
13110 
13111  if( SCIPisZero(scip, coef) )
13112  return SCIP_OKAY;
13113 
13114  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13115  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13116  {
13117  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13118  return SCIP_INVALIDCALL;
13119  }
13120 
13121  consdata = SCIPconsGetData(cons);
13122  assert(consdata != NULL);
13123 
13124  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
13125  if( pos < 0 )
13126  {
13127  SCIP_CALL( addQuadVarTerm(scip, cons, var, coef, 0.0) );
13128  return SCIP_OKAY;
13129  }
13130  assert(pos < consdata->nquadvars);
13131  assert(consdata->quadvarterms[pos].var == var);
13132 
13133  consdata->quadvarterms[pos].lincoef += coef;
13134 
13135  /* update flags and invalid activities */
13136  consdata->ispropagated = FALSE;
13137  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].lincoef);
13138 
13139  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
13140  consdata->activity = SCIP_INVALID;
13141 
13142  return SCIP_OKAY;
13143 }
13144 
13145 /** Adds a square coefficient for a quadratic variable.
13146  *
13147  * Variable will be added with linear coefficient 0.0 if not existing yet.
13148  */
13150  SCIP* scip, /**< SCIP data structure */
13151  SCIP_CONS* cons, /**< constraint */
13152  SCIP_VAR* var, /**< variable */
13153  SCIP_Real coef /**< value to add to square coefficient of variable */
13154  )
13155 {
13156  SCIP_CONSDATA* consdata;
13157  int pos;
13158 
13159  assert(scip != NULL);
13160  assert(cons != NULL);
13161  assert(var != NULL);
13162  assert(!SCIPisInfinity(scip, REALABS(coef)));
13163 
13164  if( SCIPisZero(scip, coef) )
13165  return SCIP_OKAY;
13166 
13167  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13168  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13169  {
13170  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13171  return SCIP_INVALIDCALL;
13172  }
13173 
13174  consdata = SCIPconsGetData(cons);
13175  assert(consdata != NULL);
13176 
13177  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
13178  if( pos < 0 )
13179  {
13180  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
13181  return SCIP_OKAY;
13182  }
13183  assert(pos < consdata->nquadvars);
13184  assert(consdata->quadvarterms[pos].var == var);
13185 
13186  consdata->quadvarterms[pos].sqrcoef += coef;
13187 
13188  /* update flags and invalid activities */
13189  consdata->isconvex = FALSE;
13190  consdata->isconcave = FALSE;
13191  consdata->iscurvchecked = FALSE;
13192  consdata->ispropagated = FALSE;
13193  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].sqrcoef);
13194 
13195  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
13196  consdata->activity = SCIP_INVALID;
13197 
13198  return SCIP_OKAY;
13199 }
13200 
13201 /** Adds a bilinear term to a quadratic constraint.
13202  *
13203  * Variables will be added with linear and square coefficient 0.0 if not existing yet.
13204  * If variables are equal, only the square coefficient of the variable is updated.
13205  */
13207  SCIP* scip, /**< SCIP data structure */
13208  SCIP_CONS* cons, /**< constraint */
13209  SCIP_VAR* var1, /**< first variable */
13210  SCIP_VAR* var2, /**< second variable */
13211  SCIP_Real coef /**< coefficient of bilinear term */
13212  )
13213 {
13214  SCIP_CONSDATA* consdata;
13215  int var1pos;
13216  int var2pos;
13217 
13218  assert(scip != NULL);
13219  assert(cons != NULL);
13220  assert(var1 != NULL);
13221  assert(var2 != NULL);
13222  assert(!SCIPisInfinity(scip, REALABS(coef)));
13223 
13224  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13225  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13226  {
13227  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13228  return SCIP_INVALIDCALL;
13229  }
13230 
13231  if( var1 == var2 )
13232  {
13233  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, cons, var1, coef) );
13234  return SCIP_OKAY;
13235  }
13236 
13237  consdata = SCIPconsGetData(cons);
13238  assert(consdata != NULL);
13239 
13240  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
13241  if( var1pos < 0 )
13242  {
13243  SCIP_CALL( addQuadVarTerm(scip, cons, var1, 0.0, 0.0) );
13244  var1pos = consdata->nquadvars-1;
13245  }
13246 
13247  if( !consdata->quadvarssorted )
13248  {
13249  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
13250  /* sorting may change the position of var1 */
13251  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
13252  assert(var1pos >= 0);
13253  }
13254 
13255  assert(consdata->quadvarssorted);
13256  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var2, &var2pos) );
13257  if( var2pos < 0 )
13258  {
13259  SCIP_CALL( addQuadVarTerm(scip, cons, var2, 0.0, 0.0) );
13260  var2pos = consdata->nquadvars-1;
13261  }
13262 
13263  assert(consdata->quadvarterms[var1pos].var == var1);
13264  assert(consdata->quadvarterms[var2pos].var == var2);
13265 
13266  SCIP_CALL( addBilinearTerm(scip, cons, var1pos, var2pos, coef) );
13267 
13268  return SCIP_OKAY;
13269 }
13270 
13271 /** Gets the quadratic constraint as a nonlinear row representation. */
13273  SCIP* scip, /**< SCIP data structure */
13274  SCIP_CONS* cons, /**< constraint */
13275  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
13276  )
13277 {
13278  SCIP_CONSDATA* consdata;
13279 
13280  assert(cons != NULL);
13281  assert(nlrow != NULL);
13282 
13283  consdata = SCIPconsGetData(cons);
13284  assert(consdata != NULL);
13285 
13286  if( consdata->nlrow == NULL )
13287  {
13288  SCIP_CALL( createNlRow(scip, cons) );
13289  }
13290  assert(consdata->nlrow != NULL);
13291  *nlrow = consdata->nlrow;
13292 
13293  return SCIP_OKAY;
13294 }
13295 
13296 /** Gets the number of variables in the linear term of a quadratic constraint. */
13298  SCIP* scip, /**< SCIP data structure */
13299  SCIP_CONS* cons /**< constraint */
13300  )
13301 {
13302  assert(cons != NULL);
13303  assert(SCIPconsGetData(cons) != NULL);
13304 
13305  return SCIPconsGetData(cons)->nlinvars;
13306 }
13307 
13308 /** Gets the variables in the linear part of a quadratic constraint.
13309  * Length is given by SCIPgetNLinearVarsQuadratic.
13310  */
13312  SCIP* scip, /**< SCIP data structure */
13313  SCIP_CONS* cons /**< constraint */
13314  )
13315 {
13316  assert(cons != NULL);
13317  assert(SCIPconsGetData(cons) != NULL);
13318 
13319  return SCIPconsGetData(cons)->linvars;
13320 }
13321 
13322 /** Gets the coefficients in the linear part of a quadratic constraint.
13323  * Length is given by SCIPgetNLinearVarsQuadratic.
13324  */
13326  SCIP* scip, /**< SCIP data structure */
13327  SCIP_CONS* cons /**< constraint */
13328  )
13329 {
13330  assert(cons != NULL);
13331  assert(SCIPconsGetData(cons) != NULL);
13332 
13333  return SCIPconsGetData(cons)->lincoefs;
13334 }
13335 
13336 /** Gets the number of quadratic variable terms of a quadratic constraint.
13337  */
13339  SCIP* scip, /**< SCIP data structure */
13340  SCIP_CONS* cons /**< constraint */
13341  )
13342 {
13343  assert(cons != NULL);
13344  assert(SCIPconsGetData(cons) != NULL);
13345 
13346  return SCIPconsGetData(cons)->nquadvars;
13347 }
13348 
13349 /** Gets the quadratic variable terms of a quadratic constraint.
13350  * Length is given by SCIPgetNQuadVarTermsQuadratic.
13351  */
13353  SCIP* scip, /**< SCIP data structure */
13354  SCIP_CONS* cons /**< constraint */
13355  )
13356 {
13357  assert(cons != NULL);
13358  assert(SCIPconsGetData(cons) != NULL);
13359 
13360  return SCIPconsGetData(cons)->quadvarterms;
13361 }
13362 
13363 /** Ensures that quadratic variable terms are sorted. */
13365  SCIP* scip, /**< SCIP data structure */
13366  SCIP_CONS* cons /**< constraint */
13367  )
13368 {
13369  assert(cons != NULL);
13370  assert(SCIPconsGetData(cons) != NULL);
13371 
13373 
13374  return SCIP_OKAY;
13375 }
13376 
13377 /** Finds the position of a quadratic variable term for a given variable.
13378  *
13379  * @note If the quadratic variable terms have not been sorted before, then a search may reorder the current order of the terms.
13380  */
13382  SCIP* scip, /**< SCIP data structure */
13383  SCIP_CONS* cons, /**< constraint */
13384  SCIP_VAR* var, /**< variable to search for */
13385  int* pos /**< buffer to store position of quadvarterm for var, or -1 if not found */
13386  )
13387 {
13388  assert(cons != NULL);
13389  assert(SCIPconsGetData(cons) != NULL);
13390  assert(var != NULL);
13391  assert(pos != NULL);
13392 
13393  SCIP_CALL( consdataFindQuadVarTerm(scip, SCIPconsGetData(cons), var, pos) );
13394 
13395  return SCIP_OKAY;
13396 }
13397 
13398 /** Gets the number of bilinear terms of a quadratic constraint. */
13400  SCIP* scip, /**< SCIP data structure */
13401  SCIP_CONS* cons /**< constraint */
13402  )
13403 {
13404  assert(cons != NULL);
13405  assert(SCIPconsGetData(cons) != NULL);
13406 
13407  return SCIPconsGetData(cons)->nbilinterms;
13408 }
13409 
13410 /** Gets the bilinear terms of a quadratic constraint.
13411  * Length is given by SCIPgetNBilinTermQuadratic.
13412  */
13414  SCIP* scip, /**< SCIP data structure */
13415  SCIP_CONS* cons /**< constraint */
13416  )
13417 {
13418  assert(cons != NULL);
13419  assert(SCIPconsGetData(cons) != NULL);
13420 
13421  return SCIPconsGetData(cons)->bilinterms;
13422 }
13423 
13424 /** Gets the left hand side of a quadratic constraint. */
13426  SCIP* scip, /**< SCIP data structure */
13427  SCIP_CONS* cons /**< constraint */
13428  )
13429 {
13430  assert(cons != NULL);
13431  assert(SCIPconsGetData(cons) != NULL);
13432 
13433  return SCIPconsGetData(cons)->lhs;
13434 }
13435 
13436 /** Gets the right hand side of a quadratic constraint. */
13438  SCIP* scip, /**< SCIP data structure */
13439  SCIP_CONS* cons /**< constraint */
13440  )
13441 {
13442  assert(cons != NULL);
13443  assert(SCIPconsGetData(cons) != NULL);
13444 
13445  return SCIPconsGetData(cons)->rhs;
13446 }
13447 
13448 /** Check the quadratic function of a quadratic constraint for its semi-definiteness, if not done yet. */
13450  SCIP* scip, /**< SCIP data structure */
13451  SCIP_CONS* cons /**< constraint */
13452  )
13453 {
13454  assert(cons != NULL);
13455 
13456  SCIP_CALL( checkCurvature(scip, cons, TRUE) );
13457 
13458  return SCIP_OKAY;
13459 }
13460 
13461 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) convex. */
13463  SCIP* scip, /**< SCIP data structure */
13464  SCIP_CONS* cons /**< constraint */
13465  )
13466 {
13467  SCIP_Bool determined;
13468 
13469  assert(cons != NULL);
13470  assert(SCIPconsGetData(cons) != NULL);
13471 
13472  checkCurvatureEasy(scip, cons, &determined, FALSE);
13473  assert(determined);
13474 
13475  return (SCIPconsGetData(cons)->isconvex);
13476 }
13477 
13478 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) concave. */
13480  SCIP* scip, /**< SCIP data structure */
13481  SCIP_CONS* cons /**< constraint */
13482  )
13483 {
13484  SCIP_Bool determined;
13485 
13486  assert(cons != NULL);
13487  assert(SCIPconsGetData(cons) != NULL);
13488 
13489  checkCurvatureEasy(scip, cons, &determined, FALSE);
13490  assert(determined);
13491 
13492  return (SCIPconsGetData(cons)->isconcave);
13493 }
13494 
13495 /** Computes the violation of a constraint by a solution */
13497  SCIP* scip, /**< SCIP data structure */
13498  SCIP_CONS* cons, /**< constraint */
13499  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
13500  SCIP_Real* violation /**< pointer to store violation of constraint */
13501  )
13502 {
13503  SCIP_CONSHDLR* conshdlr;
13504  SCIP_CONSDATA* consdata;
13505 
13506  assert(scip != NULL);
13507  assert(cons != NULL);
13508  assert(violation != NULL);
13509 
13510  conshdlr = SCIPconsGetHdlr(cons);
13511  assert(conshdlr != NULL);
13512 
13513  SCIP_CALL( computeViolation(scip, conshdlr, cons, sol) );
13514 
13515  consdata = SCIPconsGetData(cons);
13516  assert(consdata != NULL);
13517 
13518  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
13519 
13520  return SCIP_OKAY;
13521 }
13522 
13523 /** Indicates whether the quadratic constraint is local w.r.t. the current local bounds.
13524  *
13525  * That is, checks whether each variable with a square term is fixed and for each bilinear term at least one variable is fixed.
13526  */
13528  SCIP* scip, /**< SCIP data structure */
13529  SCIP_CONS* cons /**< constraint */
13530  )
13531 {
13532  SCIP_CONSDATA* consdata;
13533  SCIP_VAR* var1;
13534  SCIP_VAR* var2;
13535  int i;
13536 
13537  assert(scip != NULL);
13538  assert(cons != NULL);
13539 
13540  consdata = SCIPconsGetData(cons);
13541  assert(consdata != NULL);
13542 
13543  /* check all square terms */
13544  for( i = 0; i < consdata->nquadvars; ++i )
13545  {
13546  if( consdata->quadvarterms[i].sqrcoef == 0.0 )
13547  continue;
13548 
13549  var1 = consdata->quadvarterms[i].var;
13550  assert(var1 != NULL);
13551 
13552  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) )
13553  return FALSE;
13554  }
13555 
13556  for( i = 0; i < consdata->nbilinterms; ++i )
13557  {
13558  var1 = consdata->bilinterms[i].var1;
13559  var2 = consdata->bilinterms[i].var2;
13560 
13561  assert(var1 != NULL);
13562  assert(var2 != NULL);
13563 
13564  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) &&
13565  ! SCIPisRelEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
13566  return FALSE;
13567  }
13568 
13569  return TRUE;
13570 }
13571 
13572 /** Adds the constraint to an NLPI problem. */
13574  SCIP* scip, /**< SCIP data structure */
13575  SCIP_CONS* cons, /**< constraint */
13576  SCIP_NLPI* nlpi, /**< interface to NLP solver */
13577  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
13578  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
13579  SCIP_Bool names /**< whether to pass constraint names to NLPI */
13580  )
13581 {
13582  SCIP_CONSDATA* consdata;
13583  int nlininds;
13584  int* lininds;
13585  SCIP_Real* linvals;
13586  int nquadelems;
13587  SCIP_QUADELEM* quadelems;
13588  SCIP_VAR* othervar;
13589  const char* name;
13590  int j;
13591  int l;
13592  int lincnt;
13593  int quadcnt;
13594  int idx1;
13595  int idx2;
13596 
13597  assert(scip != NULL);
13598  assert(cons != NULL);
13599  assert(nlpi != NULL);
13600  assert(nlpiprob != NULL);
13601  assert(scipvar2nlpivar != NULL);
13602 
13603  consdata = SCIPconsGetData(cons);
13604  assert(consdata != NULL);
13605 
13606  /* count nonzeros in quadratic part */
13607  nlininds = consdata->nlinvars;
13608  nquadelems = consdata->nbilinterms;
13609  for( j = 0; j < consdata->nquadvars; ++j )
13610  {
13611  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
13612  ++nquadelems;
13613  if( consdata->quadvarterms[j].lincoef != 0.0 )
13614  ++nlininds;
13615  }
13616 
13617  /* setup linear part */
13618  lininds = NULL;
13619  linvals = NULL;
13620  lincnt = 0;
13621  if( nlininds > 0 )
13622  {
13623  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
13624  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
13625 
13626  for( j = 0; j < consdata->nlinvars; ++j )
13627  {
13628  linvals[j] = consdata->lincoefs[j];
13629  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->linvars[j]));
13630  lininds[j] = (int) (size_t) SCIPhashmapGetImage(scipvar2nlpivar, consdata->linvars[j]);
13631  }
13632 
13633  lincnt = consdata->nlinvars;
13634  }
13635 
13636  /* setup quadratic part */
13637  quadelems = NULL;
13638  if( nquadelems > 0 )
13639  {
13640  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
13641  }
13642  quadcnt = 0;
13643 
13644  for( j = 0; j < consdata->nquadvars; ++j )
13645  {
13646  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->quadvarterms[j].var));
13647  idx1 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, consdata->quadvarterms[j].var);
13648  if( consdata->quadvarterms[j].lincoef != 0.0 )
13649  {
13650  assert(lininds != NULL);
13651  assert(linvals != NULL);
13652  lininds[lincnt] = idx1;
13653  linvals[lincnt] = consdata->quadvarterms[j].lincoef;
13654  ++lincnt;
13655  }
13656 
13657  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
13658  {
13659  assert(quadcnt < nquadelems);
13660  assert(quadelems != NULL);
13661  quadelems[quadcnt].idx1 = idx1;
13662  quadelems[quadcnt].idx2 = idx1;
13663  quadelems[quadcnt].coef = consdata->quadvarterms[j].sqrcoef;
13664  ++quadcnt;
13665  }
13666 
13667  for( l = 0; l < consdata->quadvarterms[j].nadjbilin; ++l )
13668  {
13669  othervar = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].var2;
13670  /* if othervar is on position 2, then we process this bilinear term later (or it was processed already) */
13671  if( othervar == consdata->quadvarterms[j].var )
13672  continue;
13673 
13674  assert(quadcnt < nquadelems);
13675  assert(quadelems != NULL);
13676  assert(SCIPhashmapExists(scipvar2nlpivar, othervar));
13677  idx2 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, othervar);
13678  quadelems[quadcnt].idx1 = MIN(idx1, idx2);
13679  quadelems[quadcnt].idx2 = MAX(idx1, idx2);
13680  quadelems[quadcnt].coef = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].coef;
13681  ++quadcnt;
13682  }
13683  }
13684 
13685  assert(quadcnt == nquadelems);
13686  assert(lincnt == nlininds);
13687 
13688  name = names ? SCIPconsGetName(cons) : NULL;
13689 
13690  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
13691  &consdata->lhs, &consdata->rhs,
13692  &nlininds, &lininds, &linvals ,
13693  &nquadelems, &quadelems,
13694  NULL, NULL, &name) );
13695 
13696  SCIPfreeBufferArrayNull(scip, &quadelems);
13697  SCIPfreeBufferArrayNull(scip, &lininds);
13698  SCIPfreeBufferArrayNull(scip, &linvals);
13699 
13700  return SCIP_OKAY;
13701 }
13702 
13703 
13704 /** sets the left hand side of a quadratic constraint
13705  *
13706  * @note This method may only be called during problem creation stage for an original constraint.
13707  */
13709  SCIP* scip, /**< SCIP data structure */
13710  SCIP_CONS* cons, /**< constraint data */
13711  SCIP_Real lhs /**< new left hand side */
13712  )
13713 {
13714  SCIP_CONSDATA* consdata;
13715 
13716  assert(scip != NULL);
13717  assert(cons != NULL);
13718  assert(!SCIPisInfinity(scip, lhs));
13719 
13720  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13721  {
13722  SCIPerrorMessage("constraint is not quadratic\n");
13723  return SCIP_INVALIDDATA;
13724  }
13725 
13726  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
13727  {
13728  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
13729  return SCIP_INVALIDDATA;
13730  }
13731 
13732  consdata = SCIPconsGetData(cons);
13733  assert(consdata != NULL);
13734  assert(!SCIPisInfinity(scip, consdata->lhs));
13735 
13736  /* adjust value to not be smaller than -inf */
13737  if( SCIPisInfinity(scip, -lhs) )
13738  lhs = -SCIPinfinity(scip);
13739 
13740  /* check for lhs <= rhs */
13741  if( !SCIPisLE(scip, lhs, consdata->rhs) )
13742  return SCIP_INVALIDDATA;
13743 
13744  consdata->lhs = lhs;
13745 
13746  return SCIP_OKAY;
13747 }
13748 
13749 /** sets the right hand side of a quadratic constraint
13750  *
13751  * @note This method may only be called during problem creation stage for an original constraint.
13752  */
13754  SCIP* scip, /**< SCIP data structure */
13755  SCIP_CONS* cons, /**< constraint data */
13756  SCIP_Real rhs /**< new right hand side */
13757  )
13758 {
13759  SCIP_CONSDATA* consdata;
13760 
13761  assert(scip != NULL);
13762  assert(cons != NULL);
13763  assert(!SCIPisInfinity(scip, -rhs));
13764 
13765  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13766  {
13767  SCIPerrorMessage("constraint is not quadratic\n");
13768  return SCIP_INVALIDDATA;
13769  }
13770 
13771  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
13772  {
13773  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
13774  return SCIP_INVALIDDATA;
13775  }
13776 
13777  consdata = SCIPconsGetData(cons);
13778  assert(consdata != NULL);
13779  assert(!SCIPisInfinity(scip, -consdata->rhs));
13780 
13781  /* adjust value to not be greater than inf */
13782  if( SCIPisInfinity(scip, rhs) )
13783  rhs = SCIPinfinity(scip);
13784 
13785  /* check for lhs <= rhs */
13786  if( !SCIPisLE(scip, consdata->lhs, rhs) )
13787  return SCIP_INVALIDDATA;
13788 
13789  consdata->rhs = rhs;
13790 
13791  return SCIP_OKAY;
13792 }
13793 
13794 /** gets the feasibility of the quadratic constraint in the given solution */
13796  SCIP* scip, /**< SCIP data structure */
13797  SCIP_CONS* cons, /**< constraint data */
13798  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
13799  SCIP_Real* feasibility /**< pointer to store the feasibility */
13800  )
13801 {
13802  SCIP_CONSDATA* consdata;
13803 
13804  assert(scip != NULL);
13805  assert(cons != NULL);
13806  assert(feasibility != NULL);
13807 
13808  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13809  {
13810  SCIPerrorMessage("constraint is not quadratic\n");
13811  SCIPABORT();
13812  }
13813 
13814  SCIP_CALL( computeViolation(scip, SCIPconsGetHdlr(cons), cons, sol) );
13815 
13816  consdata = SCIPconsGetData(cons);
13817  assert(consdata != NULL);
13818 
13819  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
13820  *feasibility = SCIPinfinity(scip);
13821  else if( SCIPisInfinity(scip, -consdata->lhs) )
13822  *feasibility = (consdata->rhs - consdata->activity);
13823  else if( SCIPisInfinity(scip, consdata->rhs) )
13824  *feasibility = (consdata->activity - consdata->lhs);
13825  else
13826  {
13827  assert(!SCIPisInfinity(scip, -consdata->rhs));
13828  assert(!SCIPisInfinity(scip, consdata->lhs));
13829  *feasibility = MIN( consdata->rhs - consdata->activity, consdata->activity - consdata->lhs );
13830  }
13831 
13832  return SCIP_OKAY;
13833 }
13834 
13835 /** gets the activity of the quadratic constraint in the given solution */
13837  SCIP* scip, /**< SCIP data structure */
13838  SCIP_CONS* cons, /**< constraint data */
13839  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
13840  SCIP_Real* activity /**< pointer to store the activity */
13841  )
13842 {
13843  SCIP_CONSDATA* consdata;
13844 
13845  assert(scip != NULL);
13846  assert(cons != NULL);
13847  assert(activity != NULL);
13848 
13849  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13850  {
13851  SCIPerrorMessage("constraint is not quadratic\n");
13852  SCIPABORT();
13853  }
13854 
13855  SCIP_CALL( computeViolation(scip, SCIPconsGetHdlr(cons), cons, sol) );
13856 
13857  consdata = SCIPconsGetData(cons);
13858  assert(consdata != NULL);
13859 
13860  *activity = consdata->activity;
13861 
13862  return SCIP_OKAY;
13863 }
13864 
13865 /** changes the linear coefficient value for a given quadratic variable in a quadratic constraint data; if not
13866  * available, it adds it
13867  *
13868  * @note this is only allowed for original constraints and variables in problem creation stage
13869  */
13871  SCIP* scip, /**< SCIP data structure */
13872  SCIP_CONS* cons, /**< constraint data */
13873  SCIP_VAR* var, /**< quadratic variable */
13874  SCIP_Real coef /**< new coefficient */
13875  )
13876 {
13877  SCIP_CONSDATA* consdata;
13878  SCIP_Bool found;
13879  int i;
13880 
13881  assert(scip != NULL);
13882  assert(cons != NULL);
13883  assert(var != NULL);
13884 
13885  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13886  {
13887  SCIPerrorMessage("constraint is not quadratic\n");
13888  return SCIP_INVALIDDATA;
13889  }
13890 
13891  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
13892  {
13893  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
13894  return SCIP_INVALIDDATA;
13895  }
13896 
13897  consdata = SCIPconsGetData(cons);
13898  assert(consdata != NULL);
13899 
13900  /* check all quadratic variables */
13901  found = FALSE;
13902  for( i = 0; i < consdata->nquadvars; ++i )
13903  {
13904  if( var == consdata->quadvarterms[i].var )
13905  {
13906  if( found || SCIPisZero(scip, coef) )
13907  {
13908  consdata->quadvarterms[i].lincoef = 0.0;
13909 
13910  /* remember to merge quadratic variable terms */
13911  consdata->quadvarsmerged = FALSE;
13912  }
13913  else
13914  consdata->quadvarterms[i].lincoef = coef;
13915 
13916  found = TRUE;
13917  }
13918  }
13919 
13920  /* check all linear variables */
13921  i = 0;
13922  while( i < consdata->nlinvars )
13923  {
13924  if( var == consdata->linvars[i] )
13925  {
13926  if( found || SCIPisZero(scip, coef) )
13927  {
13928  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
13929 
13930  /* decrease i by one since otherwise we would skip the coefficient which has been switched to position i */
13931  i--;
13932  }
13933  else
13934  {
13935  SCIP_CALL( chgLinearCoefPos(scip, cons, i, coef) );
13936  }
13937 
13938  found = TRUE;
13939  }
13940  i++;
13941  }
13942 
13943  /* add linear term if necessary */
13944  if( !found && !SCIPisZero(scip, coef) )
13945  {
13946  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
13947  }
13948 
13949  consdata->ispropagated = FALSE;
13950  consdata->ispresolved = FALSE;
13951 
13952  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
13953  consdata->activity = SCIP_INVALID;
13954 
13955  return SCIP_OKAY;
13956 }
13957 
13958 /** changes the square coefficient value for a given quadratic variable in a quadratic constraint data; if not
13959  * available, it adds it
13960  *
13961  * @note this is only allowed for original constraints and variables in problem creation stage
13962  */
13964  SCIP* scip, /**< SCIP data structure */
13965  SCIP_CONS* cons, /**< constraint data */
13966  SCIP_VAR* var, /**< quadratic variable */
13967  SCIP_Real coef /**< new coefficient */
13968  )
13969 {
13970  SCIP_CONSDATA* consdata;
13971  SCIP_Bool found;
13972  int i;
13973 
13974  assert(scip != NULL);
13975  assert(cons != NULL);
13976  assert(var != NULL);
13977  assert(!SCIPisInfinity(scip, REALABS(coef)));
13978 
13979  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
13980  {
13981  SCIPerrorMessage("constraint is not quadratic\n");
13982  return SCIP_INVALIDDATA;
13983  }
13984 
13985  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
13986  {
13987  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
13988  return SCIP_INVALIDDATA;
13989  }
13990 
13991  consdata = SCIPconsGetData(cons);
13992  assert(consdata != NULL);
13993 
13994  /* find the quadratic variable and change its quadratic coefficient */
13995  found = FALSE;
13996  for( i = 0; i < consdata->nquadvars; ++i )
13997  {
13998  if( var == consdata->quadvarterms[i].var )
13999  {
14000  consdata->quadvarterms[i].sqrcoef = (found || SCIPisZero(scip, coef)) ? 0.0 : coef;
14001  found = TRUE;
14002  }
14003  }
14004 
14005  /* add bilinear term if necessary */
14006  if( !found && !SCIPisZero(scip, coef) )
14007  {
14008  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
14009  }
14010 
14011  /* update flags and invalidate activities */
14012  consdata->isconvex = FALSE;
14013  consdata->isconcave = FALSE;
14014  consdata->iscurvchecked = FALSE;
14015  consdata->ispropagated = FALSE;
14016  consdata->ispresolved = FALSE;
14017 
14018  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14019  consdata->activity = SCIP_INVALID;
14020 
14021  /* remember to merge quadratic variable terms */
14022  consdata->quadvarsmerged = FALSE;
14023 
14024  return SCIP_OKAY;
14025 }
14026 
14027 /** changes the bilinear coefficient value for a given quadratic variable in a quadratic constraint data; if not
14028  * available, it adds it
14029  *
14030  * @note this is only allowed for original constraints and variables in problem creation stage
14031  */
14033  SCIP* scip, /**< SCIP data structure */
14034  SCIP_CONS* cons, /**< constraint */
14035  SCIP_VAR* var1, /**< first variable */
14036  SCIP_VAR* var2, /**< second variable */
14037  SCIP_Real coef /**< coefficient of bilinear term */
14038  )
14039 {
14040  SCIP_CONSDATA* consdata;
14041  SCIP_Bool found;
14042  int i;
14043 
14044  assert(scip != NULL);
14045  assert(cons != NULL);
14046  assert(var1 != NULL);
14047  assert(var2 != NULL);
14048  assert(!SCIPisInfinity(scip, REALABS(coef)));
14049 
14050  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14051  {
14052  SCIPerrorMessage("constraint is not quadratic\n");
14053  return SCIP_INVALIDDATA;
14054  }
14055 
14056  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var1) || !SCIPvarIsOriginal(var2) )
14057  {
14058  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
14059  return SCIP_INVALIDDATA;
14060  }
14061 
14062  if( var1 == var2 )
14063  {
14064  SCIP_CALL( SCIPchgSquareCoefQuadratic(scip, cons, var1, coef) );
14065  return SCIP_OKAY;
14066  }
14067 
14068  consdata = SCIPconsGetData(cons);
14069  assert(consdata != NULL);
14070 
14071  /* search array of bilinear terms */
14072  found = FALSE;
14073  for( i = 0; i < consdata->nbilinterms; ++i )
14074  {
14075  if( (consdata->bilinterms[i].var1 == var1 && consdata->bilinterms[i].var2 == var2) ||
14076  (consdata->bilinterms[i].var1 == var2 && consdata->bilinterms[i].var2 == var1) )
14077  {
14078  if( found || SCIPisZero(scip, coef) )
14079  {
14080  consdata->bilinterms[i].coef = 0.0;
14081 
14082  /* remember to merge bilinear terms */
14083  consdata->bilinmerged = FALSE;
14084  }
14085  else
14086  consdata->bilinterms[i].coef = coef;
14087  found = TRUE;
14088  }
14089  }
14090 
14091  /* add bilinear term if necessary */
14092  if( !found )
14093  {
14094  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, cons, var1, var2, coef) );
14095  }
14096 
14097  /* update flags and invalidate activities */
14098  consdata->isconvex = FALSE;
14099  consdata->isconcave = FALSE;
14100  consdata->iscurvchecked = FALSE;
14101  consdata->ispropagated = FALSE;
14102  consdata->ispresolved = FALSE;
14103 
14104  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14105  consdata->activity = SCIP_INVALID;
14106 
14107  return SCIP_OKAY;
14108 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:51
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17352
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:34812
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41572
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:16861
static SCIP_Bool conshdlrdataHasUpgrade(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), const char *conshdlrname)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41685
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)
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)
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:10698
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:5878
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)
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:20526
SCIP_Bool SCIPconsIsLocked(SCIP_CONS *cons)
Definition: cons.c:7939
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:5588
static SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:25588
SCIP_BILINTERM * SCIPgetBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
static void consdataMoveLinearVar(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_EXPRGRAPH * SCIPgetExprgraphNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2252
static SCIP_RETCODE consdataSortBilinTerms(SCIP *scip, SCIP_CONSDATA *consdata)
primal heuristic that tries a given solution
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16443
SCIP_VAR * var2
#define MAXDNOM
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:48
#define GAUGESCALE
static SCIP_RETCODE separatePoint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Real *bestefficacy)
#define CONSHDLR_PRESOLTIMING
static SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
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:22886
static SCIP_RETCODE consdataEnsureQuadVarTermsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
Constraint handler for variable bound constraints .
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:20589
int SCIPnlrowGetNQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3312
static SCIP_RETCODE generateCutNonConvex(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_Real *coef, SCIP_Real *lhs, SCIP_Real *rhs, SCIP_Bool *islocal, SCIP_Bool *success, char *name)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:41648
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1147
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20573
static SCIP_RETCODE propagateBoundsBilinearTerm(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *x, SCIP_Real xsqrcoef, SCIP_Real xlincoef, SCIP_VAR *y, SCIP_Real ysqrcoef, SCIP_Real ylincoef, SCIP_Real bilincoef, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:34072
SCIP_RETCODE SCIPgetViolationQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12733
SCIP_QUADVARTERM * SCIPgetQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:10378
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11540
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16623
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1248
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:15737
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:7899
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip.c:3205
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41920
static SCIP_DECL_SORTINDCOMP(quadVarTermComp)
SCIP_Real SCIPgetRelaxFeastolFactor(SCIP *scip)
Definition: scip.c:31547
#define SCIP_MAXSTRLEN
Definition: def.h:201
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_VAR * var1
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:5246
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4288
SCIP_RETCODE SCIPaddBilinTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
static SCIP_RETCODE getImpliedBounds(SCIP *scip, SCIP_VAR *x, SCIP_Bool xval, SCIP_VAR *y, SCIP_INTERVAL *resultant)
#define NULL
Definition: lpi_spx.cpp:130
SCIP_RETCODE SCIPcreateConsBasicQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17113
#define CONSHDLR_PROPFREQ
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4258
#define INTERIOR_EPS
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1125
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)
Definition: scip.c:29365
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:940
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:7849
static SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:18915
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:18861
internal methods for NLPI solver interfaces
SCIP_RETCODE SCIPchgLhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:7681
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5334
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17067
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:236
static SCIP_RETCODE generateCutConvex(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_Real *coef, SCIP_Real *lhs, SCIP_Real *rhs, SCIP_Bool *islocal, SCIP_Bool *success, char *name)
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)
static SCIP_RETCODE addQuadVarTerm(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
SCIP_RETCODE SCIPsortQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:17429
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)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:5818
static void consdataUpdateLinearActivityLbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
static SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
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:30454
#define BMSclearMemory(ptr)
Definition: memory.h:84
#define CONSHDLR_MAXPREROUNDS
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip.c:5703
static SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip.h:20528
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip.c:7393
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:7909
#define FALSE
Definition: def.h:56
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:35113
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2057
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)
SCIP_RETCODE SCIPaddQuadVarLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPnlpiFreeProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem)
Definition: nlpi.c:224
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:16027
static SCIP_RETCODE presolveSolve(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result, SCIP_Bool *redundant, int *naggrvars)
SCIP_BOUNDTYPE SCIPvarGetBestBoundType(SCIP_VAR *var)
Definition: var.c:17169
int SCIPgetNBinVars(SCIP *scip)
Definition: scip.c:10743
#define SCIP_DECL_QUADCONSUPGD(x)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:7778
#define CONSHDLR_SEPAPRIORITY
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:8174
#define TRUE
Definition: def.h:55
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7640
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:33396
static SCIP_RETCODE registerBranchingCandidatesViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPsolveNLP(SCIP *scip)
Definition: scip.c:28767
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip.c:28790
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:5795
#define SCIP_CALL(x)
Definition: def.h:266
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:30619
static void consdataFindUnlockedLinearVar(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41972
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_VAR ** SCIPgetLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip.c:30949
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:27888
static SCIP_RETCODE removeBilinearTermsPos(SCIP *scip, SCIP_CONS *cons, int nterms, int *termposs)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20556
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:26439
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol)
SCIP_RETCODE SCIPaddQuadVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:34983
SCIP_Real SCIPselectSimpleValue(SCIP_Real lb, SCIP_Real ub, SCIP_Longint maxdnom)
Definition: misc.c:7620
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
static SCIP_RETCODE registerBranchingCandidatesCentrality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
static SCIP_RETCODE presolveTryAddAND(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
Constraint handler for "and" constraints, .
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:16905
SCIP_Bool SCIPisLinearLocalQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddToNlpiProblemQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *nlpiprob, SCIP_HASHMAP *scipvar2nlpivar, SCIP_Bool names)
static SCIP_RETCODE mergeAndCleanBilinearTerms(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetRhsNonlinear(SCIP *scip, SCIP_CONS *cons)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2116
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)
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:10878
static SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:7839
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:7779
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:26237
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:30967
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:24949
static SCIP_RETCODE dropQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:99
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty)
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28063
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:20554
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11206
SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
Definition: scip.c:28910
SCIP_Real SCIPgetLhsNonlinear(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE lockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPincludeConshdlrQuadratic(SCIP *scip)
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:5359
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:7769
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)
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
static SCIP_RETCODE unlockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:35066
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip.c:7908
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:95
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip.c:28658
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:5383
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:3547
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16562
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2159
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:3573
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16634
SCIP_Bool SCIPisIpoptAvailableIpopt(void)
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)
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12793
static SCIP_RETCODE consdataSortQuadVarTerms(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3917
#define CONSHDLR_EAGERFREQ
void SCIPaddConstantQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real constant)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:36622
static SCIP_RETCODE registerBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1096
SCIP_Real coef
Definition: type_expr.h:102
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:118
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:20542
SCIP_Real inf
Definition: intervalarith.h:38
SCIP_RETCODE SCIPincludeNonlinconsUpgrade(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)), SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)), int priority, SCIP_Bool active, const char *conshdlrname)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41585
SCIP_Bool SCIPvarIsOriginal(SCIP_VAR *var)
Definition: var.c:16572
static SCIP_RETCODE checkCurvature(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkmultivariate)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16585
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:1781
static SCIP_RETCODE presolveTryAddLinearReform(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
static void 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_Real *cutcoef, SCIP_Real *cutrhs, SCIP_Bool *islocal, SCIP_Bool *success, char *name)
SCIP_NLPTERMSTAT SCIPnlpiGetTermstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:521
SCIP_RETCODE SCIPcheckCurvatureQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real * SCIPgetLinearCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41984
static SCIP_DECL_CONSEXIT(consExitQuadratic)
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:41709
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip.c:17075
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:7879
static void propagateBoundsGetQuadActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty, SCIP_Real *minquadactivity, SCIP_Real *maxquadactivity, int *minactivityinf, int *maxactivityinf, SCIP_INTERVAL *quadactcontr)
int SCIPgetNLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addLinearizationCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *ref, SCIP_Bool *separatedlpsol, SCIP_Real minefficacy)
SCIP_Real SCIPgetPrimalRayVal(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:36516
#define SCIPerrorMessage
Definition: pub_message.h:45
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:18925
interval arithmetics for provable bounds
static SCIP_RETCODE removeFixedVariables(SCIP *scip, SCIP_CONS *cons)
#define SCIPdebugPrintf
Definition: pub_message.h:80
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:20574
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:19526
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)
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:69
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
SCIP_Bool SCIPisInRestart(SCIP *scip)
Definition: scip.c:15700
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:41996
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:25870
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
static SCIP_DECL_CONSDELETE(consDeleteQuadratic)
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3897
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:1157
SCIP_RETCODE SCIPchgRhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
static SCIP_DECL_CONSPARSE(consParseQuadratic)
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss, SCIP_PRESOLTIMING presoltiming)
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:41118
static SCIP_RETCODE catchQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16644
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip.c:28407
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41598
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:5527
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28151
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip.c:19717
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:31062
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:41353
SCIP_RETCODE SCIPnlpiSetIntPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, int ival)
Definition: nlpi.c:633
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
static SCIP_DECL_CONSCHECK(consCheckQuadratic)
SCIP_RETCODE SCIPnlpiCreateProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem, const char *name)
Definition: nlpi.c:211
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7620
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16654
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:63
static SCIP_DECL_CONSPRESOL(consPresolQuadratic)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:41758
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:19024
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:146
SCIP_RETCODE SCIPchgSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_DECL_CONSTRANS(consTransQuadratic)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2075
constraint handler for quadratic constraints
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:5503
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:20562
static SCIP_RETCODE generateCutFactorable(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_Real *cutcoef, SCIP_Real *cutlhs, SCIP_Real *cutrhs, SCIP_Bool *islocal, SCIP_Bool *success, char *name)
SCIP_RETCODE SCIPfindQuadVarTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, int *pos)
#define CONSHDLR_CHECKPRIORITY
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17367
SCIP_Bool SCIPisConcaveQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_NLPI ** SCIPgetNlpis(SCIP *scip)
Definition: scip.c:8672
SCIP_RETCODE SCIPaddLinearVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPenableNLP(SCIP *scip)
Definition: scip.c:28392
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:16837
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:30522
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:41637
struct SCIP_QuadVarEventData SCIP_QUADVAREVENTDATA
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_CONS **maxviolcon)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5292
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:55
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:50
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:5192
#define CONSHDLR_ENFOPRIORITY
SCIP_Real sup
Definition: intervalarith.h:39
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:37435
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_RETCODE SCIPaddLinearConsToNlpHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_Bool addcombconss, SCIP_Bool addcontconss)
Definition: heur_subnlp.c:2330
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:18974
static SCIP_RETCODE computeReferencePointGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real **ref, SCIP_Bool *success)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:32131
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41946
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:264
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:20598
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:97
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7650
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:16884
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
Definition: scip.c:41660
SCIP_RETCODE SCIPgetActivityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *activity)
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:96
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip.c:5726
static SCIP_RETCODE consdataEnsureAdjBilinSize(SCIP *scip, SCIP_QUADVARTERM *quadvarterm, int num)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12080
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
Definition: scip.c:38534
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41611
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12896
Ipopt NLP interface.
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip.c:22681
static SCIP_RETCODE computeInteriorPoint(SCIP *scip, SCIP_CONS *cons, char method, SCIP_Bool *success)
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1181
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20193
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:16850
static SCIP_RETCODE propagateBoundsTightenVarUb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17123
SCIP_RETCODE SCIPaddLinearCoefsToNlRow(SCIP *scip, SCIP_NLROW *nlrow, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:29587
#define CONSHDLR_NEEDSCONS
unsigned int SCIP_EVENTTYPE
Definition: type_event.h:125
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip.c:1034
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:24772
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41819
static SCIP_DECL_CONSINITLP(consInitlpQuadratic)
#define SCIP_Bool
Definition: def.h:53
static SCIP_DECL_CONSFREE(consFreeQuadratic)
static SCIP_RETCODE presolveDisaggregate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14382
#define CONSHDLR_DELAYSEPA
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
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
static SCIP_RETCODE computeGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17335
static const char * paramname[]
Definition: lpi_msk.c:4201
SCIP_RETCODE SCIPgetFeasibilityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *feasibility)
SCIP_Real SCIPvarGetBestBoundLocal(SCIP_VAR *var)
Definition: var.c:17143
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:801
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:7859
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)
#define NONLINCONSUPGD_PRIORITY
constraint handler for nonlinear constraints
SCIP_Bool SCIPhaveVarsCommonClique(SCIP *scip, SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: scip.c:22165
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)
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:8245
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 SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip.c:34271
static SCIP_RETCODE registerLargeLPValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_VAR **brvar)
methods for debugging
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:7869
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:7969
SCIP_Real * SCIPgetCoefsLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real coef
int SCIPgetNQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPgetNlRowQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:16825
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:5611
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28027
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
#define SCIPreallocMemoryArray(scip, ptr, newnum)
Definition: scip.h:20534
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:89
SCIP_RETCODE SCIPnlpiSolve(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:495
SCIP_RETCODE SCIPchgLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:16849
#define infty2infty(infty1, infty2, val)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:57
Constraint handler for linear constraints in their most general form, .
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_NAME
SCIP_Real SCIPvarGetWorstBoundLocal(SCIP_VAR *var)
Definition: var.c:17156
static SCIP_Bool consdataCheckBilinTermsSort(SCIP_CONSDATA *consdata)
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip.c:36779
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip.c:34940
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7046
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:38140
SCIP_Bool SCIPhasPrimalRay(SCIP *scip)
Definition: scip.c:36498
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12825
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:16442
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)
#define SCIPallocClearMemoryArray(scip, ptr, num)
Definition: scip.h:20530
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1298
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:12908
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41624
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:36668
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:5565
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11477
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16608
SCIP_QUADVAREVENTDATA * eventdata
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip.c:5431
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2364
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:41770
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:20585
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17057
static SCIP_RETCODE addBilinearTerm(SCIP *scip, SCIP_CONS *cons, int var1pos, int var2pos, SCIP_Real coef)
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:36588
static void consdataMoveQuadVarTerm(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:5772
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:3829
static SCIP_RETCODE consdataCreateEmpty(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_VAR ** SCIPnlrowGetQuadVars(SCIP_NLROW *nlrow)
Definition: nlp.c:3275
static SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip.c:29472
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1281
#define REALABS(x)
Definition: def.h:151
#define CONSHDLR_DESC
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
#define SCIPfreeMemoryArrayNull(scip, ptr)
Definition: scip.h:20545
static SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNIntVars(SCIP *scip)
Definition: scip.c:10788
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:4922
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_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:41721
static SCIP_DECL_CONSCOPY(consCopyQuadratic)
static SCIP_DECL_CONSINIT(consInitQuadratic)
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingModeUpwards(void)
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:18871
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:5455
static SCIP_RETCODE generateCutLTI(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_SOL *sol, SCIP_Real **cutcoeflin, SCIP_Real *cutcoefquad, SCIP_Real *cutlhs, SCIP_Real *cutrhs, SCIP_Bool *islocal, SCIP_Bool *success, char *name)
NLP local search primal heuristic using sub-SCIPs.
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41933
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:19453
void SCIPfreeParseVarsPolynomialData(SCIP *scip, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int nmonomials)
Definition: scip.c:16794
#define SCIP_Real
Definition: def.h:127
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:7799
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:30572
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:3657
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20299
#define MIN(x, y)
Definition: memory.c:67
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
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:27600
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:34044
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:28334
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41959
static SCIP_RETCODE checkFactorable(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeQuadconsUpgrade(SCIP *scip, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:20568
SCIP_RETCODE SCIPnlpiAddConstraints(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nconss, const SCIP_Real *lhss, const SCIP_Real *rhss, const int *nlininds, int *const *lininds, SCIP_Real *const *linvals, const int *nquadelems, SCIP_QUADELEM *const *quadelems, int *const *exprvaridxs, SCIP_EXPRTREE *const *exprtrees, const char **names)
Definition: nlpi.c:268
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12743
#define SCIP_INVALID
Definition: def.h:147
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:41146
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
const char * SCIPgetProbName(SCIP *scip)
Definition: scip.c:9941
SCIP_RETCODE SCIPchgBilinCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:27738
void SCIPsortInt(int *intarray, int len)
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:28735
static SCIP_RETCODE propagateBoundsTightenVarLb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE delLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIP_Longint
Definition: def.h:112
static SCIP_RETCODE consdataEnsureBilinSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
int SCIPgetNNlpis(SCIP *scip)
Definition: scip.c:8685
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip.c:19685
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:917
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:20571
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:263
static SCIP_DECL_CONSLOCK(consLockQuadratic)
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:5407
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
Definition: scip.c:41782
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:19399
SCIP_RETCODE SCIPcreateConsQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
SCIP_RETCODE SCIPaddSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:42283
int SCIP_ROUNDMODE
Definition: intervalarith.h:45
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)
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:18836
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
static SCIP_DECL_EVENTEXEC(processVarEvent)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:20597
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16730
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip.c:33701
#define SCIPdebug(x)
Definition: pub_message.h:74
static SCIP_RETCODE addLinearCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPaddConsLocal(SCIP *scip, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip.c:11999
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17381
#define CONSHDLR_PROP_TIMING
static SCIP_DECL_CONSPROP(consPropQuadratic)
static SCIP_RETCODE delQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos)
static SCIP_DECL_CONSPRINT(consPrintQuadratic)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:41422
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2094
static SCIP_RETCODE registerBranchingCandidatesGap(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
static SCIP_RETCODE presolveDisaggregateMarkComponent(SCIP *scip, SCIP_CONSDATA *consdata, int quadvaridx, SCIP_HASHMAP *var2component, int componentnr)
#define CONSHDLR_SEPAFREQ
SCIP_Real SCIPgetLhsQuadratic(SCIP *scip, SCIP_CONS *cons)
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:12932
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:18685
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41697
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1120
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
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:3629
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:5841
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:7707
#define SCIPABORT()
Definition: def.h:238
static SCIP_RETCODE consdataFindQuadVarTerm(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR *var, int *pos)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:7789
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:7083
static SCIP_RETCODE mergeAndCleanQuadVarTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:7819
SCIP_RETCODE LapackDsyev(SCIP_Bool computeeigenvectors, int N, SCIP_Real *a, SCIP_Real *w)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3149
SCIP_Real SCIPgetRhsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE consdataEnsureLinearVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
void SCIPintervalSetRoundingModeDownwards(void)
static SCIP_DECL_CONSDISABLE(consDisableQuadratic)
SCIP_NLPSOLSTAT SCIPnlpiGetSolstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:509
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:36554
SCIP_Bool SCIPisConvexQuadratic(SCIP *scip, SCIP_CONS *cons)
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_QUADELEM * SCIPnlrowGetQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3322
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:34607
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:12920