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-2015 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  /* mark activity bounds for quad term as not up to date anymore */
996  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
997  }
998  else
999  {
1000  /* update activity bounds for linear terms */
1001  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
1002  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1003  else
1004  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1005  }
1006 
1007  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1008  consdata->ispropagated = FALSE;
1009  }
1010 
1011  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1012  {
1013  consdata->isremovedfixings = FALSE;
1014  }
1015 
1016 #ifdef CHECKIMPLINBILINEAR
1017  if( eventtype & SCIP_EVENTTYPE_IMPLADDED )
1018  {
1019  assert(varidx < 0); /* we catch impladded events only for quadratic variables */
1020  /* 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 */
1021  if( SCIPvarIsBinary(SCIPeventGetVar(event)) && consdata->quadvarterms[-varidx-1].nadjbilin > 0 )
1022  consdata->isimpladded = TRUE;
1023  }
1024 #endif
1025 
1026  return SCIP_OKAY;
1027 }
1028 
1029 /** ensures, that linear vars and coefs arrays can store at least num entries */
1030 static
1032  SCIP* scip, /**< SCIP data structure */
1033  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1034  int num /**< minimum number of entries to store */
1035  )
1036 {
1037  assert(scip != NULL);
1038  assert(consdata != NULL);
1039  assert(consdata->nlinvars <= consdata->linvarssize);
1040 
1041  if( num > consdata->linvarssize )
1042  {
1043  int newsize;
1044 
1045  newsize = SCIPcalcMemGrowSize(scip, num);
1046  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1047  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1048  if( consdata->lineventdata != NULL )
1049  {
1050  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1051  }
1052  consdata->linvarssize = newsize;
1053  }
1054  assert(num <= consdata->linvarssize);
1055 
1056  return SCIP_OKAY;
1057 }
1058 
1059 /** ensures, that quadratic variable terms array can store at least num entries */
1060 static
1062  SCIP* scip, /**< SCIP data structure */
1063  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1064  int num /**< minimum number of entries to store */
1065  )
1066 {
1067  assert(scip != NULL);
1068  assert(consdata != NULL);
1069  assert(consdata->nquadvars <= consdata->quadvarssize);
1070 
1071  if( num > consdata->quadvarssize )
1072  {
1073  int newsize;
1074 
1075  newsize = SCIPcalcMemGrowSize(scip, num);
1076  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->quadvarterms, consdata->quadvarssize, newsize) );
1077  consdata->quadvarssize = newsize;
1078  }
1079  assert(num <= consdata->quadvarssize);
1080 
1081  return SCIP_OKAY;
1082 }
1083 
1084 /** ensures, that adjacency array can store at least num entries */
1085 static
1087  SCIP* scip, /**< SCIP data structure */
1088  SCIP_QUADVARTERM* quadvarterm, /**< quadratic variable term */
1089  int num /**< minimum number of entries to store */
1090  )
1091 {
1092  assert(scip != NULL);
1093  assert(quadvarterm != NULL);
1094  assert(quadvarterm->nadjbilin <= quadvarterm->adjbilinsize);
1095 
1096  if( num > quadvarterm->adjbilinsize )
1097  {
1098  int newsize;
1099 
1100  newsize = SCIPcalcMemGrowSize(scip, num);
1101  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvarterm->adjbilin, quadvarterm->adjbilinsize, newsize) );
1102  quadvarterm->adjbilinsize = newsize;
1103  }
1104  assert(num <= quadvarterm->adjbilinsize);
1105 
1106  return SCIP_OKAY;
1107 }
1108 
1109 /** ensures, that bilinear term arrays can store at least num entries */
1110 static
1112  SCIP* scip, /**< SCIP data structure */
1113  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1114  int num /**< minimum number of entries to store */
1115  )
1116 {
1117  assert(scip != NULL);
1118  assert(consdata != NULL);
1119  assert(consdata->nbilinterms <= consdata->bilintermssize);
1120 
1121  if( num > consdata->bilintermssize )
1122  {
1123  int newsize;
1124 
1125  newsize = SCIPcalcMemGrowSize(scip, num);
1126  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize, newsize) );
1127  consdata->bilintermssize = newsize;
1128  }
1129  assert(num <= consdata->bilintermssize);
1130 
1131  return SCIP_OKAY;
1132 }
1133 
1134 /** creates empty constraint data structure */
1135 static
1137  SCIP* scip, /**< SCIP data structure */
1138  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1139  )
1140 {
1141  assert(scip != NULL);
1142  assert(consdata != NULL);
1143 
1144  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1145  BMSclearMemory(*consdata);
1146 
1147  (*consdata)->lhs = -SCIPinfinity(scip);
1148  (*consdata)->rhs = SCIPinfinity(scip);
1149 
1150  (*consdata)->linvarssorted = TRUE;
1151  (*consdata)->linvarsmerged = TRUE;
1152  (*consdata)->quadvarssorted = TRUE;
1153  (*consdata)->quadvarsmerged = TRUE;
1154  (*consdata)->bilinsorted = TRUE;
1155  (*consdata)->bilinmerged = TRUE;
1156 
1157  (*consdata)->isremovedfixings = TRUE;
1158  (*consdata)->ispropagated = TRUE;
1159  (*consdata)->initialmerge = FALSE;
1160 
1161  (*consdata)->linvar_maydecrease = -1;
1162  (*consdata)->linvar_mayincrease = -1;
1163 
1164  (*consdata)->minlinactivity = SCIP_INVALID;
1165  (*consdata)->maxlinactivity = SCIP_INVALID;
1166  (*consdata)->minlinactivityinf = -1;
1167  (*consdata)->maxlinactivityinf = -1;
1168 
1169  (*consdata)->isgaugeavailable = FALSE;
1170 
1171  return SCIP_OKAY;
1172 }
1173 
1174 /** creates constraint data structure */
1175 static
1177  SCIP* scip, /**< SCIP data structure */
1178  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1179  SCIP_Real lhs, /**< left hand side of constraint */
1180  SCIP_Real rhs, /**< right hand side of constraint */
1181  int nlinvars, /**< number of linear variables */
1182  SCIP_VAR** linvars, /**< array of linear variables */
1183  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1184  int nquadvars, /**< number of quadratic variables */
1185  SCIP_QUADVARTERM* quadvarterms, /**< array of quadratic variable terms */
1186  int nbilinterms, /**< number of bilinear terms */
1187  SCIP_BILINTERM* bilinterms, /**< array of bilinear terms */
1188  SCIP_Bool capturevars /**< whether we should capture variables */
1189  )
1190 {
1191  int i;
1192 
1193  assert(scip != NULL);
1194  assert(consdata != NULL);
1195 
1196  assert(nlinvars == 0 || linvars != NULL);
1197  assert(nlinvars == 0 || lincoefs != NULL);
1198  assert(nquadvars == 0 || quadvarterms != NULL);
1199  assert(nbilinterms == 0 || bilinterms != NULL);
1200 
1201  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1202  BMSclearMemory(*consdata);
1203 
1204  (*consdata)->minlinactivity = SCIP_INVALID;
1205  (*consdata)->maxlinactivity = SCIP_INVALID;
1206  (*consdata)->minlinactivityinf = -1;
1207  (*consdata)->maxlinactivityinf = -1;
1208 
1209  (*consdata)->lhs = lhs;
1210  (*consdata)->rhs = rhs;
1211 
1212  if( nlinvars > 0 )
1213  {
1214  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1215  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1216  (*consdata)->nlinvars = nlinvars;
1217  (*consdata)->linvarssize = nlinvars;
1218 
1219  if( capturevars )
1220  for( i = 0; i < nlinvars; ++i )
1221  {
1222  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1223  }
1224  }
1225  else
1226  {
1227  (*consdata)->linvarssorted = TRUE;
1228  (*consdata)->linvarsmerged = TRUE;
1229  (*consdata)->minlinactivity = 0.0;
1230  (*consdata)->maxlinactivity = 0.0;
1231  (*consdata)->minlinactivityinf = 0;
1232  (*consdata)->maxlinactivityinf = 0;
1233  }
1234 
1235  if( nquadvars > 0 )
1236  {
1237  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms, quadvarterms, nquadvars) );
1238 
1239  for( i = 0; i < nquadvars; ++i )
1240  {
1241  (*consdata)->quadvarterms[i].eventdata = NULL;
1242  if( quadvarterms[i].nadjbilin )
1243  {
1244  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms[i].adjbilin, quadvarterms[i].adjbilin, quadvarterms[i].nadjbilin) );
1245  (*consdata)->quadvarterms[i].adjbilinsize = quadvarterms[i].nadjbilin;
1246  }
1247  else
1248  {
1249  assert((*consdata)->quadvarterms[i].nadjbilin == 0);
1250  (*consdata)->quadvarterms[i].adjbilin = NULL;
1251  (*consdata)->quadvarterms[i].adjbilinsize = 0;
1252  }
1253  if( capturevars )
1254  {
1255  SCIP_CALL( SCIPcaptureVar(scip, quadvarterms[i].var) );
1256  }
1257  }
1258 
1259  (*consdata)->nquadvars = nquadvars;
1260  (*consdata)->quadvarssize = nquadvars;
1261  SCIPintervalSetEmpty(&(*consdata)->quadactivitybounds);
1262  }
1263  else
1264  {
1265  (*consdata)->quadvarssorted = TRUE;
1266  (*consdata)->quadvarsmerged = TRUE;
1267  SCIPintervalSet(&(*consdata)->quadactivitybounds, 0.0);
1268  }
1269 
1270  if( nbilinterms > 0 )
1271  {
1272  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->bilinterms, bilinterms, nbilinterms) );
1273  (*consdata)->nbilinterms = nbilinterms;
1274  (*consdata)->bilintermssize = nbilinterms;
1275  }
1276  else
1277  {
1278  (*consdata)->bilinsorted = TRUE;
1279  (*consdata)->bilinmerged = TRUE;
1280  }
1281 
1282  (*consdata)->linvar_maydecrease = -1;
1283  (*consdata)->linvar_mayincrease = -1;
1284 
1285  (*consdata)->activity = SCIP_INVALID;
1286  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1287  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1288 
1289  (*consdata)->isgaugeavailable = FALSE;
1290 
1291  return SCIP_OKAY;
1292 }
1293 
1294 /** frees constraint data structure */
1295 static
1297  SCIP* scip, /**< SCIP data structure */
1298  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1299  )
1300 {
1301  int i;
1302 
1303  assert(scip != NULL);
1304  assert(consdata != NULL);
1305  assert(*consdata != NULL);
1306 
1307  /* free sepa arrays, may exists if constraint is deleted in solving stage */
1308  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepaquadvars, (*consdata)->nquadvars);
1309  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepabilinvar2pos, (*consdata)->nbilinterms);
1310 
1311  /* release linear variables and free linear part */
1312  if( (*consdata)->linvarssize > 0 )
1313  {
1314  for( i = 0; i < (*consdata)->nlinvars; ++i )
1315  {
1316  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1317  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1318  }
1319  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1320  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1321  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1322  }
1323  assert((*consdata)->linvars == NULL);
1324  assert((*consdata)->lincoefs == NULL);
1325  assert((*consdata)->lineventdata == NULL);
1326 
1327  /* release quadratic variables and free quadratic variable term part */
1328  for( i = 0; i < (*consdata)->nquadvars; ++i )
1329  {
1330  assert((*consdata)->quadvarterms[i].eventdata == NULL); /* variable events should have been dropped earlier */
1331  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms[i].adjbilin, (*consdata)->quadvarterms[i].adjbilinsize);
1332  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->quadvarterms[i].var) );
1333  }
1334  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms, (*consdata)->quadvarssize);
1335 
1336  /* free bilinear terms */
1337  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilinterms, (*consdata)->bilintermssize);
1338 
1339  /* free nonlinear row representation */
1340  if( (*consdata)->nlrow != NULL )
1341  {
1342  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1343  }
1344 
1345  /* free interior point information, may exists if constraint is deleted in solving stage */
1346  SCIPfreeMemoryArrayNull(scip, &(*consdata)->interiorpoint);
1347  SCIPfreeMemoryArrayNull(scip, &(*consdata)->gaugecoefs);
1348 
1349  SCIPfreeBlockMemory(scip, consdata);
1350  *consdata = NULL;
1351 
1352  return SCIP_OKAY;
1353 }
1354 
1355 /** sorts linear part of constraint data */
1356 static
1358  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1359  )
1360 {
1361  assert(consdata != NULL);
1362 
1363  if( consdata->linvarssorted )
1364  return;
1365 
1366  if( consdata->nlinvars <= 1 )
1367  {
1368  consdata->linvarssorted = TRUE;
1369  return;
1370  }
1371 
1372  if( consdata->lineventdata == NULL )
1373  {
1374  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1375  }
1376  else
1377  {
1378  int i;
1379 
1380  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1381 
1382  /* update variable indices in event data */
1383  for( i = 0; i < consdata->nlinvars; ++i )
1384  if( consdata->lineventdata[i] != NULL )
1385  consdata->lineventdata[i]->varidx = i;
1386  }
1387 
1388  consdata->linvarssorted = TRUE;
1389 }
1390 
1391 #ifdef SCIP_DISABLED_CODE /* no-one needs this routine currently */
1392 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1393 static
1394 int consdataFindLinearVar(
1395  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1396  SCIP_VAR* var /**< variable to search for */
1397  )
1398 {
1399  int pos;
1400 
1401  assert(consdata != NULL);
1402  assert(var != NULL);
1403 
1404  if( consdata->nlinvars == 0 )
1405  return -1;
1406 
1407  consdataSortLinearVars(consdata);
1408 
1409  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1410  pos = -1;
1411 
1412  return pos;
1413 }
1414 #endif
1415 
1416 /** index comparison method for quadratic variable terms: compares two indices of the quadratic variable set in the quadratic constraint */
1417 static
1418 SCIP_DECL_SORTINDCOMP(quadVarTermComp)
1419 { /*lint --e{715}*/
1420  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1421 
1422  assert(consdata != NULL);
1423  assert(0 <= ind1 && ind1 < consdata->nquadvars);
1424  assert(0 <= ind2 && ind2 < consdata->nquadvars);
1425 
1426  return SCIPvarCompare(consdata->quadvarterms[ind1].var, consdata->quadvarterms[ind2].var);
1427 }
1428 
1429 /** sorting of quadratic variable terms */
1430 static
1432  SCIP* scip, /**< SCIP data structure */
1433  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1434  )
1435 {
1436  int* perm;
1437  int i;
1438  int nexti;
1439  int v;
1440  SCIP_QUADVARTERM quadterm;
1441 
1442  assert(scip != NULL);
1443  assert(consdata != NULL);
1444 
1445  if( consdata->quadvarssorted )
1446  return SCIP_OKAY;
1447 
1448  if( consdata->nquadvars == 0 )
1449  {
1450  consdata->quadvarssorted = TRUE;
1451  return SCIP_OKAY;
1452  }
1453 
1454  /* get temporary memory to store the sorted permutation */
1455  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nquadvars) );
1456 
1457  /* call bubble sort */
1458  SCIPsort(perm, quadVarTermComp, (void*)consdata, consdata->nquadvars);
1459 
1460  /* permute the quadratic variable terms according to the resulting permutation */
1461  for( v = 0; v < consdata->nquadvars; ++v )
1462  {
1463  if( perm[v] != v )
1464  {
1465  quadterm = consdata->quadvarterms[v];
1466 
1467  i = v;
1468  do
1469  {
1470  assert(0 <= perm[i] && perm[i] < consdata->nquadvars);
1471  assert(perm[i] != i);
1472  consdata->quadvarterms[i] = consdata->quadvarterms[perm[i]];
1473  if( consdata->quadvarterms[i].eventdata != NULL )
1474  {
1475  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1476  }
1477  nexti = perm[i];
1478  perm[i] = i;
1479  i = nexti;
1480  }
1481  while( perm[i] != v );
1482  consdata->quadvarterms[i] = quadterm;
1483  if( consdata->quadvarterms[i].eventdata != NULL )
1484  {
1485  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1486  }
1487  perm[i] = i;
1488  }
1489  }
1490  consdata->quadvarssorted = TRUE;
1491 
1492  /* free temporary memory */
1493  SCIPfreeBufferArray(scip, &perm);
1494 
1495  return SCIP_OKAY;
1496 }
1497 
1498 /** returns the position of variable in the quadratic variable terms array of a constraint, or -1 if not found */
1499 static
1501  SCIP* scip, /**< SCIP data structure */
1502  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1503  SCIP_VAR* var, /**< variable to search for */
1504  int* pos /**< buffer where to store position of var in quadvarterms array, or -1 if not found */
1505  )
1506 {
1507  int left;
1508  int right;
1509  int cmpres;
1510 
1511  assert(consdata != NULL);
1512  assert(var != NULL);
1513  assert(pos != NULL);
1514 
1515  if( consdata->nquadvars == 0 )
1516  {
1517  *pos = -1;
1518  return SCIP_OKAY;
1519  }
1520 
1521  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
1522 
1523  left = 0;
1524  right = consdata->nquadvars - 1;
1525  while( left <= right )
1526  {
1527  int middle;
1528 
1529  middle = (left+right)/2;
1530  assert(0 <= middle && middle < consdata->nquadvars);
1531 
1532  cmpres = SCIPvarCompare(var, consdata->quadvarterms[middle].var);
1533 
1534  if( cmpres < 0 )
1535  right = middle - 1;
1536  else if( cmpres > 0 )
1537  left = middle + 1;
1538  else
1539  {
1540  *pos = middle;
1541  return SCIP_OKAY;
1542  }
1543  }
1544  assert(left == right+1);
1545 
1546  *pos = -1;
1547 
1548  return SCIP_OKAY;
1549 }
1550 
1551 /** index comparison method for bilinear terms: compares two index pairs of the bilinear term set in the quadratic constraint */
1552 static
1553 SCIP_DECL_SORTINDCOMP(bilinTermComp)
1554 { /*lint --e{715}*/
1555  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1556  int var1cmp;
1557 
1558  assert(consdata != NULL);
1559  assert(0 <= ind1 && ind1 < consdata->nbilinterms);
1560  assert(0 <= ind2 && ind2 < consdata->nbilinterms);
1561 
1562  var1cmp = SCIPvarCompare(consdata->bilinterms[ind1].var1, consdata->bilinterms[ind2].var1);
1563  if( var1cmp != 0 )
1564  return var1cmp;
1565 
1566  return SCIPvarCompare(consdata->bilinterms[ind1].var2, consdata->bilinterms[ind2].var2);
1567 }
1568 
1569 #ifndef NDEBUG
1570 /** checks if all bilinear terms are sorted correctly */
1571 static
1573  SCIP_CONSDATA* consdata
1574  )
1575 {
1576  int i;
1577 
1578  assert(consdata != NULL);
1579 
1580  /* nothing to check if the bilinear terms have not been sorted yet */
1581  if( !consdata->bilinsorted )
1582  return TRUE;
1583 
1584  for( i = 0; i < consdata->nbilinterms - 1; ++i )
1585  {
1586  if( bilinTermComp(consdata, i, i+1) > 0 )
1587  return FALSE;
1588  }
1589  return TRUE;
1590 }
1591 #endif
1592 
1593 /** sorting of bilinear terms */
1594 static
1596  SCIP* scip, /**< SCIP data structure */
1597  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1598  )
1599 {
1600  int* perm;
1601  int* invperm;
1602  int i;
1603  int nexti;
1604  int v;
1605  SCIP_BILINTERM bilinterm;
1606 
1607  assert(scip != NULL);
1608  assert(consdata != NULL);
1609 
1610  if( consdata->bilinsorted )
1611  return SCIP_OKAY;
1612 
1613  if( consdata->nbilinterms == 0 )
1614  {
1615  consdata->bilinsorted = TRUE;
1616  return SCIP_OKAY;
1617  }
1618 
1619  /* get temporary memory to store the sorted permutation and the inverse permutation */
1620  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nbilinterms) );
1621  SCIP_CALL( SCIPallocBufferArray(scip, &invperm, consdata->nbilinterms) );
1622 
1623  /* call bubble sort */
1624  SCIPsort(perm, bilinTermComp, (void*)consdata, consdata->nbilinterms);
1625 
1626  /* compute inverted permutation */
1627  for( v = 0; v < consdata->nbilinterms; ++v )
1628  {
1629  assert(0 <= perm[v] && perm[v] < consdata->nbilinterms);
1630  invperm[perm[v]] = v;
1631  }
1632 
1633  /* permute the bilinear terms according to the resulting permutation */
1634  for( v = 0; v < consdata->nbilinterms; ++v )
1635  {
1636  if( perm[v] != v )
1637  {
1638  bilinterm = consdata->bilinterms[v];
1639 
1640  i = v;
1641  do
1642  {
1643  assert(0 <= perm[i] && perm[i] < consdata->nbilinterms);
1644  assert(perm[i] != i);
1645  consdata->bilinterms[i] = consdata->bilinterms[perm[i]];
1646  nexti = perm[i];
1647  perm[i] = i;
1648  i = nexti;
1649  }
1650  while( perm[i] != v );
1651  consdata->bilinterms[i] = bilinterm;
1652  perm[i] = i;
1653  }
1654  }
1655 
1656  /* update the adjacency information in the quadratic variable terms */
1657  for( v = 0; v < consdata->nquadvars; ++v )
1658  for( i = 0; i < consdata->quadvarterms[v].nadjbilin; ++i )
1659  consdata->quadvarterms[v].adjbilin[i] = invperm[consdata->quadvarterms[v].adjbilin[i]];
1660 
1661  consdata->bilinsorted = TRUE;
1662  assert(consdataCheckBilinTermsSort(consdata));
1663 
1664  /* free temporary memory */
1665  SCIPfreeBufferArray(scip, &perm);
1666  SCIPfreeBufferArray(scip, &invperm);
1667 
1668  return SCIP_OKAY;
1669 }
1670 
1671 /** moves a linear variable from one position to another */
1672 static
1674  SCIP_CONSDATA* consdata, /**< constraint data */
1675  int oldpos, /**< position of variable that shall be moved */
1676  int newpos /**< new position of variable */
1677  )
1678 {
1679  assert(consdata != NULL);
1680  assert(oldpos >= 0);
1681  assert(oldpos < consdata->nlinvars);
1682  assert(newpos >= 0);
1683  assert(newpos < consdata->linvarssize);
1684 
1685  if( newpos == oldpos )
1686  return;
1687 
1688  consdata->linvars [newpos] = consdata->linvars [oldpos];
1689  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1690 
1691  if( consdata->lineventdata != NULL )
1692  {
1693  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1694 
1695  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1696  consdata->lineventdata[newpos]->varidx = newpos;
1697 
1698  consdata->lineventdata[oldpos] = NULL;
1699  }
1700 
1701  consdata->linvarssorted = FALSE;
1702 }
1703 
1704 /** moves a quadratic variable from one position to another */
1705 static
1707  SCIP_CONSDATA* consdata, /**< constraint data */
1708  int oldpos, /**< position of variable that shall be moved */
1709  int newpos /**< new position of variable */
1710  )
1711 {
1712  assert(consdata != NULL);
1713  assert(oldpos >= 0);
1714  assert(oldpos < consdata->nquadvars);
1715  assert(newpos >= 0);
1716  assert(newpos < consdata->quadvarssize);
1717 
1718  if( newpos == oldpos )
1719  return;
1720 
1721  assert(newpos >= consdata->nquadvars || consdata->quadvarterms[newpos].eventdata == NULL);
1722 
1723  consdata->quadvarterms[newpos] = consdata->quadvarterms[oldpos];
1724 
1725  if( consdata->quadvarterms[newpos].eventdata != NULL )
1726  {
1727  consdata->quadvarterms[newpos].eventdata->varidx = -newpos-1;
1728  consdata->quadvarterms[oldpos].eventdata = NULL;
1729  }
1730 
1731  consdata->quadvarssorted = FALSE;
1732 }
1733 
1734 /** adds linear coefficient in quadratic constraint */
1735 static
1737  SCIP* scip, /**< SCIP data structure */
1738  SCIP_CONS* cons, /**< quadratic constraint */
1739  SCIP_VAR* var, /**< variable of constraint entry */
1740  SCIP_Real coef /**< coefficient of constraint entry */
1741  )
1742 {
1743  SCIP_CONSDATA* consdata;
1744  SCIP_Bool transformed;
1745 
1746  assert(scip != NULL);
1747  assert(cons != NULL);
1748  assert(var != NULL);
1749 
1750  /* ignore coefficient if it is nearly zero */
1751  if( SCIPisZero(scip, coef) )
1752  return SCIP_OKAY;
1753 
1754  consdata = SCIPconsGetData(cons);
1755  assert(consdata != NULL);
1756 
1757  /* are we in the transformed problem? */
1758  transformed = SCIPconsIsTransformed(cons);
1759 
1760  /* always use transformed variables in transformed constraints */
1761  if( transformed )
1762  {
1763  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1764  }
1765  assert(var != NULL);
1766  assert(transformed == SCIPvarIsTransformed(var));
1767 
1768  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1769  consdata->linvars [consdata->nlinvars] = var;
1770  consdata->lincoefs[consdata->nlinvars] = coef;
1771 
1772  ++consdata->nlinvars;
1773 
1774  /* catch variable events */
1775  if( SCIPconsIsEnabled(cons) )
1776  {
1777  SCIP_CONSHDLR* conshdlr;
1778  SCIP_CONSHDLRDATA* conshdlrdata;
1779 
1780  /* get event handler */
1781  conshdlr = SCIPconsGetHdlr(cons);
1782  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1783  assert(conshdlrdata != NULL);
1784  assert(conshdlrdata->eventhdlr != NULL);
1785 
1786  assert(consdata->lineventdata != NULL);
1787  consdata->lineventdata[consdata->nlinvars-1] = NULL;
1788 
1789  /* catch bound change events of variable */
1790  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nlinvars-1) );
1791  }
1792 
1793  /* invalidate activity information */
1794  consdata->activity = SCIP_INVALID;
1795  consdata->minlinactivity = SCIP_INVALID;
1796  consdata->maxlinactivity = SCIP_INVALID;
1797  consdata->minlinactivityinf = -1;
1798  consdata->maxlinactivityinf = -1;
1799 
1800  /* invalidate nonlinear row */
1801  if( consdata->nlrow != NULL )
1802  {
1803  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1804  }
1805 
1806  /* install rounding locks for new variable */
1807  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1808 
1809  /* capture new variable */
1810  SCIP_CALL( SCIPcaptureVar(scip, var) );
1811 
1812  consdata->ispropagated = FALSE;
1813  consdata->ispresolved = FALSE;
1814  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
1815  if( consdata->nlinvars == 1 )
1816  consdata->linvarssorted = TRUE;
1817  else
1818  consdata->linvarssorted = consdata->linvarssorted && (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1819  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1820  consdata->linvarsmerged = FALSE;
1821 
1822  return SCIP_OKAY;
1823 }
1824 
1825 /** deletes linear coefficient at given position from quadratic constraint data */
1826 static
1828  SCIP* scip, /**< SCIP data structure */
1829  SCIP_CONS* cons, /**< quadratic constraint */
1830  int pos /**< position of coefficient to delete */
1831  )
1832 {
1833  SCIP_CONSDATA* consdata;
1834  SCIP_VAR* var;
1835  SCIP_Real coef;
1836 
1837  assert(scip != NULL);
1838  assert(cons != NULL);
1839 
1840  consdata = SCIPconsGetData(cons);
1841  assert(consdata != NULL);
1842  assert(0 <= pos && pos < consdata->nlinvars);
1843 
1844  var = consdata->linvars[pos];
1845  coef = consdata->lincoefs[pos];
1846  assert(var != NULL);
1847 
1848  /* remove rounding locks for deleted variable */
1849  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1850 
1851  /* if we catch variable events, drop the events on the variable */
1852  if( consdata->lineventdata != NULL )
1853  {
1854  SCIP_CONSHDLR* conshdlr;
1855  SCIP_CONSHDLRDATA* conshdlrdata;
1856 
1857  /* get event handler */
1858  conshdlr = SCIPconsGetHdlr(cons);
1859  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1860  assert(conshdlrdata != NULL);
1861  assert(conshdlrdata->eventhdlr != NULL);
1862 
1863  /* drop bound change events of variable */
1864  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1865  }
1866 
1867  /* release variable */
1868  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
1869 
1870  /* move the last variable to the free slot */
1871  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
1872 
1873  --consdata->nlinvars;
1874 
1875  /* invalidate activity */
1876  consdata->activity = SCIP_INVALID;
1877  consdata->minlinactivity = SCIP_INVALID;
1878  consdata->maxlinactivity = SCIP_INVALID;
1879  consdata->minlinactivityinf = -1;
1880  consdata->maxlinactivityinf = -1;
1881 
1882  /* invalidate nonlinear row */
1883  if( consdata->nlrow != NULL )
1884  {
1885  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1886  }
1887 
1888  consdata->ispropagated = FALSE;
1889  consdata->ispresolved = FALSE;
1890 
1891  return SCIP_OKAY;
1892 }
1893 
1894 /** changes linear coefficient value at given position of quadratic constraint */
1895 static
1897  SCIP* scip, /**< SCIP data structure */
1898  SCIP_CONS* cons, /**< quadratic constraint */
1899  int pos, /**< position of linear coefficient to change */
1900  SCIP_Real newcoef /**< new value of linear coefficient */
1901  )
1902 {
1903  SCIP_CONSHDLR* conshdlr;
1904  SCIP_CONSHDLRDATA* conshdlrdata;
1905  SCIP_CONSDATA* consdata;
1906  SCIP_VAR* var;
1907  SCIP_Real coef;
1908 
1909  assert(scip != NULL);
1910  assert(cons != NULL);
1911  assert(!SCIPisZero(scip, newcoef));
1912 
1913  conshdlrdata = NULL;
1914 
1915  consdata = SCIPconsGetData(cons);
1916  assert(consdata != NULL);
1917  assert(0 <= pos);
1918  assert(pos < consdata->nlinvars);
1919  assert(!SCIPisZero(scip, newcoef));
1920 
1921  var = consdata->linvars[pos];
1922  coef = consdata->lincoefs[pos];
1923  assert(var != NULL);
1924  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
1925 
1926  /* invalidate activity */
1927  consdata->activity = SCIP_INVALID;
1928  consdata->minlinactivity = SCIP_INVALID;
1929  consdata->maxlinactivity = SCIP_INVALID;
1930  consdata->minlinactivityinf = -1;
1931  consdata->maxlinactivityinf = -1;
1932 
1933  /* invalidate nonlinear row */
1934  if( consdata->nlrow != NULL )
1935  {
1936  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1937  }
1938 
1939  /* if necessary, remove the rounding locks and event catching of the variable */
1940  if( newcoef * coef < 0.0 )
1941  {
1942  if( SCIPconsIsLocked(cons) )
1943  {
1944  assert(SCIPconsIsTransformed(cons));
1945 
1946  /* remove rounding locks for variable with old coefficient */
1947  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1948  }
1949 
1950  if( consdata->lineventdata[pos] != NULL )
1951  {
1952  /* get event handler */
1953  conshdlr = SCIPconsGetHdlr(cons);
1954  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1955  assert(conshdlrdata != NULL);
1956  assert(conshdlrdata->eventhdlr != NULL);
1957 
1958  /* drop bound change events of variable */
1959  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1960  }
1961  }
1962 
1963  /* change the coefficient */
1964  consdata->lincoefs[pos] = newcoef;
1965 
1966  /* if necessary, install the rounding locks and event catching of the variable again */
1967  if( newcoef * coef < 0.0 )
1968  {
1969  if( SCIPconsIsLocked(cons) )
1970  {
1971  /* install rounding locks for variable with new coefficient */
1972  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
1973  }
1974 
1975  if( conshdlrdata != NULL )
1976  {
1977  assert(SCIPconsIsEnabled(cons));
1978 
1979  /* catch bound change events of variable */
1980  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1981  }
1982  }
1983 
1984  consdata->ispropagated = FALSE;
1985  consdata->ispresolved = FALSE;
1986 
1987  return SCIP_OKAY;
1988 }
1989 
1990 /** adds quadratic variable term to quadratic constraint */
1991 static
1993  SCIP* scip, /**< SCIP data structure */
1994  SCIP_CONS* cons, /**< quadratic constraint */
1995  SCIP_VAR* var, /**< variable to add */
1996  SCIP_Real lincoef, /**< linear coefficient of variable */
1997  SCIP_Real sqrcoef /**< square coefficient of variable */
1998  )
1999 {
2000  SCIP_CONSDATA* consdata;
2001  SCIP_Bool transformed;
2002  SCIP_QUADVARTERM* quadvarterm;
2003 
2004  assert(scip != NULL);
2005  assert(cons != NULL);
2006  assert(var != NULL);
2007 
2008  consdata = SCIPconsGetData(cons);
2009  assert(consdata != NULL);
2010 
2011  /* are we in the transformed problem? */
2012  transformed = SCIPconsIsTransformed(cons);
2013 
2014  /* always use transformed variables in transformed constraints */
2015  if( transformed )
2016  {
2017  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
2018  }
2019  assert(var != NULL);
2020  assert(transformed == SCIPvarIsTransformed(var));
2021 
2022  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars+1) );
2023 
2024  quadvarterm = &consdata->quadvarterms[consdata->nquadvars];
2025  quadvarterm->var = var;
2026  quadvarterm->lincoef = lincoef;
2027  quadvarterm->sqrcoef = sqrcoef;
2028  quadvarterm->adjbilinsize = 0;
2029  quadvarterm->nadjbilin = 0;
2030  quadvarterm->adjbilin = NULL;
2031  quadvarterm->eventdata = NULL;
2032 
2033  ++consdata->nquadvars;
2034 
2035  /* capture variable */
2036  SCIP_CALL( SCIPcaptureVar(scip, var) );
2037 
2038  /* catch variable events, if we do so */
2039  if( SCIPconsIsEnabled(cons) )
2040  {
2041  SCIP_CONSHDLR* conshdlr;
2042  SCIP_CONSHDLRDATA* conshdlrdata;
2043 
2044  /* get event handler */
2045  conshdlr = SCIPconsGetHdlr(cons);
2046  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2047  assert(conshdlrdata != NULL);
2048  assert(conshdlrdata->eventhdlr != NULL);
2049 
2050  /* catch bound change events of variable */
2051  SCIP_CALL( catchQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nquadvars-1) );
2052  }
2053 
2054  /* invalidate activity information */
2055  consdata->activity = SCIP_INVALID;
2056  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2057 
2058  /* invalidate nonlinear row */
2059  if( consdata->nlrow != NULL )
2060  {
2061  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2062  }
2063 
2064  /* install rounding locks for new variable */
2065  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2066 
2067  consdata->ispropagated = FALSE;
2068  consdata->ispresolved = FALSE;
2069  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
2070  if( consdata->nquadvars == 1 )
2071  consdata->quadvarssorted = TRUE;
2072  else
2073  consdata->quadvarssorted = consdata->quadvarssorted &&
2074  (SCIPvarCompare(consdata->quadvarterms[consdata->nquadvars-2].var, consdata->quadvarterms[consdata->nquadvars-1].var) == -1);
2075  /* also set to FALSE if nquadvars == 1, since the new variable should be checked for linearity and other stuff in mergeAndClean ... */
2076  consdata->quadvarsmerged = FALSE;
2077 
2078  consdata->iscurvchecked = FALSE;
2079 
2080  return SCIP_OKAY;
2081 }
2082 
2083 /** deletes quadratic variable term at given position from quadratic constraint data */
2084 static
2086  SCIP* scip, /**< SCIP data structure */
2087  SCIP_CONS* cons, /**< quadratic constraint */
2088  int pos /**< position of term to delete */
2089  )
2090 {
2091  SCIP_CONSDATA* consdata;
2092  SCIP_VAR* var;
2093 
2094  assert(scip != NULL);
2095  assert(cons != NULL);
2096 
2097  consdata = SCIPconsGetData(cons);
2098  assert(consdata != NULL);
2099  assert(0 <= pos && pos < consdata->nquadvars);
2100 
2101  var = consdata->quadvarterms[pos].var;
2102  assert(var != NULL);
2103  assert(consdata->quadvarterms[pos].nadjbilin == 0);
2104 
2105  /* remove rounding locks for deleted variable */
2106  SCIP_CALL( unlockQuadraticVariable(scip, cons, var) );
2107 
2108  /* if we catch variable events, drop the events on the variable */
2109  if( consdata->quadvarterms[pos].eventdata != NULL )
2110  {
2111  SCIP_CONSHDLR* conshdlr;
2112  SCIP_CONSHDLRDATA* conshdlrdata;
2113 
2114  /* get event handler */
2115  conshdlr = SCIPconsGetHdlr(cons);
2116  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2117  assert(conshdlrdata != NULL);
2118  assert(conshdlrdata->eventhdlr != NULL);
2119 
2120  /* drop bound change events of variable */
2121  SCIP_CALL( dropQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2122  }
2123 
2124  /* release variable */
2125  SCIP_CALL( SCIPreleaseVar(scip, &consdata->quadvarterms[pos].var) );
2126 
2127  /* free adjacency array */
2128  SCIPfreeBlockMemoryArrayNull(scip, &consdata->quadvarterms[pos].adjbilin, consdata->quadvarterms[pos].adjbilinsize);
2129 
2130  /* move the last variable term to the free slot */
2131  consdataMoveQuadVarTerm(consdata, consdata->nquadvars-1, pos);
2132 
2133  --consdata->nquadvars;
2134 
2135  /* invalidate activity */
2136  consdata->activity = SCIP_INVALID;
2137  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2138 
2139  /* invalidate nonlinear row */
2140  if( consdata->nlrow != NULL )
2141  {
2142  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2143  }
2144 
2145  consdata->ispropagated = FALSE;
2146  consdata->ispresolved = FALSE;
2147  consdata->iscurvchecked = FALSE;
2148 
2149  return SCIP_OKAY;
2150 }
2151 
2152 /** replace variable in quadratic variable term at given position of quadratic constraint data
2153  *
2154  * Allows to replace x by coef*y+offset, thereby maintaining linear and square coefficients and bilinear terms.
2155  */
2156 static
2158  SCIP* scip, /**< SCIP data structure */
2159  SCIP_CONS* cons, /**< quadratic constraint */
2160  int pos, /**< position of term to replace */
2161  SCIP_VAR* var, /**< new variable */
2162  SCIP_Real coef, /**< linear coefficient of new variable */
2163  SCIP_Real offset /**< offset of new variable */
2164  )
2165 {
2166  SCIP_CONSDATA* consdata;
2167  SCIP_QUADVARTERM* quadvarterm;
2168  SCIP_EVENTHDLR* eventhdlr;
2169  SCIP_BILINTERM* bilinterm;
2170  SCIP_Real constant;
2171 
2172  int i;
2173  SCIP_VAR* var2;
2174 
2175  consdata = SCIPconsGetData(cons);
2176  assert(consdata != NULL);
2177  assert(pos >= 0);
2178  assert(pos < consdata->nquadvars);
2179 
2180  quadvarterm = &consdata->quadvarterms[pos];
2181 
2182  /* remove rounding locks for old variable */
2183  SCIP_CALL( unlockQuadraticVariable(scip, cons, quadvarterm->var) );
2184 
2185  /* if we catch variable events, drop the events on the old variable */
2186  if( quadvarterm->eventdata != NULL )
2187  {
2188  SCIP_CONSHDLR* conshdlr;
2189  SCIP_CONSHDLRDATA* conshdlrdata;
2190 
2191  /* get event handler */
2192  conshdlr = SCIPconsGetHdlr(cons);
2193  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2194  assert(conshdlrdata != NULL);
2195  assert(conshdlrdata->eventhdlr != NULL);
2196 
2197  eventhdlr = conshdlrdata->eventhdlr;
2198 
2199  /* drop bound change events of variable */
2200  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, pos) );
2201  }
2202  else
2203  {
2204  eventhdlr = NULL;
2205  }
2206 
2207  /* compute constant and put into lhs/rhs */
2208  constant = quadvarterm->lincoef * offset + quadvarterm->sqrcoef * offset * offset;
2209  if( constant != 0.0 )
2210  {
2211  /* maintain constant part */
2212  if( !SCIPisInfinity(scip, -consdata->lhs) )
2213  consdata->lhs -= constant;
2214  if( !SCIPisInfinity(scip, consdata->rhs) )
2215  consdata->rhs -= constant;
2216  }
2217 
2218  /* update linear and square coefficient */
2219  quadvarterm->lincoef *= coef;
2220  quadvarterm->lincoef += 2.0 * quadvarterm->sqrcoef * coef * offset;
2221  quadvarterm->sqrcoef *= coef * coef;
2222 
2223  /* update bilinear terms */
2224  for( i = 0; i < quadvarterm->nadjbilin; ++i )
2225  {
2226  bilinterm = &consdata->bilinterms[quadvarterm->adjbilin[i]];
2227 
2228  if( bilinterm->var1 == quadvarterm->var )
2229  {
2230  bilinterm->var1 = var;
2231  var2 = bilinterm->var2;
2232  }
2233  else
2234  {
2235  assert(bilinterm->var2 == quadvarterm->var);
2236  bilinterm->var2 = var;
2237  var2 = bilinterm->var1;
2238  }
2239 
2240  if( var == var2 )
2241  {
2242  /* looks like we actually have a square term here */
2243  quadvarterm->lincoef += bilinterm->coef * offset;
2244  quadvarterm->sqrcoef += bilinterm->coef * coef;
2245  /* deleting bilinear terms is expensive, since it requires updating adjacency information
2246  * thus, for now we just set the coefficient to 0.0 and clear in later when the bilinear terms are merged */
2247  bilinterm->coef = 0.0;
2248  continue;
2249  }
2250 
2251  /* swap var1 and var2 if they are in wrong order */
2252  if( SCIPvarCompare(bilinterm->var1, bilinterm->var2) > 0 )
2253  {
2254  SCIP_VAR* tmp;
2255  tmp = bilinterm->var1;
2256  bilinterm->var1 = bilinterm->var2;
2257  bilinterm->var2 = tmp;
2258  }
2259  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2260 
2261  if( offset != 0.0 )
2262  {
2263  /* need to find var2 and add offset*bilinterm->coef to linear coefficient */
2264  int var2pos;
2265 
2266  var2pos = 0;
2267  while( consdata->quadvarterms[var2pos].var != var2 )
2268  {
2269  ++var2pos;
2270  assert(var2pos < consdata->nquadvars);
2271  }
2272 
2273  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2274  }
2275 
2276  bilinterm->coef *= coef;
2277  }
2278 
2279  /* release old variable */
2280  SCIP_CALL( SCIPreleaseVar(scip, &quadvarterm->var) );
2281 
2282  /* set new variable */
2283  quadvarterm->var = var;
2284 
2285  /* capture new variable */
2286  SCIP_CALL( SCIPcaptureVar(scip, quadvarterm->var) );
2287 
2288  /* catch variable events, if we do so */
2289  if( eventhdlr != NULL )
2290  {
2291  assert(SCIPconsIsEnabled(cons));
2292 
2293  /* catch bound change events of variable */
2294  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, pos) );
2295  }
2296 
2297  /* invalidate activity information */
2298  consdata->activity = SCIP_INVALID;
2299  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2300 
2301  /* invalidate nonlinear row */
2302  if( consdata->nlrow != NULL )
2303  {
2304  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2305  }
2306 
2307  /* install rounding locks for new variable */
2308  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2309 
2310  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
2311  consdata->quadvarssorted = (consdata->nquadvars == 1);
2312  consdata->quadvarsmerged = FALSE;
2313  consdata->bilinsorted &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2314  consdata->bilinmerged &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2315 
2316  consdata->ispropagated = FALSE;
2317  consdata->ispresolved = FALSE;
2318  consdata->iscurvchecked = FALSE;
2319 
2320  return SCIP_OKAY;
2321 }
2322 
2323 /** adds a bilinear term to quadratic constraint */
2324 static
2326  SCIP* scip, /**< SCIP data structure */
2327  SCIP_CONS* cons, /**< quadratic constraint */
2328  int var1pos, /**< position of first variable in quadratic variables array */
2329  int var2pos, /**< position of second variable in quadratic variables array */
2330  SCIP_Real coef /**< coefficient of bilinear term */
2331  )
2332 {
2333  SCIP_CONSDATA* consdata;
2334  SCIP_BILINTERM* bilinterm;
2335 
2336  assert(scip != NULL);
2337  assert(cons != NULL);
2338 
2339  if( var1pos == var2pos )
2340  {
2341  SCIPerrorMessage("tried to add bilinear term where both variables are the same\n");
2342  return SCIP_INVALIDDATA;
2343  }
2344 
2345  consdata = SCIPconsGetData(cons);
2346  assert(consdata != NULL);
2347 
2348  /* check if the bilinear terms are sorted */
2349  assert(consdataCheckBilinTermsSort(consdata));
2350 
2351  assert(var1pos >= 0);
2352  assert(var1pos < consdata->nquadvars);
2353  assert(var2pos >= 0);
2354  assert(var2pos < consdata->nquadvars);
2355 
2356  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nbilinterms + 1) );
2357 
2358  bilinterm = &consdata->bilinterms[consdata->nbilinterms];
2359  if( SCIPvarCompare(consdata->quadvarterms[var1pos].var, consdata->quadvarterms[var2pos].var) < 0 )
2360  {
2361  bilinterm->var1 = consdata->quadvarterms[var1pos].var;
2362  bilinterm->var2 = consdata->quadvarterms[var2pos].var;
2363  }
2364  else
2365  {
2366  bilinterm->var1 = consdata->quadvarterms[var2pos].var;
2367  bilinterm->var2 = consdata->quadvarterms[var1pos].var;
2368  }
2369  bilinterm->coef = coef;
2370 
2371  if( bilinterm->var1 == bilinterm->var2 )
2372  {
2373  SCIPerrorMessage("tried to add bilinear term where both variables are the same, but appear at different positions in quadvarterms array\n");
2374  return SCIP_INVALIDDATA;
2375  }
2376  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2377 
2378  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var1pos], consdata->quadvarterms[var1pos].nadjbilin + 1) );
2379  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var2pos], consdata->quadvarterms[var2pos].nadjbilin + 1) );
2380 
2381  consdata->quadvarterms[var1pos].adjbilin[consdata->quadvarterms[var1pos].nadjbilin] = consdata->nbilinterms;
2382  consdata->quadvarterms[var2pos].adjbilin[consdata->quadvarterms[var2pos].nadjbilin] = consdata->nbilinterms;
2383  ++consdata->quadvarterms[var1pos].nadjbilin;
2384  ++consdata->quadvarterms[var2pos].nadjbilin;
2385 
2386  ++consdata->nbilinterms;
2387 
2388  /* invalidate activity information */
2389  consdata->activity = SCIP_INVALID;
2390  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2391 
2392  /* invalidate nonlinear row */
2393  if( consdata->nlrow != NULL )
2394  {
2395  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2396  }
2397 
2398  consdata->ispropagated = FALSE;
2399  consdata->ispresolved = FALSE;
2400  if( consdata->nbilinterms == 1 )
2401  {
2402  consdata->bilinsorted = TRUE;
2403 
2404  /* we have to take care of the bilinear term in mergeAndCleanBilinearTerms() if the coefficient is zero */
2405  consdata->bilinmerged = !SCIPisZero(scip, consdata->bilinterms[0].coef);
2406  }
2407  else
2408  {
2409  consdata->bilinsorted = consdata->bilinsorted
2410  && (bilinTermComp(consdata, consdata->nbilinterms-2, consdata->nbilinterms-1) <= 0);
2411  consdata->bilinmerged = FALSE;
2412  }
2413 
2414  consdata->iscurvchecked = FALSE;
2415 
2416  /* check if the bilinear terms are sorted */
2417  assert(consdataCheckBilinTermsSort(consdata));
2418 
2419  return SCIP_OKAY;
2420 }
2421 
2422 /** removes a set of bilinear terms and updates adjacency information in quad var terms
2423  *
2424  * Note: this function sorts the given array termposs.
2425  */
2426 static
2428  SCIP* scip, /**< SCIP data structure */
2429  SCIP_CONS* cons, /**< quadratic constraint */
2430  int nterms, /**< number of terms to delete */
2431  int* termposs /**< indices of terms to delete */
2432  )
2433 {
2434  SCIP_CONSDATA* consdata;
2435  int* newpos;
2436  int i;
2437  int j;
2438  int offset;
2439 
2440  assert(scip != NULL);
2441  assert(cons != NULL);
2442  assert(nterms == 0 || termposs != NULL);
2443 
2444  if( nterms == 0 )
2445  return SCIP_OKAY;
2446 
2447  consdata = SCIPconsGetData(cons);
2448  assert(consdata != NULL);
2449 
2450  SCIPsortInt(termposs, nterms);
2451 
2452  SCIP_CALL( SCIPallocBufferArray(scip, &newpos, consdata->nbilinterms) );
2453 
2454  i = 0;
2455  offset = 0;
2456  for( j = 0; j < consdata->nbilinterms; ++j )
2457  {
2458  /* if j'th term is deleted, increase offset and continue */
2459  if( i < nterms && j == termposs[i] )
2460  {
2461  ++offset;
2462  ++i;
2463  newpos[j] = -1;
2464  continue;
2465  }
2466 
2467  /* otherwise, move it forward and remember new position */
2468  if( offset > 0 )
2469  consdata->bilinterms[j-offset] = consdata->bilinterms[j];
2470  newpos[j] = j - offset;
2471  }
2472  assert(offset == nterms);
2473 
2474  /* update adjacency and activity information in quad var terms */
2475  for( i = 0; i < consdata->nquadvars; ++i )
2476  {
2477  offset = 0;
2478  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2479  {
2480  assert(consdata->quadvarterms[i].adjbilin[j] < consdata->nbilinterms);
2481  if( newpos[consdata->quadvarterms[i].adjbilin[j]] == -1 )
2482  {
2483  /* corresponding bilinear term was deleted, thus increase offset */
2484  ++offset;
2485  }
2486  else
2487  {
2488  /* update index of j'th bilinear term and store at position j-offset */
2489  consdata->quadvarterms[i].adjbilin[j-offset] = newpos[consdata->quadvarterms[i].adjbilin[j]];
2490  }
2491  }
2492  consdata->quadvarterms[i].nadjbilin -= offset;
2493  /* some bilinear term was removed, so invalidate activity bounds */
2494  }
2495 
2496  consdata->nbilinterms -= nterms;
2497 
2498  SCIPfreeBufferArray(scip, &newpos);
2499 
2500  /* some quad vars may be linear now */
2501  consdata->quadvarsmerged = FALSE;
2502 
2503  consdata->ispropagated = FALSE;
2504  consdata->ispresolved = FALSE;
2505  consdata->iscurvchecked = FALSE;
2506 
2507  /* invalidate activity */
2508  consdata->activity = SCIP_INVALID;
2509  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2510 
2511  /* invalidate nonlinear row */
2512  if( consdata->nlrow != NULL )
2513  {
2514  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2515  }
2516 
2517  return SCIP_OKAY;
2518 }
2519 
2520 /** merges quad var terms that correspond to the same variable and does additional cleanup
2521  *
2522  * If a quadratic variable terms is actually linear, makes a linear term out of it
2523  * also replaces squares of binary variables by the binary variables, i.e., adds sqrcoef to lincoef.
2524  */
2525 static
2527  SCIP* scip, /**< SCIP data structure */
2528  SCIP_CONS* cons /**< quadratic constraint */
2529  )
2530 {
2531  SCIP_QUADVARTERM* quadvarterm;
2532  SCIP_CONSDATA* consdata;
2533  int i;
2534  int j;
2535 
2536  assert(scip != NULL);
2537  assert(cons != NULL);
2538 
2539  consdata = SCIPconsGetData(cons);
2540 
2541  if( consdata->quadvarsmerged )
2542  return SCIP_OKAY;
2543 
2544  if( consdata->nquadvars == 0 )
2545  {
2546  consdata->quadvarsmerged = TRUE;
2547  return SCIP_OKAY;
2548  }
2549 
2550  i = 0;
2551  while( i < consdata->nquadvars )
2552  {
2553  /* make sure quad var terms are sorted (do this in every round, since we may move variables around) */
2554  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
2555 
2556  quadvarterm = &consdata->quadvarterms[i];
2557 
2558  for( j = i+1; j < consdata->nquadvars && consdata->quadvarterms[j].var == quadvarterm->var; ++j )
2559  {
2560  /* add quad var term j to current term i */
2561  quadvarterm->lincoef += consdata->quadvarterms[j].lincoef;
2562  quadvarterm->sqrcoef += consdata->quadvarterms[j].sqrcoef;
2563  if( consdata->quadvarterms[j].nadjbilin > 0 )
2564  {
2565  /* move adjacency information from j to i */
2566  SCIP_CALL( consdataEnsureAdjBilinSize(scip, quadvarterm, quadvarterm->nadjbilin + consdata->quadvarterms[j].nadjbilin) );
2567  BMScopyMemoryArray(&quadvarterm->adjbilin[quadvarterm->nadjbilin], consdata->quadvarterms[j].adjbilin, consdata->quadvarterms[j].nadjbilin); /*lint !e866*/
2568  quadvarterm->nadjbilin += consdata->quadvarterms[j].nadjbilin;
2569  consdata->quadvarterms[j].nadjbilin = 0;
2570  }
2571  consdata->quadvarterms[j].lincoef = 0.0;
2572  consdata->quadvarterms[j].sqrcoef = 0.0;
2573  /* mark that activity information in quadvarterm is not up to date anymore */
2574  }
2575 
2576  /* remove quad var terms i+1..j-1 backwards */
2577  for( j = j-1; j > i; --j )
2578  {
2579  SCIP_CALL( delQuadVarTermPos(scip, cons, j) );
2580  }
2581 
2582  /* for binary variables, x^2 = x
2583  * however, we may destroy convexity of a quadratic term that involves also bilinear terms
2584  * thus, we do this step only if the variable does not appear in any bilinear term */
2585  if( quadvarterm->sqrcoef != 0.0 && SCIPvarIsBinary(quadvarterm->var) && quadvarterm->nadjbilin == 0 )
2586  {
2587  SCIPdebugMessage("replace square of binary variable by itself: <%s>^2 --> <%s>\n", SCIPvarGetName(quadvarterm->var), SCIPvarGetName(quadvarterm->var));
2588  quadvarterm->lincoef += quadvarterm->sqrcoef;
2589  quadvarterm->sqrcoef = 0.0;
2590 
2591  /* invalidate nonlinear row */
2592  if( consdata->nlrow != NULL )
2593  {
2594  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2595  }
2596  }
2597 
2598  /* if its 0.0 or linear, get rid of it */
2599  if( SCIPisZero(scip, quadvarterm->sqrcoef) && quadvarterm->nadjbilin == 0 )
2600  {
2601  if( !SCIPisZero(scip, quadvarterm->lincoef) )
2602  {
2603  /* seem to be a linear term now, thus add as linear term */
2604  SCIP_CALL( addLinearCoef(scip, cons, quadvarterm->var, quadvarterm->lincoef) );
2605  }
2606  /* remove term at pos i */
2607  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2608  }
2609  else
2610  {
2611  ++i;
2612  }
2613  }
2614 
2615  consdata->quadvarsmerged = TRUE;
2616  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2617 
2618  return SCIP_OKAY;
2619 }
2620 
2621 /** merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
2622 static
2624  SCIP* scip, /**< SCIP data structure */
2625  SCIP_CONS* cons /**< quadratic constraint */
2626  )
2627 {
2628  SCIP_CONSDATA* consdata;
2629  SCIP_Real newcoef;
2630  int i;
2631  int j;
2632  int qvarpos;
2633 
2634  assert(scip != NULL);
2635  assert(cons != NULL);
2636 
2637  consdata = SCIPconsGetData(cons);
2638 
2639  if( consdata->linvarsmerged )
2640  return SCIP_OKAY;
2641 
2642  if( consdata->nlinvars == 0 )
2643  {
2644  consdata->linvarsmerged = TRUE;
2645  return SCIP_OKAY;
2646  }
2647 
2648  i = 0;
2649  while( i < consdata->nlinvars )
2650  {
2651  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
2652  consdataSortLinearVars(consdata);
2653 
2654  /* sum up coefficients that correspond to variable i */
2655  newcoef = consdata->lincoefs[i];
2656  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
2657  newcoef += consdata->lincoefs[j];
2658  /* delete the additional variables in backward order */
2659  for( j = j-1; j > i; --j )
2660  {
2661  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
2662  }
2663 
2664  /* check if there is already a quadratic variable term with this variable */
2665  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->linvars[i], &qvarpos) );
2666  if( qvarpos >= 0)
2667  {
2668  /* add newcoef to linear coefficient of quadratic variable and mark linear variable as to delete */
2669  assert(qvarpos < consdata->nquadvars);
2670  assert(consdata->quadvarterms[qvarpos].var == consdata->linvars[i]);
2671  consdata->quadvarterms[qvarpos].lincoef += newcoef;
2672  newcoef = 0.0;
2673  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2674  }
2675 
2676  /* delete also entry at position i, if it became zero (or was zero before) */
2677  if( SCIPisZero(scip, newcoef) )
2678  {
2679  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2680  }
2681  else
2682  {
2683  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
2684  ++i;
2685  }
2686  }
2687 
2688  consdata->linvarsmerged = TRUE;
2689 
2690  return SCIP_OKAY;
2691 }
2692 
2693 /** merges bilinear terms with same variables into a single term, removes bilinear terms with coefficient 0.0 */
2694 static
2696  SCIP* scip, /**< SCIP data structure */
2697  SCIP_CONS* cons /**< quadratic constraint */
2698  )
2699 {
2700  SCIP_CONSDATA* consdata;
2701  SCIP_BILINTERM* bilinterm;
2702  int i;
2703  int j;
2704  int* todelete;
2705  int ntodelete;
2706 
2707  assert(scip != NULL);
2708  assert(cons != NULL);
2709 
2710  consdata = SCIPconsGetData(cons);
2711 
2712  /* check if the bilinear terms are sorted */
2713  assert(consdataCheckBilinTermsSort(consdata));
2714 
2715  if( consdata->bilinmerged )
2716  return SCIP_OKAY;
2717 
2718  if( consdata->nbilinterms == 0 )
2719  {
2720  consdata->bilinmerged = TRUE;
2721  return SCIP_OKAY;
2722  }
2723 
2724  /* alloc memory for array of terms that need to be deleted finally */
2725  ntodelete = 0;
2726  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
2727 
2728  /* make sure bilinear terms are sorted */
2729  SCIP_CALL( consdataSortBilinTerms(scip, consdata) );
2730 
2731  i = 0;
2732  while( i < consdata->nbilinterms )
2733  {
2734  bilinterm = &consdata->bilinterms[i];
2735 
2736  /* sum up coefficients that correspond to same variables as term i */
2737  for( j = i+1; j < consdata->nbilinterms && bilinterm->var1 == consdata->bilinterms[j].var1 && bilinterm->var2 == consdata->bilinterms[j].var2; ++j )
2738  {
2739  bilinterm->coef += consdata->bilinterms[j].coef;
2740  todelete[ntodelete++] = j;
2741  }
2742 
2743  /* delete also entry at position i, if it became zero (or was zero before) */
2744  if( SCIPisZero(scip, bilinterm->coef) )
2745  {
2746  todelete[ntodelete++] = i;
2747  }
2748 
2749  /* continue with term after the current series */
2750  i = j;
2751  }
2752 
2753  /* delete bilinear terms */
2754  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
2755 
2756  SCIPfreeBufferArray(scip, &todelete);
2757 
2758  consdata->bilinmerged = TRUE;
2759 
2760  /* check if the bilinear terms are sorted */
2761  assert(consdataCheckBilinTermsSort(consdata));
2762 
2763  return SCIP_OKAY;
2764 }
2765 
2766 /** removes fixes (or aggregated) variables from a quadratic constraint */
2767 static
2769  SCIP* scip, /**< SCIP data structure */
2770  SCIP_CONS* cons /**< quadratic constraint */
2771  )
2772 {
2773  SCIP_CONSDATA* consdata;
2774  SCIP_BILINTERM* bilinterm;
2775  SCIP_Real coef;
2776  SCIP_Real offset;
2777  SCIP_VAR* var;
2778  SCIP_VAR* var2;
2779  int var2pos;
2780  int i;
2781  int j;
2782  int k;
2783 
2784  SCIP_Bool have_change;
2785 
2786  assert(scip != NULL);
2787  assert(cons != NULL);
2788 
2789  consdata = SCIPconsGetData(cons);
2790 
2791  have_change = FALSE;
2792  i = 0;
2793  while( i < consdata->nlinvars )
2794  {
2795  var = consdata->linvars[i];
2796 
2797  if( SCIPvarIsActive(var) )
2798  {
2799  ++i;
2800  continue;
2801  }
2802 
2803  have_change = TRUE;
2804 
2805  coef = consdata->lincoefs[i];
2806  offset = 0.0;
2807 
2808  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2809 
2810  SCIPdebugMessage(" linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]),
2811  coef, SCIPvarGetName(var), offset);
2812 
2813  /* delete previous variable (this will move another variable to position i) */
2814  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2815 
2816  /* put constant part into bounds */
2817  if( offset != 0.0 )
2818  {
2819  if( !SCIPisInfinity(scip, -consdata->lhs) )
2820  consdata->lhs -= offset;
2821  if( !SCIPisInfinity(scip, consdata->rhs) )
2822  consdata->rhs -= offset;
2823  }
2824 
2825  /* nothing left to do if variable had been fixed */
2826  if( coef == 0.0 )
2827  continue;
2828 
2829  /* if GetProbvar gave a linear variable, just add it
2830  * if it's a multilinear variable, add it's disaggregated variables */
2831  if( SCIPvarIsActive(var) )
2832  {
2833  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
2834  }
2835  else
2836  {
2837  int naggrs;
2838  SCIP_VAR** aggrvars;
2839  SCIP_Real* aggrscalars;
2840  SCIP_Real aggrconstant;
2841 
2842  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2843 
2844  naggrs = SCIPvarGetMultaggrNVars(var);
2845  aggrvars = SCIPvarGetMultaggrVars(var);
2846  aggrscalars = SCIPvarGetMultaggrScalars(var);
2847  aggrconstant = SCIPvarGetMultaggrConstant(var);
2848 
2849  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
2850 
2851  for( j = 0; j < naggrs; ++j )
2852  {
2853  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
2854  }
2855 
2856  if( aggrconstant != 0.0 )
2857  {
2858  if( !SCIPisInfinity(scip, -consdata->lhs) )
2859  consdata->lhs -= coef * aggrconstant;
2860  if( !SCIPisInfinity(scip, consdata->rhs) )
2861  consdata->rhs -= coef * aggrconstant;
2862  }
2863  }
2864  }
2865 
2866  i = 0;
2867  while( i < consdata->nquadvars )
2868  {
2869  var = consdata->quadvarterms[i].var;
2870 
2871  if( SCIPvarIsActive(var) )
2872  {
2873  ++i;
2874  continue;
2875  }
2876 
2877  have_change = TRUE;
2878 
2879  coef = 1.0;
2880  offset = 0.0;
2881  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2882 
2883  SCIPdebugMessage(" quadratic variable <%s> with status %d is replaced by %g * <%s> + %g\n", SCIPvarGetName(consdata->quadvarterms[i].var),
2884  SCIPvarGetStatus(consdata->quadvarterms[i].var), coef, SCIPvarGetName(var), offset);
2885 
2886  /* handle fixed variable */
2887  if( coef == 0.0 )
2888  {
2889  /* if not fixed to 0.0, add to linear coefs of vars in bilinear terms, and deal with linear and square term as constant */
2890  if( offset != 0.0 )
2891  {
2892  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2893  {
2894  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
2895 
2896  var2 = bilinterm->var1 == consdata->quadvarterms[i].var ? bilinterm->var2 : bilinterm->var1;
2897  assert(var2 != consdata->quadvarterms[i].var);
2898 
2899  var2pos = 0;
2900  while( consdata->quadvarterms[var2pos].var != var2 )
2901  {
2902  ++var2pos;
2903  assert(var2pos < consdata->nquadvars);
2904  }
2905  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2906  }
2907 
2908  offset = consdata->quadvarterms[i].lincoef * offset + consdata->quadvarterms[i].sqrcoef * offset * offset;
2909  if( !SCIPisInfinity(scip, -consdata->lhs) )
2910  consdata->lhs -= offset;
2911  if( !SCIPisInfinity(scip, consdata->rhs) )
2912  consdata->rhs -= offset;
2913  }
2914 
2915  /* remove bilinear terms */
2916  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
2917 
2918  /* delete quad. var term i */
2919  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2920 
2921  continue;
2922  }
2923 
2924  assert(var != NULL);
2925 
2926  /* if GetProbvar gave an active variable, replace the quad var term so that it uses the new variable */
2927  if( SCIPvarIsActive(var) )
2928  {
2929  /* replace x by coef*y+offset */
2930  SCIP_CALL( replaceQuadVarTermPos(scip, cons, i, var, coef, offset) );
2931 
2932  continue;
2933  }
2934  else
2935  {
2936  /* if GetProbVar gave a multi-aggregated variable, add new quad var terms and new bilinear terms
2937  * x is replaced by coef * (sum_i a_ix_i + b) + offset
2938  * lcoef * x + scoef * x^2 + bcoef * x * y ->
2939  * (b*coef + offset) * (lcoef + (b*coef + offset) * scoef)
2940  * + sum_i a_i*coef * (lcoef + 2 (b*coef + offset) * scoef) x_i
2941  * + sum_i (a_i*coef)^2 * scoef * x_i^2
2942  * + 2 sum_{i,j, i<j} (a_i a_j coef^2 scoef) x_i x_j
2943  * + bcoef * (b*coef + offset + coef * sum_i a_ix_i) y
2944  */
2945  int naggrs;
2946  SCIP_VAR** aggrvars; /* x_i */
2947  SCIP_Real* aggrscalars; /* a_i */
2948  SCIP_Real aggrconstant; /* b */
2949  int nquadtermsold;
2950 
2951  SCIP_Real lcoef;
2952  SCIP_Real scoef;
2953 
2954  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2955 
2956  naggrs = SCIPvarGetMultaggrNVars(var);
2957  aggrvars = SCIPvarGetMultaggrVars(var);
2958  aggrscalars = SCIPvarGetMultaggrScalars(var);
2959  aggrconstant = SCIPvarGetMultaggrConstant(var);
2960 
2961  lcoef = consdata->quadvarterms[i].lincoef;
2962  scoef = consdata->quadvarterms[i].sqrcoef;
2963 
2964  nquadtermsold = consdata->nquadvars;
2965 
2966  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars + naggrs) );
2967 
2968  /* take care of constant part */
2969  if( aggrconstant != 0.0 || offset != 0.0 )
2970  {
2971  SCIP_Real constant;
2972  constant = (aggrconstant * coef + offset) * (lcoef + (aggrconstant * coef + offset) * scoef);
2973  if( !SCIPisInfinity(scip, -consdata->lhs) )
2974  consdata->lhs -= constant;
2975  if( !SCIPisInfinity(scip, consdata->rhs) )
2976  consdata->rhs -= constant;
2977  }
2978 
2979  /* add x_i's with linear and square coefficients */
2980  for( j = 0; j < naggrs; ++j )
2981  {
2982  SCIP_CALL( addQuadVarTerm(scip, cons, aggrvars[j],
2983  coef * aggrscalars[j] * (lcoef + 2.0 * scoef * (coef * aggrconstant + offset)),
2984  coef * coef * aggrscalars[j] * aggrscalars[j] * scoef) );
2985  }
2986 
2987  /* ensure space for bilinear terms */
2988  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nquadvars + (scoef != 0.0 ? (naggrs * (naggrs-1))/2 : 0) + consdata->quadvarterms[j].nadjbilin * naggrs) );
2989 
2990  /* add x_j*x_k's */
2991  if( scoef != 0.0 )
2992  {
2993  for( j = 0; j < naggrs; ++j )
2994  for( k = 0; k < j; ++k )
2995  {
2996  assert(aggrvars[j] != aggrvars[k]);
2997  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, nquadtermsold + k,
2998  2.0 * aggrscalars[j] * aggrscalars[k] * coef * coef * scoef) );
2999  }
3000  }
3001 
3002  /* add x_i*y's */
3003  for( k = 0; k < consdata->quadvarterms[i].nadjbilin; ++k )
3004  {
3005  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[k]];
3006  var2 = (bilinterm->var1 == consdata->quadvarterms[i].var) ? bilinterm->var2 : bilinterm->var1;
3007  assert(var2 != consdata->quadvarterms[i].var);
3008 
3009  /* this is not efficient, but we cannot sort the quadratic terms here, since we currently iterate over them */
3010  var2pos = 0;
3011  while( consdata->quadvarterms[var2pos].var != var2 )
3012  {
3013  ++var2pos;
3014  assert(var2pos < consdata->nquadvars);
3015  }
3016 
3017  for( j = 0; j < naggrs; ++j )
3018  {
3019  if( aggrvars[j] == var2 )
3020  { /* x_i == y, so we have a square term here */
3021  consdata->quadvarterms[var2pos].sqrcoef += bilinterm->coef * coef * aggrscalars[j];
3022  }
3023  else
3024  { /* x_i != y, so we need to add a bilinear term here */
3025  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, var2pos, bilinterm->coef * coef * aggrscalars[j]) );
3026  }
3027  }
3028 
3029  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * (aggrconstant * coef + offset);
3030  }
3031 
3032  /* remove bilinear terms */
3033  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3034 
3035  /* delete quad. var term i */
3036  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3037  }
3038  }
3039 
3040  consdata->isremovedfixings = TRUE;
3041 
3042  SCIPdebugMessage("removed fixations from <%s>\n -> ", SCIPconsGetName(cons));
3043  SCIPdebugPrintCons(scip, cons, NULL);
3044 
3045 #ifndef NDEBUG
3046  for( i = 0; i < consdata->nlinvars; ++i )
3047  assert(SCIPvarIsActive(consdata->linvars[i]));
3048 
3049  for( i = 0; i < consdata->nquadvars; ++i )
3050  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
3051 #endif
3052 
3053  if( !have_change )
3054  return SCIP_OKAY;
3055 
3056  /* some quadratic variable may have been replaced by an already existing linear variable
3057  * in this case, we want the linear variable to be removed, which happens in mergeAndCleanLinearVars
3058  */
3059  consdata->linvarsmerged = FALSE;
3060 
3061  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
3062  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
3063  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
3064 
3065 #ifndef NDEBUG
3066  for( i = 0; i < consdata->nbilinterms; ++i )
3067  {
3068  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
3069  assert(consdata->bilinterms[i].coef != 0.0);
3070  assert(SCIPvarCompare(consdata->bilinterms[i].var1, consdata->bilinterms[i].var2) < 0);
3071  }
3072 #endif
3073 
3074  return SCIP_OKAY;
3075 }
3076 
3077 /** create a nonlinear row representation of the constraint and stores them in consdata */
3078 static
3080  SCIP* scip, /**< SCIP data structure */
3081  SCIP_CONS* cons /**< quadratic constraint */
3082  )
3083 {
3084  SCIP_CONSDATA* consdata;
3085  int nquadvars; /* number of variables in quadratic terms */
3086  SCIP_VAR** quadvars; /* variables in quadratic terms */
3087  int nquadelems; /* number of quadratic elements (square and bilinear terms) */
3088  SCIP_QUADELEM* quadelems; /* quadratic elements (square and bilinear terms) */
3089  int nquadlinterms; /* number of linear terms using variables that are in quadratic terms */
3090  SCIP_VAR** quadlinvars; /* variables of linear terms using variables that are in quadratic terms */
3091  SCIP_Real* quadlincoefs; /* coefficients of linear terms using variables that are in quadratic terms */
3092  int i;
3093  int idx1;
3094  int idx2;
3095  int lincnt;
3096  int elcnt;
3097  SCIP_VAR* lastvar;
3098  int lastvaridx;
3099 
3100  assert(scip != NULL);
3101  assert(cons != NULL);
3102 
3103  consdata = SCIPconsGetData(cons);
3104  assert(consdata != NULL);
3105 
3106  if( consdata->nlrow != NULL )
3107  {
3108  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3109  }
3110 
3111  nquadvars = consdata->nquadvars;
3112  nquadelems = consdata->nbilinterms;
3113  nquadlinterms = 0;
3114  for( i = 0; i < nquadvars; ++i )
3115  {
3116  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3117  ++nquadelems;
3118  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3119  ++nquadlinterms;
3120  }
3121 
3122  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, nquadvars) );
3123  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
3124  SCIP_CALL( SCIPallocBufferArray(scip, &quadlinvars, nquadlinterms) );
3125  SCIP_CALL( SCIPallocBufferArray(scip, &quadlincoefs, nquadlinterms) );
3126 
3127  lincnt = 0;
3128  elcnt = 0;
3129  for( i = 0; i < nquadvars; ++i )
3130  {
3131  quadvars[i] = consdata->quadvarterms[i].var;
3132 
3133  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3134  {
3135  assert(elcnt < nquadelems);
3136  quadelems[elcnt].idx1 = i;
3137  quadelems[elcnt].idx2 = i;
3138  quadelems[elcnt].coef = consdata->quadvarterms[i].sqrcoef;
3139  ++elcnt;
3140  }
3141 
3142  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3143  {
3144  assert(lincnt < nquadlinterms);
3145  quadlinvars [lincnt] = consdata->quadvarterms[i].var;
3146  quadlincoefs[lincnt] = consdata->quadvarterms[i].lincoef;
3147  ++lincnt;
3148  }
3149  }
3150  assert(lincnt == nquadlinterms);
3151 
3152  /* bilinear terms are sorted first by first variable, then by second variable
3153  * 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 */
3154  lastvar = NULL;
3155  lastvaridx = -1;
3156  for( i = 0; i < consdata->nbilinterms; ++i )
3157  {
3158  if( lastvar == consdata->bilinterms[i].var1 )
3159  {
3160  assert(lastvaridx >= 0);
3161  assert(consdata->quadvarterms[lastvaridx].var == consdata->bilinterms[i].var1);
3162  }
3163  else
3164  {
3165  lastvar = consdata->bilinterms[i].var1;
3166  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, lastvar, &lastvaridx) );
3167  }
3168  idx1 = lastvaridx;
3169 
3170  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &idx2) );
3171 
3172  assert(elcnt < nquadelems);
3173  quadelems[elcnt].idx1 = MIN(idx1, idx2);
3174  quadelems[elcnt].idx2 = MAX(idx1, idx2);
3175  quadelems[elcnt].coef = consdata->bilinterms[i].coef;
3176  ++elcnt;
3177  }
3178  assert(elcnt == nquadelems);
3179 
3180  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3181  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
3182  nquadvars, quadvars, nquadelems, quadelems,
3183  NULL, consdata->lhs, consdata->rhs) );
3184 
3185  SCIP_CALL( SCIPaddLinearCoefsToNlRow(scip, consdata->nlrow, nquadlinterms, quadlinvars, quadlincoefs) );
3186 
3187  SCIPfreeBufferArray(scip, &quadvars);
3188  SCIPfreeBufferArray(scip, &quadelems);
3189  SCIPfreeBufferArray(scip, &quadlinvars);
3190  SCIPfreeBufferArray(scip, &quadlincoefs);
3191 
3192  return SCIP_OKAY;
3193 }
3194 
3195 /** solve constraint as presolving */
3196 static
3198  SCIP* scip, /**< SCIP data structure */
3199  SCIP_CONS* cons, /**< constraint */
3200  SCIP_RESULT* result, /**< to store result of solve: cutoff, success, or do-not-find */
3201  SCIP_Bool* redundant, /**< to store whether constraint is redundant now (should be deleted) */
3202  int* naggrvars /**< counter on number of variable aggregations */
3203  )
3204 {
3205  SCIP_CONSDATA* consdata;
3206 
3207  assert(scip != NULL);
3208  assert(cons != NULL);
3209  assert(result != NULL);
3210  assert(redundant != NULL);
3211 
3212  *result = SCIP_DIDNOTFIND;
3213  *redundant = FALSE;
3214 
3215  consdata = SCIPconsGetData(cons);
3216  assert(consdata != NULL);
3217 
3218  /* if constraint is an equality with two variables, at least one of them binary,
3219  * and linear after fixing the binary, then we can aggregate the variables */
3220  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && consdata->nlinvars == 0 && consdata->nquadvars == 2 &&
3221  ((SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ||
3222  (SCIPvarIsBinary(consdata->quadvarterms[1].var) && consdata->quadvarterms[0].sqrcoef == 0.0)) )
3223  {
3224  SCIP_Bool infeasible;
3225  SCIP_Bool aggregated;
3226  SCIP_Real a;
3227  SCIP_Real b;
3228  SCIP_Real c;
3229  SCIP_VAR* x;
3230  SCIP_VAR* y;
3231  int binvaridx;
3232 
3233  /* constraint is a*(x+x^2) + b*y + c*x*y = rhs, with x binary variable
3234  * x = 0 -> b*y == rhs
3235  * x = 1 -> (b+c)*y == rhs - a
3236  *
3237  * 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
3238  */
3239 
3240  binvaridx = (SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ? 0 : 1;
3241 
3242  x = consdata->quadvarterms[binvaridx].var;
3243  a = consdata->quadvarterms[binvaridx].sqrcoef + consdata->quadvarterms[binvaridx].lincoef;
3244 
3245  y = consdata->quadvarterms[1-binvaridx].var;
3246  b = consdata->quadvarterms[1-binvaridx].lincoef;
3247 
3248  assert(consdata->nbilinterms <= 1); /* should actually be 1, since constraint is otherwise linear */
3249  c = (consdata->nbilinterms == 1) ? consdata->bilinterms[0].coef : 0.0;
3250 
3251  if( !SCIPisZero(scip, b) && !SCIPisZero(scip, b+c) )
3252  {
3253  SCIPdebugMessage("<%s> = 0 -> %g*<%s> = %g and <%s> = 1 -> %g*<%s> = %g\n", SCIPvarGetName(x), b, SCIPvarGetName(y), consdata->rhs,
3254  SCIPvarGetName(x), b+c, SCIPvarGetName(y), consdata->rhs - a);
3255  SCIPdebugMessage("=> attempt aggregation <%s> = %g*<%s> + %g\n", SCIPvarGetName(y), (consdata->rhs-a)/(b+c) - consdata->rhs/b,
3256  SCIPvarGetName(x), consdata->rhs/b);
3257 
3258  SCIP_CALL( SCIPaggregateVars(scip, x, y, (consdata->rhs-a)/(b+c) - consdata->rhs/b, -1.0, -consdata->rhs/b, &infeasible, redundant, &aggregated) );
3259  if( infeasible )
3260  *result = SCIP_CUTOFF;
3261  else if( *redundant || aggregated )
3262  {
3263  /* aggregated (or were already aggregated), so constraint is now redundant */
3264  *result = SCIP_SUCCESS;
3265  *redundant = TRUE;
3266 
3267  if( aggregated )
3268  ++*naggrvars;
3269  }
3270  }
3271 
3272  /* @todo if b is 0 or b+c is 0, or lhs != rhs, then could replace by varbound constraint */
3273  }
3274 
3275  return SCIP_OKAY;
3276 }
3277 
3278 
3279 /** reformulates products of binary variables as AND constraint
3280  *
3281  * 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.
3282  */
3283 static
3285  SCIP* scip, /**< SCIP data structure */
3286  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3287  SCIP_CONS* cons, /**< constraint */
3288  int* naddconss /**< buffer where to add the number of AND constraints added */
3289  )
3290 {
3291  SCIP_CONSHDLRDATA* conshdlrdata;
3292  SCIP_CONSDATA* consdata;
3293  char name[SCIP_MAXSTRLEN];
3294  SCIP_VAR* vars[2];
3295  SCIP_VAR* auxvar;
3296  SCIP_CONS* andcons;
3297  int i;
3298  int ntodelete;
3299  int* todelete;
3300 
3301  assert(scip != NULL);
3302  assert(conshdlr != NULL);
3303  assert(cons != NULL);
3304  assert(naddconss != NULL);
3305 
3306  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3307  assert(conshdlrdata != NULL);
3308 
3309  /* if user does not like AND very much, then return */
3310  if( conshdlrdata->empathy4and < 2 )
3311  return SCIP_OKAY;
3312 
3313  consdata = SCIPconsGetData(cons);
3314  assert(consdata != NULL);
3315 
3316  if( consdata->nbilinterms == 0 )
3317  return SCIP_OKAY;
3318 
3319  /* get array to store indices of bilinear terms that shall be deleted */
3320  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
3321  ntodelete = 0;
3322 
3323  for( i = 0; i < consdata->nbilinterms; ++i )
3324  {
3325  vars[0] = consdata->bilinterms[i].var1;
3326  if( !SCIPvarIsBinary(vars[0]) )
3327  continue;
3328 
3329  vars[1] = consdata->bilinterms[i].var2;
3330  if( !SCIPvarIsBinary(vars[1]) )
3331  continue;
3332 
3333  /* create auxiliary variable */
3334  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]), SCIPconsGetName(cons));
3335  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
3336  SCIPvarIsInitial(vars[0]) || SCIPvarIsInitial(vars[1]), SCIPvarIsRemovable(vars[0]) && SCIPvarIsRemovable(vars[1]), NULL, NULL, NULL, NULL, NULL) );
3337  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3338 #ifdef SCIP_DEBUG_SOLUTION
3339  if( SCIPdebugIsMainscip(scip) )
3340  {
3341  SCIP_Real var0val;
3342  SCIP_Real var1val;
3343  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[0], &var0val) );
3344  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[1], &var1val) );
3345  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3346  }
3347 #endif
3348 
3349  /* create AND-constraint auxvar = x and y, need to be enforced as not redundant */
3350  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3351  SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, auxvar, 2, vars,
3352  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3353  SCIPconsIsSeparated(cons), TRUE, TRUE,
3356  SCIP_CALL( SCIPaddCons(scip, andcons) );
3357  SCIPdebugMessage("added AND constraint: ");
3358  SCIPdebugPrintCons(scip, andcons, NULL);
3359  SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
3360  ++*naddconss;
3361 
3362  /* add bilincoef * auxvar to linear terms */
3363  SCIP_CALL( addLinearCoef(scip, cons, auxvar, consdata->bilinterms[i].coef) );
3364  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3365 
3366  /* remember that we have to delete this bilinear term */
3367  assert(ntodelete < consdata->nbilinterms);
3368  todelete[ntodelete++] = i;
3369  }
3370 
3371  /* remove bilinear terms that have been replaced */
3372  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3373  SCIPfreeBufferArray(scip, &todelete);
3374 
3375  return SCIP_OKAY;
3376 }
3377 
3378 /** gets bounds of variable y if x takes a certain value; checks whether x = xval has implications on y */
3379 static
3381  SCIP* scip, /**< SCIP data structure */
3382  SCIP_VAR* x, /**< variable which implications to check */
3383  SCIP_Bool xval, /**< value of x to check for (TRUE for 1, FALSE for 0) */
3384  SCIP_VAR* y, /**< variable to check if bounds can be reduced */
3385  SCIP_INTERVAL* resultant /**< buffer to store bounds on y */
3386  )
3387 {
3388  SCIP_VAR** implvars;
3389  SCIP_BOUNDTYPE* impltypes;
3390  SCIP_Real* implbounds;
3391  int nimpls;
3392  int pos;
3393 
3394  assert(scip != NULL);
3395  assert(x != NULL);
3396  assert(y != NULL);
3397  assert(resultant != NULL);
3398 
3400 
3401  if( !SCIPvarIsBinary(x) || !SCIPvarIsActive(x) )
3402  return SCIP_OKAY;
3403 
3404  /* check in cliques for binary to binary implications */
3405  if( SCIPvarIsBinary(y) )
3406  {
3407  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 0.0));
3408  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 1.0));
3409 
3410  if( SCIPhaveVarsCommonClique(scip, x, xval, y, TRUE, FALSE) )
3411  {
3412  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 0.0));
3413  }
3414  else if( SCIPhaveVarsCommonClique(scip, x, xval, y, FALSE, FALSE) )
3415  {
3416  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 1.0));
3417  }
3418 
3419  return SCIP_OKAY;
3420  }
3421 
3422  /* analyze implications for x = xval */
3423  nimpls = SCIPvarGetNImpls(x, xval);
3424  if( nimpls == 0 )
3425  return SCIP_OKAY;
3426 
3427  implvars = SCIPvarGetImplVars (x, xval);
3428  impltypes = SCIPvarGetImplTypes (x, xval);
3429  implbounds = SCIPvarGetImplBounds(x, xval);
3430 
3431  assert(implvars != NULL);
3432  assert(impltypes != NULL);
3433  assert(implbounds != NULL);
3434 
3435  /* find implications */
3436  if( !SCIPsortedvecFindPtr((void**)implvars, SCIPvarComp, (void*)y, nimpls, &pos) )
3437  return SCIP_OKAY;
3438 
3439  /* if there are several implications on y, go to the first one */
3440  while( pos > 0 && implvars[pos-1] == y )
3441  --pos;
3442 
3443  /* update implied lower and upper bounds on y
3444  * but make sure that resultant will not be empty, due to tolerances
3445  */
3446  while( pos < nimpls && implvars[pos] == y )
3447  {
3448  if( impltypes[pos] == SCIP_BOUNDTYPE_LOWER )
3449  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, implbounds[pos]));
3450  else
3451  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, implbounds[pos]));
3452  ++pos;
3453  }
3454 
3455  assert(resultant->sup >= resultant->inf);
3456 
3457  return SCIP_OKAY;
3458 }
3459 
3460 /** Reformulates products of binary times bounded continuous variables as system of linear inequalities (plus auxiliary variable).
3461  *
3462  * For a product x*y, with y a binary variable and x a continous variable with finite bounds,
3463  * 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.
3464  *
3465  * 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.
3466  * For each product of linear term of length at most maxnrvar with y, an auxiliary z and linear inequalities are added.
3467  *
3468  * If y is a binary variable, the AND constraint \f$ z = x \wedge y \f$ may be added instead of linear constraints.
3469  */
3470 static
3472  SCIP* scip, /**< SCIP data structure */
3473  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3474  SCIP_CONS* cons, /**< constraint */
3475  int* naddconss /**< buffer where to add the number of auxiliary constraints added */
3476  )
3477 { /*lint --e{666} */
3478  SCIP_CONSHDLRDATA* conshdlrdata;
3479  SCIP_CONSDATA* consdata;
3480  SCIP_VAR** xvars;
3481  SCIP_Real* xcoef;
3482  SCIP_INTERVAL xbndszero;
3483  SCIP_INTERVAL xbndsone;
3484  SCIP_INTERVAL act0;
3485  SCIP_INTERVAL act1;
3486  int nxvars;
3487  SCIP_VAR* y;
3488  SCIP_VAR* bvar;
3489  char name[SCIP_MAXSTRLEN];
3490  int nbilinterms;
3491  SCIP_VAR* auxvar;
3492  SCIP_CONS* auxcons;
3493  int i;
3494  int j;
3495  int k;
3496  int bilinidx;
3497  SCIP_Real bilincoef;
3498  SCIP_Real mincoef;
3499  SCIP_Real maxcoef;
3500  int* todelete;
3501  int ntodelete;
3502  int maxnrvar;
3503  SCIP_Bool integral;
3504  SCIP_Longint gcd;
3505  SCIP_Bool auxvarinitial;
3506  SCIP_Bool auxvarremovable;
3507 
3508  assert(scip != NULL);
3509  assert(conshdlr != NULL);
3510  assert(cons != NULL);
3511  assert(naddconss != NULL);
3512 
3513  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3514  assert(conshdlrdata != NULL);
3515 
3516  maxnrvar = conshdlrdata->replacebinaryprodlength;
3517  if( maxnrvar == 0 )
3518  return SCIP_OKAY;
3519 
3520  consdata = SCIPconsGetData(cons);
3521  assert(consdata != NULL);
3522 
3523  xvars = NULL;
3524  xcoef = NULL;
3525  todelete = NULL;
3526  gcd = 0;
3527 
3528  for( i = 0; i < consdata->nquadvars; ++i )
3529  {
3530  y = consdata->quadvarterms[i].var;
3531  if( !SCIPvarIsBinary(y) )
3532  continue;
3533 
3534  nbilinterms = consdata->quadvarterms[i].nadjbilin;
3535  if( nbilinterms == 0 )
3536  continue;
3537 
3538  SCIP_CALL( SCIPreallocBufferArray(scip, &xvars, MIN(maxnrvar, nbilinterms)+2) ); /* add 2 for later use when creating linear constraints */
3539  SCIP_CALL( SCIPreallocBufferArray(scip, &xcoef, MIN(maxnrvar, nbilinterms)+2) );
3540 
3541  /* alloc array to store indices of bilinear terms that shall be deleted */
3542  SCIP_CALL( SCIPreallocBufferArray(scip, &todelete, nbilinterms) );
3543  ntodelete = 0;
3544 
3545  auxvarinitial = SCIPvarIsInitial(y);
3546  auxvarremovable = SCIPvarIsRemovable(y);
3547 
3548  /* 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)
3549  * and compute range of sum_i a_i*x_i for the cases y = 0 and y = 1
3550  * we may need several rounds of maxnrvar < nbilinterms
3551  */
3552  j = 0;
3553  do
3554  {
3555  nxvars = 0;
3556  SCIPintervalSet(&xbndszero, 0.0);
3557  SCIPintervalSet(&xbndsone, 0.0);
3558 
3559  mincoef = SCIPinfinity(scip);
3560  maxcoef = 0.0;
3561  integral = TRUE;
3562 
3563  /* collect at most maxnrvar variables for x term */
3564  for( ; j < nbilinterms && nxvars < maxnrvar; ++j )
3565  {
3566  bilinidx = consdata->quadvarterms[i].adjbilin[j];
3567  assert(bilinidx >= 0);
3568  assert(bilinidx < consdata->nbilinterms);
3569 
3570  bvar = consdata->bilinterms[bilinidx].var1;
3571  if( bvar == y )
3572  bvar = consdata->bilinterms[bilinidx].var2;
3573  assert(bvar != y);
3574 
3575  /* skip products with unbounded variables */
3576  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(bvar)) || SCIPisInfinity(scip, SCIPvarGetUbGlobal(bvar)) )
3577  {
3578  SCIPdebugMessage("skip reform of <%s><%s> due to unbounded second variable [%g,%g]\n",
3580  continue;
3581  }
3582 
3583  bilincoef = consdata->bilinterms[bilinidx].coef;
3584  assert(bilincoef != 0.0);
3585 
3586  /* get activity of bilincoef * x if y = 0 */
3587  SCIP_CALL( getImpliedBounds(scip, y, FALSE, bvar, &act0) );
3588  SCIPintervalMulScalar(SCIPinfinity(scip), &act0, act0, bilincoef);
3589 
3590  /* get activity of bilincoef * x if y = 1 */
3591  SCIP_CALL( getImpliedBounds(scip, y, TRUE, bvar, &act1) );
3592  SCIPintervalMulScalar(SCIPinfinity(scip), &act1, act1, bilincoef);
3593 
3594  /* skip products that give rise to very large coefficients (big big-M's) */
3595  if( SCIPfeastol(scip) * REALABS(act0.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act0.sup) >= conshdlrdata->binreformmaxcoef )
3596  {
3597  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 0.0\n",
3598  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act0), SCIPintervalGetSup(act0), SCIPvarGetName(y));
3599  continue;
3600  }
3601  if( SCIPfeastol(scip) * REALABS(act1.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act1.sup) >= conshdlrdata->binreformmaxcoef )
3602  {
3603  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 1.0\n",
3604  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act1), SCIPintervalGetSup(act1), SCIPvarGetName(y));
3605  continue;
3606  }
3607  if( !SCIPisZero(scip, MIN(REALABS(act0.inf), REALABS(act0.sup))) &&
3608  SCIPfeastol(scip) * MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)) >= conshdlrdata->binreformmaxcoef )
3609  {
3610  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3611  MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)), SCIPvarGetName(y));
3612  continue;
3613  }
3614  if( !SCIPisZero(scip, MIN(REALABS(act1.inf), REALABS(act1.sup))) &&
3615  SCIPfeastol(scip) * MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)) >= conshdlrdata->binreformmaxcoef )
3616  {
3617  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3618  MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)), SCIPvarGetName(y));
3619  continue;
3620  }
3621 
3622  /* add bvar to x term */
3623  xvars[nxvars] = bvar;
3624  xcoef[nxvars] = bilincoef;
3625  ++nxvars;
3626 
3627  /* update bounds on x term */
3628  SCIPintervalAdd(SCIPinfinity(scip), &xbndszero, xbndszero, act0);
3629  SCIPintervalAdd(SCIPinfinity(scip), &xbndsone, xbndsone, act1);
3630 
3631  if( REALABS(bilincoef) < mincoef )
3632  mincoef = ABS(bilincoef);
3633  if( REALABS(bilincoef) > maxcoef )
3634  maxcoef = ABS(bilincoef);
3635 
3636  /* update whether all coefficients will be integral and if so, compute their gcd */
3637  integral &= (SCIPvarGetType(bvar) < SCIP_VARTYPE_CONTINUOUS) && SCIPisIntegral(scip, bilincoef); /*lint !e514 */
3638  if( integral )
3639  {
3640  if( nxvars == 1 )
3641  gcd = (SCIP_Longint)SCIPround(scip, REALABS(bilincoef));
3642  else
3643  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)SCIPround(scip, REALABS(bilincoef)));
3644  }
3645 
3646  /* if bvar is initial, then also the auxiliary variable should be initial
3647  * if bvar is not removable, then also the auxiliary variable should not be removable
3648  */
3649  auxvarinitial |= SCIPvarIsInitial(bvar);
3650  auxvarremovable &= SCIPvarIsRemovable(bvar);
3651 
3652  /* remember that we have to remove this bilinear term later */
3653  assert(ntodelete < nbilinterms);
3654  todelete[ntodelete++] = bilinidx;
3655  }
3656 
3657  if( nxvars == 0 ) /* all (remaining) x_j seem to be unbounded */
3658  break;
3659 
3660  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndszero)));
3661  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndszero)));
3662  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndsone)));
3663  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndsone)));
3664 
3665 #ifdef SCIP_DEBUG
3666  if( SCIPintervalGetInf(xbndszero) != SCIPintervalGetInf(xbndsone) || /*lint !e777*/
3667  +SCIPintervalGetSup(xbndszero) != SCIPintervalGetSup(xbndsone) ) /*lint !e777*/
3668  {
3669  SCIPdebugMessage("got different bounds for y = 0: [%g, %g] and y = 1: [%g, %g]\n", xbndszero.inf, xbndszero.sup, xbndsone.inf, xbndsone.sup);
3670  }
3671 #endif
3672 
3673  if( nxvars == 1 && conshdlrdata->empathy4and >= 1 && SCIPvarIsBinary(xvars[0]) )
3674  {
3675  /* product of two binary variables, replace by auxvar and AND constraint */
3676  /* add auxiliary variable z */
3677  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3678  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT,
3679  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3680  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3681 
3682 #ifdef SCIP_DEBUG_SOLUTION
3683  if( SCIPdebugIsMainscip(scip) )
3684  {
3685  SCIP_Real var0val;
3686  SCIP_Real var1val;
3687  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[0], &var0val) );
3688  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &var1val) );
3689  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3690  }
3691 #endif
3692 
3693  /* add constraint z = x and y; need to be enforced, as it is not redundant w.r.t. existing constraints */
3694  xvars[1] = y;
3695  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3696  SCIP_CALL( SCIPcreateConsAnd(scip, &auxcons, name, auxvar, 2, xvars,
3697  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3698  SCIPconsIsSeparated(cons), TRUE, TRUE,
3701  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3702  SCIPdebugMessage("added AND constraint: ");
3703  SCIPdebugPrintCons(scip, auxcons, NULL);
3704  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3705  ++*naddconss;
3706 
3707  /* add linear term coef*auxvar */
3708  SCIP_CALL( addLinearCoef(scip, cons, auxvar, xcoef[0]) );
3709 
3710  /* forget about auxvar */
3711  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3712  }
3713  else
3714  {
3715  /* product of binary variable with more than one binary or with continuous variables or with binary and user
3716  * did not like AND -> replace by auxvar and linear constraints */
3717  SCIP_Real scale;
3718 
3719  /* scale auxiliary constraint by some nice value,
3720  * if all coefficients are integral, take a value that preserves integrality (-> gcd), so we can make the auxiliary variable impl. integer
3721  */
3722  if( integral )
3723  {
3724  scale = (SCIP_Real)gcd;
3725  assert(scale >= 1.0);
3726  }
3727  else if( nxvars == 1 )
3728  {
3729  /* scaling by the only coefficient gives auxiliary variable = x * y, which thus will be implicit integral provided y is not continuous */
3730  assert(mincoef == maxcoef); /*lint !e777 */
3731  scale = mincoef;
3732  integral = SCIPvarGetType(xvars[0]) < SCIP_VARTYPE_CONTINUOUS;
3733  }
3734  else
3735  {
3736  scale = 1.0;
3737  if( maxcoef < 0.5 )
3738  scale = maxcoef;
3739  if( mincoef > 2.0 )
3740  scale = mincoef;
3741  if( scale != 1.0 )
3742  scale = SCIPselectSimpleValue(scale / 2.0, 1.5 * scale, MAXDNOM);
3743  }
3744  assert(scale > 0.0);
3745  assert(!SCIPisInfinity(scip, scale));
3746 
3747  /* if x-term is always negative for y = 1, negate scale so we get a positive auxiliary variable; maybe this is better sometimes? */
3748  if( !SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3749  scale = -scale;
3750 
3751  SCIPdebugMessage("binary reformulation using scale %g, nxvars = %d, integral = %u\n", scale, nxvars, integral);
3752  if( scale != 1.0 )
3753  {
3754  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndszero, xbndszero, scale);
3755  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndsone, xbndsone, scale);
3756  for( k = 0; k < nxvars; ++k )
3757  xcoef[k] /= scale;
3758  }
3759 
3760  /* add auxiliary variable z */
3761  if( nxvars == 1 )
3762  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3763  else
3764  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_more_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3765  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, MIN(0., SCIPintervalGetInf(xbndsone)), MAX(0., SCIPintervalGetSup(xbndsone)),
3767  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3768  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3769 
3770  /* compute value of auxvar in debug solution */
3771 #ifdef SCIP_DEBUG_SOLUTION
3772  if( SCIPdebugIsMainscip(scip) )
3773  {
3774  SCIP_Real debugval;
3775  SCIP_Real varval;
3776 
3777  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &varval) );
3778  if( SCIPisZero(scip, varval) )
3779  {
3780  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, 0.0) );
3781  }
3782  else
3783  {
3784  assert(SCIPisEQ(scip, varval, 1.0));
3785 
3786  debugval = 0.0;
3787  for( k = 0; k < nxvars; ++k )
3788  {
3789  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[k], &varval) );
3790  debugval += xcoef[k] * varval;
3791  }
3792  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
3793  }
3794  }
3795 #endif
3796 
3797  /* add auxiliary constraints
3798  * it seems to be advantageous to make the varbound constraints initial and the linear constraints not initial
3799  * maybe because it is more likely that a binary variable takes value 0 instead of 1, and thus the varbound constraints
3800  * are more often active, compared to the linear constraints added below
3801  * also, the varbound constraints are more sparse than the linear cons
3802  */
3803  if( SCIPisNegative(scip, SCIPintervalGetInf(xbndsone)) )
3804  {
3805  /* add 0 <= z - xbndsone.inf * y constraint (as varbound constraint), need to be enforced as not redundant */
3806  if( nxvars == 1 )
3807  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3808  else
3809  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3810  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetInf(xbndsone), 0.0, SCIPinfinity(scip),
3811  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3812  SCIPconsIsSeparated(cons), TRUE, TRUE,
3815  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3816  SCIPdebugMessage("added varbound constraint: ");
3817  SCIPdebugPrintCons(scip, auxcons, NULL);
3818  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3819  ++*naddconss;
3820  }
3821  if( SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3822  {
3823  /* add z - xbndsone.sup * y <= 0 constraint (as varbound constraint), need to be enforced as not redundant */
3824  if( nxvars == 1 )
3825  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3826  else
3827  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3828  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetSup(xbndsone), -SCIPinfinity(scip), 0.0,
3829  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3830  SCIPconsIsSeparated(cons), TRUE, TRUE,
3833  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3834  SCIPdebugMessage("added varbound constraint: ");
3835  SCIPdebugPrintCons(scip, auxcons, NULL);
3836  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3837  ++*naddconss;
3838  }
3839 
3840  /* add xbndszero.inf <= sum_i a_i*x_i + xbndszero.inf * y - z constraint, need to be enforced as not redundant */
3841  xvars[nxvars] = y;
3842  xvars[nxvars+1] = auxvar;
3843  xcoef[nxvars] = SCIPintervalGetInf(xbndszero);
3844  xcoef[nxvars+1] = -1;
3845 
3846  if( nxvars == 1 )
3847  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3848  else
3849  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3850  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, SCIPintervalGetInf(xbndszero), SCIPinfinity(scip),
3851  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3852  SCIPconsIsSeparated(cons), TRUE, TRUE,
3855  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3856  SCIPdebugMessage("added linear constraint: ");
3857  SCIPdebugPrintCons(scip, auxcons, NULL);
3858  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3859  ++*naddconss;
3860 
3861  /* add sum_i a_i*x_i + xbndszero.sup * y - z <= xbndszero.sup constraint, need to be enforced as not redundant */
3862  xcoef[nxvars] = SCIPintervalGetSup(xbndszero);
3863 
3864  if( nxvars == 1 )
3865  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3866  else
3867  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3868  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, -SCIPinfinity(scip), SCIPintervalGetSup(xbndszero),
3869  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3870  SCIPconsIsSeparated(cons), TRUE, TRUE,
3873  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3874  SCIPdebugMessage("added linear constraint: ");
3875  SCIPdebugPrintCons(scip, auxcons, NULL);
3876  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3877  ++*naddconss;
3878 
3879  /* add linear term scale*auxvar to this constraint */
3880  SCIP_CALL( addLinearCoef(scip, cons, auxvar, scale) );
3881 
3882  /* forget about auxvar */
3883  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3884  }
3885  }
3886  while( j < nbilinterms );
3887 
3888  /* remove bilinear terms that have been replaced */
3889  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3890  }
3891  SCIPdebugMessage("resulting quadratic constraint: ");
3892  SCIPdebugPrintCons(scip, cons, NULL);
3893 
3894  SCIPfreeBufferArrayNull(scip, &xvars);
3895  SCIPfreeBufferArrayNull(scip, &xcoef);
3896  SCIPfreeBufferArrayNull(scip, &todelete);
3897 
3898  return SCIP_OKAY;
3899 }
3900 
3901 /** tries to automatically convert a quadratic constraint (or a part of it) into a more specific and more specialized constraint */
3902 static
3904  SCIP* scip, /**< SCIP data structure */
3905  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
3906  SCIP_CONS* cons, /**< source constraint to try to convert */
3907  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
3908  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
3909  int* naddconss, /**< buffer to increase with number of additional constraints created during upgrade */
3910  SCIP_PRESOLTIMING presoltiming /**< current presolving timing */
3911  )
3912 {
3913  SCIP_CONSHDLRDATA* conshdlrdata;
3914  SCIP_CONSDATA* consdata;
3915  SCIP_VAR* var;
3916  SCIP_Real lincoef;
3917  SCIP_Real quadcoef;
3918  SCIP_Real lb;
3919  SCIP_Real ub;
3920  int nbinlin;
3921  int nbinquad;
3922  int nintlin;
3923  int nintquad;
3924  int nimpllin;
3925  int nimplquad;
3926  int ncontlin;
3927  int ncontquad;
3928  SCIP_Bool integral;
3929  int i;
3930  int j;
3931  SCIP_CONS** upgdconss;
3932  int upgdconsssize;
3933  int nupgdconss_;
3934 
3935  assert(scip != NULL);
3936  assert(conshdlr != NULL);
3937  assert(cons != NULL);
3938  assert(!SCIPconsIsModifiable(cons));
3939  assert(upgraded != NULL);
3940  assert(nupgdconss != NULL);
3941  assert(naddconss != NULL);
3942 
3943  *upgraded = FALSE;
3944 
3945  nupgdconss_ = 0;
3946 
3947  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3948  assert(conshdlrdata != NULL);
3949 
3950  /* if there are no upgrade methods, we can also stop */
3951  if( conshdlrdata->nquadconsupgrades == 0 )
3952  return SCIP_OKAY;
3953 
3954  upgdconsssize = 2;
3955  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
3956 
3957  consdata = SCIPconsGetData(cons);
3958  assert(consdata != NULL);
3959 
3960  /* calculate some statistics on quadratic constraint */
3961  nbinlin = 0;
3962  nbinquad = 0;
3963  nintlin = 0;
3964  nintquad = 0;
3965  nimpllin = 0;
3966  nimplquad = 0;
3967  ncontlin = 0;
3968  ncontquad = 0;
3969  integral = TRUE;
3970  for( i = 0; i < consdata->nlinvars; ++i )
3971  {
3972  var = consdata->linvars[i];
3973  lincoef = consdata->lincoefs[i];
3974  lb = SCIPvarGetLbLocal(var);
3975  ub = SCIPvarGetUbLocal(var);
3976  assert(!SCIPisZero(scip, lincoef));
3977 
3978  switch( SCIPvarGetType(var) )
3979  {
3980  case SCIP_VARTYPE_BINARY:
3981  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3982  integral = integral && SCIPisIntegral(scip, lincoef);
3983  nbinlin++;
3984  break;
3985  case SCIP_VARTYPE_INTEGER:
3986  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3987  integral = integral && SCIPisIntegral(scip, lincoef);
3988  nintlin++;
3989  break;
3990  case SCIP_VARTYPE_IMPLINT:
3991  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3992  integral = integral && SCIPisIntegral(scip, lincoef);
3993  nimpllin++;
3994  break;
3996  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb);
3997  ncontlin++;
3998  break;
3999  default:
4000  SCIPerrorMessage("unknown variable type\n");
4001  return SCIP_INVALIDDATA;
4002  }
4003  }
4004 
4005  for( i = 0; i < consdata->nquadvars; ++i )
4006  {
4007  var = consdata->quadvarterms[i].var;
4008  lincoef = consdata->quadvarterms[i].lincoef;
4009  quadcoef = consdata->quadvarterms[i].sqrcoef;
4010  lb = SCIPvarGetLbLocal(var);
4011  ub = SCIPvarGetUbLocal(var);
4012 
4013  switch( SCIPvarGetType(var) )
4014  {
4015  case SCIP_VARTYPE_BINARY:
4016  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4017  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4018  nbinquad++;
4019  break;
4020  case SCIP_VARTYPE_INTEGER:
4021  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4022  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4023  nintquad++;
4024  break;
4025  case SCIP_VARTYPE_IMPLINT:
4026  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4027  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4028  nimplquad++;
4029  break;
4031  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb + quadcoef * lb * lb);
4032  ncontquad++;
4033  break;
4034  default:
4035  SCIPerrorMessage("unknown variable type\n");
4036  return SCIP_INVALIDDATA;
4037  }
4038  }
4039 
4040  if( integral )
4041  {
4042  for( i = 0; i < consdata->nbilinterms && integral; ++i )
4043  {
4044  if( SCIPvarGetType(consdata->bilinterms[i].var1) < SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->bilinterms[i].var2) < SCIP_VARTYPE_CONTINUOUS )
4045  integral = integral && SCIPisIntegral(scip, consdata->bilinterms[i].coef);
4046  else
4047  integral = FALSE;
4048  }
4049  }
4050 
4051  /* call the upgrading methods */
4052 
4053  SCIPdebugMessage("upgrading quadratic constraint <%s> (%d upgrade methods):\n",
4054  SCIPconsGetName(cons), conshdlrdata->nquadconsupgrades);
4055  SCIPdebugMessage(" binlin=%d binquad=%d intlin=%d intquad=%d impllin=%d implquad=%d contlin=%d contquad=%d integral=%u\n",
4056  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral);
4057  SCIPdebugPrintCons(scip, cons, NULL);
4058 
4059  /* try all upgrading methods in priority order in case the upgrading step is enable */
4060  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
4061  {
4062  if( !conshdlrdata->quadconsupgrades[i]->active )
4063  continue;
4064 
4065  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4066  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4067  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4068 
4069  while( nupgdconss_ < 0 )
4070  {
4071  /* upgrade function requires more memory: resize upgdconss and call again */
4072  assert(-nupgdconss_ > upgdconsssize);
4073  upgdconsssize = -nupgdconss_;
4074  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
4075 
4076  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4077  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4078  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4079 
4080  assert(nupgdconss_ != 0);
4081  }
4082 
4083  if( nupgdconss_ > 0 )
4084  {
4085  /* got upgrade */
4086  SCIPdebugPrintCons(scip, cons, NULL);
4087  SCIPdebugMessage(" -> upgraded to %d constraints:\n", nupgdconss_);
4088 
4089  /* add the upgraded constraints to the problem and forget them */
4090  for( j = 0; j < nupgdconss_; ++j )
4091  {
4092  SCIPdebugPrintf("\t");
4093  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
4094 
4095  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
4096  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
4097  }
4098 
4099  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
4100  *nupgdconss += 1;
4101  *naddconss += nupgdconss_ - 1;
4102  *upgraded = TRUE;
4103 
4104  /* delete upgraded constraint */
4105  SCIPdebugMessage("delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
4106  SCIP_CALL( SCIPdelCons(scip, cons) );
4107 
4108  break;
4109  }
4110  }
4111 
4112  SCIPfreeBufferArray(scip, &upgdconss);
4113 
4114  return SCIP_OKAY;
4115 }
4116 
4117 /** helper function for presolveDisaggregate */
4118 static
4120  SCIP* scip, /**< SCIP data structure */
4121  SCIP_CONSDATA* consdata, /**< constraint data */
4122  int quadvaridx, /**< index of quadratic variable to mark */
4123  SCIP_HASHMAP* var2component, /**< variables to components mapping */
4124  int componentnr /**< the component number to mark to */
4125  )
4126 {
4127  SCIP_QUADVARTERM* quadvarterm;
4128  SCIP_VAR* othervar;
4129  int othervaridx;
4130  int i;
4131 
4132  assert(consdata != NULL);
4133  assert(quadvaridx >= 0);
4134  assert(quadvaridx < consdata->nquadvars);
4135  assert(var2component != NULL);
4136  assert(componentnr >= 0);
4137 
4138  quadvarterm = &consdata->quadvarterms[quadvaridx];
4139 
4140  if( SCIPhashmapExists(var2component, quadvarterm->var) )
4141  {
4142  /* if we saw the variable before, then it should have the same component number */
4143  assert((int)(size_t)SCIPhashmapGetImage(var2component, quadvarterm->var) == componentnr);
4144  return SCIP_OKAY;
4145  }
4146 
4147  /* assign component number to variable */
4148  SCIP_CALL( SCIPhashmapInsert(var2component, quadvarterm->var, (void*)(size_t)componentnr) );
4149 
4150  /* assign same component number to all variables this variable is multiplied with */
4151  for( i = 0; i < quadvarterm->nadjbilin; ++i )
4152  {
4153  othervar = consdata->bilinterms[quadvarterm->adjbilin[i]].var1 == quadvarterm->var ?
4154  consdata->bilinterms[quadvarterm->adjbilin[i]].var2 : consdata->bilinterms[quadvarterm->adjbilin[i]].var1;
4155  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, othervar, &othervaridx) );
4156  assert(othervaridx >= 0);
4157  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, othervaridx, var2component, componentnr) );
4158  }
4159 
4160  return SCIP_OKAY;
4161 }
4162 
4163 /** for quadratic constraints that consists of a sum of quadratic terms, disaggregates the sum into a set of constraints by introducing auxiliary variables */
4164 static
4166  SCIP* scip, /**< SCIP data structure */
4167  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4168  SCIP_CONS* cons, /**< source constraint to try to convert */
4169  int* naddconss /**< pointer to counter of added constraints */
4170  )
4171 {
4172  SCIP_CONSDATA* consdata;
4173  SCIP_HASHMAP* var2component;
4174  int ncomponents;
4175  int i;
4176  int comp;
4177  SCIP_CONS** auxconss;
4178  SCIP_VAR** auxvars;
4179  SCIP_Real* auxcoefs;
4180  char name[SCIP_MAXSTRLEN];
4181 
4182  assert(scip != NULL);
4183  assert(conshdlr != NULL);
4184  assert(cons != NULL);
4185  assert(naddconss != NULL);
4186 
4187  consdata = SCIPconsGetData(cons);
4188  assert(consdata != NULL);
4189 
4190  /* make sure there are no quadratic variables without coefficients */
4191  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4192  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
4193 
4194  if( consdata->nquadvars <= 1 )
4195  return SCIP_OKAY;
4196 
4197  /* sort quadratic variable terms here, so we can later search in it without reordering the array */
4198  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4199 
4200  /* check how many quadratic terms with non-overlapping variables we have
4201  * in other words, the number of components in the sparsity graph of the quadratic term matrix */
4202  ncomponents = 0;
4203  SCIP_CALL( SCIPhashmapCreate(&var2component, SCIPblkmem(scip), SCIPcalcHashtableSize(consdata->nquadvars)) );
4204  for( i = 0; i < consdata->nquadvars; ++i )
4205  {
4206  /* if variable was marked already, skip it */
4207  if( SCIPhashmapExists(var2component, (void*)consdata->quadvarterms[i].var) )
4208  continue;
4209 
4210  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, i, var2component, ncomponents) );
4211  ++ncomponents;
4212  }
4213  assert(ncomponents >= 1);
4214 
4215  /* if there is only one component, we cannot disaggregate
4216  * @todo we could still split the constraint into several while keeping the number of variables sharing several constraints as small as possible
4217  */
4218  if( ncomponents == 1 )
4219  {
4220  SCIPhashmapFree(&var2component);
4221  return SCIP_OKAY;
4222  }
4223 
4224  SCIP_CALL( SCIPallocBufferArray(scip, &auxconss, ncomponents) );
4225  SCIP_CALL( SCIPallocBufferArray(scip, &auxvars, ncomponents) );
4226  SCIP_CALL( SCIPallocBufferArray(scip, &auxcoefs, ncomponents) );
4227 
4228  /* create auxiliary variables and empty constraints for each component */
4229  for( comp = 0; comp < ncomponents; ++comp )
4230  {
4231  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp%d", SCIPconsGetName(cons), comp);
4232 
4233  SCIP_CALL( SCIPcreateVar(scip, &auxvars[comp], name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
4235 
4236  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &auxconss[comp], name, 0, NULL, NULL, 0, NULL, 0, NULL,
4237  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : 0.0),
4238  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : 0.0),
4241  SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons)) );
4242 
4243  auxcoefs[comp] = SCIPinfinity(scip);
4244  }
4245 
4246  /* add quadratic variables to each component constraint
4247  * delete adjacency information */
4248  for( i = 0; i < consdata->nquadvars; ++i )
4249  {
4250  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->quadvarterms[i].var);
4251  assert(comp >= 0);
4252  assert(comp < ncomponents);
4253 
4254  /* add variable term to corresponding constraint */
4255  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, auxconss[comp], consdata->quadvarterms[i].var, consdata->quadvarterms[i].lincoef, consdata->quadvarterms[i].sqrcoef) );
4256 
4257  /* reduce coefficient of aux variable */
4258  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) && ABS(consdata->quadvarterms[i].lincoef) < auxcoefs[comp] )
4259  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].lincoef);
4260  if( !SCIPisZero(scip, consdata->quadvarterms[i].sqrcoef) && ABS(consdata->quadvarterms[i].sqrcoef) < auxcoefs[comp] )
4261  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].sqrcoef);
4262 
4263  SCIPfreeBlockMemoryArray(scip, &consdata->quadvarterms[i].adjbilin, consdata->quadvarterms[i].adjbilinsize);
4264  consdata->quadvarterms[i].nadjbilin = 0;
4265  consdata->quadvarterms[i].adjbilinsize = 0;
4266  }
4267 
4268  /* add bilinear terms to each component constraint */
4269  for( i = 0; i < consdata->nbilinterms; ++i )
4270  {
4271  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var1);
4272  assert(comp == (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var2));
4273  assert(!SCIPisZero(scip, consdata->bilinterms[i].coef));
4274 
4275  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, auxconss[comp],
4276  consdata->bilinterms[i].var1, consdata->bilinterms[i].var2, consdata->bilinterms[i].coef) );
4277 
4278  if( ABS(consdata->bilinterms[i].coef) < auxcoefs[comp] )
4279  auxcoefs[comp] = ABS(consdata->bilinterms[i].coef);
4280  }
4281 
4282  /* forget about bilinear terms in cons */
4283  SCIPfreeBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize);
4284  consdata->nbilinterms = 0;
4285  consdata->bilintermssize = 0;
4286 
4287  /* remove quadratic variable terms from cons */
4288  for( i = consdata->nquadvars - 1; i >= 0; --i )
4289  {
4290  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
4291  }
4292  assert(consdata->nquadvars == 0);
4293 
4294  /* add auxiliary variables to auxiliary constraints
4295  * add aux vars and constraints to SCIP
4296  * add aux vars to this constraint
4297  * @todo compute debug solution values and set for auxvars
4298  */
4299  SCIPdebugMessage("add %d constraints for disaggregation of quadratic constraint <%s>\n", ncomponents, SCIPconsGetName(cons));
4300  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + ncomponents) );
4301  for( comp = 0; comp < ncomponents; ++comp )
4302  {
4303  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, auxconss[comp], auxvars[comp], -auxcoefs[comp]) );
4304 
4305  SCIP_CALL( SCIPaddVar(scip, auxvars[comp]) );
4306 
4307  SCIP_CALL( SCIPaddCons(scip, auxconss[comp]) );
4308  SCIPdebugPrintCons(scip, auxconss[comp], NULL);
4309 
4310  SCIP_CALL( addLinearCoef(scip, cons, auxvars[comp], auxcoefs[comp]) );
4311 
4312  SCIP_CALL( SCIPreleaseCons(scip, &auxconss[comp]) );
4313  SCIP_CALL( SCIPreleaseVar(scip, &auxvars[comp]) );
4314  }
4315  *naddconss += ncomponents;
4316 
4317  SCIPdebugPrintCons(scip, cons, NULL);
4318 
4319  SCIPfreeBufferArray(scip, &auxconss);
4320  SCIPfreeBufferArray(scip, &auxvars);
4321  SCIPfreeBufferArray(scip, &auxcoefs);
4322  SCIPhashmapFree(&var2component);
4323 
4324  return SCIP_OKAY;
4325 }
4326 
4327 #ifdef CHECKIMPLINBILINEAR
4328 /** checks if there are bilinear terms x*y with a binary variable x and an implication x = {0,1} -> y = 0
4329  *
4330  * In this case, the bilinear term can be removed (x=0 case) or replaced by y (x=1 case).
4331  */
4332 static
4333 SCIP_RETCODE presolveApplyImplications(
4334  SCIP* scip, /**< SCIP data structure */
4335  SCIP_CONS* cons, /**< quadratic constraint */
4336  int* nbilinremoved /**< buffer to store number of removed bilinear terms */
4337  )
4338 {
4339  SCIP_CONSDATA* consdata;
4340  SCIP_VAR* x;
4341  SCIP_VAR* y;
4342  SCIP_INTERVAL implbnds;
4343  int i;
4344  int j;
4345  int k;
4346 
4347  assert(scip != NULL);
4348  assert(cons != NULL);
4349  assert(nbilinremoved != NULL);
4350 
4351  *nbilinremoved = 0;
4352 
4353  consdata = SCIPconsGetData(cons);
4354  assert(consdata != NULL);
4355 
4356  SCIPdebugMessage("apply implications in <%s>\n", SCIPconsGetName(cons));
4357 
4358  /* sort quadvarterms in case we need to search */
4359  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4360 
4361  for( i = 0; i < consdata->nquadvars; ++i )
4362  {
4363  x = consdata->quadvarterms[i].var;
4364  assert(x != NULL);
4365 
4366  if( consdata->quadvarterms[i].nadjbilin == 0 )
4367  continue;
4368 
4369  if( !SCIPvarIsBinary(x) )
4370  continue;
4371 
4372  if( !SCIPvarIsActive(x) )
4373  continue;
4374 
4375  if( SCIPvarGetNImpls(x, TRUE) == 0 && SCIPvarGetNImpls(x, FALSE) == 0 )
4376  continue;
4377 
4378  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4379  {
4380  k = consdata->quadvarterms[i].adjbilin[j];
4381  assert(k >= 0);
4382  assert(k < consdata->nbilinterms);
4383 
4384  if( consdata->bilinterms[k].coef == 0.0 )
4385  continue;
4386 
4387  y = consdata->bilinterms[k].var1 == x ? consdata->bilinterms[k].var2 : consdata->bilinterms[k].var1;
4388  assert(x != y);
4389 
4390  SCIP_CALL( getImpliedBounds(scip, x, TRUE, y, &implbnds) );
4391  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4392  {
4393  /* if x = 1 implies y = 0, then we can remove the bilinear term x*y, since it is always 0
4394  * we only set the coefficient to 0.0 here and mark the bilinterms as not merged */
4395  SCIPdebugMessage("remove bilinear term %g<%s><%s> from <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), SCIPconsGetName(cons));
4396  consdata->bilinterms[k].coef = 0.0;
4397  consdata->bilinmerged = FALSE;
4398  ++*nbilinremoved;
4399  continue;
4400  }
4401 
4402  SCIP_CALL( getImpliedBounds(scip, x, FALSE, y, &implbnds) );
4403  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4404  {
4405  /* if x = 0 implies y = 0, then we can replace the bilinear term x*y by y
4406  * we only move the coefficient to the linear coef of y here and mark the bilinterms as not merged */
4407  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));
4408  assert(consdata->quadvarssorted);
4409  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, cons, y, consdata->bilinterms[k].coef) );
4410  consdata->bilinterms[k].coef = 0.0;
4411  consdata->bilinmerged = FALSE;
4412  ++*nbilinremoved;
4413  }
4414  }
4415  }
4416 
4417  if( *nbilinremoved > 0 )
4418  {
4419  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4420 
4421  /* invalidate nonlinear row */
4422  if( consdata->nlrow != NULL )
4423  {
4424  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4425  }
4426 
4427  consdata->ispropagated = FALSE;
4428  consdata->ispresolved = FALSE;
4429  consdata->iscurvchecked = FALSE;
4430  }
4431 
4432  consdata->isimpladded = FALSE;
4433 
4434  return SCIP_OKAY;
4435 }
4436 #endif
4437 
4438 /** checks a quadratic constraint for convexity and/or concavity without checking multivariate functions */
4439 static
4440 void checkCurvatureEasy(
4441  SCIP* scip, /**< SCIP data structure */
4442  SCIP_CONS* cons, /**< quadratic constraint */
4443  SCIP_Bool* determined, /**< pointer to store whether the curvature could be determined */
4444  SCIP_Bool checkmultivariate /**< whether curvature will be checked later on for multivariate functions */
4445  )
4446 {
4447  SCIP_CONSDATA* consdata;
4448  int nquadvars;
4449 
4450  assert(scip != NULL);
4451  assert(cons != NULL);
4452  assert(determined != NULL);
4453 
4454  consdata = SCIPconsGetData(cons);
4455  assert(consdata != NULL);
4456 
4457  nquadvars = consdata->nquadvars;
4458  *determined = TRUE;
4459 
4460  if( consdata->iscurvchecked )
4461  return;
4462 
4463  SCIPdebugMessage("Checking curvature of constraint <%s> without multivariate functions\n", SCIPconsGetName(cons));
4464 
4465  if( nquadvars == 1 )
4466  {
4467  assert(consdata->nbilinterms == 0);
4468  consdata->isconvex = !SCIPisNegative(scip, consdata->quadvarterms[0].sqrcoef);
4469  consdata->isconcave = !SCIPisPositive(scip, consdata->quadvarterms[0].sqrcoef);
4470  consdata->iscurvchecked = TRUE;
4471  }
4472  else if( nquadvars == 0 )
4473  {
4474  consdata->isconvex = TRUE;
4475  consdata->isconcave = TRUE;
4476  consdata->iscurvchecked = TRUE;
4477  }
4478  else if( consdata->nbilinterms == 0 )
4479  {
4480  int v;
4481 
4482  consdata->isconvex = TRUE;
4483  consdata->isconcave = TRUE;
4484 
4485  for( v = nquadvars - 1; v >= 0; --v )
4486  {
4487  consdata->isconvex = consdata->isconvex && !SCIPisNegative(scip, consdata->quadvarterms[v].sqrcoef);
4488  consdata->isconcave = consdata->isconcave && !SCIPisPositive(scip, consdata->quadvarterms[v].sqrcoef);
4489  }
4490 
4491  consdata->iscurvchecked = TRUE;
4492  }
4493  else if( !checkmultivariate )
4494  {
4495  consdata->isconvex = FALSE;
4496  consdata->isconcave = FALSE;
4497  consdata->iscurvchecked = TRUE;
4498  }
4499  else
4500  *determined = FALSE;
4501 }
4502 
4503 /** checks a quadratic constraint for convexity and/or concavity */
4504 static
4506  SCIP* scip, /**< SCIP data structure */
4507  SCIP_CONS* cons, /**< quadratic constraint */
4508  SCIP_Bool checkmultivariate /**< whether curvature should also be checked for multivariate functions */
4509  )
4510 {
4511  SCIP_CONSDATA* consdata;
4512  double* matrix;
4513  SCIP_HASHMAP* var2index;
4514  int i;
4515  int n;
4516  int nn;
4517  int row;
4518  int col;
4519  double* alleigval;
4520  SCIP_Bool determined;
4521 
4522  assert(scip != NULL);
4523  assert(cons != NULL);
4524 
4525  consdata = SCIPconsGetData(cons);
4526  assert(consdata != NULL);
4527 
4528  n = consdata->nquadvars;
4529 
4530  if( consdata->iscurvchecked )
4531  return SCIP_OKAY;
4532 
4533  /* easy checks for curvature detection */
4534  checkCurvatureEasy(scip, cons, &determined, checkmultivariate);
4535 
4536  /* if curvature was already detected stop */
4537  if( determined )
4538  {
4539  return SCIP_OKAY;
4540  }
4541 
4542  SCIPdebugMessage("Checking curvature of constraint <%s> with multivariate functions\n", SCIPconsGetName(cons));
4543 
4544  if( n == 2 )
4545  {
4546  /* compute eigenvalues by hand */
4547  assert(consdata->nbilinterms == 1);
4548  consdata->isconvex =
4549  consdata->quadvarterms[0].sqrcoef >= 0 &&
4550  consdata->quadvarterms[1].sqrcoef >= 0 &&
4551  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4552  consdata->isconcave =
4553  consdata->quadvarterms[0].sqrcoef <= 0 &&
4554  consdata->quadvarterms[1].sqrcoef <= 0 &&
4555  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4556 
4557  consdata->iscurvchecked = TRUE;
4558  return SCIP_OKAY;
4559  }
4560 
4561  /* do not check curvature if n is too large */
4562  nn = n * n;
4563  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
4564  {
4565  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "cons_quadratic - n is too large to check the curvature\n");
4566  consdata->isconvex = FALSE;
4567  consdata->isconcave = FALSE;
4568  consdata->iscurvchecked = TRUE;
4569  return SCIP_OKAY;
4570  }
4571 
4572  /* lower triangular of quadratic term matrix */
4573  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, nn) );
4574  BMSclearMemoryArray(matrix, nn);
4575 
4576  consdata->isconvex = TRUE;
4577  consdata->isconcave = TRUE;
4578 
4579  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * n)) );
4580  for( i = 0; i < n; ++i )
4581  {
4582  if( consdata->quadvarterms[i].nadjbilin > 0 )
4583  {
4584  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
4585  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4586  }
4587  /* nonzero elements on diagonal tell a lot about convexity/concavity */
4588  if( SCIPisNegative(scip, consdata->quadvarterms[i].sqrcoef) )
4589  consdata->isconvex = FALSE;
4590  if( SCIPisPositive(scip, consdata->quadvarterms[i].sqrcoef) )
4591  consdata->isconcave = FALSE;
4592  }
4593 
4594  if( !consdata->isconvex && !consdata->isconcave )
4595  {
4596  SCIPfreeBufferArray(scip, &matrix);
4597  SCIPhashmapFree(&var2index);
4598  consdata->iscurvchecked = TRUE;
4599  return SCIP_OKAY;
4600  }
4601 
4603  {
4604  for( i = 0; i < consdata->nbilinterms; ++i )
4605  {
4606  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
4607  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
4608  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
4609  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
4610  if( row < col )
4611  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
4612  else
4613  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
4614  }
4615 
4616  SCIP_CALL( SCIPallocBufferArray(scip, &alleigval, n) );
4617  /* @todo Can we compute only min and max eigen value?
4618  * @todo Can we estimate the numerical error?
4619  * @todo Trying a cholesky factorization may be much faster.
4620  */
4621  if( LapackDsyev(FALSE, n, matrix, alleigval) != SCIP_OKAY )
4622  {
4623  SCIPwarningMessage(scip, "Failed to compute eigenvalues of quadratic coefficient matrix of constraint %s. Assuming matrix is indefinite.\n", SCIPconsGetName(cons));
4624  consdata->isconvex = FALSE;
4625  consdata->isconcave = FALSE;
4626  }
4627  else
4628  {
4629  /* deconvexification reformulates a stricly convex quadratic function in binaries such that it becomes not-strictly convex
4630  * by adding the -lambda*(x^2-x) terms for lambda the smallest eigenvalue of the matrix
4631  * 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
4632  */
4633 #ifdef DECONVEXIFY
4634  SCIP_Bool allbinary;
4635  printf("cons <%s>[%g,%g] spectrum = [%g,%g]\n", SCIPconsGetName(cons), consdata->lhs, consdata->rhs, alleigval[0], alleigval[n-1]);
4636 #endif
4637  consdata->isconvex &= !SCIPisNegative(scip, alleigval[0]); /*lint !e514*/
4638  consdata->isconcave &= !SCIPisPositive(scip, alleigval[n-1]); /*lint !e514*/
4639  consdata->iscurvchecked = TRUE;
4640 #ifdef DECONVEXIFY
4641  for( i = 0; i < consdata->nquadvars; ++i )
4642  if( !SCIPvarIsBinary(consdata->quadvarterms[i].var) )
4643  break;
4644  allbinary = i == consdata->nquadvars;
4645 
4646  if( !SCIPisInfinity(scip, consdata->rhs) && alleigval[0] > 0.1 && allbinary )
4647  {
4648  printf("deconvexify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[0]);
4649  for( i = 0; i < consdata->nquadvars; ++i )
4650  {
4651  consdata->quadvarterms[i].sqrcoef -= alleigval[0];
4652  consdata->quadvarterms[i].lincoef += alleigval[0];
4653  }
4654  }
4655 
4656  if( !SCIPisInfinity(scip, consdata->lhs) && alleigval[n-1] < -0.1 && allbinary )
4657  {
4658  printf("deconcavify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[n-1]);
4659  for( i = 0; i < consdata->nquadvars; ++i )
4660  {
4661  consdata->quadvarterms[i].sqrcoef -= alleigval[n-1];
4662  consdata->quadvarterms[i].lincoef += alleigval[n-1];
4663  }
4664  }
4665 #endif
4666  }
4667 
4668  SCIPfreeBufferArray(scip, &alleigval);
4669  }
4670  else
4671  {
4672  consdata->isconvex = FALSE;
4673  consdata->isconcave = FALSE;
4674  consdata->iscurvchecked = TRUE; /* set to TRUE since it does not help to repeat this procedure again and again (that will not bring Ipopt in) */
4675  }
4676 
4677  SCIPhashmapFree(&var2index);
4678  SCIPfreeBufferArray(scip, &matrix);
4679 
4680  return SCIP_OKAY;
4681 }
4682 
4683 /** check whether indefinite constraint function is factorable and store corresponding coefficients */
4684 static
4686  SCIP* scip, /**< SCIP data structure */
4687  SCIP_CONS* cons /**< constraint */
4688  )
4689 {
4690  SCIP_BILINTERM* bilinterm;
4691  SCIP_CONSDATA* consdata;
4692  SCIP_Real* a;
4693  SCIP_Real* eigvals;
4694  SCIP_Real sigma1;
4695  SCIP_Real sigma2;
4696  SCIP_Bool success;
4697  int n;
4698  int i;
4699  int idx1;
4700  int idx2;
4701  int posidx;
4702  int negidx;
4703 
4704  assert(scip != NULL);
4705  assert(cons != NULL);
4706 
4707  consdata = SCIPconsGetData(cons);
4708  assert(consdata != NULL);
4709  assert(consdata->factorleft == NULL);
4710  assert(consdata->factorright == NULL);
4711 
4712  /* we don't need this if there are no bilinear terms */
4713  if( consdata->nbilinterms == 0 )
4714  return SCIP_OKAY;
4715 
4716  /* write constraint as lhs <= linear + x'^T A x' <= rhs where x' = (x,1) and
4717  * A = ( Q b/2 )
4718  * ( b^T/2 0 )
4719  * compute an eigenvalue factorization of A and check if there are one positive and one negative eigenvalue
4720  * 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
4721  * thus, x'^T A x' = sigma1^2 (v1^T x')^2 - sigma2^2 (v2^T x')^2
4722  * = (sigma1 (v1^T x') - sigma2 (v2^T x')) * (sigma1 (v1^T x') + sigma2 (v2^T x'))
4723  * we then store sigma1 v1^T - sigma2 v2^T as left factor coef, and sigma1 v1^T + sigma2 v2^T as right factor coef
4724  */
4725 
4726  /* if we already know that there are only positive or only negative eigenvalues, then don't try */
4727  if( consdata->iscurvchecked && (consdata->isconvex || consdata->isconcave) )
4728  return SCIP_OKAY;
4729 
4730  n = consdata->nquadvars + 1;
4731 
4732  /* @todo handle case n=3 explicitly */
4733 
4734  /* skip too large matrices */
4735  if( n > 50 )
4736  return SCIP_OKAY;
4737 
4738  /* need routine to compute eigenvalues/eigenvectors */
4739  if( !SCIPisIpoptAvailableIpopt() )
4740  return SCIP_OKAY;
4741 
4742  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4743 
4744  SCIP_CALL( SCIPallocBufferArray(scip, &a, n*n) );
4745  BMSclearMemoryArray(a, n*n);
4746 
4747  /* set lower triangular entries of A corresponding to bilinear terms */
4748  for( i = 0; i < consdata->nbilinterms; ++i )
4749  {
4750  bilinterm = &consdata->bilinterms[i];
4751 
4752  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4753  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4754  assert(idx1 >= 0);
4755  assert(idx2 >= 0);
4756  assert(idx1 != idx2);
4757 
4758  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
4759  }
4760 
4761  /* set lower triangular entries of A corresponding to square and linear terms */
4762  for( i = 0; i < consdata->nquadvars; ++i )
4763  {
4764  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4765  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
4766  }
4767 
4768  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, n) );
4769  if( LapackDsyev(TRUE, n, a, eigvals) != SCIP_OKAY )
4770  {
4771  SCIPdebugMessage("Failed to compute eigenvalues and eigenvectors of augmented quadratic form matrix for constraint <%s>.\n", SCIPconsGetName(cons));
4772  goto CLEANUP;
4773  }
4774 
4775  /* check if there is exactly one positive and one negative eigenvalue */
4776  posidx = -1;
4777  negidx = -1;
4778  for( i = 0; i < n; ++i )
4779  {
4780  if( SCIPisPositive(scip, eigvals[i]) )
4781  {
4782  if( posidx == -1 )
4783  posidx = i;
4784  else
4785  break;
4786  }
4787  else if( SCIPisNegative(scip, eigvals[i]) )
4788  {
4789  if( negidx == -1 )
4790  negidx = i;
4791  else
4792  break;
4793  }
4794  }
4795  if( i < n || posidx == -1 || negidx == -1 )
4796  {
4797  SCIPdebugMessage("Augmented quadratic form of constraint <%s> is not factorable.\n", SCIPconsGetName(cons));
4798  goto CLEANUP;
4799  }
4800  assert(SCIPisPositive(scip, eigvals[posidx]));
4801  assert(SCIPisNegative(scip, eigvals[negidx]));
4802 
4803  /* compute factorleft and factorright */
4804  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1) );
4805  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1) );
4806 
4807  /* eigenvectors are stored in a, inverse eigenvector matrix is transposed of a
4808  * it seems that v1 and v2 are at &a[posidx*n] and &a[negidx*n]
4809  */
4810  sigma1 = sqrt( eigvals[posidx]);
4811  sigma2 = sqrt(-eigvals[negidx]);
4812  for( i = 0; i < n; ++i )
4813  {
4814  consdata->factorleft[i] = sigma1 * a[posidx * n + i] - sigma2 * a[negidx * n + i];
4815  consdata->factorright[i] = sigma1 * a[posidx * n + i] + sigma2 * a[negidx * n + i];
4816  /* set almost-zero elements to zero */
4817  if( SCIPisZero(scip, consdata->factorleft[i]) )
4818  consdata->factorleft[i] = 0.0;
4819  if( SCIPisZero(scip, consdata->factorright[i]) )
4820  consdata->factorright[i] = 0.0;
4821  }
4822 
4823 #ifdef SCIP_DEBUG
4824  SCIPdebugMessage("constraint <%s> has factorable quadratic form: (%g", SCIPconsGetName(cons), consdata->factorleft[n-1]);
4825  for( i = 0; i < consdata->nquadvars; ++i )
4826  {
4827  if( consdata->factorleft[i] != 0.0 )
4828  SCIPdebugPrintf(" %+g<%s>", consdata->factorleft[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4829  }
4830  SCIPdebugPrintf(") * (%g", consdata->factorright[n-1]);
4831  for( i = 0; i < consdata->nquadvars; ++i )
4832  {
4833  if( consdata->factorright[i] != 0.0 )
4834  SCIPdebugPrintf(" %+g<%s>", consdata->factorright[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4835  }
4836  SCIPdebugPrintf(")\n");
4837 #endif
4838 
4839  /* check whether factorleft * factorright^T is matrix of augmented quadratic form
4840  * we check here only the nonzero entries from the quadratic form
4841  */
4842  success = TRUE;
4843 
4844  /* check bilinear terms */
4845  for( i = 0; i < consdata->nbilinterms; ++i )
4846  {
4847  bilinterm = &consdata->bilinterms[i];
4848 
4849  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4850  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4851 
4852  if( !SCIPisRelEQ(scip, consdata->factorleft[idx1] * consdata->factorright[idx2] + consdata->factorleft[idx2] * consdata->factorright[idx1], bilinterm->coef) )
4853  {
4854  success = FALSE;
4855  break;
4856  }
4857  }
4858 
4859  /* set lower triangular entries of A corresponding to square and linear terms */
4860  for( i = 0; i < consdata->nquadvars; ++i )
4861  {
4862  if( !SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[i], consdata->quadvarterms[i].sqrcoef) )
4863  {
4864  success = FALSE;
4865  break;
4866  }
4867 
4868  if( !SCIPisRelEQ(scip, consdata->factorleft[n-1] * consdata->factorright[i] + consdata->factorleft[i] * consdata->factorright[n-1], consdata->quadvarterms[i].lincoef) )
4869  {
4870  success = FALSE;
4871  break;
4872  }
4873  }
4874 
4875  if( !success )
4876  {
4877  SCIPdebugMessage("Factorization not accurate enough. Dropping it.\n");
4878  SCIPfreeBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1);
4879  SCIPfreeBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1);
4880  }
4881 
4882  CLEANUP:
4883  SCIPfreeBufferArray(scip, &a);
4884  SCIPfreeBufferArray(scip, &eigvals);
4885 
4886  return SCIP_OKAY;
4887 }
4888 
4889 /** gets maximal absolute value in gradient of quadratic function */
4890 static
4892  SCIP* scip, /**< SCIP data structure */
4893  SCIP_CONS* cons, /**< constraint */
4894  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
4895  )
4896 {
4897  SCIP_CONSDATA* consdata;
4898  SCIP_Real maxelem;
4899  SCIP_Real g;
4900  int i, j, k;
4901  SCIP_VAR* var;
4902 
4903  assert(scip != NULL);
4904  assert(cons != NULL);
4905 
4906  consdata = SCIPconsGetData(cons);
4907  assert(consdata != NULL);
4908 
4909  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
4910  {
4911  maxelem = 0.0;
4912  for( i = 0; i < consdata->nlinvars; ++i )
4913  if( REALABS(consdata->lincoefs[i]) > maxelem )
4914  maxelem = REALABS(consdata->lincoefs[i]);
4915  }
4916  else
4917  maxelem = consdata->lincoefsmax;
4918 
4919  for( i = 0; i < consdata->nquadvars; ++i )
4920  {
4921  var = consdata->quadvarterms[i].var;
4922  assert(!SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)));
4923  assert(!SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)));
4924  g = consdata->quadvarterms[i].lincoef;
4925  g += 2.0 * consdata->quadvarterms[i].sqrcoef * SCIPgetSolVal(scip, sol, var);
4926  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4927  {
4928  k = consdata->quadvarterms[i].adjbilin[j];
4929  if( consdata->bilinterms[k].var1 == var )
4930  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var2);
4931  else
4932  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var1);
4933  }
4934  if( REALABS(g) > maxelem )
4935  maxelem = REALABS(g);
4936  }
4937 
4938  return maxelem;
4939 }
4940 
4941 /** computes activity and violation of a constraint */
4942 static
4944  SCIP* scip, /**< SCIP data structure */
4945  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4946  SCIP_CONS* cons, /**< constraint */
4947  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
4948  )
4949 { /*lint --e{666}*/
4950  SCIP_CONSHDLRDATA* conshdlrdata;
4951  SCIP_CONSDATA* consdata;
4952  SCIP_Real varval;
4953  SCIP_Real varval2;
4954  SCIP_VAR* var;
4955  SCIP_VAR* var2;
4956  int i;
4957  int j;
4958 
4959  assert(scip != NULL);
4960  assert(cons != NULL);
4961 
4962  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4963  assert(conshdlrdata != NULL);
4964 
4965  consdata = SCIPconsGetData(cons);
4966  assert(consdata != NULL);
4967 
4968  consdata->activity = 0.0;
4969  varval = 0.0;
4970 
4971  /* @todo Take better care of variables at +/- infinity: e.g., run instance waste in debug mode with a short timelimit (30s). */
4972  for( i = 0; i < consdata->nlinvars; ++i )
4973  {
4974  var = consdata->linvars[i];
4975  varval = SCIPgetSolVal(scip, sol, var);
4976 
4977  if( SCIPisInfinity(scip, REALABS(varval)) )
4978  {
4979  consdata->activity = SCIPinfinity(scip);
4980  if( !SCIPisInfinity(scip, -consdata->lhs) )
4981  consdata->lhsviol = SCIPinfinity(scip);
4982  if( !SCIPisInfinity(scip, consdata->rhs) )
4983  consdata->rhsviol = SCIPinfinity(scip);
4984  return SCIP_OKAY;
4985  }
4986 
4987  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
4988  if( sol == NULL )
4989  {
4990  /* 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
4991  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
4992  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
4993  */
4994  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
4995  }
4996 
4997  consdata->activity += consdata->lincoefs[i] * varval;
4998  }
4999 
5000  for( j = 0; j < consdata->nquadvars; ++j )
5001  {
5002  var = consdata->quadvarterms[j].var;
5003  varval = SCIPgetSolVal(scip, sol, var);
5004  if( SCIPisInfinity(scip, REALABS(varval)) )
5005  {
5006  consdata->activity = SCIPinfinity(scip);
5007  if( !SCIPisInfinity(scip, -consdata->lhs) )
5008  consdata->lhsviol = SCIPinfinity(scip);
5009  if( !SCIPisInfinity(scip, consdata->rhs) )
5010  consdata->rhsviol = SCIPinfinity(scip);
5011  return SCIP_OKAY;
5012  }
5013 
5014  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5015  if( sol == NULL )
5016  {
5017  /* 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
5018  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
5019  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
5020  */
5021  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5022  }
5023 
5024  consdata->activity += (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5025  }
5026 
5027  for( j = 0; j < consdata->nbilinterms; ++j )
5028  {
5029  var = consdata->bilinterms[j].var1;
5030  var2 = consdata->bilinterms[j].var2;
5031  varval = SCIPgetSolVal(scip, sol, var);
5032  varval2 = SCIPgetSolVal(scip, sol, var2);
5033 
5034  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5035  if( sol == NULL )
5036  {
5037 #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 */
5038  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
5039  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
5040 #endif
5041  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5042 
5043 #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 */
5044  assert(SCIPisFeasGE(scip, varval2, SCIPvarGetLbLocal(var2)));
5045  assert(SCIPisFeasLE(scip, varval2, SCIPvarGetUbLocal(var2)));
5046 #endif
5047  varval2 = MAX(SCIPvarGetLbLocal(var2), MIN(SCIPvarGetUbLocal(var2), varval2));
5048  }
5049 
5050  consdata->activity += consdata->bilinterms[j].coef * varval * varval2;
5051  }
5052 
5053  /* compute absolute violation left hand side */
5054  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
5055  consdata->lhsviol = consdata->lhs - consdata->activity;
5056  else
5057  consdata->lhsviol = 0.0;
5058 
5059  /* compute absolute violation right hand side */
5060  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
5061  consdata->rhsviol = consdata->activity - consdata->rhs;
5062  else
5063  consdata->rhsviol = 0.0;
5064 
5065  switch( conshdlrdata->scaling )
5066  {
5067  case 'o' :
5068  /* no scaling */
5069  break;
5070 
5071  case 'g' :
5072  /* scale by sup-norm of gradient in current point */
5073  if( consdata->lhsviol > 0.0 || consdata->rhsviol > 0.0 )
5074  {
5075  SCIP_Real norm;
5076  norm = getGradientMaxElement(scip, cons, sol);
5077  if( norm > 1.0 )
5078  {
5079  consdata->lhsviol /= norm;
5080  consdata->rhsviol /= norm;
5081  }
5082  }
5083  break;
5084 
5085  case 's' :
5086  /* scale by left/right hand side of constraint */
5087  if( consdata->lhsviol > 0.0 )
5088  consdata->lhsviol /= MAX(1.0, REALABS(consdata->lhs));
5089 
5090  if( consdata->rhsviol > 0.0 )
5091  consdata->rhsviol /= MAX(1.0, REALABS(consdata->rhs));
5092 
5093  break;
5094 
5095  default :
5096  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
5097  SCIPABORT();
5098  return SCIP_INVALIDDATA; /*lint !e527*/
5099  }
5100 
5101  return SCIP_OKAY;
5102 }
5103 
5104 /** computes violation of a set of constraints */
5105 static
5107  SCIP* scip, /**< SCIP data structure */
5108  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5109  SCIP_CONS** conss, /**< constraints */
5110  int nconss, /**< number of constraints */
5111  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5112  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
5113  )
5114 {
5115  SCIP_CONSDATA* consdata;
5116  SCIP_Real viol;
5117  SCIP_Real maxviol;
5118  int c;
5119 
5120  assert(scip != NULL);
5121  assert(conss != NULL || nconss == 0);
5122  assert(maxviolcon != NULL);
5123 
5124  *maxviolcon = NULL;
5125 
5126  maxviol = 0.0;
5127 
5128  for( c = 0; c < nconss; ++c )
5129  {
5130  assert(conss != NULL);
5131  assert(conss[c] != NULL);
5132 
5133  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
5134 
5135  consdata = SCIPconsGetData(conss[c]);
5136  assert(consdata != NULL);
5137 
5138  viol = MAX(consdata->lhsviol, consdata->rhsviol);
5139  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
5140  {
5141  maxviol = viol;
5142  *maxviolcon = conss[c];
5143  }
5144  }
5145 
5146  return SCIP_OKAY;
5147 }
5148 
5149 /** tries to compute cut for multleft * <coefleft, x'> * multright <= rhs / (multright * <coefright, x'>) where x'=(x,1) */
5150 static
5152  SCIP* scip, /**< SCIP data structure */
5153  SCIP_CONS* cons, /**< constraint */
5154  SCIP_Real* ref, /**< reference solution where to generate the cut */
5155  SCIP_Real multleft, /**< multiplicator on lhs */
5156  SCIP_Real* coefleft, /**< coefficient for factor on lhs */
5157  SCIP_Real multright, /**< multiplicator on both sides */
5158  SCIP_Real* coefright, /**< coefficient for factor that goes to rhs */
5159  SCIP_Real rightminactivity, /**< minimal activity of <coefright, x> */
5160  SCIP_Real rightmaxactivity, /**< maximal activity of <coefright, x> */
5161  SCIP_Real rhs, /**< denominator on rhs */
5162  SCIP_Real* cutcoef, /**< array to store cut coefficients for quadratic variables */
5163  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5164  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5165  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5166  char* name /**< buffer to store name of cut */
5167  )
5168 {
5169  SCIP_CONSDATA* consdata;
5170  SCIP_Real constant;
5171  int i;
5172 
5173  assert(cutcoef != NULL);
5174  assert(rightminactivity * multright > 0.0);
5175  assert(rightmaxactivity * multright > 0.0);
5176  assert(multright == 1.0 || multright == -1.0);
5177 
5178  consdata = SCIPconsGetData(cons);
5179  assert(consdata != NULL);
5180 
5181  if( rhs > 0.0 )
5182  {
5183  /* if rhs > 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need secant:
5184  * 1 / multright*<coefright, x'> <= 1/minact + 1/maxact - 1/(minact * maxact) multright*<coefright, x'>
5185  * where [minact, maxact] = multright * [rightminactivity, rightmaxactivity]
5186  *
5187  * assuming multright is either -1 or 1, and substituting gives
5188  * multright/rightminactivity + multright/rightmaxactivity - multright/(rightminactivity * rightmaxactivity) *<coefright, x'>
5189  *
5190  * multiplying by rhs, gives the estimate
5191  * rhs / (multright * <coefright, x'>) <= rhs * multright * (1/rightminactivity + 1/rightmaxactivity - 1/(rightminactivity * rightmaxactivity) * <coefright, x'>)
5192  */
5193 
5194  /* cannot do if unbounded */
5195  if( SCIPisInfinity(scip, rightmaxactivity) )
5196  {
5197  *success = FALSE;
5198  return;
5199  }
5200 
5201  assert(SCIPisFeasLE(scip, rightminactivity, rightmaxactivity));
5202 
5203  constant = multleft * multright * coefleft[consdata->nquadvars];
5204  constant -= rhs * multright * (1.0 / rightminactivity + 1.0 / rightmaxactivity);
5205  constant += rhs * multright * coefright[consdata->nquadvars] / (rightminactivity * rightmaxactivity);
5206 
5207  for( i = 0; i < consdata->nquadvars; ++i )
5208  {
5209  cutcoef[i] = multleft * multright * coefleft[i];
5210  cutcoef[i] += rhs * multright / (rightminactivity * rightmaxactivity) * coefright[i];
5211  }
5212 
5213  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_factorablesecant_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5214  }
5215  else
5216  {
5217  SCIP_Real refvalue;
5218 
5219  /* if rhs < 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need linearization:
5220  * rhs / (multright * <coefright, x'>)
5221  * <= rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'> - multright * <coefright, ref'>)
5222  * = 2*rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'>)
5223  *
5224  * where ref' = (ref, 1)
5225  */
5226 
5227  /* compute <coefright, ref'> */
5228  refvalue = coefright[consdata->nquadvars];
5229  for( i = 0; i < consdata->nquadvars; ++i )
5230  refvalue += coefright[i] * ref[i];
5231 
5232  /* should not happen, since we checked activity of <coefright,x> before, and assume ref within bounds */
5233  assert(!SCIPisZero(scip, refvalue));
5234 
5235  constant = multleft * multright * coefleft[consdata->nquadvars];
5236  constant -= 2.0 * rhs / (multright * refvalue);
5237  constant += rhs / (refvalue * refvalue) * multright * coefright[consdata->nquadvars];
5238 
5239  for( i = 0; i < consdata->nquadvars; ++i )
5240  {
5241  cutcoef[i] = multleft * multright * coefleft[i];
5242  cutcoef[i] += rhs / (refvalue * refvalue) * multright * coefright[i];
5243  }
5244 
5245  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_factorablelinearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5246  }
5247 
5248  *cutrhs = -constant;
5249 
5250  /* @todo does not always need to be local */
5251  *islocal = TRUE;
5252  *success = TRUE;
5253 }
5254 
5255 /** tries to generate a cut if constraint quadratic function is factorable and there are no linear variables
5256  * (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
5257  */
5258 static
5260  SCIP* scip, /**< SCIP data structure */
5261  SCIP_CONS* cons, /**< constraint */
5262  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
5263  SCIP_Real* ref, /**< reference solution where to generate the cut */
5264  SCIP_Real* cutcoef, /**< array to store cut coefficients for quadratic variables */
5265  SCIP_Real* cutlhs, /**< buffer to store cut lhs */
5266  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5267  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5268  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5269  char* name /**< buffer to store name of cut */
5270  )
5271 {
5272  SCIP_CONSDATA* consdata;
5273  SCIP_Real leftminactivity;
5274  SCIP_Real leftmaxactivity;
5275  SCIP_Real rightminactivity;
5276  SCIP_Real rightmaxactivity;
5277  SCIP_Real multleft;
5278  SCIP_Real multright;
5279  SCIP_Real rhs;
5280  int i;
5281 
5282  assert(scip != NULL);
5283  assert(cons != NULL);
5284  assert(ref != NULL);
5285  assert(cutcoef != NULL);
5286  assert(cutlhs != NULL);
5287  assert(cutrhs != NULL);
5288  assert(islocal != NULL);
5289  assert(success != NULL);
5290  assert(name != NULL);
5291 
5292  consdata = SCIPconsGetData(cons);
5293  assert(consdata != NULL);
5294  assert(consdata->nlinvars == 0);
5295  assert(consdata->factorleft != NULL);
5296  assert(consdata->factorright != NULL);
5297 
5298  *success = FALSE;
5299  *cutlhs = -SCIPinfinity(scip);
5300 
5301  leftminactivity = consdata->factorleft[consdata->nquadvars];
5302  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
5303  rightminactivity = consdata->factorright[consdata->nquadvars];
5304  rightmaxactivity = consdata->factorright[consdata->nquadvars];
5305  for( i = 0; i < consdata->nquadvars; ++i )
5306  {
5307  if( !SCIPisInfinity(scip, -leftminactivity) )
5308  {
5309  if( consdata->factorleft[i] > 0.0 )
5310  {
5311  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5312  leftminactivity = -SCIPinfinity(scip);
5313  else
5314  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5315  }
5316  else if( consdata->factorleft[i] < 0.0 )
5317  {
5318  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5319  leftminactivity = -SCIPinfinity(scip);
5320  else
5321  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5322  }
5323  }
5324  if( !SCIPisInfinity(scip, leftmaxactivity) )
5325  {
5326  if( consdata->factorleft[i] > 0.0 )
5327  {
5328  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5329  leftmaxactivity = SCIPinfinity(scip);
5330  else
5331  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5332  }
5333  else if( consdata->factorleft[i] < 0.0 )
5334  {
5335  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5336  leftmaxactivity = SCIPinfinity(scip);
5337  else
5338  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5339  }
5340  }
5341 
5342  if( !SCIPisInfinity(scip, -rightminactivity) )
5343  {
5344  if( consdata->factorright[i] > 0.0 )
5345  {
5346  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5347  rightminactivity = -SCIPinfinity(scip);
5348  else
5349  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5350  }
5351  else if( consdata->factorright[i] < 0.0 )
5352  {
5353  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5354  rightminactivity = -SCIPinfinity(scip);
5355  else
5356  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5357  }
5358  }
5359  if( !SCIPisInfinity(scip, rightmaxactivity) )
5360  {
5361  if( consdata->factorright[i] > 0.0 )
5362  {
5363  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5364  rightmaxactivity = SCIPinfinity(scip);
5365  else
5366  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5367  }
5368  else if( consdata->factorright[i] < 0.0 )
5369  {
5370  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5371  rightmaxactivity = SCIPinfinity(scip);
5372  else
5373  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5374  }
5375  }
5376  }
5377 
5378  /* write violated constraints as multleft * factorleft * factorright <= rhs */
5379  if( violside == SCIP_SIDETYPE_RIGHT )
5380  {
5381  rhs = consdata->rhs;
5382  multleft = 1.0;
5383  }
5384  else
5385  {
5386  rhs = -consdata->lhs;
5387  multleft = -1.0;
5388  }
5389 
5390  if( SCIPisZero(scip, rhs) )
5391  {
5392  /* @todo do something for rhs == 0.0? */
5393  return SCIP_OKAY;
5394  }
5395 
5396  if( !SCIPisFeasPositive(scip, leftminactivity) && !SCIPisFeasNegative(scip, leftmaxactivity) )
5397  {
5398  /* left factor has 0 within activity bounds, or is very close, at least */
5399  if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5400  {
5401  /* right factor also has 0 within activity bounds, or is very close, at least
5402  * -> cannot separate
5403  */
5404  return SCIP_OKAY;
5405  }
5406 
5407  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5408  * such that multright * factorright > 0.0
5409  */
5410  if( rightminactivity < 0.0 )
5411  multright = -1.0;
5412  else
5413  multright = 1.0;
5414 
5415  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5416  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5417  }
5418  else if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5419  {
5420  /* left factor is bounded away from 0
5421  * right factor has 0 within activity bounds, or is very close, at least
5422  * -> so divide by left factor
5423  */
5424 
5425  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5426  * such that multright * factorleft > 0.0
5427  */
5428  if( leftminactivity < 0.0 )
5429  multright = -1.0;
5430  else
5431  multright = 1.0;
5432 
5433  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5434  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5435  }
5436  else if( SCIPisInfinity(scip, -leftminactivity) || SCIPisInfinity(scip, leftmaxactivity) ||
5437  (!SCIPisInfinity(scip, -rightminactivity) && !SCIPisInfinity(scip, rightmaxactivity) && rightmaxactivity - rightminactivity < leftmaxactivity - leftminactivity) )
5438  {
5439  /* both factors are bounded away from 0, but the right one has a smaller activity range, so divide by that one */
5440 
5441  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5442  * such that multright * factorright > 0.0
5443  */
5444  if( rightminactivity < 0.0 )
5445  multright = -1.0;
5446  else
5447  multright = 1.0;
5448 
5449  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5450  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5451  }
5452  else
5453  {
5454  /* both factors are bounded away from 0, but the left one has a smaller activity range, so divide by that one */
5455 
5456  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5457  * such that multright * factorleft > 0.0
5458  */
5459  if( leftminactivity < 0.0 )
5460  multright = -1.0;
5461  else
5462  multright = 1.0;
5463 
5464  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5465  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5466  }
5467 
5468  return SCIP_OKAY;
5469 }
5470 
5471 /* finds intersections of a parametric line (x,y) = (x0,y0) + t [(x1,y1) - (x0,y0)] on curves x*y = wl and x*y = wu;
5472  * returns TRUE if unsuccessful and FALSE otherwise
5473  */
5474 static
5476  SCIP* scip,
5477  SCIP_Real x0,
5478  SCIP_Real y0_,
5479  SCIP_Real x1,
5480  SCIP_Real y1_,
5481  SCIP_Real wl,
5482  SCIP_Real wu,
5483  SCIP_Real* xl,
5484  SCIP_Real* yl,
5485  SCIP_Real* xu,
5486  SCIP_Real* yu
5487  )
5488 {
5489  SCIP_Real a;
5490  SCIP_Real b;
5491  SCIP_Real c;
5492  SCIP_Real tl;
5493  SCIP_Real tu;
5494 
5495  assert(wl == SCIP_INVALID || (xl != NULL && yl != NULL)); /*lint !e777 */
5496  assert(wu == SCIP_INVALID || (xu != NULL && yu != NULL)); /*lint !e777 */
5497 
5498  /* The parametric line is of the form
5499  *
5500  * x = x0 + t (x1-x0)
5501  * y = y0 + t (y1-y0)
5502  *
5503  * and for that to satisfy xy = wl and xy = wu we must have
5504  *
5505  * x0 y0 + t [x0 (y1-y0) + y0 (x1-x0)] + t^2 (x1-x0) (y1-y0) = wl
5506  * = wu
5507  *
5508  * or a t^2 + b t + c - wl = 0 for proper values of a,b,c.
5509  * a t^2 + b t + c - wu = 0
5510  *
5511  * Because of the way this procedure will be used, one of the two
5512  * solutions found we must always use the minimum nonnegative one
5513  */
5514 
5515  a = (x1 - x0) * (y1_ - y0_);
5516  c = x0 * y0_;
5517  b = x0 * y1_ + y0_ * x1 - 2.0 * c;
5518 
5519  tl = 0.0;
5520  tu = 0.0;
5521 
5522  if( !SCIPisZero(scip, (SCIP_Real)a) )
5523  {
5524  if( wl != SCIP_INVALID ) /*lint !e777 */
5525  {
5526  SCIP_Real tl1;
5527  SCIP_Real tl2;
5528  SCIP_Real denom;
5529 
5530  assert(b * b - 4.0 * a * (c - wl) >= 0.0);
5531  denom = sqrt(b * b - 4.0 * a * (c - wl));
5532  tl1 = (-b - denom) / (2.0 * a);
5533  tl2 = (-b + denom) / (2.0 * a);
5534  tl = (tl1 < 0.0) ? tl2 : tl1;
5535  }
5536 
5537  if( wu != SCIP_INVALID ) /*lint !e777 */
5538  {
5539  SCIP_Real tu1;
5540  SCIP_Real tu2;
5541  SCIP_Real denom;
5542 
5543  assert(b * b - 4.0 * a * (c - wu) >= 0.0);
5544  denom = sqrt(b * b - 4.0 * a * (c - wu));
5545  tu1 = (-b - denom) / (2.0 * a);
5546  tu2 = (-b + denom) / (2.0 * a);
5547  tu = (tu1 < 0.0) ? tu2 : tu1;
5548  }
5549  }
5550  else if( !SCIPisZero(scip, (SCIP_Real)b) )
5551  {
5552  if( wl != SCIP_INVALID ) /*lint !e777 */
5553  tl = (wl - c) / b;
5554  if( wu != SCIP_INVALID ) /*lint !e777 */
5555  tu = (wu - c) / b;
5556  }
5557  else
5558  {
5559  /* no or infinitely many solutions */
5560  return TRUE;
5561  }
5562 
5563  if( wl != SCIP_INVALID ) /*lint !e777 */
5564  {
5565  *xl = (SCIP_Real)(x0 + tl * (x1 - x0 ));
5566  *yl = (SCIP_Real)(y0_ + tl * (y1_ - y0_));
5567 
5568  if( !SCIPisRelEQ(scip, *xl * *yl, wl) )
5569  {
5570  SCIPdebugMessage("probable numerical difficulties, give up\n");
5571  return TRUE;
5572  }
5573  }
5574 
5575  if( wu != SCIP_INVALID ) /*lint !e777 */
5576  {
5577  *xu = (SCIP_Real)(x0 + tu * (x1 - x0));
5578  *yu = (SCIP_Real)(y0_ + tu * (y1_ - y0_));
5579 
5580  if( !SCIPisRelEQ(scip, *xu * *yu, wu) )
5581  {
5582  SCIPdebugMessage("probable numerical difficulties, give up\n");
5583  return TRUE;
5584  }
5585  }
5586 
5587  return FALSE;
5588 }
5589 
5590 /** generate coefficients for a plane through points (x1, y1_, x1*y1) and (x2, y2, x2*y2)
5591  * such that intersecting it with one of them (the first if whichuse is FALSE, the second otherwise)
5592  * gives a tangent to the curve x*y = k
5593  *
5594  * Returns TRUE on error and FALSE on success.
5595  */
5596 static
5598  SCIP* scip,
5599  SCIP_Real x1,
5600  SCIP_Real y1_,
5601  SCIP_Real x2,
5602  SCIP_Real y2,
5603  SCIP_Bool whichuse,
5604  SCIP_Real* cx,
5605  SCIP_Real* cy,
5606  SCIP_Real* cw
5607  )
5608 {
5609  SCIP_Real xd;
5610  SCIP_Real yd;
5611  SCIP_Real xo;
5612  SCIP_Real yo;
5613 
5614  assert(cx != NULL);
5615  assert(cy != NULL);
5616  assert(cw != NULL);
5617 
5618  /* the x-y slope of this constraint must be tangent to a curve x*y = k at (xD,yD) */
5619  if( !whichuse )
5620  {
5621  xd = x1;
5622  xo = x2;
5623  yd = y1_;
5624  yo = y2;
5625  }
5626  else
5627  {
5628  xd = x2;
5629  xo = x1;
5630  yd = y2;
5631  yo = y1_;
5632  }
5633 
5634  *cx = yd;
5635  *cy = xd;
5636 
5637  /* lift it so that it touches the other curve */
5638 
5639  /* if the two points are on the same curve, then no cut */
5640  if( SCIPisZero(scip, xo * yo - xd * yd) )
5641  return TRUE;
5642 
5643  /* should ALWAYS be negative */
5644  *cw = (2.0 * xd * yd - (*cx * xo + *cy * yo)) / (xo * yo - xd * yd);
5645 
5646  return FALSE;
5647 }
5648 
5649 /** computes coefficients of a lifted-tangent inequality for x*y = w
5650  *
5651  * The code is an adaptation of the methods in exprMul-upperHull.cpp in Couenne/stable/0.4 rev773,
5652  * written by P. Belotti and licensed under Eclipse Public License.
5653  */
5654 static
5656  SCIP* scip, /**< SCIP data structure */
5657  SCIP_Real xl, /**< lower bound on x */
5658  SCIP_Real xu, /**< upper bound on x */
5659  SCIP_Real x0, /**< reference point for x */
5660  SCIP_Real yl, /**< lower bound on y */
5661  SCIP_Real yu, /**< upper bound on y */
5662  SCIP_Real y0_, /**< reference point for y */
5663  SCIP_Real wl, /**< lower bound on w */
5664  SCIP_Real wu, /**< upper bound on w */
5665  SCIP_Real w0, /**< reference point for w */
5666  SCIP_Real* cx, /**< buffer where to store cut coefficient for x */
5667  SCIP_Real* cy, /**< buffer where to store cut coefficient for y */
5668  SCIP_Real* cw, /**< buffer where to store cut coefficient for w */
5669  SCIP_Real* c0, /**< buffer where to store cut left-hand-side */
5670  SCIP_Bool* success /**< buffer where to indicate whether cut coefficients were computed */
5671  )
5672 {
5673  SCIP_Bool flipx;
5674  SCIP_Bool flipy;
5675  SCIP_Bool flipw;
5676  SCIP_Real tmp;
5677  SCIP_Real xlow;
5678  SCIP_Real ylow;
5679  SCIP_Real xupp;
5680  SCIP_Real yupp;
5681  SCIP_Real c0x;
5682  SCIP_Real c0y;
5683  SCIP_Real c0w;
5684 
5685  assert(scip != NULL);
5686  assert(cx != NULL);
5687  assert(cy != NULL);
5688  assert(cw != NULL);
5689  assert(c0 != NULL);
5690  assert(success != NULL);
5691 
5692  *success = FALSE;
5693  *cx = 0.0;
5694  *cy = 0.0;
5695  *cw = 0.0;
5696  *c0 = 0.0;
5697 
5698  SCIPdebugMessage("entering points:\n");
5699  SCIPdebugMessage("x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5700  SCIPdebugMessage("y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5701  SCIPdebugMessage("w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5702 
5703  /* generateCutLTI should have recognized these */
5704  assert(wl >= 0.0 || wu <= 0.0);
5705  assert(!SCIPisInfinity(scip, -wl));
5706  assert(!SCIPisInfinity(scip, wu));
5707 
5708  assert(SCIPisFeasGE(scip, x0, xl));
5709  assert(SCIPisFeasLE(scip, x0, xu));
5710  assert(SCIPisFeasGE(scip, y0_, yl));
5711  assert(SCIPisFeasLE(scip, y0_, yu));
5712 
5713  /* preliminary bound tightening */
5714  if( wl >= 0.0 )
5715  {
5716  if( xl >= 0.0 || yl >= 0.0 || SCIPisLT(scip, xl * yl, wl) )
5717  {
5718  xl = MAX(xl, 0.0);
5719  yl = MAX(yl, 0.0);
5720  }
5721  else if( xu <= 0.0 || yu <= 0.0 || SCIPisLT(scip, xu * yu, wl) )
5722  {
5723  xu = MIN(xu, 0.0);
5724  yu = MIN(yu, 0.0);
5725  }
5726  else
5727  {
5728  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yl and xu*yu are feasible
5729  * cannot generate cut for this
5730  */
5731  return;
5732  }
5733  }
5734  else
5735  {
5736  if( xl >= 0.0 || yu <= 0.0 || SCIPisGT(scip, xl * yu, wu) )
5737  {
5738  xl = MAX(xl, 0.0);
5739  yu = MIN(yu, 0.0);
5740  }
5741  else if( xu <= 0.0 || yl >= 0.0 || SCIPisGT(scip, xu * yl, wu))
5742  {
5743  xu = MIN(xu, 0.0);
5744  yl = MAX(yl, 0.0);
5745  }
5746  else
5747  {
5748  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yu and xu*yl are feasible
5749  * cannot generate cut for this
5750  */
5751  return;
5752  }
5753  }
5754 
5755  /* if x or y is fixed now or even infeasible, then do not think about a cut */
5756  if( SCIPisGE(scip, xl, xu) || SCIPisGE(scip, yl, yu) )
5757  return;
5758 
5759  /* reduce to positive orthant by flipping variables */
5760  if( xl < 0.0 )
5761  {
5762  flipx = TRUE;
5763  tmp = xu;
5764  xu = -xl;
5765  xl = -tmp;
5766  x0 = -x0;
5767  }
5768  else
5769  flipx = FALSE;
5770 
5771  if( yl < 0.0 )
5772  {
5773  flipy = TRUE;
5774  tmp = yu;
5775  yu = -yl;
5776  yl = -tmp;
5777  y0_ = -y0_;
5778  }
5779  else
5780  flipy = FALSE;
5781 
5782  if( flipx ^ flipy )
5783  {
5784  flipw = TRUE;
5785  tmp = wu;
5786  wu = -wl;
5787  wl = -tmp;
5788  w0 = -w0;
5789  }
5790  else
5791  flipw = FALSE;
5792 
5793  /* project refpoint into box not only for numerical reasons, but also due to preliminary bound tightening above */
5794  x0 = MIN(xu, MAX(x0, xl));
5795  y0_ = MIN(yu, MAX(y0_, yl));
5796  w0 = MIN(wu, MAX(w0, wl));
5797 
5798  SCIPdebugMessage("reduced points:\n");
5799  SCIPdebugMessage("x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5800  SCIPdebugMessage("y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5801  SCIPdebugMessage("w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5802 
5803  if( SCIPisGE(scip, xl * yl, wl) && SCIPisLE(scip, xu * yu, wu) )
5804  {
5805  SCIPdebugMessage("box for x and y inside feasible region -> nothing to separate\n");
5806  return;
5807  }
5808  if( SCIPisGE(scip, x0 * y0_, w0) )
5809  {
5810  SCIPdebugMessage("point to separate not below curve -> cannot separate\n");
5811  return;
5812  }
5813 
5814  /* find intersections of halfline from origin
5815  * return if no proper point could be found
5816  */
5817  if( generateCutLTIfindIntersection(scip, 0.0, 0.0, x0, y0_, wl, wu, &xlow, &ylow, &xupp, &yupp) )
5818  return;
5819 
5820  SCIPdebugMessage("intersections:\n");
5821  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5822  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5823 
5824  /* Case 1: If both are outside of bounding box, either NW or SE, then McCormick is sufficient, so return */
5825  if( (xlow <= xl && yupp >= yu) || (ylow <= yl && xupp >= xu) )
5826  return;
5827 
5828  /* There will be at least one cut. Define coefficients and rhs ---will have to change them back if (flipX || flipY) */
5829  if( xlow >= xl && xupp <= xu && ylow >= yl && yupp <= yu )
5830  {
5831  /* Case 2: both are inside. Easy lifting... */
5832  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5833  return;
5834 
5835  c0x = *cx * xlow;
5836  c0y = *cy * ylow;
5837  c0w = *cw * wl;
5838  }
5839  else if( xlow >= xl && ylow >= yl && (xupp > xu || yupp > yu) )
5840  {
5841  /* Case 3a and 3b: through lower curve, but not upper. */
5842  if( yupp > yu )
5843  {
5844  /* upper intersect is North; place it within box */
5845  assert(!SCIPisInfinity(scip, yu));
5846  yupp = yu;
5847  xupp = wu / yu;
5848  }
5849  else
5850  {
5851  /* upper intersect is East; place it within box */
5852  assert(!SCIPisInfinity(scip, xu));
5853  xupp = xu;
5854  yupp = wu / xu;
5855  }
5856 
5857  /* find intersection on low curve on half line through new point and (x0,y0_) */
5858  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow, &ylow, NULL, NULL) )
5859  return;
5860 
5861  /* check whether McCormick is sufficient */
5862  if( xlow < xl || ylow < yl )
5863  return;
5864 
5865  /* lift inequality on lower point */
5866  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5867  return;
5868 
5869  c0x = *cx * xlow;
5870  c0y = *cy * ylow;
5871  c0w = *cw * wl;
5872  }
5873  else if( xupp <= xu && yupp <= yu && (xlow < xl || ylow < yl) )
5874  {
5875  /* Case 4a and 4b: viceversa (lift for validity) */
5876  if( ylow < yl )
5877  {
5878  /* upper intersect is South; place it within box */
5879  assert(!SCIPisZero(scip, yl));
5880  ylow = yl;
5881  xlow = wl / yl;
5882  }
5883  else
5884  {
5885  /* upper intersect is West; place it within box */
5886  assert(!SCIPisZero(scip, xl));
5887  xlow = xl;
5888  ylow = wl / xl;
5889  }
5890 
5891  /* find intersection on low curve on half line through new point and (x0,y0) */
5892  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp, &yupp) )
5893  return;
5894 
5895  /* check whether McCormick is sufficient */
5896  if( xupp > xu || yupp > yu )
5897  return;
5898 
5899  /* lift inequality on UPPER point */
5900  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
5901  return;
5902 
5903  c0x = *cx * xupp;
5904  c0y = *cy * yupp;
5905  c0w = *cw * wu;
5906  }
5907  else if( (xlow < xl && xupp > xu) || (ylow < yl && yupp > yu) )
5908  {
5909  /* Case 5: both outside of bounding box, N and S or W and E. */
5910 #if 0
5911  SCIP_Real xlow2;
5912  SCIP_Real ylow2;
5913  SCIP_Real xupp2;
5914  SCIP_Real yupp2;
5915 #endif
5916 
5917  if( ylow < yl )
5918  {
5919  /* upper intersect is South; place it within box */
5920  assert(!SCIPisZero(scip, yl));
5921  assert(!SCIPisZero(scip, yu));
5922  ylow = yl;
5923  yupp = yu;
5924  xlow = wl / yl;
5925  xupp = wu / yu;
5926  }
5927  else
5928  {
5929  /* upper intersect is West; place it within box */
5930  assert(!SCIPisZero(scip, xl));
5931  assert(!SCIPisZero(scip, xu));
5932  xlow = xl;
5933  xupp = xu;
5934  ylow = wl / xl;
5935  yupp = wu / xu;
5936  }
5937 
5938  SCIPdebugMessage("New intersections:\n");
5939  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5940  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5941 
5942 #if 1
5943  /* Nothing to find. Just separate two inequalities at the same point, just using different support */
5944  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5945  {
5946  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
5947  return;
5948 
5949  c0x = *cx * xupp;
5950  c0y = *cy * yupp;
5951  c0w = *cw * wu;
5952  }
5953  else
5954  {
5955  c0x = *cx * xlow;
5956  c0y = *cy * ylow;
5957  c0w = *cw * wl;
5958  }
5959 
5960 #else
5961  /* find the intersection on the lower (upper) curve on the line through xLP and the upper (lower) point
5962  * this does not seem to work (cuts off solution at nous2), so it is disabled for now
5963  */
5964  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp2, &yupp2) ||
5965  generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp2, yupp2, FALSE, cx, cx, cw) )
5966  {
5967  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow2, &ylow2, NULL, NULL) ||
5968  generateCutLTIgenMulCoeff(scip, xlow2, ylow2, xupp, yupp, TRUE, cx, cy, cw) )
5969  return;
5970 
5971  c0x = *cx * xupp;
5972  c0y = *cy * yupp;
5973  c0w = *cw * wu;
5974  }
5975  else
5976  {
5977  c0x = *cx * xlow;
5978  c0y = *cy * ylow;
5979  c0w = *cw * wl;
5980  }
5981 #endif
5982  }
5983  else
5984  {
5985  SCIPdebugMessage("points are in a weird position:\n");
5986  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5987  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5988 
5989  return;
5990  }
5991 
5992  SCIPdebugMessage("cut w.r.t. reduced points: %gx-%g %+gy-%g %+gw-%g >= 0\n",
5993  *cx, c0x, *cy, c0y, *cw, c0w);
5994 
5995  /* re-transform back into original variables */
5996  if( flipx )
5997  *cx = -*cx;
5998  if( flipy )
5999  *cy = -*cy;
6000  if( flipw )
6001  *cw = -*cw;
6002 
6003  *c0 = c0x + c0y + c0w;
6004 
6005  *success = TRUE;
6006 }
6007 
6008 /** tries to generate a cut if constraint quadratic function is factorable and there are linear variables
6009  *
6010  * Computes what is called a lifted tangent inequality described in@n
6011  * Belotti, Miller, Namazifar, Lifted inequalities for bounded products of variables, SIAG/OPT Views-and-News 22:1, 2011
6012  */
6013 static
6015  SCIP* scip, /**< SCIP data structure */
6016  SCIP_CONS* cons, /**< constraint */
6017  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6018  SCIP_Real* ref, /**< reference solution where to generate the cut */
6019  SCIP_SOL* sol, /**< solution that shall be cutoff, NULL for LP solution */
6020  SCIP_Real** cutcoeflin, /**< buffer to store pointer to array with coefficients for linear variables */
6021  SCIP_Real* cutcoefquad, /**< array to store cut coefficients for quadratic variables */
6022  SCIP_Real* cutlhs, /**< buffer to store cut lhs */
6023  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
6024  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
6025  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6026  char* name /**< buffer to store name of cut */
6027  )
6028 {
6029  SCIP_CONSDATA* consdata;
6030  SCIP_Real leftminactivity;
6031  SCIP_Real leftmaxactivity;
6032  SCIP_Real leftrefactivity;
6033  SCIP_Real rightminactivity;
6034  SCIP_Real rightmaxactivity;
6035  SCIP_Real rightrefactivity;
6036  SCIP_Real rhsminactivity;
6037  SCIP_Real rhsmaxactivity;
6038  SCIP_Real rhsrefactivity;
6039  SCIP_Real coefleft;
6040  SCIP_Real coefright;
6041  SCIP_Real coefrhs;
6042  int i;
6043 
6044  assert(scip != NULL);
6045  assert(cons != NULL);
6046  assert(ref != NULL);
6047  assert(cutcoeflin != NULL);
6048  assert(cutcoefquad != NULL);
6049  assert(cutlhs != NULL);
6050  assert(cutrhs != NULL);
6051  assert(islocal != NULL);
6052  assert(success != NULL);
6053  assert(name != NULL);
6054  /* currently only separate LP solution or solutions given as SCIP_SOL, i.e., no cutgeneration during initlp */
6055  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
6056 
6057  consdata = SCIPconsGetData(cons);
6058  assert(consdata != NULL);
6059  assert(consdata->nlinvars > 0);
6060  assert(consdata->factorleft != NULL);
6061  assert(consdata->factorright != NULL);
6062 
6063  *success = FALSE;
6064  *cutlhs = -SCIPinfinity(scip); /* for compiler */
6065 
6066  /* write violated constraints as factorleft * factorright '==' rhs
6067  * where rhs are constraint sides - activity bound of linear part
6068  */
6069  rhsminactivity = consdata->lhs;
6070  rhsmaxactivity = consdata->rhs;
6071  rhsrefactivity = (violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
6072 
6073  for( i = 0; i < consdata->nlinvars; ++i )
6074  {
6075  if( !SCIPisInfinity(scip, -rhsminactivity) )
6076  {
6077  if( consdata->lincoefs[i] < 0.0 )
6078  {
6079  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6080  rhsminactivity = -SCIPinfinity(scip);
6081  else
6082  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6083  }
6084  else
6085  {
6086  assert(consdata->lincoefs[i] > 0.0);
6087  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6088  rhsminactivity = -SCIPinfinity(scip);
6089  else
6090  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6091  }
6092  }
6093  if( !SCIPisInfinity(scip, rhsmaxactivity) )
6094  {
6095  if( consdata->lincoefs[i] < 0.0 )
6096  {
6097  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6098  rhsmaxactivity = SCIPinfinity(scip);
6099  else
6100  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6101  }
6102  else
6103  {
6104  assert(consdata->lincoefs[i] > 0.0);
6105  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6106  rhsmaxactivity = SCIPinfinity(scip);
6107  else
6108  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6109  }
6110  }
6111  rhsrefactivity -= consdata->lincoefs[i] * SCIPgetSolVal(scip, sol, consdata->linvars[i]);
6112  }
6113 
6114  if( SCIPisInfinity(scip, -rhsminactivity) || SCIPisInfinity(scip, rhsmaxactivity) )
6115  {
6116  /* if right hand side is unbounded, then cannot do LTI */
6117  return SCIP_OKAY;
6118  }
6119 
6120  if( !SCIPisFeasPositive(scip, rhsminactivity) && !SCIPisFeasNegative(scip, rhsmaxactivity) )
6121  {
6122  /* if right hand side has 0 inside activity, then cannot do anything
6123  * if it has 0.0 as min or max activity, then a usual McCormick should be sufficient, too
6124  */
6125  return SCIP_OKAY;
6126  }
6127 
6128  leftminactivity = consdata->factorleft[consdata->nquadvars];
6129  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
6130  leftrefactivity = consdata->factorleft[consdata->nquadvars];
6131  rightminactivity = consdata->factorright[consdata->nquadvars];
6132  rightmaxactivity = consdata->factorright[consdata->nquadvars];
6133  rightrefactivity = consdata->factorright[consdata->nquadvars];
6134  for( i = 0; i < consdata->nquadvars; ++i )
6135  {
6136  if( !SCIPisInfinity(scip, -leftminactivity) )
6137  {
6138  if( consdata->factorleft[i] > 0.0 )
6139  {
6140  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6141  leftminactivity = -SCIPinfinity(scip);
6142  else
6143  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6144  }
6145  else if( consdata->factorleft[i] < 0.0 )
6146  {
6147  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6148  leftminactivity = -SCIPinfinity(scip);
6149  else
6150  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6151  }
6152  }
6153  if( !SCIPisInfinity(scip, leftmaxactivity) )
6154  {
6155  if( consdata->factorleft[i] > 0.0 )
6156  {
6157  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6158  leftmaxactivity = SCIPinfinity(scip);
6159  else
6160  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6161  }
6162  else if( consdata->factorleft[i] < 0.0 )
6163  {
6164  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6165  leftmaxactivity = SCIPinfinity(scip);
6166  else
6167  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6168  }
6169  }
6170  leftrefactivity += consdata->factorleft[i] * ref[i];
6171 
6172  if( !SCIPisInfinity(scip, -rightminactivity) )
6173  {
6174  if( consdata->factorright[i] > 0.0 )
6175  {
6176  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6177  rightminactivity = -SCIPinfinity(scip);
6178  else
6179  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6180  }
6181  else if( consdata->factorright[i] < 0.0 )
6182  {
6183  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6184  rightminactivity = -SCIPinfinity(scip);
6185  else
6186  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6187  }
6188  }
6189  if( !SCIPisInfinity(scip, rightmaxactivity) )
6190  {
6191  if( consdata->factorright[i] > 0.0 )
6192  {
6193  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6194  rightmaxactivity = SCIPinfinity(scip);
6195  else
6196  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6197  }
6198  else if( consdata->factorright[i] < 0.0 )
6199  {
6200  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6201  rightmaxactivity = SCIPinfinity(scip);
6202  else
6203  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6204  }
6205  }
6206  rightrefactivity += consdata->factorright[i] * ref[i];
6207  }
6208 
6209  /* if activities exceed "opposite" infinity, huge bounds seem to be involved, for which the below method is not prepared */
6210  if( SCIPisInfinity(scip, leftminactivity) || SCIPisInfinity(scip, -leftmaxactivity) ||
6211  SCIPisInfinity(scip, rightminactivity) || SCIPisInfinity(scip, -rightmaxactivity) )
6212  return SCIP_OKAY;
6213 
6214  /* if any of the factors is essentially fixed, give up and do usual method (numerically less sensitive, I hope) */
6215  if( SCIPisRelEQ(scip, leftminactivity, leftmaxactivity) || SCIPisRelEQ(scip, rightminactivity, rightmaxactivity) )
6216  return SCIP_OKAY;
6217 
6218  /* success can only be expected for separation of violated x*y <= w, assuming x>=0, y>=0
6219  * @todo we should check this early? */
6220 
6221  /* call Couenne magic */
6223  leftminactivity, leftmaxactivity, leftrefactivity,
6224  rightminactivity, rightmaxactivity, rightrefactivity,
6225  rhsminactivity, rhsmaxactivity, rhsrefactivity,
6226  &coefleft, &coefright, &coefrhs, cutlhs,
6227  success);
6228 
6229  if( !*success )
6230  return SCIP_OKAY;
6231 
6232  SCIPdebugMessage("LTI for x[%g,%g] * y[%g,%g] = w[%g,%g]: %gx %+gy %+gw >= %g; feas: %g\n",
6233  leftminactivity, leftmaxactivity, rightminactivity, rightmaxactivity, rhsminactivity, rhsmaxactivity,
6234  coefleft, coefright, coefrhs, *cutlhs,
6235  coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity - *cutlhs
6236  );
6237 
6238  if( coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity >= *cutlhs )
6239  {
6240  SCIPdebugMessage("does not cutoff point? :-(\n");
6241  *success = FALSE;
6242  return SCIP_OKAY;
6243  }
6244 
6245  /* setup cut coefs for
6246  * coefleft * leftfactor + coefright * rightfactor + coefrhs * w >= cutlhs, where conslhs - lincoefs <= w <= consrhs - lincoefs
6247  */
6248  for( i = 0; i < consdata->nquadvars; ++i )
6249  cutcoefquad[i] = coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i];
6250  assert(i == consdata->nquadvars);
6251  *cutlhs -= coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i];
6252 
6253  SCIP_CALL( SCIPallocBufferArray(scip, cutcoeflin, consdata->nlinvars) );
6254  for( i = 0; i < consdata->nlinvars; ++i )
6255  (*cutcoeflin)[i] = -coefrhs * consdata->lincoefs[i];
6256  if( coefrhs > 0.0 )
6257  {
6258  /* use coefrhs * w <= coefrhs * (consrhs - lincoefs) */
6259  assert(!SCIPisInfinity(scip, consdata->rhs));
6260  *cutlhs -= coefrhs * consdata->rhs;
6261  }
6262  else
6263  {
6264  /* use coefrhs * w <= coeflhs * (conslhs - lincoefs) */
6265  assert(!SCIPisInfinity(scip, -consdata->lhs));
6266  *cutlhs -= coefrhs * consdata->lhs;
6267  }
6268 
6269  *cutrhs = SCIPinfinity(scip);
6270  *islocal = TRUE;
6271 
6272  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_lti_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6273 
6274  *success = TRUE;
6275 
6276  return SCIP_OKAY;
6277 }
6278 
6279 /** computes coefficients of linearization of a square term in a reference point */
6281  SCIP* scip, /**< SCIP data structure */
6282  SCIP_Real sqrcoef, /**< coefficient of square term */
6283  SCIP_Real refpoint, /**< point where to linearize */
6284  SCIP_Bool isint, /**< whether corresponding variable is a discrete variable, and thus linearization could be moved */
6285  SCIP_Real* lincoef, /**< buffer to add coefficient of linearization */
6286  SCIP_Real* linconstant, /**< buffer to add constant of linearization */
6287  SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
6288  )
6289 {
6290  assert(scip != NULL);
6291  assert(lincoef != NULL);
6292  assert(linconstant != NULL);
6293  assert(success != NULL);
6294 
6295  if( sqrcoef == 0.0 )
6296  return;
6297 
6298  if( SCIPisInfinity(scip, REALABS(refpoint)) )
6299  {
6300  *success = FALSE;
6301  return;
6302  }
6303 
6304  if( !isint || SCIPisIntegral(scip, refpoint) )
6305  {
6306  SCIP_Real tmp;
6307 
6308  /* sqrcoef * x^2 -> tangent in refpoint = sqrcoef * 2 * refpoint * (x - refpoint) */
6309 
6310  tmp = sqrcoef * refpoint;
6311 
6312  if( SCIPisInfinity(scip, 2.0 * REALABS(tmp)) )
6313  {
6314  *success = FALSE;
6315  return;
6316  }
6317 
6318  *lincoef += 2.0 * tmp;
6319  tmp *= refpoint;
6320  *linconstant -= tmp;
6321  }
6322  else
6323  {
6324  /* sqrcoef * x^2 -> secant between f=floor(refpoint) and f+1 = sqrcoef * (f^2 + ((f+1)^2 - f^2) * (x-f)) = sqrcoef * (-f*(f+1) + (2*f+1)*x) */
6325  SCIP_Real f;
6326  SCIP_Real coef;
6327  SCIP_Real constant;
6328 
6329  f = SCIPfloor(scip, refpoint);
6330 
6331  coef = sqrcoef * (2.0 * f + 1.0);
6332  constant = -sqrcoef * f * (f + 1.0);
6333 
6334  if( SCIPisInfinity(scip, REALABS(coef)) || SCIPisInfinity(scip, REALABS(constant)) )
6335  {
6336  *success = FALSE;
6337  return;
6338  }
6339 
6340  *lincoef += coef;
6341  *linconstant += constant;
6342  }
6343 }
6344 
6345 /** computes coefficients of secant of a square term */
6346 void SCIPaddSquareSecant(
6347  SCIP* scip, /**< SCIP data structure */
6348  SCIP_Real sqrcoef, /**< coefficient of square term */
6349  SCIP_Real lb, /**< lower bound on variable */
6350  SCIP_Real ub, /**< upper bound on variable */
6351  SCIP_Real refpoint, /**< point for which to compute value of linearization */
6352  SCIP_Real* lincoef, /**< buffer to add coefficient of secant */
6353  SCIP_Real* linconstant, /**< buffer to add constant of secant */
6354  SCIP_Bool* success /**< buffer to set to FALSE if secant has failed due to large numbers or unboundedness */
6355  )
6356 {
6357  SCIP_Real coef;
6358  SCIP_Real constant;
6359 
6360  assert(scip != NULL);
6361  assert(!SCIPisInfinity(scip, lb));
6362  assert(!SCIPisInfinity(scip, -ub));
6363  assert(SCIPisLE(scip, lb, ub));
6364  assert(SCIPisLE(scip, lb, refpoint));
6365  assert(SCIPisGE(scip, ub, refpoint));
6366  assert(lincoef != NULL);
6367  assert(linconstant != NULL);
6368  assert(success != NULL);
6369 
6370  if( sqrcoef == 0.0 )
6371  return;
6372 
6373  if( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
6374  {
6375  /* unboundedness */
6376  *success = FALSE;
6377  return;
6378  }
6379 
6380  /* sqrcoef * x^2 -> sqrcoef * (lb * lb + (ub*ub - lb*lb)/(ub-lb) * (x-lb)) = sqrcoef * (lb*lb + (ub+lb)*(x-lb)) = sqrcoef * ((lb+ub)*x - lb*ub) */
6381 
6382  coef = sqrcoef * (lb + ub);
6383  constant = -sqrcoef * lb * ub;
6384  if( SCIPisInfinity(scip, REALABS(coef)) || SCIPisInfinity(scip, REALABS(constant)) )
6385  {
6386  *success = FALSE;
6387  return;
6388  }
6389 
6390  *lincoef += coef;
6391  *linconstant += constant;
6392 }
6393 
6394 /** computes coefficients of linearization of a bilinear term in a reference point */
6396  SCIP* scip, /**< SCIP data structure */
6397  SCIP_Real bilincoef, /**< coefficient of bilinear term */
6398  SCIP_Real refpointx, /**< point where to linearize first variable */
6399  SCIP_Real refpointy, /**< point where to linearize second variable */
6400  SCIP_Real* lincoefx, /**< buffer to add coefficient of first variable in linearization */
6401  SCIP_Real* lincoefy, /**< buffer to add coefficient of second variable in linearization */
6402  SCIP_Real* linconstant, /**< buffer to add constant of linearization */
6403  SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
6404  )
6405 {
6406  SCIP_Real constant;
6407 
6408  assert(scip != NULL);
6409  assert(lincoefx != NULL);
6410  assert(lincoefy != NULL);
6411  assert(linconstant != NULL);
6412  assert(success != NULL);
6413 
6414  if( bilincoef == 0.0 )
6415  return;
6416 
6417  if( SCIPisInfinity(scip, REALABS(refpointx)) || SCIPisInfinity(scip, REALABS(refpointy)) )
6418  {
6419  *success = FALSE;
6420  return;
6421  }
6422 
6423  /* bilincoef * x * y -> bilincoef * (refpointx * refpointy + refpointy * (x - refpointx) + refpointx * (y - refpointy))
6424  * = -bilincoef * refpointx * refpointy + bilincoef * refpointy * x + bilincoef * refpointx * y
6425  */
6426 
6427  constant = -bilincoef * refpointx * refpointy;
6428 
6429  if( SCIPisInfinity(scip, REALABS(bilincoef * refpointx)) || SCIPisInfinity(scip, REALABS(bilincoef * refpointy)) || SCIPisInfinity(scip, REALABS(constant)) )
6430  {
6431  *success = FALSE;
6432  return;
6433  }
6434 
6435  *lincoefx += bilincoef * refpointy;
6436  *lincoefy += bilincoef * refpointx;
6437  *linconstant += constant;
6438 }
6439 
6440 /** computes coefficients of McCormick under- or overestimation of a bilinear term */
6442  SCIP* scip, /**< SCIP data structure */
6443  SCIP_Real bilincoef, /**< coefficient of bilinear term */
6444  SCIP_Real lbx, /**< lower bound on first variable */
6445  SCIP_Real ubx, /**< upper bound on first variable */
6446  SCIP_Real refpointx, /**< reference point for first variable */
6447  SCIP_Real lby, /**< lower bound on second variable */
6448  SCIP_Real uby, /**< upper bound on second variable */
6449  SCIP_Real refpointy, /**< reference point for second variable */
6450  SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
6451  SCIP_Real* lincoefx, /**< buffer to add coefficient of first variable in linearization */
6452  SCIP_Real* lincoefy, /**< buffer to add coefficient of second variable in linearization */
6453  SCIP_Real* linconstant, /**< buffer to add constant of linearization */
6454  SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
6455  )
6456 {
6457  SCIP_Real constant;
6458  SCIP_Real coefx;
6459  SCIP_Real coefy;
6460 
6461  assert(scip != NULL);
6462  assert(!SCIPisInfinity(scip, lbx));
6463  assert(!SCIPisInfinity(scip, -ubx));
6464  assert(!SCIPisInfinity(scip, lby));
6465  assert(!SCIPisInfinity(scip, -uby));
6466  assert(SCIPisLE(scip, lbx, ubx));
6467  assert(SCIPisLE(scip, lby, uby));
6468  assert(SCIPisLE(scip, lbx, refpointx));
6469  assert(SCIPisGE(scip, ubx, refpointx));
6470  assert(SCIPisLE(scip, lby, refpointy));
6471  assert(SCIPisGE(scip, uby, refpointy));
6472  assert(lincoefx != NULL);
6473  assert(lincoefy != NULL);
6474  assert(linconstant != NULL);
6475  assert(success != NULL);
6476 
6477  if( bilincoef == 0.0 )
6478  return;
6479 
6480  if( overestimate )
6481  bilincoef = -bilincoef;
6482 
6483  if( SCIPisRelEQ(scip, lbx, ubx) && SCIPisRelEQ(scip, lby, uby) )
6484  {
6485  /* both x and y are mostly fixed */
6486  SCIP_Real cand1;
6487  SCIP_Real cand2;
6488  SCIP_Real cand3;
6489  SCIP_Real cand4;
6490 
6491  coefx = 0.0;
6492  coefy = 0.0;
6493 
6494  /* estimate x * y by constant */
6495  cand1 = lbx * lby;
6496  cand2 = lbx * uby;
6497  cand3 = ubx * lby;
6498  cand4 = ubx * uby;
6499 
6500  /* take most conservative value for underestimator */
6501  if( bilincoef < 0.0 )
6502  constant = bilincoef * MAX( MAX(cand1, cand2), MAX(cand3, cand4) );
6503  else
6504  constant = bilincoef * MIN( MIN(cand1, cand2), MIN(cand3, cand4) );
6505  }
6506  else if( bilincoef > 0.0 )
6507  {
6508  /* either x or y is not fixed and coef > 0.0 */
6509  if( !SCIPisInfinity(scip, -lbx) && !SCIPisInfinity(scip, -lby) &&
6510  (SCIPisInfinity(scip, ubx) || SCIPisInfinity(scip, uby) || (uby - refpointy) * (ubx - refpointx) >= (refpointy - lby) * (refpointx - lbx)) )
6511  {
6512  if( SCIPisRelEQ(scip, lbx, ubx) )
6513  {
6514  /* x*y = lbx * y + (x-lbx) * y >= lbx * y + (x-lbx) * lby >= lbx * y + min{(ubx-lbx) * lby, 0 * lby} */
6515  coefx = 0.0;
6516  coefy = bilincoef * lbx;
6517  constant = bilincoef * (lby < 0.0 ? (ubx-lbx) * lby : 0.0);
6518  }
6519  else if( SCIPisRelEQ(scip, lby, uby) )
6520  {
6521  /* x*y = lby * x + (y-lby) * x >= lby * x + (y-lby) * lbx >= lby * x + min{(uby-lby) * lbx, 0 * lbx} */
6522  coefx = bilincoef * lby;
6523  coefy = 0.0;
6524  constant = bilincoef * (lbx < 0.0 ? (uby-lby) * lbx : 0.0);
6525  }
6526  else
6527  {
6528  coefx = bilincoef * lby;
6529  coefy = bilincoef * lbx;
6530  constant = -bilincoef * lbx * lby;
6531  }
6532  }
6533  else if( !SCIPisInfinity(scip, ubx) && !SCIPisInfinity(scip, uby) )
6534  {
6535  if( SCIPisRelEQ(scip, lbx, ubx) )
6536  {
6537  /* x*y = ubx * y + (x-ubx) * y >= ubx * y + (x-ubx) * uby >= ubx * y + min{(lbx-ubx) * uby, 0 * uby} */
6538  coefx = 0.0;
6539  coefy = bilincoef * ubx;
6540  constant = bilincoef * (uby > 0.0 ? (lbx-ubx) * uby : 0.0);
6541  }
6542  else if( SCIPisRelEQ(scip, lby, uby) )
6543  {
6544  /* x*y = uby * x + (y-uby) * x >= uby * x + (y-uby) * ubx >= uby * x + min{(lby-uby) * ubx, 0 * ubx} */
6545  coefx = bilincoef * uby;
6546  coefy = 0.0;
6547  constant = bilincoef * (ubx > 0.0 ? (lby-uby) * ubx : 0.0);
6548  }
6549  else
6550  {
6551  coefx = bilincoef * uby;
6552  coefy = bilincoef * ubx;
6553  constant = -bilincoef * ubx * uby;
6554  }
6555  }
6556  else
6557  {
6558  *success = FALSE;
6559  return;
6560  }
6561  }
6562  else
6563  {
6564  /* either x or y is not fixed and coef < 0.0 */
6565  if( !SCIPisInfinity(scip, ubx) && !SCIPisInfinity(scip, -lby) &&
6566  (SCIPisInfinity(scip, -lbx) || SCIPisInfinity(scip, uby) || (ubx - lbx) * (refpointy - lby) <= (uby - lby) * (refpointx - lbx)) )
6567  {
6568  if( SCIPisRelEQ(scip, lbx, ubx) )
6569  {
6570  /* x*y = ubx * y + (x-ubx) * y <= ubx * y + (x-ubx) * lby <= ubx * y + max{(lbx-ubx) * lby, 0 * lby} */
6571  coefx = 0.0;
6572  coefy = bilincoef * ubx;
6573  constant = bilincoef * (lby < 0.0 ? (lbx - ubx) * lby : 0.0);
6574  }
6575  else if( SCIPisRelEQ(scip, lby, uby) )
6576  {
6577  /* x*y = lby * x + (y-lby) * x <= lby * x + (y-lby) * ubx <= lby * x + max{(uby-lby) * ubx, 0 * ubx} */
6578  coefx = bilincoef * lby;
6579  coefy = 0.0;
6580  constant = bilincoef * (ubx > 0.0 ? (uby - lby) * ubx : 0.0);
6581  }
6582  else
6583  {
6584  coefx = bilincoef * lby;
6585  coefy = bilincoef * ubx;
6586  constant = -bilincoef * ubx * lby;
6587  }
6588  }
6589  else if( !SCIPisInfinity(scip, -lbx) && !SCIPisInfinity(scip, uby) )
6590  {
6591  if( SCIPisRelEQ(scip, lbx, ubx) )
6592  {
6593  /* x*y = lbx * y + (x-lbx) * y <= lbx * y + (x-lbx) * uby <= lbx * y + max{(ubx-lbx) * uby, 0 * uby} */
6594  coefx = 0.0;
6595  coefy = bilincoef * lbx;
6596  constant = bilincoef * (uby > 0.0 ? (ubx-lbx) * uby : 0.0);
6597  }
6598  else if( SCIPisRelEQ(scip, lby, uby) )
6599  {
6600  /* x*y = uby * x + (y-uby) * x <= uby * x + (y-uby) * lbx <= uby * x + max{(lby-uby) * lbx, 0 * lbx} */
6601  coefx = bilincoef * uby;
6602  coefy = 0.0;
6603  constant = bilincoef * (lbx < 0.0 ? (lby-uby) * lbx : 0.0);
6604  }
6605  else
6606  {
6607  coefx = bilincoef * uby;
6608  coefy = bilincoef * lbx;
6609  constant = -bilincoef * lbx * uby;
6610  }
6611  }
6612  else
6613  {
6614  *success = FALSE;
6615  return;
6616  }
6617  }
6618 
6619  if( SCIPisInfinity(scip, REALABS(coefx)) || SCIPisInfinity(scip, REALABS(coefy)) || SCIPisInfinity(scip, REALABS(constant)) )
6620  {
6621  *success = FALSE;
6622  return;
6623  }
6624 
6625  if( overestimate )
6626  {
6627  coefx = -coefx;
6628  coefy = -coefy;
6629  constant = -constant;
6630  }
6631 
6632  /* SCIPdebugMessage("%.20g * x[%.20g,%.20g] * y[%.20g,%.20g] %c= %.20g * x %+.20g * y %+.20g\n", bilincoef, lbx, ubx, lby, uby,
6633  overestimate ? '<' : '>', coefx, coefy, constant); */
6634 
6635  *lincoefx += coefx;
6636  *lincoefy += coefy;
6637  *linconstant += constant;
6638 }
6639 
6640 /** computes cut coefficients by linearizing a quadratic function */
6641 static
6643  SCIP* scip, /**< SCIP data structure */
6644  SCIP_CONS* cons, /**< constraint */
6645  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6646  SCIP_Real* ref, /**< reference solution where to generate the cut */
6647  SCIP_Real* coef, /**< array to store cut coefficients w.r.t. quadratic variables */
6648  SCIP_Real* lhs, /**< buffer to store left-hand-side of cut */
6649  SCIP_Real* rhs, /**< buffer to store right-hand-side of cut */
6650  SCIP_Bool* islocal, /**< buffer to set to TRUE if local bounds were used */
6651  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6652  char* name /**< buffer to store name for cut */
6653  )
6654 {
6655  SCIP_CONSDATA* consdata;
6656  SCIP_BILINTERM* bilinterm;
6657  SCIP_Real constant;
6658  SCIP_VAR* var;
6659  int var2pos;
6660  int j;
6661  int k;
6662 
6663  assert(scip != NULL);
6664  assert(cons != NULL);
6665  assert(ref != NULL);
6666  assert(coef != NULL);
6667  assert(lhs != NULL);
6668  assert(rhs != NULL);
6669  assert(islocal != NULL);
6670  assert(success != NULL);
6671 
6672  consdata = SCIPconsGetData(cons);
6673  assert(consdata != NULL);
6674 
6675  constant = 0.0;
6676  BMSclearMemoryArray(coef, consdata->nquadvars);
6677  *success = TRUE;
6678 
6679  /* do first-order Taylor for each term */
6680  for( j = 0; j < consdata->nquadvars && *success; ++j )
6681  {
6682  /* initialize coefficients to linear coefficients of quadratic variables */
6683  coef[j] += consdata->quadvarterms[j].lincoef;
6684 
6685  /* add linearization of square term */
6686  var = consdata->quadvarterms[j].var;
6687  SCIPaddSquareLinearization(scip, consdata->quadvarterms[j].sqrcoef, ref[j],
6688  consdata->quadvarterms[j].nadjbilin == 0 && SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef[j], &constant, success);
6689 
6690  /* add linearization of bilinear terms that have var as first variable */
6691  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6692  {
6693  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6694  if( bilinterm->var1 != var )
6695  continue;
6696  assert(bilinterm->var2 != var);
6697  assert(consdata->sepabilinvar2pos != NULL);
6698 
6699  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6700  assert(var2pos >= 0);
6701  assert(var2pos < consdata->nquadvars);
6702  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6703 
6704  SCIPaddBilinLinearization(scip, bilinterm->coef, ref[j], ref[var2pos], &coef[j], &coef[var2pos], &constant, success);
6705  }
6706  }
6707 
6708  if( !*success )
6709  {
6710  SCIPdebugMessage("no success in linearization of <%s> in reference point\n", SCIPconsGetName(cons));
6711  return SCIP_OKAY;
6712  }
6713 
6714  if( violside == SCIP_SIDETYPE_LEFT )
6715  {
6716  *lhs = consdata->lhs - constant;
6717  *rhs = SCIPinfinity(scip);
6718  }
6719  else
6720  {
6721  *lhs = -SCIPinfinity(scip);
6722  *rhs = consdata->rhs - constant;
6723  }
6724 
6725  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_side%d_linearization_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6726 
6727  return SCIP_OKAY;
6728 }
6729 
6730 /** computes cut coefficients for a nonconvex quadratic function */
6731 static
6733  SCIP* scip, /**< SCIP data structure */
6734  SCIP_CONS* cons, /**< constraint */
6735  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6736  SCIP_Real* ref, /**< reference solution where to generate the cut */
6737  SCIP_Real* coef, /**< array to store cut coefficients w.r.t. quadratic variables */
6738  SCIP_Real* lhs, /**< buffer to store left-hand-side of cut */
6739  SCIP_Real* rhs, /**< buffer to store right-hand-side of cut */
6740  SCIP_Bool* islocal, /**< buffer to set to TRUE if local bounds were used */
6741  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6742  char* name /**< buffer to store name for cut */
6743  )
6744 {
6745  SCIP_CONSDATA* consdata;
6746  SCIP_BILINTERM* bilinterm;
6747  SCIP_Real constant;
6748  SCIP_Real sqrcoef;
6749  SCIP_VAR* var;
6750  int var2pos;
6751  int j;
6752  int k;
6753 
6754  assert(scip != NULL);
6755  assert(cons != NULL);
6756  assert(ref != NULL);
6757  assert(coef != NULL);
6758  assert(lhs != NULL);
6759  assert(rhs != NULL);
6760  assert(islocal != NULL);
6761  assert(success != NULL);
6762 
6763  consdata = SCIPconsGetData(cons);
6764  assert(consdata != NULL);
6765 
6766  *islocal = TRUE;
6767  constant = 0.0;
6768  BMSclearMemoryArray(coef, consdata->nquadvars);
6769  *success = TRUE;
6770 
6771  /* underestimate (secant, McCormick) or linearize each term separately */
6772  for( j = 0; j < consdata->nquadvars && *success; ++j )
6773  {
6774  /* initialize coefficients to linear coefficients of quadratic variables */
6775  coef[j] += consdata->quadvarterms[j].lincoef;
6776 
6777  var = consdata->quadvarterms[j].var;
6778 
6779  sqrcoef = consdata->quadvarterms[j].sqrcoef;
6780  if( sqrcoef != 0.0 )
6781  {
6782  if( (violside == SCIP_SIDETYPE_LEFT && sqrcoef <= 0.0) || (violside == SCIP_SIDETYPE_RIGHT && sqrcoef > 0.0) )
6783  {
6784  /* convex -> linearize */
6785  SCIPaddSquareLinearization(scip, sqrcoef, ref[j], SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef[j],
6786  &constant, success);
6787  }
6788  else
6789  {
6790  /* not convex -> secant approximation */
6791  SCIPaddSquareSecant(scip, sqrcoef, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j], &coef[j],
6792  &constant, success);
6793  }
6794  }
6795 
6796  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6797  {
6798  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6799  if( bilinterm->var1 != var )
6800  continue;
6801  assert(bilinterm->var2 != var);
6802  assert(consdata->sepabilinvar2pos != NULL);
6803 
6804  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6805  assert(var2pos >= 0);
6806  assert(var2pos < consdata->nquadvars);
6807  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6808 
6809  SCIPaddBilinMcCormick(scip, bilinterm->coef,
6810  SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j],
6811  SCIPvarGetLbLocal(bilinterm->var2), SCIPvarGetUbLocal(bilinterm->var2), ref[var2pos],
6812  violside == SCIP_SIDETYPE_LEFT, &coef[j], &coef[var2pos], &constant, success);
6813  }
6814  }
6815 
6816  if( !*success )
6817  {
6818  SCIPdebugMessage("no success to find estimator for nonconvex <%s>\n", SCIPconsGetName(cons));
6819  return SCIP_OKAY;
6820  }
6821 
6822  if( violside == SCIP_SIDETYPE_LEFT )
6823  {
6824  *lhs = consdata->lhs - constant;
6825  *rhs = SCIPinfinity(scip);
6826  }
6827  else
6828  {
6829  *lhs = -SCIPinfinity(scip);
6830  *rhs = consdata->rhs - constant;
6831  }
6832 
6833  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_side%d_estimation_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6834 
6835  return SCIP_OKAY;
6836 }
6837 
6838 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a given reference point */
6839 static
6841  SCIP* scip, /**< SCIP data structure */
6842  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6843  SCIP_CONS* cons, /**< constraint */
6844  SCIP_Real* ref, /**< reference solution where to generate the cut */
6845  SCIP_SOL* sol, /**< point that we aim to separate, or NULL for LP solution */
6846  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6847  SCIP_ROW** row, /**< storage for cut */
6848  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
6849  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
6850  SCIP_Real minefficacy /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
6851  )
6852 {
6853  SCIP_CONSHDLRDATA* conshdlrdata;
6854  SCIP_CONSDATA* consdata;
6855  SCIP_Bool islocal;
6856  char cutname[SCIP_MAXSTRLEN];
6857  SCIP_Real* lincoefs;
6858  SCIP_Real* coef;
6859  SCIP_Real lhs;
6860  SCIP_Real rhs;
6861  SCIP_Bool success;
6862  SCIP_Real mincoef;
6863  SCIP_Real maxcoef;
6864  SCIP_Real lincoefsmax;
6865  SCIP_Real lincoefsmin;
6866  SCIP_Real viol;
6867  SCIP_Real rowefficacy;
6868  SCIP_VAR* var;
6869  int j;
6870 
6871  assert(scip != NULL);
6872  assert(conshdlr != NULL);
6873  assert(cons != NULL);
6874  assert(ref != NULL);
6875  assert(row != NULL);
6876 
6877  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6878  assert(conshdlrdata != NULL);
6879 
6880  consdata = SCIPconsGetData(cons);
6881  assert(consdata != NULL);
6882  assert(violside != SCIP_SIDETYPE_LEFT || !SCIPisInfinity(scip, -consdata->lhs));
6883  assert(violside != SCIP_SIDETYPE_RIGHT || !SCIPisInfinity(scip, consdata->rhs));
6884 
6885  *row = NULL;
6886  SCIP_CALL( SCIPallocBufferArray(scip, &coef, consdata->nquadvars) );
6887  lincoefs = consdata->lincoefs;
6888  lincoefsmax = consdata->lincoefsmax;
6889  lincoefsmin = consdata->lincoefsmin;
6890  islocal = SCIPconsIsLocal(cons);
6891  success = FALSE;
6892  lhs = -SCIPinfinity(scip);
6893  rhs = SCIPinfinity(scip);
6894  cutname[0] = '\0';
6895  rowefficacy = 0.0;
6896 
6897  /* if constraint function is factorable, then try to use factorable form to generate cut */
6898  if( consdata->factorleft != NULL )
6899  {
6900  if( consdata->nlinvars == 0 )
6901  {
6902  SCIP_CALL( generateCutFactorable(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6903  }
6904  else if( sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
6905  {
6906  int i;
6907 
6908  /* generateCutLTI needs reference values also for the linear variables, which we only have if sol is given or LP has been solved */
6909  SCIP_CALL( generateCutLTI(scip, cons, violside, ref, sol, &lincoefs, coef, &lhs, &rhs, &islocal, &success, cutname) );
6910 
6911  /* in case of LTI cuts, we have to recompute the min and max of lincoefs, since they may have been modified */
6912  for( i = 0; i < consdata->nlinvars; ++i )
6913  {
6914  if( REALABS(lincoefs[i]) > lincoefsmax )
6915  lincoefsmax = REALABS(lincoefs[i]);
6916  if( REALABS(lincoefs[i]) < lincoefsmin )
6917  lincoefsmin = REALABS(lincoefs[i]);
6918  }
6919  }
6920  }
6921 
6922  /* if constraint is not factorable or failed to generate cut, try default method */
6923  if( !success )
6924  {
6925  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
6926 
6927  if( (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave) || (violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex) )
6928  {
6929  SCIP_CALL( generateCutConvex(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6930  }
6931  else
6932  {
6933  SCIP_CALL( generateCutNonConvex(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6934  }
6935  }
6936 
6937  /* cut should be one-sided, if any found */
6938  assert(!success || SCIPisInfinity(scip, -lhs) || SCIPisInfinity(scip, rhs));
6939 
6940  /* check if range of cut coefficients is ok
6941  * compute cut activity and violation in sol
6942  */
6943  mincoef = 0.0; /* only for lint */
6944  maxcoef = 0.0; /* only for compiler */
6945  viol = 0.0; /* only for compiler */
6946  if( success )
6947  {
6948  SCIP_Real constant;
6949  SCIP_Real abscoef;
6950  SCIP_Real roundcoef;
6951  int mincoefidx;
6952  SCIP_Real refactivity;
6953  SCIP_Real refactivitylinpart;
6954 
6955  /* compute activity of linear part in sol, if required
6956  * it is required if we need to check or return cut efficacy, for some debug output below, and some assert
6957  * round almost integral coefficients in integers, since this will happen when adding coefs to row (see comments below)
6958  */
6959  refactivitylinpart = 0.0;
6960 #if !defined(SCIP_DEBUG)
6961  if( !SCIPisInfinity(scip, -minefficacy) || efficacy != NULL )
6962 #endif
6963  for( j = 0; j < consdata->nlinvars; ++j )
6964  /* Loose variable have the best bound as LP solution value.
6965  * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
6966  * When this happens, their LP solution value changes to 0.0!
6967  * So when calculating the row activity, we treat loose variable as if they were already column variables.
6968  */
6969  if( SCIPvarGetStatus(consdata->linvars[j]) != SCIP_VARSTATUS_LOOSE )
6970  refactivitylinpart += (SCIPisIntegral(scip, lincoefs[j]) ? SCIPround(scip, lincoefs[j]) : lincoefs[j]) * SCIPgetSolVal(scip, sol, consdata->linvars[j]);
6971 
6972  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
6973 
6974  constant = 0.0;
6975  do
6976  {
6977  refactivity = refactivitylinpart;
6978  mincoefidx = -1;
6979  mincoef = lincoefsmin;
6980  maxcoef = lincoefsmax;
6981 
6982  for( j = 0; j < consdata->nquadvars; ++j )
6983  {
6984  /* coefficients smaller than epsilon are rounded to 0.0 when added to row
6985  * further, coefficients very close to integral values are rounded to integers when added to LP
6986  * both cases can be problematic if variable value is very large (bad numerics)
6987  * thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible)
6988  * i.e., estimate coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x)
6989  * if required bound of x is not finite, then do nothing
6990  */
6991  roundcoef = SCIPround(scip, coef[j]);
6992  if( SCIPisEQ(scip, coef[j], roundcoef) && coef[j] != roundcoef ) /*lint !e777*/
6993  {
6994  SCIP_Real xbnd;
6995 
6996  var = consdata->quadvarterms[j].var;
6997  if( !SCIPisInfinity(scip, rhs) )
6998  if( islocal )
6999  xbnd = coef[j] > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
7000  else
7001  xbnd = coef[j] > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
7002  else
7003  if( islocal )
7004  xbnd = coef[j] > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
7005  else
7006  xbnd = coef[j] > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
7007 
7008  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
7009  {
7010  SCIPdebugMessage("var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g and add constant %g\n",
7011  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef[j], roundcoef, (coef[j]-roundcoef) * xbnd);
7012  constant += (coef[j]-roundcoef) * xbnd;
7013  coef[j] = roundcoef;
7014  }
7015  }
7016 
7017  if( coef[j] == 0.0 )
7018  continue;
7019 
7020  /* As above: When calculating the row activity, we treat loose variable as if they were already column variables. */
7021  if( SCIPvarGetStatus(consdata->quadvarterms[j].var) != SCIP_VARSTATUS_LOOSE )
7022  refactivity += coef[j] * SCIPgetSolVal(scip, sol, consdata->quadvarterms[j].var);
7023 
7024  abscoef = REALABS(coef[j]);
7025  if( abscoef < mincoef )
7026  {
7027  mincoef = abscoef;
7028  mincoefidx = j;
7029  }
7030  if( abscoef > maxcoef )
7031  maxcoef = abscoef;
7032  }
7033 
7034  if( maxcoef < mincoef )
7035  {
7036  /* if all coefficients are zero, then mincoef and maxcoef are still at their initial values
7037  * thus, skip cut generation if its boring
7038  */
7039  assert(maxcoef == 0.0); /*lint !e777 */
7040  assert(mincoef == SCIPinfinity(scip)); /*lint !e777 */
7041 
7042  if( !SCIPisFeasPositive(scip, lhs) && !SCIPisFeasNegative(scip, rhs) )
7043  {
7044  SCIPdebugMessage("skip cut for constraint <%s> since all coefficients are zero and it's always satisfied\n", SCIPconsGetName(cons));
7045  success = FALSE;
7046  }
7047  else
7048  {
7049  /* cut will cutoff node */
7050  }
7051 
7052  break;
7053  }
7054 
7055  if( maxcoef / mincoef > conshdlrdata->cutmaxrange )
7056  {
7057  SCIPdebugMessage("cut coefficients for constraint <%s> have very large range: mincoef = %g maxcoef = %g\n", SCIPconsGetName(cons), mincoef, maxcoef);
7058  if( mincoefidx >= 0 )
7059  {
7060  var = consdata->quadvarterms[mincoefidx].var;
7061  /* try to eliminate coefficient with minimal absolute value by weakening cut and try again
7062  * since we use local bounds, we need to make the row local if they are different from their global counterpart
7063  */
7064  if( ((coef[mincoefidx] > 0.0 && !SCIPisInfinity(scip, rhs)) || (coef[mincoefidx] < 0.0 && !SCIPisInfinity(scip, -lhs))) &&
7065  !SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
7066  {
7067  SCIPdebugMessage("eliminate coefficient %g for <%s> [%g, %g]\n", coef[mincoefidx], SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7068  constant += coef[mincoefidx] * SCIPvarGetLbLocal(var);
7069  coef[mincoefidx] = 0.0;
7070  islocal |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
7071  continue;
7072  }
7073  else if( ((coef[mincoefidx] < 0.0 && !SCIPisInfinity(scip, rhs)) || (coef[mincoefidx] > 0.0 && !SCIPisInfinity(scip, -lhs))) &&
7074  !SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
7075  {
7076  SCIPdebugMessage("eliminate coefficient %g for <%s> [%g, %g]\n", coef[mincoefidx], SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7077  constant += coef[mincoefidx] * SCIPvarGetUbLocal(var);
7078  coef[mincoefidx] = 0.0;
7079  islocal |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
7080  continue;
7081  }
7082  }
7083 
7084  SCIPdebugMessage("skip cut\n");
7085  success = FALSE;
7086  }
7087  break;
7088  }
7089  while( TRUE ); /*lint !e506 */
7090 
7091  if( !SCIPisInfinity(scip, -lhs) )
7092  {
7093  lhs -= constant;
7094  viol = lhs - refactivity;
7095  }
7096  if( !SCIPisInfinity(scip, rhs) )
7097  {
7098  rhs -= constant;
7099  viol = refactivity - rhs;
7100  }
7101  }
7102 
7103  if( success && SCIPisInfinity(scip, REALABS(lhs)) && SCIPisInfinity(scip, REALABS(rhs)) )
7104  {
7105  SCIPdebugMessage("skip cut for constraint <%s> because both sides are not finite: lhs = %g, rhs = %g\n", SCIPconsGetName(cons), lhs, rhs);
7106  success = FALSE;
7107  }
7108 
7109  /* check if reference point violates cut sufficiently */
7110  if( success )
7111  {
7112  rowefficacy = viol;
7113  switch( conshdlrdata->scaling )
7114  {
7115  case 'o' :
7116  break;
7117 
7118  case 'g' :
7119  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
7120  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too also we
7121  * use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium scaling) */
7122  rowefficacy /= MAX(1.0, maxcoef);
7123  break;
7124 
7125  case 's' :
7126  {
7127  SCIP_Real abslhs = REALABS(lhs);
7128 
7129  if( !SCIPisInfinity(scip, abslhs) )
7130  rowefficacy /= MAX(1.0, abslhs);
7131  else
7132  {
7133  SCIP_Real absrhs = REALABS(rhs);
7134 
7135  rowefficacy /= MAX(1.0, absrhs);
7136  }
7137 
7138  break;
7139  }
7140 
7141  default:
7142  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
7143  SCIPABORT();
7144  return SCIP_INVALIDDATA; /*lint !e527*/
7145  }
7146  }
7147 
7148  if( success && !SCIPisInfinity(scip, -minefficacy) && rowefficacy < minefficacy ) /*lint !e644*/
7149  {
7150  SCIPdebugMessage("skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), rowefficacy, minefficacy);
7151  success = FALSE;
7152  }
7153 
7154  /* generate row */
7155  if( success )
7156  {
7157  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, lhs, rhs, islocal && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
7158 
7159  /* add coefficients from linear part */
7160  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nlinvars, consdata->linvars, lincoefs) );
7161 
7162  /* add coefficients from quadratic part */
7163  assert(consdata->sepaquadvars != NULL || consdata->nquadvars == 0);
7164  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nquadvars, consdata->sepaquadvars, coef) );
7165 
7166  SCIPdebugMessage("found cut <%s>, lhs=%g, rhs=%g, mincoef=%g, maxcoef=%g, range=%g, nnz=%d, violation=%g, efficacy=%g\n",
7167  SCIProwGetName(*row), lhs, rhs,
7168  mincoef, maxcoef, maxcoef/mincoef,
7169  SCIProwGetNNonz(*row), viol, rowefficacy); /*lint !e414 */
7170 
7171  if( efficacy != NULL )
7172  {
7173  *efficacy = rowefficacy;
7174 
7175  /* check that our computed efficacy is > feastol, iff efficacy computed by row is > feastol
7176  * computing efficacy w.r.t. the LP solution makes only sense if the LP was solved to optimality (see bug 612)
7177  *
7178  * disabled these asserts as they can fail due to numerical reasons (cancelation when substracting big numbers),
7179  * as the order in which we add up the activity for the single terms can be different than the one that lp.c uses
7180  */
7181  /*
7182  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
7183  assert((conshdlrdata->scaling != 'g') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol)/MAX(1.0,SCIPgetRowMaxCoef(scip, *row)))));
7184  assert((conshdlrdata->scaling != 's') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol)/MAX(1.0,MIN(REALABS(lhs),REALABS(rhs))))));
7185  assert((conshdlrdata->scaling != 'o') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol))));
7186  */
7187  }
7188  }
7189 
7190  SCIPfreeBufferArray(scip, &coef);
7191 
7192  /* if coefficients for linear variables are different than those in constraint, then free array */
7193  if( lincoefs != consdata->lincoefs )
7194  {
7195  SCIPfreeBufferArray(scip, &lincoefs);
7196  }
7197 
7198  return SCIP_OKAY;
7199 }
7200 
7201 
7202 /** computes an interior point for the quadratic part of the convex constraint
7203  *
7204  * There are different methods for computing the interior point
7205  * - 'a'ny: solves min 0, f(x) <= rhs, x in bounds
7206  * - 'm'ost interior: solves min f(x), x in bounds
7207  *
7208  * @todo: other methods for computing an interior point?
7209  */
7210 static
7212  SCIP* scip, /**< SCIP data structure */
7213  SCIP_CONS* cons, /**< constraint */
7214  char method, /**< method for computing interior point ('a' any point, 'm'ost interior) */
7215  SCIP_Bool* success /**< buffer to store if an interior point was found */
7216 )
7217 {
7218  SCIP_CONSDATA* consdata;
7219  SCIP_QUADELEM* nlrowquadelems;
7220  SCIP_NLPIPROBLEM* prob;
7221  SCIP_NLPI* nlpi;
7222  SCIP_Real* interiorpoint;
7223  SCIP_Real* lbs;
7224  SCIP_Real* ubs;
7225  SCIP_Real* lincoefs;
7226  SCIP_Real nlpiside;
7227  char probname[SCIP_MAXSTRLEN];
7228  int* lininds;
7229  int nlrownquadelems;
7230  int nquadvars;
7231  int i;
7232 
7233  assert(scip != NULL);
7234  assert(cons != NULL);
7235 
7236  assert(success != NULL);
7237  *success = FALSE;
7238 
7239  consdata = SCIPconsGetData(cons);
7240  assert(consdata != NULL);
7241 
7242  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
7243  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7244 
7245  /* need an NLP solver */
7246  if( SCIPgetNNlpis(scip) == 0 )
7247  return SCIP_OKAY;
7248 
7249  nlpi = NULL;
7250  prob = NULL;
7251  lbs = NULL;
7252  ubs = NULL;
7253  lincoefs = NULL;
7254  lininds = NULL;
7255 
7256 #ifdef SCIP_DEBUG_INT
7257  SCIPinfoMessage(scip, NULL, "Computing interior point for\n");
7258  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7259  SCIPinfoMessage(scip, NULL, ";\n");
7260 #endif
7261 
7262  /* in the convex case, we try to find an interior point of x^T A x + b^T x <= rhs - maximum activity linear part
7263  * in the concave case: lhs - minimum activity linear part <= x^T A x + b^T x; we compute activities ourselves,
7264  * since consdata->max(min)linactivity are only computed when lhs (rhs) is finite and this not always holds
7265  */
7266  if( consdata->isconvex )
7267  {
7268  /* compute maximum activity */
7269  nlpiside = 0;
7270  for( i = 0; i < consdata->nlinvars; ++i )
7271  {
7272  if( consdata->lincoefs[i] >= 0.0 )
7273  {
7274  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i]) ) )
7275  nlpiside = SCIPinfinity(scip);
7276  else
7277  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7278  }
7279  else
7280  {
7281  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i]) ) )
7282  nlpiside = SCIPinfinity(scip);
7283  else
7284  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7285  }
7286 
7287  if( SCIPisInfinity(scip, nlpiside) )
7288  {
7289  SCIPdebugMessage("maximum activity is infinity: there is no interior point for fun <= rhs - maxlinactivity!\n");
7290  return SCIP_OKAY;
7291  }
7292  }
7293 
7294  if( consdata->nlinvars == 0 )
7295  nlpiside = INTERIOR_EPS;
7296 
7297  nlpiside = consdata->rhs - nlpiside;
7298  }
7299  else
7300  {
7301  /* compute minimum activity */
7302  nlpiside = 0;
7303  for( i = 0; i < consdata->nlinvars; ++i )
7304  {
7305  if( consdata->lincoefs[i] >= 0.0 )
7306  {
7307  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
7308  nlpiside = -SCIPinfinity(scip);
7309  else
7310  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7311  }
7312  else
7313  {
7314  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
7315  nlpiside = -SCIPinfinity(scip);
7316  else
7317  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7318  }
7319 
7320  if( SCIPisInfinity(scip, -nlpiside) )
7321  {
7322  SCIPdebugMessage("minimum activity is -infinity: there is no interior point for fun >= lhs - minlinactivity!\n");
7323  return SCIP_OKAY;
7324  }
7325  }
7326 
7327  if( consdata->nlinvars == 0 )
7328  nlpiside = INTERIOR_EPS;
7329 
7330  nlpiside = consdata->lhs - nlpiside;
7331  }
7332 
7333  nquadvars = consdata->nquadvars;
7334 
7335  /* if we are looking for any interior point and the 0 is one, then use it */
7336  if( method == 'a' && ((consdata->isconvex && SCIPisGE(scip, nlpiside, 0.0))
7337  || (consdata->isconcave && SCIPisLE(scip, nlpiside, 0.0))) )
7338  {
7339  SCIP_CALL( SCIPallocClearMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
7340 
7341  *success = TRUE;
7342  goto TERMINATE;
7343  }
7344 
7345  /* build nlrow */
7346  if( consdata->nlrow == NULL )
7347  {
7348  SCIP_CALL( createNlRow(scip, cons) );
7349  assert(consdata->nlrow != NULL);
7350  }
7351 
7352  nlpi = SCIPgetNlpis(scip)[0];
7353  assert(nlpi != NULL);
7354 
7355  /* initializing the subproblem */
7356  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_subquad", SCIPgetProbName(scip));
7357  SCIP_CALL( SCIPnlpiCreateProblem(nlpi, &prob, probname) );
7358  assert(prob != NULL);
7359 
7360 #ifdef SCIP_DEBUG_INT
7362 #endif
7363  /* TODO: maybe one should set some generous iteration limit and/or a timelimit (remaining scip solve time)? */
7364 
7365  /* ask for memory to store data needed to create vars and linear coefficients */
7366  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nquadvars) );
7367  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nquadvars) );
7368  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nquadvars) );
7369  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nquadvars) );
7370 
7371  /* get bounds and linear coefficients */
7372  for( i = 0; i < nquadvars; i++ )
7373  {
7374  lbs[i] = SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
7375  ubs[i] = SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
7376 
7377  lincoefs[i] = consdata->quadvarterms[i].lincoef;
7378  lininds[i] = i;
7379  }
7380 
7381  /* add vars */
7382  SCIP_CALL( SCIPnlpiAddVars(nlpi, prob, nquadvars, lbs, ubs, NULL) );
7383 
7384  /* get nlrow info */
7385  nlrownquadelems = SCIPnlrowGetNQuadElems(consdata->nlrow);
7386  nlrowquadelems = SCIPnlrowGetQuadElems(consdata->nlrow);
7387 
7388 #ifndef NDEBUG
7389  {
7390  SCIP_VAR** nlrowquadvars;
7391 
7392  nlrowquadvars = SCIPnlrowGetQuadVars(consdata->nlrow);
7393  for( i = 0; i < nlrownquadelems; i++ )
7394  {
7395  assert(nlrowquadvars[nlrowquadelems[i].idx1] == consdata->quadvarterms[nlrowquadelems[i].idx1].var);
7396  assert(nlrowquadvars[nlrowquadelems[i].idx2] == consdata->quadvarterms[nlrowquadelems[i].idx2].var);
7397  }
7398  }
7399 #endif
7400 
7401  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
7402 
7403  switch( method )
7404  {
7405  case 'a':
7406  /* add constraint */
7407  if( consdata->isconvex )
7408  {
7409  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, NULL, &nlpiside, &nquadvars, &lininds, &lincoefs,
7410  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
7411  }
7412  else
7413  {
7414  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, &nlpiside, NULL, &nquadvars, &lininds, &lincoefs,
7415  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
7416  }
7417  break;
7418 
7419  case 'm':
7420  /* add objective */
7421  if( consdata->isconvex )
7422  {
7423  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
7424  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
7425  }
7426  else
7427  {
7428  /* NLPI assumes minimization: change signs */
7429  for( i = 0; i < nquadvars; i++ )
7430  lincoefs[i] *= -1;
7431 
7432  /* WARNING: this pointer is not ours, information should be restored! */
7433  for( i = 0; i < nlrownquadelems; i++ )
7434  nlrowquadelems->coef *= -1;
7435 
7436  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
7437  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
7438 
7439  /* WARNING: restore information! */
7440  for( i = 0; i < nlrownquadelems; i++ )
7441  nlrowquadelems->coef *= -1;
7442  }
7443  break;
7444 
7445  default:
7446  SCIPerrorMessage("undefined method for computing interior point: %c\n", method);
7447  return SCIP_INVALIDDATA;
7448  }
7449 
7450  /* solve NLP problem */
7451  SCIP_CALL( SCIPnlpiSolve(nlpi, prob) );
7452 
7453  /* check termination status */
7454  if( SCIPnlpiGetTermstat(nlpi, prob) != SCIP_NLPTERMSTAT_OKAY )
7455  {
7456  SCIPdebugMessage("cons <%s>: NLP Solver termination status not okay: %d\n",
7457  SCIPconsGetName(cons), SCIPnlpiGetTermstat(nlpi, prob));
7458  *success = FALSE;
7459  goto TERMINATE;
7460  }
7461 
7462  /* check solution status */
7463  switch( SCIPnlpiGetSolstat(nlpi, prob) )
7464  {
7468  /* fallthrough */
7469  SCIPdebugMessage("cons <%s>: found an interior point. solution status: %d, termination status: %d\n",
7470  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7471  break;
7472 
7475  /* fallthrough */
7476  /* TODO: we could still use the point, and let evaluateGauge decide whether the point is interior or not */
7477  SCIPdebugMessage("cons <%s>: failed to find an interior point. solution status: %d, termination status: %d\n",
7478  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7479  goto TERMINATE;
7480 
7483  default:
7484  /* fallthrough */
7485  SCIPerrorMessage("cons <%s>: undefined behaviour of NLP Solver. solution status: %d, termination status: %d\n",
7486  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7487  SCIPABORT();
7488  goto TERMINATE; /*lint !e527*/
7489  }
7490 
7491  /* fetch solution
7492  * note: nlpiGetSolution (at least for IPOPT) makes interiorpoint point to the internal solution stored in the
7493  * nlpi problem data structure; we need to copy it here because it will be destroyed once the problem is free'd
7494  */
7495  SCIP_CALL( SCIPnlpiGetSolution(nlpi, prob, &interiorpoint, NULL, NULL, NULL) );
7496 
7497  SCIP_CALL( SCIPallocMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
7498 
7499  for( i = 0; i < nquadvars; i++ )
7500  {
7501  if( SCIPisFeasZero(scip, interiorpoint[i]) )
7502  consdata->interiorpoint[i] = 0.0;
7503  else
7504  consdata->interiorpoint[i] = interiorpoint[i];
7505  }
7506 
7507  *success = TRUE;
7508 
7509 TERMINATE:
7510 
7511 #ifdef SCIP_DEBUG_INT
7512  printf("Computation of interior point for cons <%s>:\n", SCIPconsGetName(cons));
7513  printf(" - has %d linear variables\n", consdata->nlinvars);
7514  if( consdata->isconvex )
7515  {
7516  printf(" - is convex. rhs: %g maximum activity of linear variables: %g\n", consdata->rhs, consdata->rhs - nlpiside);
7517  printf(" - searched for point whose quadratic part is <= %g\n", nlpiside);
7518  }
7519  else
7520  {
7521  printf(" - is concave. lhs: %g minimum activity of linear variables: %g\n", consdata->lhs, consdata->lhs - nlpiside);
7522  printf(" - searched for point whose quadratic part is >= %g\n", nlpiside);
7523  }
7524 
7525  if( *success )
7526  {
7527  if( prob == NULL )
7528  {
7529  printf("Computation successful, 0 is interior point.\n");
7530  for( i = 0; i < nquadvars; i++ )
7531  {
7532  assert(consdata->interiorpoint[i] == 0.0);
7533  }
7534  }
7535  else
7536  {
7537  printf("Computation successful, NLP soltat: %d, termstat: %d\nPoint found:\n",
7538  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7539  for( i = 0; i < nquadvars; i++ )
7540  {
7541  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[i].var), consdata->interiorpoint[i]);
7542  }
7543  }
7544  }
7545  else
7546  {
7547  printf("Computation failed. NLP soltat: %d, termstat: %d\n",
7548  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7549  printf("run with SCIP_DEBUG for more info\n");
7550  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7551  SCIPinfoMessage(scip, NULL, ";\n");
7552  /* FIXME: instance camshape100 says that there is no interior point (interior empty)
7553  * is there something intelligent that can be said?
7554  */
7555  }
7556 #endif
7557 
7558  /* free memory */
7559  SCIPfreeBufferArrayNull(scip, &lbs);
7560  SCIPfreeBufferArrayNull(scip, &ubs);
7561  SCIPfreeBufferArrayNull(scip, &lininds);
7562  SCIPfreeBufferArrayNull(scip, &lincoefs);
7563 
7564  if( prob != NULL )
7565  {
7566  SCIP_CALL( SCIPnlpiFreeProblem(nlpi, &prob) );
7567  }
7568 
7569  return SCIP_OKAY;
7570 }
7571 
7572 /** 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$.
7573  *
7574  * Here, \f$ f(x) \f$ is a purely quadratic (i.e, all \f$x\f$ variables appear in a bilinear or quadratic term).
7575  * Explicitly, \f$ f(x) = \pm x^T A x \pm b^T x \f$ depending whether \f$A\f$
7576  * is positive semidefinite (+) or negative semidefinite (-).
7577  * The constant \f$c\f$ is rhs - maximum activity of the purely linear part of the constraint
7578  * if \f$A \succeq 0\f$ and minimum activity - lhs if \f$A \preceq 0\f$.
7579  * This is computed only at INITSOL.
7580  *
7581  * The method does:
7582  * 1. compute interior point
7583  * 2. compute gauge function
7584  */
7585 static
7587  SCIP* scip, /**< SCIP data structure */
7588  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7589  SCIP_CONS* cons /**< constraint */
7590  )
7591 {
7592  SCIP_CONSHDLRDATA* conshdlrdata;
7593  SCIP_CONSDATA* consdata;
7594  SCIP_QUADVARTERM* quadvarterm;
7595  SCIP_BILINTERM* bilinterm;
7596  SCIP_Bool success;
7597  SCIP_Bool convex;
7598  int i;
7599  int j;
7600 
7601  assert(scip != NULL);
7602  assert(conshdlr != NULL);
7603  assert(cons != NULL);
7604 
7605  consdata = SCIPconsGetData(cons);
7606  assert(consdata != NULL);
7607  assert(consdata->sepabilinvar2pos != NULL || consdata->nbilinterms == 0); /* this should have been computed in INITSOL */
7608 
7609  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7610  assert(conshdlrdata != NULL);
7611  assert(conshdlrdata->gaugecuts);
7612 
7613  /* function has to be convex with finite rhs or concave with finite lhs */
7614  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
7615  assert(convex || (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7616 
7617  SCIPdebugMessage("cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
7618 
7619  /* 1. */
7620  SCIP_CALL( computeInteriorPoint(scip, cons, conshdlrdata->interiorcomputation, &success) );
7621 
7622  /* if success, compute gaugecoefs (b_gauge) and gaugeconst (c_gauge) */
7623  if( !success )
7624  {
7625  SCIPdebugMessage("failed to compute gauge function\n");
7626  consdata->isgaugeavailable = FALSE;
7627  return SCIP_OKAY;
7628  }
7629 
7630  /* 2.
7631  * we are going to evaluate the function at interiorpoint; so, we need to compute interiorpoint^T A interiorpoint;
7632  * therefore, we need a mechanism that for a given variable, it returns its interior point value
7633  * fortunately, sepabilinvar2pos in consdata gives us all the information that we need
7634  */
7635 
7636  SCIP_CALL( SCIPallocMemoryArray(scip, &(consdata->gaugecoefs), consdata->nquadvars) );
7637 
7638  /* compute value of quadratic part at interior point, build map and compute gaugeconst (c_gauge) */
7639  consdata->interiorpointval = 0;
7640  consdata->gaugeconst = 0;
7641  for( i = 0; i < consdata->nquadvars; i++ )
7642  {
7643  SCIP_Real val;
7644  SCIP_Real val2;
7645 
7646  val = consdata->interiorpoint[i];
7647  quadvarterm = &consdata->quadvarterms[i];
7648 
7649  consdata->interiorpointval += (quadvarterm->lincoef + quadvarterm->sqrcoef * val) * val;
7650  consdata->gaugeconst += quadvarterm->sqrcoef * val * val;
7651 
7652  for( j = 0; j < quadvarterm->nadjbilin; ++j )
7653  {
7654  int bilintermidx;
7655 
7656  bilintermidx = quadvarterm->adjbilin[j];
7657  bilinterm = &consdata->bilinterms[bilintermidx];
7658 
7659  if( bilinterm->var1 != quadvarterm->var )
7660  continue;
7661 
7662  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
7663  assert(consdata->quadvarterms[consdata->sepabilinvar2pos[bilintermidx]].var == bilinterm->var2);
7664 
7665  val2 = consdata->interiorpoint[consdata->sepabilinvar2pos[bilintermidx]];
7666 
7667  consdata->interiorpointval += bilinterm->coef * val * val2;
7668  consdata->gaugeconst += bilinterm->coef * val * val2;
7669  }
7670  }
7671 
7672  /* compute gaugecoefs (b_gauge) */
7673  for( i = 0; i < consdata->nquadvars; i++ )
7674  {
7675  SCIP_Real val;
7676 
7677  quadvarterm = &consdata->quadvarterms[i];
7678 
7679  val = consdata->interiorpoint[i];
7680  consdata->gaugecoefs[i] = quadvarterm->lincoef + 2.0 * quadvarterm->sqrcoef * val;
7681  for( j = 0; j < quadvarterm->nadjbilin; j++ )
7682  {
7683  int varpos;
7684  int bilintermidx;
7685 
7686  bilintermidx = quadvarterm->adjbilin[j];
7687  bilinterm = &consdata->bilinterms[bilintermidx];
7688 
7689  if( bilinterm->var1 == quadvarterm->var )
7690  {
7691  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
7692  assert(consdata->quadvarterms[consdata->sepabilinvar2pos[bilintermidx]].var == bilinterm->var2);
7693  varpos = consdata->sepabilinvar2pos[bilintermidx];
7694  }
7695  else
7696  {
7697  assert(bilinterm->var2 == quadvarterm->var);
7698  varpos = i;
7699  }
7700 
7701  consdata->gaugecoefs[i] += bilinterm->coef * consdata->interiorpoint[varpos];
7702  }
7703  }
7704 
7705 #ifdef SCIP_DEBUG_INT
7706  printf("quadratic part at interior point: %g\n", consdata->interiorpointval);
7707 
7708  for( j = 0; j < consdata->nquadvars; j++ )
7709  {
7710  printf("b_gauge[%s] = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), consdata->gaugecoefs[j]);
7711  }
7712  printf("c_gauge = %g\n", consdata->gaugeconst);
7713 #endif
7714 
7715  SCIPdebugMessage("gauge function computed successfully\n");
7716  consdata->isgaugeavailable = TRUE;
7717 
7718  return SCIP_OKAY;
7719 }
7720 
7721 /** 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$.
7722  *
7723  * \f$ S = \{ x : f(x) \le c \}\f$ at \f$sol - s_0\f$;
7724  * see computeGauge() for more details
7725  *
7726  * @todo Think about if user should tell that function is convex or ...
7727  */
7728 static
7730  SCIP* scip, /**< SCIP data structure */
7731  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7732  SCIP_CONS* cons, /**< constraint */
7733  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
7734  SCIP_Real* gaugeval, /**< buffer to store the value of the gauge function */
7735  SCIP_Bool* success /**< buffer to store if evaluation was successful */
7736  )
7737 {
7738  SCIP_CONSDATA* consdata;
7739  SCIP_Real side;
7740  SCIP_Real aterm;
7741  SCIP_Real bterm;
7742  SCIP_Real cterm;
7743  SCIP_Bool convex;
7744  int i;
7745 
7746  assert(scip != NULL);
7747  assert(conshdlr != NULL);
7748  assert(cons != NULL);
7749 
7750  consdata = SCIPconsGetData(cons);
7751  assert(consdata != NULL);
7752  assert(consdata->isgaugeavailable);
7753 
7754  *success = FALSE;
7755 
7756  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
7757 
7758  SCIPdebugMessage("cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
7759 
7760  /* evaluate gauge function at x0 = (refsol - interior point)
7761  *
7762  * compute aterm = side - function(interior point)
7763  */
7764  if( convex )
7765  {
7766  side = consdata->rhs;
7767  for( i = 0; i < consdata->nlinvars; i++ )
7768  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
7769 
7770  aterm = side - consdata->interiorpointval;
7771 
7772  /* it can happen that the interior point is not really interior, since we are not so strict at the moment of
7773  * computing the interior point, which makes sense in the case that the constraint is quadratic <= linear expr,
7774  * since we compute a point in quadratic <= min linear expr and it might be that this set consists of a single
7775  * point which will not be interior. furthermore, if this set is empty, we could just take any point and it could
7776  * happen that for some value of linear expr, the point is actually interior, but for many it could not be.
7777  * also, if min linear expr = -infinity, we might have computed an interior point using some finite value.
7778  * the point will not be an interior point, if and only if aterm is negative.
7779  */
7780 #ifdef SCIP_DEBUG_GAUGE
7781  if( SCIPisLE(scip, aterm, 0.0) )
7782  {
7783  printf("For current level, there is no interior point. ");
7784  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
7785  if( consdata->nlinvars == 1 )
7786  {
7787  SCIP_VAR* var;
7788 
7789  var = consdata->linvars[0];
7790  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
7791  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7792  }
7793  }
7794  else
7795  {
7796  printf("For current level, there is interior point. ");
7797  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
7798  }
7799 #endif
7800  if( !SCIPisPositive(scip, aterm) )
7801  {
7802  *gaugeval = -1.0;
7803  return SCIP_OKAY;
7804  }
7805  }
7806  else
7807  {
7808  side = consdata->lhs;
7809  for( i = 0; i < consdata->nlinvars; i++ )
7810  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
7811 
7812  aterm = side - consdata->interiorpointval;
7813 
7814 #ifdef SCIP_DEBUG_GAUGE
7815  if( SCIPisGE(scip, aterm, 0.0) )
7816  {
7817  printf("For current level, there is no interior point. ");
7818  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
7819  if( consdata->nlinvars == 1 )
7820  {
7821  SCIP_VAR* var;
7822 
7823  var = consdata->linvars[0];
7824  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
7825  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7826  }
7827  }
7828  else
7829  {
7830  printf("For current level, there is interior point. ");
7831  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
7832  }
7833 #endif
7834  if( !SCIPisNegative(scip, aterm) )
7835  {
7836  *gaugeval = -1.0;
7837  return SCIP_OKAY;
7838  }
7839  }
7840 
7841  /* compute bterm = b_gauge^T * refsol - f(interiorpoint) - c_gauge
7842  * compute cterm = f(refsol) - b_gauge^T * refsol + c_gauge */
7843  bterm = -consdata->interiorpointval - consdata->gaugeconst;
7844  cterm = consdata->gaugeconst;
7845  for( i = 0; i < consdata->nquadvars; i++ )
7846  {
7847  SCIP_Real val;
7848 
7849  val = SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var);
7850  bterm += consdata->gaugecoefs[i] * val;
7851  cterm -= consdata->gaugecoefs[i] * val;
7852  cterm += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val) * val;
7853  }
7854 
7855  for( i = 0; i < consdata->nbilinterms; i++ )
7856  {
7857  SCIP_VAR* var1;
7858  SCIP_VAR* var2;
7859 
7860  var1 = consdata->bilinterms[i].var1;
7861  var2 = consdata->bilinterms[i].var2;
7862  cterm += consdata->bilinterms[i].coef * SCIPgetSolVal(scip, refsol, var1) * SCIPgetSolVal(scip, refsol, var2);
7863  }
7864 
7865  /* now compute gauge */
7866  if( convex && cterm < 0.0 )
7867  {
7868  assert(SCIPisZero(scip, cterm));
7869  cterm = 0.0;
7870  }
7871  else if( !convex && cterm > 0.0 )
7872  {
7873  assert(SCIPisZero(scip, cterm));
7874  cterm = 0.0;
7875  }
7876  assert(bterm*bterm + 4*aterm*cterm >= 0);
7877 
7878  if( convex )
7879  {
7880  *gaugeval = bterm + sqrt(bterm*bterm + 4 * aterm * cterm);
7881  *gaugeval = *gaugeval / (2 * aterm);
7882  }
7883  else
7884  {
7885  *gaugeval = bterm - sqrt(bterm*bterm + 4 * aterm * cterm);
7886  *gaugeval = *gaugeval / (2 * aterm);
7887  }
7888  assert(!SCIPisNegative(scip, *gaugeval));
7889  *success = TRUE;
7890 
7891 #ifdef SCIP_DEBUG_GAUGE
7892  printf("Gauge's aterm = %g, bterm = %g, cterm = %g\n", aterm, bterm, cterm);
7893 #endif
7894  return SCIP_OKAY;
7895 }
7896 
7897 /** compute reference point suggested by gauge function
7898  *
7899  * @todo Should we modify a point in the interior? Currently we do not.
7900  */
7901 static
7903  SCIP* scip, /**< SCIP data structure */
7904  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7905  SCIP_CONS* cons, /**< constraint */
7906  SCIP_SOL* refsol, /**< reference point where to compute gauge, or NULL if LP solution should be used */
7907  SCIP_Real** ref, /**< pointer to store reference point */
7908  SCIP_Bool* success /**< buffer to store whether we succeeded computing reference point */
7909  )
7910 {
7911  SCIP_CONSDATA* consdata;
7912  SCIP_Real gaugeval;
7913  SCIP_Real intpoint;
7914  SCIP_Real lb;
7915  SCIP_Real ub;
7916  SCIP_VAR* var;
7917  int j;
7918 
7919  assert(scip != NULL);
7920  assert(conshdlr != NULL);
7921  assert(cons != NULL);
7922 
7923  consdata = SCIPconsGetData(cons);
7924  assert(consdata != NULL);
7925  assert(consdata->isgaugeavailable);
7926 
7927  SCIPdebugMessage("evaluating gauge\n");
7928  SCIP_CALL( evaluateGauge(scip, conshdlr, cons, refsol, &gaugeval, success) );
7929 
7930  if( !(*success) )
7931  {
7932 #ifdef SCIP_DEBUG_GAUGE
7933  printf("Couldn't evaluate gauge!\n");
7934 #endif
7935  return SCIP_OKAY;
7936  }
7937 
7938 #ifdef SCIP_DEBUG_GAUGE
7939  {
7940  SCIP_Real level;
7941 
7942  level = consdata->rhs;
7943  for( j = 0; j < consdata->nlinvars; j++ )
7944  level -= SCIPgetSolVal(scip, refsol, consdata->linvars[j]) * consdata->lincoefs[j];
7945 
7946  printf("Summary:\n");
7947  printf("For cons <%s>: gauge at level %g evaluated at (refsol - intpoint) is %.10f\n",
7948  SCIPconsGetName(cons), level, gaugeval);
7949  printf("refsol - intpoint:\n");
7950 
7951  for( j = 0; j < consdata->nquadvars; ++j )
7952  {
7953  SCIP_VAR* vvar;
7954  vvar = consdata->quadvarterms[j].var;
7955  printf("%s: % 20.15g - %g = %g\n", SCIPvarGetName(vvar), SCIPgetSolVal(scip, refsol, vvar),
7956  consdata->interiorpoint[j], SCIPgetSolVal(scip, refsol, vvar) - consdata->interiorpoint[j]);
7957  }
7958  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
7959  printf("refsol is in the closure of the region (gaugeval <= 1), don't modify reference point\n");
7960  }
7961 #endif
7962 
7963  /* scale gauge value so that point is close to the boundary, but not on the boundary */
7964  gaugeval *= GAUGESCALE;
7965 
7966  /* when a new solution is found, this method is called from addLinearizationCuts.
7967  * in this case, since the solution is feasible, gaugeval <= 1
7968  * is it a good idea to modify the point if it is interior?
7969  */
7970  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
7971  {
7972  *success = FALSE;
7973 
7974  return SCIP_OKAY;
7975  }
7976 
7977  /* set reference to (refsol - interior point)/gaugeval + interior point and project into bounds
7978  * this is important for some cut generation methods such as generateCutLTI
7979  */
7980  for( j = 0; j < consdata->nquadvars; ++j )
7981  {
7982  var = consdata->quadvarterms[j].var;
7983  lb = SCIPvarGetLbLocal(var);
7984  ub = SCIPvarGetUbLocal(var);
7985  /* do not like variables at infinity */
7986  assert(!SCIPisInfinity(scip, lb));
7987  assert(!SCIPisInfinity(scip, -ub));
7988 
7989  intpoint = consdata->interiorpoint[j];
7990  (*ref)[j] = (SCIPgetSolVal(scip, refsol, var) - intpoint) / gaugeval + intpoint;
7991  (*ref)[j] = MIN(ub, MAX(lb, (*ref)[j])); /* project value into bounds */
7992  }
7993 
7994 #ifdef SCIP_DEBUG_GAUGE
7995  printf("successful application of guage: %g\n", gaugeval);
7996  printf("modified reference point:\n");
7997  for( j = 0; j < consdata->nquadvars; ++j )
7998  {
7999  printf("%s = % 20.15g\n", SCIPvarGetName(consdata->quadvarterms[j].var), (*ref)[j]);
8000  }
8001 #endif
8002 
8003  return SCIP_OKAY;
8004 }
8005 
8006 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a solution */
8007 static
8009  SCIP* scip, /**< SCIP data structure */
8010  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8011  SCIP_CONS* cons, /**< constraint */
8012  SCIP_SOL* sol, /**< solution where to generate cut, or NULL if LP solution should be used */
8013  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
8014  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
8015  SCIP_ROW** row, /**< storage for cut */
8016  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
8017  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
8018  SCIP_Real minefficacy /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
8019  )
8020 {
8021  SCIP_CONSHDLRDATA* conshdlrdata;
8022  SCIP_CONSDATA* consdata;
8023  SCIP_VAR* var;
8024  SCIP_Real lb;
8025  SCIP_Real ub;
8026  SCIP_Real* ref;
8027  SCIP_Bool success;
8028  int j;
8029 
8030  assert(scip != NULL);
8031  assert(conshdlr != NULL);
8032  assert(cons != NULL);
8033 
8034  consdata = SCIPconsGetData(cons);
8035  assert(consdata != NULL);
8036 
8037  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8038  assert(conshdlrdata != NULL);
8039 
8040  if( refsol == NULL )
8041  refsol = sol;
8042 
8043  /* get reference point */
8044  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
8045  success = FALSE;
8046 
8047  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable &&
8048  ((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
8049  (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT)) )
8050  {
8051  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, &ref, &success) );
8052  }
8053 
8054  if( success )
8055  {
8056  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8057 
8058  /* if cut fails, try again without modifying reference point via gauge */
8059  if( *row == NULL || (efficacy != NULL && !SCIPisGT(scip, *efficacy, minefficacy)) || !SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
8060  {
8061  SCIPdebugMessage("gauge cut fail, try without modifying\n");
8062  success = FALSE;
8063  }
8064  }
8065 
8066  if( !success )
8067  {
8068  for( j = 0; j < consdata->nquadvars; ++j )
8069  {
8070  var = consdata->quadvarterms[j].var;
8071  lb = SCIPvarGetLbLocal(var);
8072  ub = SCIPvarGetUbLocal(var);
8073  /* do not like variables at infinity */
8074  assert(!SCIPisInfinity(scip, lb));
8075  assert(!SCIPisInfinity(scip, -ub));
8076 
8077  ref[j] = SCIPgetSolVal(scip, refsol, var);
8078  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8079  }
8080 
8081  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8082  }
8083 
8084  SCIPfreeBufferArray(scip, &ref);
8085 
8086  return SCIP_OKAY;
8087 }
8088 
8089 /** tries to find a cut that intersects with an unbounded ray of the LP
8090  *
8091  * For convex functions, we do this by linearizing in the feasible solution of the LPI.
8092  * For nonconvex functions, we just call generateCutSol with the unbounded solution as reference point.
8093  */
8094 static
8096  SCIP* scip, /**< SCIP data structure */
8097  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8098  SCIP_CONS* cons, /**< constraint */
8099  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
8100  SCIP_ROW** row, /**< storage for cut */
8101  SCIP_Real* rowrayprod, /**< buffer to store product of ray with row coefficients, or NULL if not of interest */
8102  SCIP_Bool checkcurvmultivar /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
8103  )
8104 {
8105  SCIP_CONSDATA* consdata;
8106  SCIP_BILINTERM* bilinterm;
8107  SCIP_VAR* var;
8108  SCIP_Real* ref;
8109  SCIP_Real matrixrayprod;
8110  SCIP_Real linrayprod;
8111  SCIP_Real quadrayprod;
8112  SCIP_Real rayval;
8113  int i;
8114  int j;
8115 
8116  assert(scip != NULL);
8117  assert(conshdlr != NULL);
8118  assert(cons != NULL);
8119  assert(row != NULL);
8121 
8122  consdata = SCIPconsGetData(cons);
8123  assert(consdata != NULL);
8124 
8125  *row = NULL;
8126 
8127  if( !SCIPhasPrimalRay(scip) )
8128  {
8129  SCIPdebugMessage("do not have primal ray, thus cannot resolve unboundedness\n");
8130  return SCIP_OKAY;
8131  }
8132 
8133  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
8134  if( (!consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
8135  (!consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
8136  {
8137  /* if not convex, just call generateCut and hope it's getting something useful */
8138  SCIP_CALL( generateCutSol(scip, conshdlr, cons, NULL, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
8139 
8140  /* compute product of cut coefficients with ray, if required */
8141  if( *row != NULL && rowrayprod != NULL )
8142  {
8143  *rowrayprod = 0.0;
8144  for( i = 0; i < SCIProwGetNNonz(*row); ++i )
8145  {
8146  assert(SCIProwGetCols(*row)[i] != NULL);
8147  var = SCIPcolGetVar(SCIProwGetCols(*row)[i]);
8148  assert(var != NULL);
8149 
8150  *rowrayprod += SCIProwGetVals(*row)[i] * SCIPgetPrimalRayVal(scip, var);
8151  }
8152  }
8153 
8154  return SCIP_OKAY;
8155  }
8156 
8157  /* we seek for a linearization of the quadratic function such that it intersects with the unbounded ray
8158  * that is, we need a reference point ref such that for the gradient g of xAx+bx in ref, we have
8159  * <g, ray> > 0.0 if rhs is finite and <g, ray> < 0.0 if lhs is finite
8160  * Since g = 2*A*ref + b, we have <g, ray> = <2*A*ref + b, ray> = <ref, 2*A*ray> + <b,ray>
8161  * 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)
8162  * <ref, 2*A*ray> + <b,ray> is sufficiently larger 0.0, we call generateCut for this point, otherwise, we scale up ref
8163  */
8164 
8165  quadrayprod = 0.0; /* <ref, 2*A*ray> */
8166  linrayprod = 0.0; /* <b, ray> */
8167  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
8168  for( i = 0; i < consdata->nquadvars; ++i )
8169  {
8170  var = consdata->quadvarterms[i].var;
8171  rayval = SCIPgetPrimalRayVal(scip, var);
8172 
8173  /* compute i-th entry of (2*A*ray) */
8174  matrixrayprod = 2.0 * consdata->quadvarterms[i].sqrcoef * rayval;
8175  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
8176  {
8177  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
8178  matrixrayprod += bilinterm->coef * SCIPgetPrimalRayVal(scip, bilinterm->var1 == var ? bilinterm->var2 : bilinterm->var1);
8179  }
8180 
8181  if( SCIPisPositive(scip, matrixrayprod) )
8182  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? 1.0 : -1.0);
8183  else if( SCIPisNegative(scip, matrixrayprod) )
8184  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? -1.0 : 1.0);
8185  else
8186  ref[i] = 0.0;
8187 
8188  quadrayprod += matrixrayprod * ref[i];
8189  linrayprod += consdata->quadvarterms[i].lincoef * rayval;
8190  }
8191  assert((violside == SCIP_SIDETYPE_RIGHT && quadrayprod >= 0.0) || (violside == SCIP_SIDETYPE_LEFT && quadrayprod <= 0.0));
8192 
8193  if( SCIPisZero(scip, quadrayprod) )
8194  {
8195  SCIPdebugMessage("ray is zero along cons <%s>\n", SCIPconsGetName(cons));
8196  SCIPfreeBufferArray(scip, &ref);
8197  return SCIP_OKAY;
8198  }
8199 
8200  /* add linear part to linrayprod */
8201  for( i = 0; i < consdata->nlinvars; ++i )
8202  linrayprod += consdata->lincoefs[i] * SCIPgetPrimalRayVal(scip, consdata->linvars[i]);
8203 
8204  SCIPdebugMessage("initially have <b,ray> = %g and <ref, 2*A*ref> = %g\n", linrayprod, quadrayprod);
8205 
8206  /* 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
8207  * if <b,ray> is zero, then we scale refpoint up if |<ref, 2*A*ray>| < 1.0
8208  */
8209  if( (!SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_RIGHT && quadrayprod < -2*linrayprod) ||
8210  ( !SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_LEFT && quadrayprod > -2*linrayprod) ||
8211  (SCIPisZero(scip, linrayprod) && REALABS(quadrayprod) < 1.0) )
8212  {
8213  SCIP_Real scale;
8214 
8215  if( !SCIPisZero(scip, linrayprod) )
8216  scale = 2*REALABS(linrayprod/quadrayprod); /*lint !e795 */
8217  else
8218  scale = 1.0/REALABS(quadrayprod);
8219 
8220  SCIPdebugMessage("scale refpoint by %g\n", scale);
8221  for( i = 0; i < consdata->nquadvars; ++i )
8222  ref[i] *= scale;
8223  quadrayprod *= scale;
8224  }
8225 
8226  if( rowrayprod != NULL )
8227  *rowrayprod = quadrayprod + linrayprod;
8228 
8229  SCIPdebugMessage("calling generateCut, expecting ray product %g\n", quadrayprod + linrayprod);
8230  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
8231 
8232  SCIPfreeBufferArray(scip, &ref);
8233 
8234  return SCIP_OKAY;
8235 }
8236 
8237 /** tries to separate solution or LP solution by a linear cut
8238  *
8239  * assumes that constraint violations have been computed
8240  */
8241 static
8243  SCIP* scip, /**< SCIP data structure */
8244  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
8245  SCIP_CONS** conss, /**< constraints */
8246  int nconss, /**< number of constraints */
8247  int nusefulconss, /**< number of constraints that seem to be useful */
8248  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8249  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
8250  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
8251  SCIP_RESULT* result, /**< result of separation */
8252  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 */
8253  )
8254 {
8255  SCIP_CONSHDLRDATA* conshdlrdata;
8256  SCIP_CONSDATA* consdata;
8257  SCIP_Real efficacy;
8258  SCIP_Real actminefficacy;
8259  SCIP_SIDETYPE violside;
8260  int c;
8261  SCIP_ROW* row;
8262 
8263  assert(scip != NULL);
8264  assert(conshdlr != NULL);
8265  assert(conss != NULL || nconss == 0);
8266  assert(nusefulconss <= nconss);
8267  assert(result != NULL);
8268 
8269  *result = SCIP_FEASIBLE;
8270 
8271  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8272  assert(conshdlrdata != NULL);
8273 
8274  if( bestefficacy != NULL )
8275  *bestefficacy = 0.0;
8276 
8277  for( c = 0; c < nconss; ++c )
8278  {
8279  assert(conss != NULL);
8280  consdata = SCIPconsGetData(conss[c]);
8281  assert(consdata != NULL);
8282 
8283  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
8284  {
8285  /* we are not feasible anymore */
8286  if( *result == SCIP_FEASIBLE )
8287  *result = SCIP_DIDNOTFIND;
8288 
8289  violside = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT;
8290 
8291  /* actual minimal efficacy */
8292  actminefficacy = inenforcement && ((violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex ) || (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave))
8293  ? (SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip))
8294  : minefficacy;
8295 
8296  /* generate cut */
8297  if( sol == NULL && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
8298  {
8299  /* if the LP is unbounded, then we need a cut that cuts into the direction of a hopefully existing primal ray
8300  * 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
8301  * given a cut lhs <= <c,x> <= rhs, we check whether it imposes an upper bound on t and thus bounds the ray
8302  * 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>
8303  * similar, lhs > -infinity and <c,r> < 0 is good
8304  */
8305  SCIP_Real rayprod;
8306  SCIP_Real norm;
8307 
8308  rayprod = 0.0; /* for compiler */
8309  SCIP_CALL( generateCutUnboundedLP(scip, conshdlr, conss[c], violside, &row, &rayprod, conshdlrdata->checkcurvature) );
8310 
8311  if( row != NULL )
8312  {
8313  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) && SCIPisPositive(scip, rayprod) )
8314  efficacy = rayprod;
8315  else if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) && SCIPisNegative(scip, rayprod) )
8316  efficacy = -rayprod;
8317  else
8318  efficacy = 0.0;
8319 
8320  switch( conshdlrdata->scaling )
8321  {
8322  case 'o' :
8323  break;
8324 
8325  case 'g' :
8326  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding
8327  * cuts efficient which are only very slightly violated CPLEX does not seem to scale row
8328  * coefficients up too also we use infinity norm, since that seem to be the usual scaling strategy
8329  * in LP solvers (equilibrium scaling) */
8330  norm = SCIPgetRowMaxCoef(scip, row);
8331  efficacy /= MAX(1.0, norm);
8332  break;
8333 
8334  case 's' :
8335  {
8336  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
8337  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
8338  SCIP_Real minval = MIN(abslhs, absrhs);
8339 
8340  efficacy /= MAX(1.0, minval);
8341  break;
8342  }
8343 
8344  default:
8345  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
8346  SCIPABORT();
8347  return SCIP_INVALIDDATA; /*lint !e527*/
8348  }
8349  }
8350  }
8351  else
8352  {
8353  /* @todo If convex, can we easily move the refpoint closer to the feasible region to get a stronger cut?
8354  * E.g., use bisection on the line between LP solution and best primal (or LP interior)
8355  */
8356  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], sol, NULL, violside, &row, &efficacy, conshdlrdata->checkcurvature, actminefficacy) );
8357  /* @todo If generation failed not because of low efficacy, then probably because of numerical issues;
8358  * if the constraint is convex and we are desperate to get a cut, then we may try again with a better chosen reference point
8359  */
8360  }
8361 
8362  if( row == NULL ) /* failed to generate cut */
8363  continue;
8364 
8365  if( SCIPisGT(scip, efficacy, actminefficacy) && SCIPisCutApplicable(scip, row) ) /*lint !e644 */
8366  {
8367  SCIP_Bool infeasible;
8368 
8369  /* cut cuts off solution */
8370  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE /* forcecut */, &infeasible) );
8371  if( infeasible )
8372  {
8373  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(conss[c]));
8374  *result = SCIP_CUTOFF;
8375  }
8376  else
8377  {
8378  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy,
8379  SCIPconsGetName(conss[c]), consdata->lhsviol+consdata->rhsviol);
8380  *result = SCIP_SEPARATED;
8381  }
8382  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
8383 
8384  /* mark row as not removable from LP for current node, if in enforcement */
8385  if( inenforcement && !conshdlrdata->enfocutsremovable )
8386  SCIPmarkRowNotRemovableLocal(scip, row);
8387  }
8388  if( bestefficacy != NULL && efficacy > *bestefficacy )
8389  *bestefficacy = efficacy;
8390 
8391  SCIP_CALL( SCIPreleaseRow (scip, &row) );
8392  }
8393 
8394  if( *result == SCIP_CUTOFF )
8395  break;
8396 
8397  /* enforce only useful constraints
8398  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
8399  */
8400  if( c >= nusefulconss && *result == SCIP_SEPARATED )
8401  break;
8402  }
8403 
8404  return SCIP_OKAY;
8405 }
8406 
8407 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
8408  *
8409  * - 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.
8410  * - If separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only.
8411  * - If separatedlpsol is NULL, then cut is added to cutpool only.
8412  */
8413 static
8415  SCIP* scip, /**< SCIP data structure */
8416  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
8417  SCIP_CONS** conss, /**< constraints */
8418  int nconss, /**< number of constraints */
8419  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
8420  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP,
8421  * or NULL if adding to cutpool only */
8422  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
8423  )
8424 {
8425  SCIP_CONSHDLRDATA* conshdlrdata;
8426  SCIP_CONSDATA* consdata;
8427  SCIP_Bool addedtolp;
8428  SCIP_ROW* row;
8429  int c;
8430 
8431  assert(scip != NULL);
8432  assert(conshdlr != NULL);
8433  assert(conss != NULL || nconss == 0);
8434 
8435  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8436  assert(conshdlrdata != NULL);
8437 
8438  if( separatedlpsol != NULL )
8439  *separatedlpsol = FALSE;
8440 
8441  for( c = 0; c < nconss; ++c )
8442  {
8443  assert(conss[c] != NULL); /*lint !e613 */
8444 
8445  if( SCIPconsIsLocal(conss[c]) || !SCIPconsIsEnabled(conss[c]) ) /*lint !e613 */
8446  continue;
8447 
8448  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
8449 
8450  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
8451  assert(consdata != NULL);
8452 
8453  if( consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
8454  {
8455  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_RIGHT, &row, NULL,
8456  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
8457  }
8458  else if( consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
8459  {
8460  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_LEFT, &row, NULL,
8461  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
8462  }
8463  else
8464  continue;
8465 
8466  if( row == NULL )
8467  continue;
8468 
8469  addedtolp = FALSE;
8470 
8471  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
8472  if( separatedlpsol != NULL )
8473  {
8474  SCIP_Real efficacy;
8475  SCIP_Real norm;
8476 
8477  efficacy = -SCIPgetRowLPFeasibility(scip, row);
8478  switch( conshdlrdata->scaling )
8479  {
8480  case 'o' :
8481  break;
8482 
8483  case 'g' :
8484  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
8485  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too
8486  * also we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
8487  * scaling) */
8488  norm = SCIPgetRowMaxCoef(scip, row);
8489  efficacy /= MAX(1.0, norm);
8490  break;
8491 
8492  case 's' :
8493  {
8494  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
8495  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
8496  SCIP_Real minval = MIN(abslhs, absrhs);
8497 
8498  efficacy /= MAX(1.0, minval);
8499  break;
8500  }
8501 
8502  default:
8503  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
8504  SCIPABORT();
8505  return SCIP_INVALIDDATA; /*lint !e527*/
8506  }
8507 
8508  if( efficacy >= minefficacy )
8509  {
8510  SCIP_Bool infeasible;
8511 
8512  *separatedlpsol = TRUE;
8513  addedtolp = TRUE;
8514  SCIP_CALL( SCIPaddCut(scip, NULL, row, TRUE, &infeasible) );
8515  assert( ! infeasible );
8516  SCIPdebugMessage("added linearization cut <%s> to LP, efficacy = %g\n", SCIProwGetName(row), efficacy);
8517  }
8518  }
8519 
8520  if( !SCIProwIsLocal(row) && !addedtolp )
8521  {
8522  SCIP_CALL( SCIPaddPoolCut(scip, row) );
8523  SCIPdebugMessage("added linearization cut <%s> to cutpool\n", SCIProwGetName(row));
8524  }
8525 
8526  SCIP_CALL( SCIPreleaseRow(scip, &row) );
8527  }
8528 
8529  return SCIP_OKAY;
8530 }
8531 
8532 /** processes the event that a new primal solution has been found */
8533 static
8534 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
8536  SCIP_CONSHDLRDATA* conshdlrdata;
8537  SCIP_CONSHDLR* conshdlr;
8538  SCIP_CONS** conss;
8539  int nconss;
8540  SCIP_SOL* sol;
8541 
8542  assert(scip != NULL);
8543  assert(event != NULL);
8544  assert(eventdata != NULL);
8545  assert(eventhdlr != NULL);
8546 
8547  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
8548 
8549  conshdlr = (SCIP_CONSHDLR*)eventdata;
8550 
8551  nconss = SCIPconshdlrGetNConss(conshdlr);
8552 
8553  if( nconss == 0 )
8554  return SCIP_OKAY;
8555 
8556  sol = SCIPeventGetSol(event);
8557  assert(sol != NULL);
8558 
8559  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8560  assert(conshdlrdata != NULL);
8561 
8562  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
8563  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
8564  * or are from the tree, but postprocessed via proposeFeasibleSolution
8565  */
8566  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
8567  return SCIP_OKAY;
8568 
8569  conss = SCIPconshdlrGetConss(conshdlr);
8570  assert(conss != NULL);
8571 
8572  SCIPdebugMessage("caught new sol event %x from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
8573 
8574  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
8575 
8576  return SCIP_OKAY;
8577 }
8578 
8579 /** registers branching candidates according to convexification gap rule
8580  *
8581  * That is, computes for every nonconvex term the gap between the terms value in the LP solution and the value of the underestimator
8582  * as it would be (and maybe has been) constructed by the separation routines of this constraint handler. Then it registers all
8583  * variables occurring in each term with the computed gap. If variables appear in more than one term, they are registered several times.
8584  */
8585 static
8587  SCIP* scip, /**< SCIP data structure */
8588  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8589  SCIP_CONS** conss, /**< constraints to check */
8590  int nconss, /**< number of constraints to check */
8591  int* nnotify /**< counter for number of notifications performed */
8592  )
8593 {
8594  SCIP_CONSDATA* consdata;
8595  int c;
8596  int j;
8597  SCIP_Bool xbinary;
8598  SCIP_Bool ybinary;
8599  SCIP_Bool xunbounded;
8600  SCIP_Bool yunbounded;
8601  SCIP_VAR* x;
8602  SCIP_VAR* y;
8603  SCIP_Real xlb;
8604  SCIP_Real xub;
8605  SCIP_Real xval;
8606  SCIP_Real ylb;
8607  SCIP_Real yub;
8608  SCIP_Real yval;
8609  SCIP_Real gap;
8610  SCIP_Real coef_;
8611 
8612  assert(scip != NULL);
8613  assert(conshdlr != NULL);
8614  assert(conss != NULL || nconss == 0);
8615 
8616  *nnotify = 0;
8617  yval = SCIP_INVALID;
8618  xval = SCIP_INVALID;
8619 
8620  for( c = 0; c < nconss; ++c )
8621  {
8622  assert(conss != NULL);
8623  consdata = SCIPconsGetData(conss[c]);
8624  assert(consdata != NULL);
8625 
8626  if( !consdata->nquadvars )
8627  continue;
8628 
8629  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
8630  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
8631  continue;
8632  SCIPdebugMessage("cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
8633 
8634  /* square terms */
8635  for( j = 0; j < consdata->nquadvars; ++j )
8636  {
8637  x = consdata->quadvarterms[j].var;
8638  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef < 0) ||
8639  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef > 0) )
8640  {
8641  xlb = SCIPvarGetLbLocal(x);
8642  xub = SCIPvarGetUbLocal(x);
8643  if( SCIPisRelEQ(scip, xlb, xub) )
8644  {
8645  SCIPdebugMessage("ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
8646  continue;
8647  }
8648 
8649  xval = SCIPgetSolVal(scip, NULL, x);
8650 
8651  /* if variable is at bounds, then no need to branch, since secant is exact there */
8652  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
8653  continue;
8654 
8655  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
8656  gap = SCIPinfinity(scip);
8657  else
8658  gap = (xval-xlb)*(xub-xval)/(1+2*ABS(xval));
8659  assert(!SCIPisFeasNegative(scip, gap));
8660  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(gap, 0.0), SCIP_INVALID) );
8661  ++*nnotify;
8662  }
8663  }
8664 
8665  /* bilinear terms */
8666  for( j = 0; j < consdata->nbilinterms; ++j )
8667  {
8668  /* if any of the variables if fixed, then it actually behaves like a linear term, so we don't need to branch on it */
8669  x = consdata->bilinterms[j].var1;
8670  xlb = SCIPvarGetLbLocal(x);
8671  xub = SCIPvarGetUbLocal(x);
8672  if( SCIPisRelEQ(scip, xlb, xub) )
8673  continue;
8674 
8675  y = consdata->bilinterms[j].var2;
8676  ylb = SCIPvarGetLbLocal(y);
8677  yub = SCIPvarGetUbLocal(y);
8678  if( SCIPisRelEQ(scip, ylb, yub) )
8679  continue;
8680 
8681  xunbounded = SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub);
8682  yunbounded = SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub);
8683 
8684  /* compute gap, if both variable are bounded */
8685  gap = SCIPinfinity(scip);
8686  if( !xunbounded && !yunbounded )
8687  {
8688  xval = SCIPgetSolVal(scip, NULL, x);
8689  yval = SCIPgetSolVal(scip, NULL, y);
8690 
8691  /* if both variables are at one of its bounds, then no need to branch, since McCormick is exact there */
8692  if( (SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub)) &&
8693  ( SCIPisLE(scip, yval, ylb) || SCIPisGE(scip, yval, yub)) )
8694  continue;
8695 
8696  xval = MAX(xlb, MIN(xval, xub));
8697  yval = MAX(ylb, MIN(yval, yub));
8698 
8699  coef_ = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? -consdata->bilinterms[j].coef : consdata->bilinterms[j].coef;
8700  if( coef_ > 0.0 )
8701  {
8702  if( (xub-xlb)*yval + (yub-ylb)*xval <= xub*yub - xlb*ylb )
8703  gap = (xval*yval - xlb*yval - ylb*xval + xlb*ylb) / (1+sqrt(xval*xval + yval*yval));
8704  else
8705  gap = (xval*yval - xval*yub - yval*xub + xub*yub) / (1+sqrt(xval*xval + yval*yval));
8706  }
8707  else
8708  { /* coef_ < 0 */
8709  if( (xub-xlb)*yval - (yub-ylb)*xval <= xub*ylb - xlb*yub )
8710  gap = -(xval*yval - xval*ylb - yval*xub + xub*ylb) / (1+sqrt(xval*xval + yval*yval));
8711  else
8712  gap = -(xval*yval - xval*yub - yval*xlb + xlb*yub) / (1+sqrt(xval*xval + yval*yval));
8713  }
8714 
8715  assert(!SCIPisNegative(scip, gap / MAX3(MAX(REALABS(xlb), REALABS(xub)), MAX(REALABS(ylb), REALABS(yub)), 1.0))); /*lint !e666*/
8716  if( gap < 0.0 )
8717  gap = 0.0;
8718  }
8719 
8720  /* if one of the variables is binary or integral with domain width 1, then branching on this makes the term linear, so prefer this */
8721  xbinary = SCIPvarIsBinary(x) || (SCIPvarIsIntegral(x) && xub - xlb < 1.5);
8722  ybinary = SCIPvarIsBinary(y) || (SCIPvarIsIntegral(y) && yub - ylb < 1.5);
8723  if( xbinary )
8724  {
8726  ++*nnotify;
8727  }
8728  if( ybinary )
8729  {
8731  ++*nnotify;
8732  }
8733  if( xbinary || ybinary )
8734  continue;
8735 
8736  /* if one of the variables is unbounded, then branch on it first */
8737  if( xunbounded )
8738  {
8740  ++*nnotify;
8741  }
8742  if( yunbounded )
8743  {
8745  ++*nnotify;
8746  }
8747  if( xunbounded || yunbounded )
8748  continue;
8749 
8750  /* if both variables are integral, prefer the one with the smaller domain, so variable gets fixed soon
8751  * does not seem to work well on tln instances, so disable for now and may look at it later again
8752  */
8753 #ifdef BRANCHTOLINEARITY
8754  if( SCIPvarIsIntegral(x) && SCIPvarIsIntegral(y) )
8755  {
8756  if( SCIPisLT(scip, xub-xlb, yub-ylb) )
8757  {
8759  ++*nnotify;
8760  continue;
8761  }
8762  if( SCIPisGT(scip, xub-xlb, yub-ylb) )
8763  {
8765  ++*nnotify;
8766  continue;
8767  }
8768  }
8769 #endif
8770 
8771  /* in the regular case, suggest those variables which are not at its bounds for branching
8772  * this is, because after branching both variables will be one the bounds, and McCormick will be exact then */
8773  if( !SCIPisLE(scip, xval, xlb) && !SCIPisGE(scip, xval, xub) )
8774  {
8776  ++*nnotify;
8777  }
8778  if( !SCIPisLE(scip, yval, ylb) && !SCIPisGE(scip, yval, yub) )
8779  {
8781  ++*nnotify;
8782  }
8783  }
8784  }
8785 
8786  SCIPdebugMessage("registered %d branching candidates\n", *nnotify);
8787 
8788  return SCIP_OKAY;
8789 }
8790 
8791 /** registers branching candidates according to constraint violation rule
8792  *
8793  * That is, registers all variables appearing in nonconvex terms^1 with a score that is the violation of the constraint.
8794  * This is the same rule as is applied in cons_nonlinear and other nonlinear constraint handlers.
8795  *
8796  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
8797  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
8798  */
8799 static
8801  SCIP* scip, /**< SCIP data structure */
8802  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8803  SCIP_CONS** conss, /**< constraints to check */
8804  int nconss, /**< number of constraints to check */
8805  int* nnotify /**< counter for number of notifications performed */
8806  )
8807 {
8808  SCIP_CONSDATA* consdata;
8809  SCIP_QUADVARTERM* quadvarterm;
8810  int c;
8811  int j;
8812  SCIP_VAR* x;
8813  SCIP_Real xlb;
8814  SCIP_Real xub;
8815  SCIP_Real xval;
8816 
8817  assert(scip != NULL);
8818  assert(conshdlr != NULL);
8819  assert(conss != NULL || nconss == 0);
8820 
8821  *nnotify = 0;
8822 
8823  for( c = 0; c < nconss; ++c )
8824  {
8825  assert(conss != NULL);
8826  consdata = SCIPconsGetData(conss[c]);
8827  assert(consdata != NULL);
8828 
8829  if( !consdata->nquadvars )
8830  continue;
8831 
8832  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
8833  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
8834  continue;
8835  SCIPdebugMessage("cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
8836 
8837  for( j = 0; j < consdata->nquadvars; ++j )
8838  {
8839  quadvarterm = &consdata->quadvarterms[j];
8840  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
8841  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
8842  quadvarterm->nadjbilin > 0 )
8843  {
8844  x = quadvarterm->var;
8845  xlb = SCIPvarGetLbLocal(x);
8846  xub = SCIPvarGetUbLocal(x);
8847 
8848  if( quadvarterm->nadjbilin == 0 )
8849  {
8850  xval = SCIPgetSolVal(scip, NULL, x);
8851 
8852  /* if variable is at bounds and only in a nonconvex square term, then no need to branch, since secant is exact there */
8853  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
8854  continue;
8855  }
8856 
8857  if( SCIPisRelEQ(scip, xlb, xub) )
8858  {
8859  SCIPdebugMessage("ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
8860  continue;
8861  }
8862 
8863  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
8864  ++*nnotify;
8865  }
8866  }
8867  }
8868 
8869  SCIPdebugMessage("registered %d branching candidates\n", *nnotify);
8870 
8871  return SCIP_OKAY;
8872 }
8873 
8874 /** registers branching candidates according to centrality rule
8875  *
8876  * That is, registers all variables appearing in nonconvex terms^1 with a score that is given by the distance of the
8877  * variable value from its bounds. This rule should not make sense, as the distance to the bounds is also (often) considered
8878  * by the branching rule later on.
8879  *
8880  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
8881  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
8882  */
8883 static
8885  SCIP* scip, /**< SCIP data structure */
8886  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8887  SCIP_CONS** conss, /**< constraints to check */
8888  int nconss, /**< number of constraints to check */
8889  int* nnotify /**< counter for number of notifications performed */
8890  )
8891 {
8892  SCIP_CONSDATA* consdata;
8893  SCIP_QUADVARTERM* quadvarterm;
8894  int c;
8895  int j;
8896  SCIP_VAR* x;
8897  SCIP_Real xlb;
8898  SCIP_Real xub;
8899  SCIP_Real xval;
8900  SCIP_Real score;
8901 
8902  assert(scip != NULL);
8903  assert(conshdlr != NULL);
8904  assert(conss != NULL || nconss == 0);
8905 
8906  *nnotify = 0;
8907 
8908  for( c = 0; c < nconss; ++c )
8909  {
8910  assert(conss != NULL);
8911  consdata = SCIPconsGetData(conss[c]);
8912  assert(consdata != NULL);
8913 
8914  if( !consdata->nquadvars )
8915  continue;
8916 
8917  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
8918  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
8919  continue;
8920  SCIPdebugMessage("cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
8921 
8922  for( j = 0; j < consdata->nquadvars; ++j )
8923  {
8924  quadvarterm = &consdata->quadvarterms[j];
8925  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
8926  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
8927  quadvarterm->nadjbilin > 0 )
8928  {
8929  x = quadvarterm->var;
8930  xlb = SCIPvarGetLbLocal(x);
8931  xub = SCIPvarGetUbLocal(x);
8932 
8933  if( SCIPisRelEQ(scip, xlb, xub) )
8934  {
8935  SCIPdebugMessage("ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
8936  continue;
8937  }
8938 
8939  xval = SCIPgetSolVal(scip, NULL, x);
8940  xval = MAX(xlb, MIN(xub, xval));
8941 
8942  /* compute relative difference of xval to each of its bounds
8943  * and scale such that if xval were in the middle, we get a score of 1
8944  * and if xval is on one its bounds, the score is 0
8945  */
8946  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
8947  {
8948  if( (!SCIPisInfinity(scip, -xlb) && SCIPisEQ(scip, xval, xlb)) || (!SCIPisInfinity(scip, xub) && SCIPisEQ(scip, xval, xub)) )
8949  score = 0.0;
8950  else
8951  score = 1.0;
8952  }
8953  else
8954  {
8955  score = 4.0 * (xval - xlb) * (xub - xval) / ((xub - xlb) * (xub - xlb));
8956  }
8957 
8958  SCIP_CALL( SCIPaddExternBranchCand(scip, x, score, SCIP_INVALID) );
8959  ++*nnotify;
8960  }
8961  }
8962  }
8963 
8964  SCIPdebugMessage("registered %d branching candidates\n", *nnotify);
8965 
8966  return SCIP_OKAY;
8967 }
8968 
8969 /** registers branching candidates */
8970 static
8972  SCIP* scip, /**< SCIP data structure */
8973  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8974  SCIP_CONS** conss, /**< constraints to check */
8975  int nconss, /**< number of constraints to check */
8976  int* nnotify /**< counter for number of notifications performed */
8977  )
8978 {
8979  SCIP_CONSHDLRDATA* conshdlrdata;
8980 
8981  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8982  assert(conshdlrdata != NULL);
8983 
8984  switch( conshdlrdata->branchscoring )
8985  {
8986  case 'g' :
8987  SCIP_CALL( registerBranchingCandidatesGap(scip, conshdlr, conss, nconss, nnotify) );
8988  break;
8989 
8990  case 'v' :
8991  SCIP_CALL( registerBranchingCandidatesViolation(scip, conshdlr, conss, nconss, nnotify) );
8992  break;
8993 
8994  case 'c' :
8995  SCIP_CALL( registerBranchingCandidatesCentrality(scip, conshdlr, conss, nconss, nnotify) );
8996  break;
8997 
8998  default :
8999  SCIPerrorMessage("invalid branchscoring selection");
9000  SCIPABORT();
9001  return SCIP_ERROR; /*lint !e527*/
9002  }
9003 
9004  return SCIP_OKAY;
9005 }
9006 
9007 
9008 /** registers a quadratic variable from a violated constraint as branching candidate that has a large absolute value in the LP relaxation */
9009 static
9011  SCIP* scip, /**< SCIP data structure */
9012  SCIP_CONS** conss, /**< constraints */
9013  int nconss, /**< number of constraints */
9014  SCIP_VAR** brvar /**< buffer to store branching variable */
9015  )
9016 {
9017  SCIP_CONSDATA* consdata;
9018  SCIP_Real val;
9019  SCIP_Real brvarval;
9020  int i;
9021  int c;
9022 
9023  assert(scip != NULL);
9024  assert(conss != NULL || nconss == 0);
9025 
9026  *brvar = NULL;
9027  brvarval = -1.0;
9028 
9029  for( c = 0; c < nconss; ++c )
9030  {
9031  assert(conss != NULL);
9032  consdata = SCIPconsGetData(conss[c]);
9033  assert(consdata != NULL);
9034 
9035  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
9036  continue;
9037 
9038  for( i = 0; i < consdata->nquadvars; ++i )
9039  {
9040  /* do not propose fixed variables */
9041  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
9042  continue;
9043  val = SCIPgetSolVal(scip, NULL, consdata->quadvarterms[i].var);
9044  if( ABS(val) > brvarval )
9045  {
9046  brvarval = ABS(val);
9047  *brvar = consdata->quadvarterms[i].var;
9048  }
9049  }
9050  }
9051 
9052  if( *brvar != NULL )
9053  {
9054  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
9055  }
9056 
9057  return SCIP_OKAY;
9058 }
9059 
9060 /** replaces violated quadratic constraints where all quadratic variables are fixed by linear constraints */
9061 static
9063  SCIP* scip, /**< SCIP data structure */
9064  SCIP_CONS** conss, /**< constraints */
9065  int nconss, /**< number of constraints */
9066  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
9067  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
9068  SCIP_Bool* infeasible /**< whether we detected infeasibility */
9069  )
9070 {
9071  SCIP_CONS* cons;
9072  SCIP_CONSDATA* consdata;
9073  SCIP_RESULT checkresult;
9074  SCIP_Real constant;
9075  SCIP_Real val1;
9076  SCIP_Real val2;
9077  int i;
9078  int c;
9079 
9080  assert(scip != NULL);
9081  assert(conss != NULL || nconss == 0);
9082  assert(addedcons != NULL);
9083  assert(reduceddom != NULL);
9084  assert(infeasible != NULL);
9085 
9086  *addedcons = FALSE;
9087  *reduceddom = FALSE;
9088  *infeasible = FALSE;
9089 
9090  for( c = 0; c < nconss; ++c )
9091  {
9092  assert(conss != NULL);
9093  consdata = SCIPconsGetData(conss[c]);
9094  assert(consdata != NULL);
9095 
9096  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
9097  continue;
9098 
9099  constant = 0.0;
9100 
9101  for( i = 0; i < consdata->nquadvars; ++i )
9102  {
9103  /* variables should be fixed if constraint is violated */
9104  assert(SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
9105 
9106  val1 = (SCIPvarGetUbLocal(consdata->quadvarterms[i].var) + SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) / 2.0;
9107  constant += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val1) * val1;
9108  }
9109 
9110  for( i = 0; i < consdata->nbilinterms; ++i )
9111  {
9112  val1 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var1) + SCIPvarGetLbLocal(consdata->bilinterms[i].var1)) / 2.0;
9113  val2 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var2) + SCIPvarGetLbLocal(consdata->bilinterms[i].var2)) / 2.0;
9114  constant += consdata->bilinterms[i].coef * val1 * val2;
9115  }
9116 
9117  /* check if we have a bound change */
9118  if ( consdata->nlinvars == 1 )
9119  {
9120  SCIP_Bool tightened;
9121  SCIP_Real coef;
9122  SCIP_Real lhs;
9123  SCIP_Real rhs;
9124 
9125  coef = *consdata->lincoefs;
9126 
9127  /* compute lhs/rhs */
9128  if ( SCIPisInfinity(scip, -consdata->lhs) )
9129  lhs = -SCIPinfinity(scip);
9130  else
9131  lhs = consdata->lhs - constant;
9132 
9133  if ( SCIPisInfinity(scip, consdata->rhs) )
9134  rhs = SCIPinfinity(scip);
9135  else
9136  rhs = consdata->rhs - constant;
9137 
9138  SCIPdebugMessage("Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(*consdata->linvars), rhs);
9139 
9140  /* possibly correct lhs/rhs */
9141  assert( ! SCIPisZero(scip, coef) );
9142  if ( coef >= 0.0 )
9143  {
9144  if ( ! SCIPisInfinity(scip, -lhs) )
9145  lhs /= coef;
9146  if ( ! SCIPisInfinity(scip, rhs) )
9147  rhs /= coef;
9148  }
9149  else
9150  {
9151  SCIP_Real h;
9152  h = rhs;
9153  if ( ! SCIPisInfinity(scip, -lhs) )
9154  rhs = lhs/coef;
9155  else
9156  rhs = SCIPinfinity(scip);
9157 
9158  if ( ! SCIPisInfinity(scip, h) )
9159  lhs = h/coef;
9160  else
9161  lhs = -SCIPinfinity(scip);
9162  }
9163  SCIPdebugMessage("Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(*consdata->linvars), rhs);
9164 
9165  if( SCIPisInfinity(scip, -rhs) || SCIPisInfinity(scip, lhs) )
9166  {
9167  SCIPdebugMessage("node will marked as infeasible since lb/ub of %s is +/-infinity\n",
9168  SCIPvarGetName(consdata->linvars[0]));
9169 
9170  *infeasible = TRUE;
9171  return SCIP_OKAY;
9172  }
9173 
9174  if ( ! SCIPisInfinity(scip, -lhs) )
9175  {
9176  SCIP_CALL( SCIPtightenVarLb(scip, *consdata->linvars, lhs, TRUE, infeasible, &tightened) );
9177  if ( *infeasible )
9178  {
9179  SCIPdebugMessage("Lower bound leads to infeasibility.\n");
9180  return SCIP_OKAY;
9181  }
9182  if ( tightened )
9183  {
9184  SCIPdebugMessage("Lower boundx changed.\n");
9185  *reduceddom = TRUE;
9186  return SCIP_OKAY;
9187  }
9188  }
9189 
9190  if ( ! SCIPisInfinity(scip, rhs) )
9191  {
9192  SCIP_CALL( SCIPtightenVarUb(scip, *consdata->linvars, rhs, TRUE, infeasible, &tightened) );
9193  if ( *infeasible )
9194  {
9195  SCIPdebugMessage("Upper bound leads to infeasibility.\n");
9196  return SCIP_OKAY;
9197  }
9198  if ( tightened )
9199  {
9200  SCIPdebugMessage("Upper bound changed.\n");
9201  *reduceddom = TRUE;
9202  return SCIP_OKAY;
9203  }
9204  }
9205  }
9206  else
9207  {
9208  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
9209  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
9210  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : (consdata->lhs - constant)),
9211  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : (consdata->rhs - constant)),
9212  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
9213  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
9214  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
9215  SCIPconsIsStickingAtNode(conss[c])) );
9216 
9217  SCIPdebugMessage("replace quadratic constraint <%s> by linear constraint after all quadratic vars have been fixed\n", SCIPconsGetName(conss[c]) );
9218  SCIPdebugPrintCons(scip, cons, NULL);
9219 
9220  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
9221 
9222  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
9223  {
9224  SCIPdebugMessage("linear constraint is feasible and LP optimal, thus do not add\n");
9225  }
9226  else
9227  {
9228  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
9229  *addedcons = TRUE;
9230  }
9231  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9232  }
9233  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
9234  }
9235 
9236  return SCIP_OKAY;
9237 }
9238 
9239 /** tightens a lower bound on a variable and checks the result */
9240 static
9242  SCIP* scip, /**< SCIP data structure */
9243  SCIP_CONS* cons, /**< constraint where we currently propagate */
9244  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9245  SCIP_VAR* var, /**< variable which domain we might reduce */
9246  SCIP_Real bnd, /**< new lower bound for variable */
9247  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
9248  int* nchgbds /**< counter to increase if a bound was tightened */
9249  )
9250 {
9251  SCIP_Bool infeas;
9252  SCIP_Bool tightened;
9253 
9254  assert(scip != NULL);
9255  assert(cons != NULL);
9256  assert(intervalinfty > 0.0);
9257  assert(bnd > -intervalinfty);
9258  assert(var != NULL);
9259  assert(result != NULL);
9260  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9261  assert(nchgbds != NULL);
9262 
9263  /* new bound is no improvement */
9264  if( SCIPisHugeValue(scip, -bnd) || SCIPisLE(scip, bnd, SCIPvarGetLbLocal(var)) )
9265  return SCIP_OKAY;
9266 
9267  if( SCIPisInfinity(scip, bnd) )
9268  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
9269  *result = SCIP_CUTOFF;
9270  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9271  return SCIP_OKAY;
9272  }
9273 
9274  /* new lower bound is very low (between -intervalinfty and -SCIPinfinity()) */
9275  if( SCIPisInfinity(scip, -bnd) )
9276  return SCIP_OKAY;
9277 
9278  bnd = SCIPadjustedVarLb(scip, var, bnd);
9279  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
9280  if( infeas )
9281  {
9282  SCIPdebugMessage("%s found constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n",
9283  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
9284  *result = SCIP_CUTOFF;
9285  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9286  return SCIP_OKAY;
9287  }
9288  if( tightened )
9289  {
9290  SCIPdebugMessage("%s tightened lower bound of variable <%s> in constraint <%s> to %g\n",
9291  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
9292  ++*nchgbds;
9293  *result = SCIP_REDUCEDDOM;
9294  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9295  }
9296 
9297  return SCIP_OKAY;
9298 }
9299 
9300 /** tightens an upper bound on a variable and checks the result */
9301 static
9303  SCIP* scip, /**< SCIP data structure */
9304  SCIP_CONS* cons, /**< constraint where we currently propagate */
9305  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9306  SCIP_VAR* var, /**< variable which domain we might reduce */
9307  SCIP_Real bnd, /**< new upper bound for variable */
9308  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
9309  int* nchgbds /**< counter to increase if a bound was tightened */
9310  )
9311 {
9312  SCIP_Bool infeas;
9313  SCIP_Bool tightened;
9314 
9315  assert(scip != NULL);
9316  assert(cons != NULL);
9317  assert(intervalinfty > 0.0);
9318  assert(bnd < intervalinfty);
9319  assert(var != NULL);
9320  assert(result != NULL);
9321  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9322  assert(nchgbds != NULL);
9323 
9324  /* new bound is no improvement */
9325  if( SCIPisHugeValue(scip, bnd) || SCIPisGE(scip, bnd, SCIPvarGetUbLocal(var)) )
9326  return SCIP_OKAY;
9327 
9328  if( SCIPisInfinity(scip, -bnd) )
9329  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
9330  *result = SCIP_CUTOFF;
9331  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9332  return SCIP_OKAY;
9333  }
9334 
9335  /* new upper bound is very high (between SCIPinfinity() and intervalinfty) */
9336  if( SCIPisInfinity(scip, bnd) )
9337  return SCIP_OKAY;
9338 
9339  bnd = SCIPadjustedVarUb(scip, var, bnd);
9340  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
9341  if( infeas )
9342  {
9343  SCIPdebugMessage("%s found constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n",
9344  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
9345  *result = SCIP_CUTOFF;
9346  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9347  return SCIP_OKAY;
9348  }
9349  if( tightened )
9350  {
9351  SCIPdebugMessage("%s tightened upper bound of variable <%s> in constraint <%s> to %g\n",
9352  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
9353  ++*nchgbds;
9354  *result = SCIP_REDUCEDDOM;
9355  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9356  }
9357 
9358  return SCIP_OKAY;
9359 }
9360 
9361 /** 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 */
9362 static
9364  SCIP* scip, /**< SCIP data structure */
9365  SCIP_CONS* cons, /**< constraint where we currently propagate */
9366  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9367  SCIP_VAR* var, /**< variable which bounds with might tighten */
9368  SCIP_Real a, /**< coefficient in square term */
9369  SCIP_INTERVAL b, /**< coefficient in linear term */
9370  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9371  SCIP_RESULT* result, /**< result of propagation */
9372  int* nchgbds /**< buffer where to add number of tightened bounds */
9373  )
9374 {
9375  SCIP_INTERVAL newrange;
9376 
9377  assert(scip != NULL);
9378  assert(cons != NULL);
9379  assert(var != NULL);
9380  assert(result != NULL);
9381  assert(nchgbds != NULL);
9382 
9383  /* compute solution of a*x^2 + b*x \in rhs */
9384  if( a == 0.0 && SCIPintervalGetInf(b) == 0.0 && SCIPintervalGetSup(b) == 0.0 )
9385  {
9386  /* relatively easy case: 0.0 \in rhs, thus check if infeasible or just redundant */
9387  if( SCIPintervalGetInf(rhs) > 0.0 || SCIPintervalGetSup(rhs) < 0.0 )
9388  {
9389  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9390  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9391  *result = SCIP_CUTOFF;
9392  }
9393  return SCIP_OKAY;
9394  }
9395  else if( SCIPvarGetLbLocal(var) >= 0.0 )
9396  {
9397  SCIP_INTERVAL a_;
9398 
9399  /* need only positive solutions */
9400  SCIPintervalSet(&a_, a);
9401  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &newrange, a_, b, rhs);
9402  }
9403  else if( SCIPvarGetUbLocal(var) <= 0.0 )
9404  {
9405  /* need only negative solutions */
9406  SCIP_INTERVAL a_;
9407  SCIP_INTERVAL tmp;
9408  SCIPintervalSet(&a_, a);
9410  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &tmp, a_, tmp, rhs);
9411  if( SCIPintervalIsEmpty(intervalinfty, tmp) )
9412  {
9413  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9414  *result = SCIP_CUTOFF;
9415  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9416  return SCIP_OKAY;
9417  }
9419  }
9420  else
9421  {
9422  /* need both positive and negative solution */
9423  SCIP_INTERVAL a_;
9424  SCIPintervalSet(&a_, a);
9425  SCIPintervalSolveUnivariateQuadExpression(intervalinfty, &newrange, a_, b, rhs);
9426  }
9427 
9428  /* 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); */
9429 
9430  if( SCIPisInfinity(scip, SCIPintervalGetInf(newrange)) || SCIPisInfinity(scip, -SCIPintervalGetSup(newrange)) )
9431  {
9432  /* domain outside [-infty, +infty] -> declare node infeasible */
9433  SCIPdebugMessage("found <%s> infeasible because propagated domain of quadratic variable <%s> is outside of (-infty, +infty)\n",
9434  SCIPconsGetName(cons), SCIPvarGetName(var));
9435  *result = SCIP_CUTOFF;
9436  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9437  return SCIP_OKAY;
9438  }
9439 
9440  if( SCIPintervalIsEmpty(intervalinfty, newrange) )
9441  {
9442  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9443  *result = SCIP_CUTOFF;
9444  return SCIP_OKAY;
9445  }
9446 
9447  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(newrange)) )
9448  {
9449  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, SCIPintervalGetInf(newrange), result, nchgbds) );
9450  if( *result == SCIP_CUTOFF )
9451  return SCIP_OKAY;
9452  }
9453 
9454  if( !SCIPisInfinity(scip, SCIPintervalGetSup(newrange)) )
9455  {
9456  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, SCIPintervalGetSup(newrange), result, nchgbds) );
9457  if( *result == SCIP_CUTOFF )
9458  return SCIP_OKAY;
9459  }
9460 
9461  return SCIP_OKAY;
9462 }
9463 
9464 /* The new version below computes potentially tighter bounds, but also always adds a small safety area since it is not implemented roundingsafe.
9465  * This may be a reason why it gives worse results on one of two instances.
9466  * Further, I have only very few instances where one can expect a difference.
9467  */
9468 #ifndef PROPBILINNEW
9469 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
9470  *
9471  * @note Domain reductions for y are not deduced.
9472  */
9473 static
9475  SCIP* scip, /**< SCIP data structure */
9476  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
9477  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9478  SCIP_VAR* x, /**< first variable */
9479  SCIP_Real xsqrcoef, /**< square coefficient of x */
9480  SCIP_Real xlincoef, /**< linear coefficient of x */
9481  SCIP_VAR* y, /**< second variable */
9482  SCIP_Real ysqrcoef, /**< square coefficient of y */
9483  SCIP_Real ylincoef, /**< linear coefficient of y */
9484  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
9485  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9486  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
9487  int* nchgbds /**< counter to increment if domain reductions are found */
9488  )
9489 {
9490  SCIP_INTERVAL myrhs;
9491  SCIP_INTERVAL varbnds;
9492  SCIP_INTERVAL lincoef;
9493 
9494  assert(scip != NULL);
9495  assert(cons != NULL);
9496  assert(x != NULL);
9497  assert(y != NULL);
9498  assert(x != y);
9499  assert(result != NULL);
9500  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9501  assert(nchgbds != NULL);
9502  assert(bilincoef != 0.0);
9503 
9504  if( SCIPintervalIsEntire(intervalinfty, rhs) )
9505  return SCIP_OKAY;
9506 
9507  /* try to find domain reductions for x */
9509 
9510  /* put ysqrcoef*y^2 + ylincoef * y into rhs */
9511  if( SCIPintervalGetSup(rhs) >= intervalinfty )
9512  {
9513  /* if rhs is unbounded by above, it is sufficient to get an upper bound on ysqrcoef*y^2 + ylincoef * y */
9514  SCIP_ROUNDMODE roundmode;
9515  SCIP_Real tmp;
9516 
9517  SCIPintervalSet(&lincoef, ylincoef);
9518  tmp = SCIPintervalQuadUpperBound(intervalinfty, ysqrcoef, lincoef, varbnds);
9519  roundmode = SCIPintervalGetRoundingMode();
9521  SCIPintervalSetBounds(&myrhs, SCIPintervalGetInf(rhs) - tmp, intervalinfty);
9522  SCIPintervalSetRoundingMode(roundmode);
9523  }
9524  else if( SCIPintervalGetInf(rhs) <= -intervalinfty )
9525  {
9526  /* if rhs is unbounded by below, it is sufficient to get a lower bound on ysqrcoef*y^2 + ylincoef * y */
9527  SCIP_ROUNDMODE roundmode;
9528  SCIP_Real tmp;
9529 
9530  SCIPintervalSet(&lincoef, -ylincoef);
9531  tmp = -SCIPintervalQuadUpperBound(intervalinfty, -ysqrcoef, lincoef, varbnds);
9532  roundmode = SCIPintervalGetRoundingMode();
9534  SCIPintervalSetBounds(&myrhs, -intervalinfty, SCIPintervalGetSup(rhs) - tmp);
9535  SCIPintervalSetRoundingMode(roundmode);
9536  }
9537  else
9538  {
9539  /* if rhs is bounded, we need both bounds on ysqrcoef*y^2 + ylincoef * y */
9540  SCIP_INTERVAL tmp;
9541 
9542  SCIPintervalSet(&lincoef, ylincoef);
9543  SCIPintervalQuad(intervalinfty, &tmp, ysqrcoef, lincoef, varbnds);
9544  SCIPintervalSub(intervalinfty, &myrhs, rhs, tmp);
9545  }
9546 
9547  /* create equation xsqrcoef * x^2 + (xlincoef + bilincoef * [ylb, yub]) * x \in myrhs */
9548  SCIPintervalMulScalar(intervalinfty, &lincoef, varbnds, bilincoef);
9549  SCIPintervalAddScalar(intervalinfty, &lincoef, lincoef, xlincoef);
9550 
9551  /* propagate bounds on x */
9552  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, x, xsqrcoef, lincoef, myrhs, result, nchgbds) );
9553 
9554  return SCIP_OKAY;
9555 }
9556 #else
9557 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
9558  *
9559  * @note Domain reductions for y are not deduced.
9560  */
9561 static
9563  SCIP* scip, /**< SCIP data structure */
9564  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
9565  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9566  SCIP_VAR* x, /**< first variable */
9567  SCIP_Real xsqrcoef, /**< square coefficient of x */
9568  SCIP_Real xlincoef, /**< linear coefficient of x */
9569  SCIP_VAR* y, /**< second variable */
9570  SCIP_Real ysqrcoef, /**< square coefficient of y */
9571  SCIP_Real ylincoef, /**< linear coefficient of y */
9572  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
9573  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9574  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
9575  int* nchgbds /**< counter to increment if domain reductions are found */
9576  )
9577 {
9578  SCIP_INTERVAL xbnds;
9579  SCIP_INTERVAL ybnds;
9580 
9581  assert(scip != NULL);
9582  assert(cons != NULL);
9583  assert(x != NULL);
9584  assert(y != NULL);
9585  assert(x != y);
9586  assert(result != NULL);
9587  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9588  assert(nchgbds != NULL);
9589  assert(bilincoef != 0.0);
9590 
9591  if( SCIPintervalIsEntire(intervalinfty, rhs) )
9592  return SCIP_OKAY;
9593 
9594  SCIPintervalSetBounds(&xbnds,
9595  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x))), /*lint !e666*/
9596  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)))); /*lint !e666*/
9597  SCIPintervalSetBounds(&ybnds,
9598  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))), /*lint !e666*/
9599  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))); /*lint !e666*/
9600 
9601  /* try to find domain reductions for x */
9602  SCIPintervalSolveBivariateQuadExpressionAllScalar(intervalinfty, &xbnds, xsqrcoef, ysqrcoef, bilincoef, xlincoef, ylincoef, rhs, xbnds, ybnds);
9603 
9604  if( SCIPintervalIsEmpty(intervalinfty, xbnds) )
9605  {
9606  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(x));
9607  *result = SCIP_CUTOFF;
9608  return SCIP_OKAY;
9609  }
9610 
9611  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(xbnds)) )
9612  {
9613  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, x, SCIPintervalGetInf(xbnds), result, nchgbds) );
9614  if( *result == SCIP_CUTOFF )
9615  return SCIP_OKAY;
9616  }
9617 
9618  if( !SCIPisInfinity(scip, SCIPintervalGetSup(xbnds)) )
9619  {
9620  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, x, SCIPintervalGetSup(xbnds), result, nchgbds) );
9621  if( *result == SCIP_CUTOFF )
9622  return SCIP_OKAY;
9623  }
9624 
9625  return SCIP_OKAY;
9626 }
9627 #endif
9628 
9629 /** computes the minimal and maximal activity for the quadratic part in a constraint data
9630  *
9631  * Only sums up terms that contribute finite values.
9632  * Gives the number of terms that contribute infinite values.
9633  * Only computes those activities where the corresponding side of the constraint is finite.
9634  */
9635 static
9637  SCIP* scip, /**< SCIP data structure */
9638  SCIP_CONSDATA* consdata, /**< constraint data */
9639  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9640  SCIP_Real* minquadactivity, /**< minimal activity of quadratic variable terms where only terms with finite minimal activity contribute */
9641  SCIP_Real* maxquadactivity, /**< maximal activity of quadratic variable terms where only terms with finite maximal activity contribute */
9642  int* minactivityinf, /**< number of quadratic variables that contribute -infinity to minimal activity */
9643  int* maxactivityinf, /**< number of quadratic variables that contribute +infinity to maximal activity */
9644  SCIP_INTERVAL* quadactcontr /**< contribution of each quadratic variables to quadactivity */
9645  )
9646 { /*lint --e{666}*/
9647  SCIP_ROUNDMODE prevroundmode;
9648  int i;
9649  int j;
9650  int k;
9651  SCIP_INTERVAL tmp;
9652  SCIP_Real bnd;
9653  SCIP_INTERVAL xrng;
9654  SCIP_INTERVAL lincoef;
9655 
9656  assert(scip != NULL);
9657  assert(consdata != NULL);
9658  assert(minquadactivity != NULL);
9659  assert(maxquadactivity != NULL);
9660  assert(minactivityinf != NULL);
9661  assert(maxactivityinf != NULL);
9662  assert(quadactcontr != NULL);
9663 
9664  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
9665  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
9666  */
9667  *minquadactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
9668  *maxquadactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
9669 
9670  *minactivityinf = 0;
9671  *maxactivityinf = 0;
9672 
9673  if( consdata->nquadvars == 0 )
9674  {
9675  SCIPintervalSet(&consdata->quadactivitybounds, 0.0);
9676  return;
9677  }
9678 
9679  for( i = 0; i < consdata->nquadvars; ++i )
9680  {
9681  /* there should be no quadratic variables fixed at -/+ infinity due to our locks */
9682  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var)));
9683  assert(!SCIPisInfinity(scip, -SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
9684 
9685  SCIPintervalSetBounds(&quadactcontr[i], -intervalinfty, intervalinfty);
9686 
9687  SCIPintervalSetBounds(&xrng,
9688  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))),
9689  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))));
9690 
9691  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
9692  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
9693  {
9694  k = consdata->quadvarterms[i].adjbilin[j];
9695  if( consdata->bilinterms[k].var1 != consdata->quadvarterms[i].var )
9696  continue; /* handle this term later */
9697 
9698  SCIPintervalSetBounds(&tmp,
9699  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9700  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9701  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9702  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9703  }
9704 
9705  if( !SCIPisInfinity(scip, -consdata->lhs) )
9706  {
9707  /* compute maximal activity only if there is a finite left hand side */
9708  bnd = SCIPintervalQuadUpperBound(intervalinfty, consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
9709  if( SCIPisInfinity(scip, bnd) )
9710  {
9711  ++*maxactivityinf;
9712  }
9713  else if( SCIPisInfinity(scip, -bnd) )
9714  {
9715  /* if maximal activity is below value for -infinity, let's take -1e10 as upper bound on maximal activity
9716  * @todo Something better?
9717  */
9718  bnd = -sqrt(SCIPinfinity(scip));
9719  *maxquadactivity += bnd;
9720  quadactcontr[i].sup = bnd;
9721  }
9722  else
9723  {
9724  prevroundmode = SCIPintervalGetRoundingMode();
9726  *maxquadactivity += bnd;
9727  SCIPintervalSetRoundingMode(prevroundmode);
9728  quadactcontr[i].sup = bnd;
9729  }
9730  }
9731 
9732  if( !SCIPisInfinity(scip, consdata->rhs) )
9733  {
9734  /* compute minimal activity only if there is a finite right hand side */
9735  SCIPintervalSetBounds(&lincoef, -SCIPintervalGetSup(lincoef), -SCIPintervalGetInf(lincoef));
9736  bnd = -SCIPintervalQuadUpperBound(intervalinfty, -consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
9737 
9738  if( SCIPisInfinity(scip, -bnd) )
9739  {
9740  ++*minactivityinf;
9741  }
9742  else if( SCIPisInfinity(scip, bnd) )
9743  {
9744  /* if minimal activity is above value for infinity, let's take 1e10 as lower bound on minimal activity
9745  * @todo Something better?
9746  */
9747  bnd = sqrt(SCIPinfinity(scip));
9748  *minquadactivity += bnd;
9749  quadactcontr[i].inf = bnd;
9750  }
9751  else
9752  {
9753  prevroundmode = SCIPintervalGetRoundingMode();
9755  *minquadactivity += bnd;
9756  SCIPintervalSetRoundingMode(prevroundmode);
9757  quadactcontr[i].inf = bnd;
9758  }
9759  }
9760 
9761  }
9762 
9763  SCIPintervalSetBounds(&consdata->quadactivitybounds,
9764  (*minactivityinf > 0 ? -intervalinfty : *minquadactivity),
9765  (*maxactivityinf > 0 ? intervalinfty : *maxquadactivity));
9766  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
9767 }
9768 
9769 /** propagates bounds on a quadratic constraint */
9770 static
9772  SCIP* scip, /**< SCIP data structure */
9773  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9774  SCIP_CONS* cons, /**< constraint to process */
9775  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
9776  int* nchgbds, /**< buffer where to add the the number of changed bounds */
9777  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
9778  )
9779 { /*lint --e{666}*/
9780  SCIP_CONSDATA* consdata;
9781  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
9782  SCIP_INTERVAL consactivity; /* activity of linear plus quadratic part */
9783  SCIP_Real intervalinfty; /* infinity used for interval computation */
9784  SCIP_Real minquadactivity; /* lower bound on finite activities of quadratic part */
9785  SCIP_Real maxquadactivity; /* upper bound on finite activities of quadratic part */
9786  int quadminactinf; /* number of quadratic variables that contribute -infinity to minimal activity of quadratic term */
9787  int quadmaxactinf; /* number of quadratic variables that contribute +infinity to maximal activity of quadratic term */
9788  SCIP_INTERVAL* quadactcontr; /* contribution of each quadratic variable term to quadactivity */
9789 
9790  SCIP_VAR* var;
9791  SCIP_INTERVAL rhs; /* right hand side of quadratic equation */
9792  SCIP_INTERVAL tmp;
9793  SCIP_ROUNDMODE roundmode;
9794  SCIP_Real bnd;
9795  int i;
9796 
9797  assert(scip != NULL);
9798  assert(conshdlr != NULL);
9799  assert(cons != NULL);
9800  assert(result != NULL);
9801  assert(nchgbds != NULL);
9802  assert(redundant != NULL);
9803 
9804  consdata = SCIPconsGetData(cons);
9805  assert(consdata != NULL);
9806 
9807  *result = SCIP_DIDNOTRUN;
9808  *redundant = FALSE;
9809 
9810  if( consdata->ispropagated )
9811  return SCIP_OKAY;
9812 
9813  *result = SCIP_DIDNOTFIND;
9814 
9815  intervalinfty = 1000 * SCIPinfinity(scip) * SCIPinfinity(scip);
9816 
9817  quadactcontr = NULL;
9818  quadminactinf = -1;
9819  quadmaxactinf = -1;
9820 
9821  SCIPdebugMessage("start domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
9822 
9823  consdata->ispropagated = TRUE;
9824 
9825  /* make sure we have activity of linear term and that they are consistent */
9826  consdataUpdateLinearActivity(scip, consdata, intervalinfty);
9827  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
9828  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
9829  assert(consdata->minlinactivityinf >= 0);
9830  assert(consdata->maxlinactivityinf >= 0);
9831 
9832  /* sort quadratic variable terms, in case we need to search for terms occuring in bilinear terms later
9833  * we sort here already, since we rely on a constant variable order during this method
9834  */
9835  if( consdata->nbilinterms > 0 )
9836  {
9837  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
9838  }
9839 
9840  /* compute activity of quad term part, if not up to date
9841  * in that case, we also collect the contribution of each quad var term for later */
9842  if( SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds) )
9843  {
9844  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
9845  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
9846  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
9847  }
9848 
9849  SCIPdebugMessage("linear activity: [%g, %g] quadratic activity: [%g, %g]\n",
9850  (consdata->minlinactivityinf > 0 ? -SCIPinfinity(scip) : consdata->minlinactivity),
9851  (consdata->maxlinactivityinf > 0 ? SCIPinfinity(scip) : consdata->maxlinactivity),
9852  consdata->quadactivitybounds.inf, consdata->quadactivitybounds.sup);
9853 
9854  /* extend constraint bounds by epsilon to avoid some numerical difficulties */
9855  SCIPintervalSetBounds(&consbounds,
9856  -infty2infty(SCIPinfinity(scip), intervalinfty, -consdata->lhs+SCIPepsilon(scip)),
9857  +infty2infty(SCIPinfinity(scip), intervalinfty, consdata->rhs+SCIPepsilon(scip)));
9858 
9859  /* check redundancy and infeasibility */
9860  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity,
9861  consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity);
9862  SCIPintervalAdd(intervalinfty, &consactivity, consactivity, consdata->quadactivitybounds);
9863  if( SCIPintervalIsSubsetEQ(intervalinfty, consactivity, consbounds) )
9864  {
9865  SCIPdebugMessage("found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
9866  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
9867  *redundant = TRUE;
9868  goto CLEANUP;
9869  }
9870 
9871  /* was SCIPintervalAreDisjoint(consbounds, consactivity), but that would allow violations up to eps only
9872  * we need to decide feasibility w.r.t. feastol (but still want to propagate w.r.t. eps)
9873  */
9874  if( SCIPisFeasGT(scip, consbounds.inf, consactivity.sup) || SCIPisFeasLT(scip, consbounds.sup, consactivity.inf) )
9875  {
9876  SCIPdebugMessage("found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
9877  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
9878  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
9879  *result = SCIP_CUTOFF;
9880  goto CLEANUP;
9881  }
9882 
9883  /* propagate linear part \in rhs = consbounds - quadactivity (use the one from consdata, since that includes infinities) */
9884  SCIPintervalSub(intervalinfty, &rhs, consbounds, consdata->quadactivitybounds);
9885  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
9886  {
9887  SCIP_Real coef;
9888 
9889  for( i = 0; i < consdata->nlinvars; ++i )
9890  {
9891  coef = consdata->lincoefs[i];
9892  var = consdata->linvars[i];
9893 
9894  /* skip fixed variables
9895  * @todo is that a good or a bad idea?
9896  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
9897  */
9898  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
9899  continue;
9900 
9901  if( coef > 0.0 )
9902  {
9903  if( SCIPintervalGetSup(rhs) < intervalinfty )
9904  {
9905  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
9906  /* try to tighten the upper bound on var x */
9907  if( consdata->minlinactivityinf == 0 )
9908  {
9909  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
9910  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
9911  roundmode = SCIPintervalGetRoundingMode();
9913  bnd = SCIPintervalGetSup(rhs);
9914  bnd -= consdata->minlinactivity;
9915  bnd += coef * SCIPvarGetLbLocal(var);
9916  bnd /= coef;
9917  SCIPintervalSetRoundingMode(roundmode);
9918  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9919  if( *result == SCIP_CUTOFF )
9920  break;
9921  }
9922  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
9923  {
9924  /* x was the variable that made the minimal linear activity equal -infinity, so
9925  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
9926  roundmode = SCIPintervalGetRoundingMode();
9928  bnd = SCIPintervalGetSup(rhs);
9929  bnd -= consdata->minlinactivity;
9930  bnd /= coef;
9931  SCIPintervalSetRoundingMode(roundmode);
9932  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9933  if( *result == SCIP_CUTOFF )
9934  break;
9935  }
9936  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
9937  }
9938 
9939  if( SCIPintervalGetInf(rhs) > -intervalinfty )
9940  {
9941  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
9942  /* try to tighten the lower bound on var x */
9943  if( consdata->maxlinactivityinf == 0 )
9944  {
9945  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
9946  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
9947  roundmode = SCIPintervalGetRoundingMode();
9949  bnd = SCIPintervalGetInf(rhs);
9950  bnd -= consdata->maxlinactivity;
9951  bnd += coef * SCIPvarGetUbLocal(var);
9952  bnd /= coef;
9953  SCIPintervalSetRoundingMode(roundmode);
9954  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9955  if( *result == SCIP_CUTOFF )
9956  break;
9957  }
9958  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
9959  {
9960  /* x was the variable that made the maximal linear activity equal infinity, so
9961  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
9962  roundmode = SCIPintervalGetRoundingMode();
9964  bnd = SCIPintervalGetInf(rhs);
9965  bnd -= consdata->maxlinactivity;
9966  bnd /= coef;
9967  SCIPintervalSetRoundingMode(roundmode);
9968  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9969  if( *result == SCIP_CUTOFF )
9970  break;
9971  }
9972  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
9973  }
9974  }
9975  else
9976  {
9977  assert(coef < 0.0 );
9978  if( SCIPintervalGetInf(rhs) > -intervalinfty )
9979  {
9980  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
9981  /* try to tighten the upper bound on var x */
9982  if( consdata->maxlinactivityinf == 0 )
9983  {
9984  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
9985  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
9986  roundmode = SCIPintervalGetRoundingMode();
9988  bnd = consdata->maxlinactivity;
9989  bnd += (-coef) * SCIPvarGetLbLocal(var);
9990  bnd -= SCIPintervalGetInf(rhs);
9991  bnd /= (-coef);
9992  SCIPintervalSetRoundingMode(roundmode);
9993  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
9994  if( *result == SCIP_CUTOFF )
9995  break;
9996  }
9997  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
9998  {
9999  /* x was the variable that made the maximal linear activity equal infinity, so
10000  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
10001  roundmode = SCIPintervalGetRoundingMode();
10003  bnd = consdata->maxlinactivity;
10004  bnd -= SCIPintervalGetInf(rhs);
10005  bnd /= (-coef);
10006  SCIPintervalSetRoundingMode(roundmode);
10007  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10008  if( *result == SCIP_CUTOFF )
10009  break;
10010  }
10011  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
10012  }
10013 
10014  if( SCIPintervalGetSup(rhs) < intervalinfty )
10015  {
10016  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10017  /* try to tighten the lower bound on var x */
10018  if( consdata->minlinactivityinf == 0 )
10019  {
10020  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
10021  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
10022  roundmode = SCIPintervalGetRoundingMode();
10024  bnd = consdata->minlinactivity;
10025  bnd += (-coef) * SCIPvarGetUbLocal(var);
10026  bnd -= SCIPintervalGetSup(rhs);
10027  bnd /= (-coef);
10028  SCIPintervalSetRoundingMode(roundmode);
10029  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10030  if( *result == SCIP_CUTOFF )
10031  break;
10032  }
10033  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
10034  {
10035  /* x was the variable that made the maximal linear activity equal -infinity, so
10036  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
10037  roundmode = SCIPintervalGetRoundingMode();
10039  bnd = consdata->minlinactivity;
10040  bnd -= SCIPintervalGetSup(rhs);
10041  bnd /= (-coef);
10042  SCIPintervalSetRoundingMode(roundmode);
10043  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10044  if( *result == SCIP_CUTOFF )
10045  break;
10046  }
10047  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
10048  }
10049  }
10050  }
10051  if( *result == SCIP_CUTOFF )
10052  goto CLEANUP;
10053  }
10054 
10055  /* propagate quadratic part \in rhs = consbounds - linactivity */
10056  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10057  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10058  consdataUpdateLinearActivity(scip, consdata, intervalinfty); /* make sure, activities of linear part did not become invalid by above bound changes, if any */
10059  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
10060  SCIPintervalSetBounds(&tmp,
10061  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
10062  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity));
10063  SCIPintervalSub(intervalinfty, &rhs, consbounds, tmp);
10064  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
10065  {
10066  if( consdata->nquadvars == 1 )
10067  {
10068  /* quadratic part is just a*x^2+b*x -> a common case that we treat directly */
10069  SCIP_INTERVAL lincoef; /* linear coefficient of quadratic equation */
10070 
10071  assert(consdata->nbilinterms == 0);
10072 
10073  var = consdata->quadvarterms[0].var;
10074  SCIPintervalSet(&lincoef, consdata->quadvarterms[0].lincoef);
10075 
10076  /* propagate a*x^2 + b*x \in rhs */
10077  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[0].sqrcoef, lincoef, rhs, result, nchgbds) );
10078  }
10079  else if( consdata->nbilinterms == 1 && consdata->nquadvars == 2 )
10080  {
10081  /* quadratic part is just ax*x^2+bx*x + ay*y^2+by*y + c*xy -> a common case that we treat directly */
10082  assert(consdata->bilinterms[0].var1 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var1 == consdata->quadvarterms[1].var);
10083  assert(consdata->bilinterms[0].var2 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var2 == consdata->quadvarterms[1].var);
10084 
10085  /* 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 */
10086  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
10087  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
10088  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
10089  consdata->bilinterms[0].coef,
10090  rhs, result, nchgbds) );
10091  if( *result != SCIP_CUTOFF )
10092  {
10093  /* 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 */
10094  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
10095  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
10096  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
10097  consdata->bilinterms[0].coef,
10098  rhs, result, nchgbds) );
10099  }
10100  }
10101  else
10102  {
10103  /* general case */
10104 
10105  /* compute "advanced" information on quad var term activities, if not up-to-date */
10106  if( quadminactinf == -1 )
10107  {
10108  assert(quadactcontr == NULL);
10109  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
10110  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
10111  }
10112  assert(quadactcontr != NULL);
10113  assert(quadminactinf >= 0);
10114  assert(quadmaxactinf >= 0);
10115 
10116  /* if the quad activities are not hopelessly unbounded on useful sides, try to deduce domain reductions on quad vars */
10117  if( (SCIPintervalGetSup(rhs) < intervalinfty && quadminactinf <= 1) ||
10118  ( SCIPintervalGetInf(rhs) > -intervalinfty && quadmaxactinf <= 1) )
10119  {
10120  SCIP_INTERVAL lincoef;
10121  SCIP_INTERVAL rhs2;
10122  int j;
10123  int k;
10124 
10125  for( i = 0; i < consdata->nquadvars; ++i )
10126  {
10127  var = consdata->quadvarterms[i].var;
10128 
10129  /* skip fixed variables
10130  * @todo is that a good or a bad idea?
10131  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
10132  */
10133  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10134  continue;
10135 
10136  /* compute rhs2 such that we can propagate quadvarterm(x_i) \in rhs2 */
10137 
10138  /* setup rhs2.sup = rhs.sup - (quadactivity.inf - quadactcontr[i].inf), if everything were finite
10139  * if only quadactcontr[i].inf is infinite (i.e., the other i are all finite), we just get rhs2.sup = rhs.sup
10140  * otherwise we get rhs2.sup = infinity */
10141  if( SCIPintervalGetSup(rhs) < intervalinfty )
10142  {
10143  if( quadminactinf == 0 || (quadminactinf == 1 && SCIPintervalGetInf(quadactcontr[i]) <= -intervalinfty) )
10144  {
10145  roundmode = SCIPintervalGetRoundingMode();
10147  rhs2.sup = rhs.sup - minquadactivity; /*lint !e644*/
10148  /* if the residual quad min activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
10149  if( quadminactinf == 0 && SCIPintervalGetInf(quadactcontr[i]) != 0.0 )
10150  rhs2.sup += SCIPintervalGetInf(quadactcontr[i]);
10151  SCIPintervalSetRoundingMode(roundmode);
10152  }
10153  else
10154  {
10155  /* there are either >= 2 quad var terms contributing -infinity, or there is one which is not i */
10156  rhs2.sup = intervalinfty;
10157  }
10158  }
10159  else
10160  {
10161  rhs2.sup = intervalinfty;
10162  }
10163 
10164  /* setup rhs2.inf = rhs.inf - (quadactivity.sup - quadactcontr[i].sup), see also above */
10165  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10166  {
10167  if( quadmaxactinf == 0 || (quadmaxactinf == 1 && SCIPintervalGetSup(quadactcontr[i]) >= intervalinfty) )
10168  {
10169  roundmode = SCIPintervalGetRoundingMode();
10171  rhs2.inf = rhs.inf - maxquadactivity; /*lint !e644*/
10172  /* if the residual quad max activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
10173  if( quadmaxactinf == 0 && SCIPintervalGetSup(quadactcontr[i]) != 0.0 )
10174  rhs2.inf += SCIPintervalGetSup(quadactcontr[i]);
10175  SCIPintervalSetRoundingMode(roundmode);
10176  }
10177  else
10178  {
10179  /* there are either >= 2 quad var terms contributing infinity, or there is one which is not i */
10180  rhs2.inf = -intervalinfty;
10181  }
10182  }
10183  else
10184  {
10185  rhs2.inf = -intervalinfty;
10186  }
10187  assert(!SCIPintervalIsEmpty(intervalinfty, rhs2));
10188 
10189  /* if rhs2 is entire, then there is nothing we could propagate */
10190  if( SCIPintervalIsEntire(intervalinfty, rhs2) )
10191  continue;
10192 
10193  /* assemble linear coefficient for quad equation a*x^2 + b*x \in rhs2 */
10194  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
10195  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
10196  {
10197  k = consdata->quadvarterms[i].adjbilin[j];
10198 #if 1
10199  if( consdata->bilinterms[k].var1 == var )
10200  {
10201  /* bilinear term k contributes to the activity of quad var term i, so just add bounds to linear coef */
10202  SCIPintervalSetBounds(&tmp,
10203  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10204  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10205  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10206  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10207  }
10208  else
10209  {
10210  /* bilinear term k does not contribute to the activity of quad var term i
10211  * so bounds on term k are contained in rhs2
10212  * if they are finite, we try to remove them from rhs2 and update lincoef instead
10213  * 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
10214  * HOWEVER: when computing rhs2, we may not just have added the bounds for the bilinear term, but for the associated quadratic term
10215  * for this complete term, we used SCIPintervalQuad to compute the bounds
10216  * since we do not want to repeat a call to SCIPintervalQuad for that quadratic term with bilinear term k removed,
10217  * we only remove the bounds for the bilinear term k from rhs2 if the associated quadratic term consists only of this bilinear term,
10218  * i.e., the quadratic term corresponding to var1 should be only var1*var2, but have no square or linear coefs or other bilinear terms
10219  * (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)
10220  */
10221  SCIP_INTERVAL me;
10222  SCIP_INTERVAL bilinbounds;
10223  int otherpos;
10224 
10225  assert(consdata->bilinterms[k].var2 == var);
10226 
10227  assert(consdata->quadvarssorted);
10228  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[k].var1, &otherpos) );
10229  assert(otherpos >= 0);
10230  assert(consdata->quadvarterms[otherpos].var == consdata->bilinterms[k].var1);
10231 
10232  if( (consdata->quadvarterms[otherpos].sqrcoef != 0.0) || consdata->quadvarterms[otherpos].lincoef != 0.0 ||
10233  consdata->quadvarterms[otherpos].nadjbilin > 1 )
10234  continue;
10235 
10236  /* set tmp to bounds of other variable and multiply with bilin coef */
10237  SCIPintervalSetBounds(&tmp,
10238  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))),
10239  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))));
10240  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10241 
10242  /* set me to bounds of i'th variable */
10244  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10245  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10246 
10247  /* remove me*tmp from rhs2 */
10248 
10249  roundmode = SCIPintervalGetRoundingMode();
10250 
10251  if( rhs2.inf > -intervalinfty )
10252  {
10253  /* need upward rounding for SCIPintervalMulSup */
10255  SCIPintervalMulSup(intervalinfty, &bilinbounds, me, tmp);
10256  /* rhs2.inf += bilinbounds.sup, but we are in upward rounding */
10257  if( bilinbounds.sup < intervalinfty )
10258  rhs2.inf = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.inf) - bilinbounds.sup);
10259  }
10260 
10261  if( rhs2.sup < intervalinfty )
10262  {
10263  /* need downward rounding for SCIPintervalMulInf */
10265  SCIPintervalMulInf(intervalinfty, &bilinbounds, me, tmp);
10266  /* rhs2.sup += bilinbounds.inf, but we are in downward rounding */
10267  if( bilinbounds.inf > -intervalinfty )
10268  rhs2.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.sup) - bilinbounds.inf);
10269  }
10270 
10271  SCIPintervalSetRoundingMode(roundmode);
10272 
10273  /* add tmp to lincoef */
10274  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10275  }
10276 #else
10277  if( consdata->bilinterms[k].var1 != var )
10278  continue; /* this term does not contribute to the activity of quad var term i */
10279 
10280  SCIPintervalSetBounds(&tmp,
10281  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10282  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10283  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10284  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10285 #endif
10286  }
10287 
10288  /* deduce domain reductions for x_i */
10289  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[i].sqrcoef, lincoef, rhs2, result, nchgbds) );
10290  if( *result == SCIP_CUTOFF )
10291  goto CLEANUP;
10292  }
10293  }
10294  }
10295  }
10296 
10297  CLEANUP:
10298  SCIPfreeBufferArrayNull(scip, &quadactcontr);
10299 
10300  return SCIP_OKAY;
10301 }
10302 
10303 /** calls domain propagation for a set of constraints */
10304 static
10306  SCIP* scip, /**< SCIP data structure */
10307  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10308  SCIP_CONS** conss, /**< constraints to process */
10309  int nconss, /**< number of constraints */
10310  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
10311  int* nchgbds /**< buffer where to add the the number of changed bounds */
10312  )
10313 {
10314  SCIP_CONSHDLRDATA* conshdlrdata;
10315  SCIP_RESULT propresult;
10316  SCIP_Bool redundant;
10317  int c;
10318  int roundnr;
10319  SCIP_Bool success;
10320  int maxproprounds;
10321 
10322  assert(scip != NULL);
10323  assert(conshdlr != NULL);
10324  assert(conss != NULL || nconss == 0);
10325  assert(result != NULL);
10326  assert(nchgbds != NULL);
10327 
10329 
10330  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10331  assert(conshdlrdata != NULL);
10332 
10333  *result = SCIP_DIDNOTFIND;
10334  roundnr = 0;
10335  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
10336  maxproprounds = conshdlrdata->maxproproundspresolve;
10337  else
10338  maxproprounds = conshdlrdata->maxproprounds;
10339 
10340  do
10341  {
10342  success = FALSE;
10343  ++roundnr;
10344 
10345  SCIPdebugMessage("starting domain propagation round %d of %d for %d constraints\n", roundnr, maxproprounds, nconss);
10346 
10347  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
10348  {
10349  assert(conss != NULL);
10350  if( !SCIPconsIsEnabled(conss[c]) )
10351  continue;
10352 
10353  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
10354  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
10355  {
10356  *result = propresult;
10357  success = TRUE;
10358  }
10359  if( redundant )
10360  {
10361  SCIPdebugMessage("deleting constraint <%s> locally\n", SCIPconsGetName(conss[c]));
10362  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
10363  }
10364  }
10365 
10366  }
10367  while( success && *result != SCIP_CUTOFF && roundnr < maxproprounds );
10368 
10369  return SCIP_OKAY;
10370 }
10371 
10372 /** checks for a linear variable that can be increase or decreased without harming feasibility */
10373 static
10375  SCIP* scip, /**< SCIP data structure */
10376  SCIP_CONSDATA* consdata /**< constraint data */
10377  )
10378 {
10379  int i;
10380  int poslock;
10381  int neglock;
10382 
10383  consdata->linvar_maydecrease = -1;
10384  consdata->linvar_mayincrease = -1;
10385 
10386  /* check for a linear variable that can be increase or decreased without harming feasibility */
10387  for( i = 0; i < consdata->nlinvars; ++i )
10388  {
10389  /* compute locks of i'th linear variable */
10390  assert(consdata->lincoefs[i] != 0.0);
10391  if( consdata->lincoefs[i] > 0.0 )
10392  {
10393  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
10394  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
10395  }
10396  else
10397  {
10398  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
10399  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
10400  }
10401 
10402  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - neglock == 0 )
10403  {
10404  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
10405  /* if we have already one candidate, then take the one where the loss in the objective function is less */
10406  if( (consdata->linvar_maydecrease < 0) ||
10407  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
10408  consdata->linvar_maydecrease = i;
10409  }
10410 
10411  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - poslock == 0 )
10412  {
10413  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
10414  /* if we have already one candidate, then take the one where the loss in the objective function is less */
10415  if( (consdata->linvar_mayincrease < 0) ||
10416  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
10417  consdata->linvar_mayincrease = i;
10418  }
10419  }
10420 
10421 #ifdef SCIP_DEBUG
10422  if( consdata->linvar_mayincrease >= 0 )
10423  {
10424  SCIPdebugMessage("may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
10425  }
10426  if( consdata->linvar_maydecrease >= 0 )
10427  {
10428  SCIPdebugMessage("may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
10429  }
10430 #endif
10431 }
10432 
10433 /** Given a solution where every quadratic constraint is either feasible or can be made feasible by
10434  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
10435  *
10436  * The method assumes that this is always possible and that not all constraints are feasible already.
10437  */
10438 static
10440  SCIP* scip, /**< SCIP data structure */
10441  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10442  SCIP_CONS** conss, /**< constraints to process */
10443  int nconss, /**< number of constraints */
10444  SCIP_SOL* sol, /**< solution to process */
10445  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
10446  )
10447 {
10448  SCIP_CONSHDLRDATA* conshdlrdata;
10449  SCIP_CONSDATA* consdata;
10450  char origscaling;
10451  SCIP_SOL* newsol;
10452  SCIP_VAR* var;
10453  int c;
10454  SCIP_Real viol;
10455  SCIP_Real delta;
10456  SCIP_Real gap;
10457 
10458  assert(scip != NULL);
10459  assert(conshdlr != NULL);
10460  assert(conss != NULL || nconss == 0);
10461  assert(success != NULL);
10462 
10463  *success = FALSE;
10464 
10465  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10466  assert(conshdlrdata != NULL);
10467 
10468  if( sol != NULL )
10469  {
10470  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
10471  }
10472  else
10473  {
10474  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
10475  }
10476  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
10477  SCIPdebugMessage("attempt to make solution from <%s> feasible by shifting linear variable\n",
10478  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
10479 
10480  origscaling = conshdlrdata->scaling;
10481  for( c = 0; c < nconss; ++c )
10482  {
10483  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
10484  assert(consdata != NULL);
10485 
10486  /* recompute violation of solution in case solution has changed
10487  * get absolution violation and sign
10488  * @todo avoid doing it this way
10489  */
10490  conshdlrdata->scaling = 'o';
10491  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
10492  {
10493  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
10494  viol = consdata->lhs - consdata->activity;
10495  }
10496  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10497  {
10498  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
10499  viol = consdata->rhs - consdata->activity;
10500  }
10501  else
10502  continue; /* constraint is satisfied */
10503 
10504  assert(viol != 0.0);
10505  if( consdata->linvar_mayincrease >= 0 &&
10506  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
10507  {
10508  /* have variable where increasing makes the constraint less violated */
10509  var = consdata->linvars[consdata->linvar_mayincrease];
10510  /* compute how much we would like to increase var */
10511  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
10512  assert(delta > 0.0);
10513  /* if var has an upper bound, may need to reduce delta */
10514  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
10515  {
10516  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
10517  delta = MIN(MAX(0.0, gap), delta);
10518  }
10519  if( SCIPisPositive(scip, delta) )
10520  {
10521  /* if variable is integral, round delta up so that it will still have an integer value */
10522  if( SCIPvarIsIntegral(var) )
10523  delta = SCIPceil(scip, delta);
10524 
10525  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
10526  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
10527 
10528  /* adjust constraint violation, if satisfied go on to next constraint */
10529  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
10530  if( SCIPisZero(scip, viol) )
10531  continue;
10532  }
10533  }
10534 
10535  assert(viol != 0.0);
10536  if( consdata->linvar_maydecrease >= 0 &&
10537  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
10538  {
10539  /* have variable where decreasing makes constraint less violated */
10540  var = consdata->linvars[consdata->linvar_maydecrease];
10541  /* compute how much we would like to decrease var */
10542  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
10543  assert(delta < 0.0);
10544  /* if var has a lower bound, may need to reduce delta */
10545  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
10546  {
10547  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
10548  delta = MAX(MIN(0.0, gap), delta);
10549  }
10550  if( SCIPisNegative(scip, delta) )
10551  {
10552  /* if variable is integral, round delta down so that it will still have an integer value */
10553  if( SCIPvarIsIntegral(var) )
10554  delta = SCIPfloor(scip, delta);
10555  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
10556  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
10557 
10558  /* adjust constraint violation, if satisfied go on to next constraint */
10559  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
10560  if( SCIPisZero(scip, viol) )
10561  continue;
10562  }
10563  }
10564 
10565  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
10566  break;
10567  }
10568  conshdlrdata->scaling = origscaling;
10569 
10570  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
10571  * then pass it to the trysol heuristic
10572  */
10573  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
10574  {
10575  SCIPdebugMessage("pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
10576 
10577  assert(conshdlrdata->trysolheur != NULL);
10578  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
10579 
10580  *success = TRUE;
10581  }
10582 
10583  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
10584 
10585  return SCIP_OKAY;
10586 }
10587 
10588 /** tries to upgrade a nonlinear constraint into a quadratic constraint */
10589 static
10590 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
10592  SCIP_EXPRGRAPH* exprgraph;
10593  SCIP_EXPRGRAPHNODE* node;
10594  int i;
10595 
10596  assert(nupgdconss != NULL);
10597  assert(upgdconss != NULL);
10598 
10599  *nupgdconss = 0;
10600 
10601  node = SCIPgetExprgraphNodeNonlinear(scip, cons);
10602 
10603  /* no interest in linear constraints */
10604  if( node == NULL )
10605  return SCIP_OKAY;
10606 
10607  /* if a quadratic expression has been simplified, then all children of the node should be variables */
10609  return SCIP_OKAY;
10610 
10611  switch( SCIPexprgraphGetNodeOperator(node) )
10612  {
10613  case SCIP_EXPR_VARIDX:
10614  case SCIP_EXPR_CONST:
10615  case SCIP_EXPR_PLUS:
10616  case SCIP_EXPR_MINUS:
10617  case SCIP_EXPR_SUM:
10618  case SCIP_EXPR_LINEAR:
10619  /* these should not appear as exprgraphnodes after constraint presolving */
10620  return SCIP_OKAY;
10621 
10622  case SCIP_EXPR_DIV:
10623  case SCIP_EXPR_SQRT:
10624  case SCIP_EXPR_REALPOWER:
10625  case SCIP_EXPR_INTPOWER:
10626  case SCIP_EXPR_SIGNPOWER:
10627  case SCIP_EXPR_EXP:
10628  case SCIP_EXPR_LOG:
10629  case SCIP_EXPR_SIN:
10630  case SCIP_EXPR_COS:
10631  case SCIP_EXPR_TAN:
10632  /* case SCIP_EXPR_ERF: */
10633  /* case SCIP_EXPR_ERFI: */
10634  case SCIP_EXPR_MIN:
10635  case SCIP_EXPR_MAX:
10636  case SCIP_EXPR_ABS:
10637  case SCIP_EXPR_SIGN:
10638  case SCIP_EXPR_PRODUCT:
10639  case SCIP_EXPR_POLYNOMIAL:
10640  case SCIP_EXPR_USER:
10641  /* these do not look like an quadratic expression (assuming the expression graph simplifier did run) */
10642  return SCIP_OKAY;
10643 
10644  case SCIP_EXPR_MUL:
10645  case SCIP_EXPR_SQUARE:
10646  case SCIP_EXPR_QUADRATIC:
10647  /* these mean that we have something quadratic */
10648  break;
10649 
10650  case SCIP_EXPR_PARAM:
10651  case SCIP_EXPR_LAST:
10652  default:
10653  SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
10654  return SCIP_OKAY;
10655  }
10656 
10657  /* setup a quadratic constraint */
10658 
10659  if( upgdconsssize < 1 )
10660  {
10661  /* request larger upgdconss array */
10662  *nupgdconss = -1;
10663  return SCIP_OKAY;
10664  }
10665 
10666  *nupgdconss = 1;
10667  SCIP_CALL( SCIPcreateConsQuadratic(scip, &upgdconss[0], SCIPconsGetName(cons),
10669  0, NULL, 0, NULL,
10670  SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
10674  assert(!SCIPconsIsStickingAtNode(cons));
10675 
10676  exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
10677 
10678  /* add variables from expression tree as "quadratic" variables to quadratic constraint */
10679  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
10680  {
10681  assert(SCIPexprgraphGetNodeChildren(node)[i] != NULL);
10682  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, upgdconss[0], (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[i]), 0.0, 0.0) );
10683  }
10684 
10685  switch( SCIPexprgraphGetNodeOperator(node) )
10686  {
10687  case SCIP_EXPR_MUL:
10688  /* expression is product of two variables, so add bilinear term to constraint */
10689  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
10690 
10691  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
10694  1.0) );
10695 
10696  break;
10697 
10698  case SCIP_EXPR_SQUARE:
10699  /* expression is square of a variable, so change square coefficient of quadratic variable */
10700  assert(SCIPexprgraphGetNodeNChildren(node) == 1);
10701 
10702  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
10704  1.0) );
10705 
10706  break;
10707 
10708  case SCIP_EXPR_QUADRATIC:
10709  {
10710  /* expression is quadratic */
10711  SCIP_QUADELEM* quadelems;
10712  int nquadelems;
10713  SCIP_Real* lincoefs;
10714 
10716  nquadelems = SCIPexprgraphGetNodeQuadraticNQuadElements(node);
10718 
10720 
10721  if( lincoefs != NULL )
10722  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
10723  if( lincoefs[i] != 0.0 )
10724  {
10725  /* linear term */
10726  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, upgdconss[0],
10728  lincoefs[i]) );
10729  }
10730 
10731  for( i = 0; i < nquadelems; ++i )
10732  {
10733  assert(quadelems[i].idx1 < SCIPexprgraphGetNodeNChildren(node));
10734  assert(quadelems[i].idx2 < SCIPexprgraphGetNodeNChildren(node));
10735 
10736  if( quadelems[i].idx1 == quadelems[i].idx2 )
10737  {
10738  /* square term */
10739  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
10740  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
10741  quadelems[i].coef) );
10742  }
10743  else
10744  {
10745  /* bilinear term */
10746  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
10747  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
10748  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx2]),
10749  quadelems[i].coef) );
10750  }
10751  }
10752 
10753  break;
10754  }
10755 
10756  default:
10757  SCIPerrorMessage("you should not be here\n");
10758  return SCIP_ERROR;
10759  } /*lint !e788 */
10760 
10761  return SCIP_OKAY;
10762 }
10763 
10764 /*
10765  * Callback methods of constraint handler
10766  */
10767 
10768 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
10769 static
10770 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
10771 { /*lint --e{715}*/
10772  assert(scip != NULL);
10773  assert(conshdlr != NULL);
10774  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
10775 
10776  /* call inclusion method of constraint handler */
10778 
10779  *valid = TRUE;
10780 
10781  return SCIP_OKAY;
10782 }
10783 
10784 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
10785 static
10786 SCIP_DECL_CONSFREE(consFreeQuadratic)
10788  SCIP_CONSHDLRDATA* conshdlrdata;
10789  int i;
10790 
10791  assert(scip != NULL);
10792  assert(conshdlr != NULL);
10793 
10794  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10795  assert(conshdlrdata != NULL);
10796 
10797  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
10798  {
10799  assert(conshdlrdata->quadconsupgrades[i] != NULL);
10800  SCIPfreeMemory(scip, &conshdlrdata->quadconsupgrades[i]);
10801  }
10802  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->quadconsupgrades);
10803 
10804  SCIPfreeMemory(scip, &conshdlrdata);
10805 
10806  return SCIP_OKAY;
10807 }
10808 
10809 /** initialization method of constraint handler (called after problem was transformed) */
10810 static
10811 SCIP_DECL_CONSINIT(consInitQuadratic)
10812 { /*lint --e{715} */
10813  SCIP_CONSHDLRDATA* conshdlrdata;
10814 
10815  assert(scip != NULL);
10816  assert(conshdlr != NULL);
10817 
10818  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10819  assert(conshdlrdata != NULL);
10820 
10821  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
10822  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
10823 
10824  return SCIP_OKAY;
10825 }
10826 
10827 
10828 /** deinitialization method of constraint handler (called before transformed problem is freed) */
10829 static
10830 SCIP_DECL_CONSEXIT(consExitQuadratic)
10831 { /*lint --e{715} */
10832  SCIP_CONSHDLRDATA* conshdlrdata;
10833 
10834  assert(scip != NULL);
10835  assert(conshdlr != NULL);
10836 
10837  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10838  assert(conshdlrdata != NULL);
10839 
10840  conshdlrdata->subnlpheur = NULL;
10841  conshdlrdata->trysolheur = NULL;
10842 
10843  return SCIP_OKAY;
10844 }
10845 
10846 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
10847 #if 0
10848 static
10849 SCIP_DECL_CONSINITPRE(consInitpreQuadratic)
10850 { /*lint --e{715}*/
10851  SCIP_CONSHDLRDATA* conshdlrdata;
10852  SCIP_CONSDATA* consdata;
10853  int c;
10854 
10855  assert(scip != NULL);
10856  assert(conshdlr != NULL);
10857  assert(conss != NULL || nconss == 0);
10858 
10859  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10860  assert(conshdlrdata != NULL);
10861 
10862  return SCIP_OKAY;
10863 }
10864 #endif
10865 
10866 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
10867 static
10868 SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
10869 { /*lint --e{715}*/
10870  SCIP_CONSDATA* consdata;
10871  int c;
10872 #ifndef NDEBUG
10873  int i;
10874 #endif
10875 
10876  assert(scip != NULL);
10877  assert(conshdlr != NULL);
10878  assert(conss != NULL || nconss == 0);
10879 
10880  for( c = 0; c < nconss; ++c )
10881  {
10882  assert(conss != NULL);
10883  consdata = SCIPconsGetData(conss[c]);
10884  assert(consdata != NULL);
10885 
10886  if( !consdata->isremovedfixings )
10887  {
10888  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
10889  }
10890 
10891  /* make sure we do not have duplicate bilinear terms, quad var terms, or linear vars */
10892  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
10893  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
10894  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
10895 
10896  assert(consdata->isremovedfixings);
10897  assert(consdata->linvarsmerged);
10898  assert(consdata->quadvarsmerged);
10899  assert(consdata->bilinmerged);
10900 
10901 #ifndef NDEBUG
10902  for( i = 0; i < consdata->nlinvars; ++i )
10903  assert(SCIPvarIsActive(consdata->linvars[i]));
10904 
10905  for( i = 0; i < consdata->nquadvars; ++i )
10906  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
10907 #endif
10908 
10909  /* tell SCIP that we have something nonlinear */
10910  if( SCIPconsIsAdded(conss[c]) && consdata->nquadvars > 0 )
10911  SCIPenableNLP(scip);
10912  }
10913 
10914  return SCIP_OKAY;
10915 }
10916 
10917 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin)
10918  *
10919  * @note Also called from consEnableQuadratic during solving stage.
10920  */
10921 static
10922 SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
10924  SCIP_CONSHDLRDATA* conshdlrdata;
10925  SCIP_CONSDATA* consdata;
10926  int c;
10927  int i;
10928 
10929  assert(scip != NULL);
10930  assert(conshdlr != NULL);
10931  assert(conss != NULL || nconss == 0);
10932 
10933  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10934  assert(conshdlrdata != NULL);
10935 
10936  for( c = 0; c < nconss; ++c )
10937  {
10938  assert(conss != NULL);
10939  consdata = SCIPconsGetData(conss[c]);
10940  assert(consdata != NULL);
10941 
10942  /* check for a linear variable that can be increase or decreased without harming feasibility */
10943  consdataFindUnlockedLinearVar(scip, consdata);
10944 
10945  /* setup lincoefsmin, lincoefsmax */
10946  consdata->lincoefsmin = SCIPinfinity(scip);
10947  consdata->lincoefsmax = 0.0;
10948  for( i = 0; i < consdata->nlinvars; ++i )
10949  {
10950  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666 */
10951  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666 */
10952  }
10953 
10954  /* add nlrow representation to NLP, if NLP had been constructed */
10955  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
10956  {
10957  if( consdata->nlrow == NULL )
10958  {
10959  SCIP_CALL( createNlRow(scip, conss[c]) );
10960  assert(consdata->nlrow != NULL);
10961  }
10962  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
10963  }
10964 
10965  /* setup sepaquadvars and sepabilinvar2pos */
10966  assert(consdata->sepaquadvars == NULL);
10967  assert(consdata->sepabilinvar2pos == NULL);
10968  if( consdata->nquadvars > 0 )
10969  {
10970  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepaquadvars, consdata->nquadvars) );
10971  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms) );
10972 
10973  /* make sure, quadratic variable terms are sorted */
10974  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
10975 
10976  for( i = 0; i < consdata->nquadvars; ++i )
10977  consdata->sepaquadvars[i] = consdata->quadvarterms[i].var;
10978 
10979  for( i = 0; i < consdata->nbilinterms; ++i )
10980  {
10981  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &consdata->sepabilinvar2pos[i]) );
10982  }
10983  }
10984 
10985  if( conshdlrdata->checkfactorable )
10986  {
10987  /* check if constraint function is factorable, i.e., can be written as product of two linear functions */
10988  SCIP_CALL( checkFactorable(scip, conss[c]) );
10989  }
10990 
10991  /* compute gauge function using interior points per constraint, only when there are quadratic variables */
10992  if( conshdlrdata->gaugecuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
10993  {
10994  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
10995  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
10996  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
10997  {
10998  SCIP_CALL( computeGauge(scip, conshdlr, conss[c]) );
10999  }
11000 
11001  }
11002  }
11003 
11004  if( SCIPgetStage(scip) != SCIP_STAGE_INITSOLVE )
11005  {
11006  /* if called from consEnableQuadratic, then don't do below */
11007  return SCIP_OKAY;
11008  }
11009 
11010  conshdlrdata->newsoleventfilterpos = -1;
11011  if( nconss != 0 && conshdlrdata->linearizeheursol )
11012  {
11013  SCIP_EVENTHDLR* eventhdlr;
11014 
11015  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
11016  assert(eventhdlr != NULL);
11017 
11018  /* @todo Should we catch every new solution or only new *best* solutions */
11019  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11020  }
11021 
11022  if( nconss != 0 && !SCIPisIpoptAvailableIpopt() && !SCIPisInRestart(scip) )
11023  {
11024  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");
11025  }
11026 
11027  /* reset flags and counters */
11028  conshdlrdata->sepanlp = FALSE;
11029  conshdlrdata->lastenfolpnode = NULL;
11030  conshdlrdata->nenfolprounds = 0;
11031 
11032  return SCIP_OKAY;
11033 }
11034 
11035 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed)
11036  *
11037  * @note Also called from consDisableQuadratic during solving stage.
11038  */
11039 static
11040 SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
11041 { /*lint --e{715}*/
11042  SCIP_CONSHDLRDATA* conshdlrdata;
11043  SCIP_CONSDATA* consdata;
11044  int c;
11045 
11046  assert(scip != NULL);
11047  assert(conshdlr != NULL);
11048  assert(conss != NULL || nconss == 0);
11049 
11050  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11051  assert(conshdlrdata != NULL);
11052 
11053  for( c = 0; c < nconss; ++c )
11054  {
11055  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
11056  assert(consdata != NULL);
11057 
11058  /* free nonlinear row representation */
11059  if( consdata->nlrow != NULL )
11060  {
11061  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
11062  }
11063 
11064  assert(consdata->sepaquadvars != NULL || consdata->nquadvars == 0);
11065  assert(consdata->sepabilinvar2pos != NULL || consdata->nquadvars == 0);
11066  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepaquadvars, consdata->nquadvars);
11067  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms);
11068 
11069  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorleft, consdata->nquadvars + 1);
11070  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorright, consdata->nquadvars + 1);
11071 
11072  SCIPfreeMemoryArrayNull(scip, &consdata->interiorpoint);
11073  SCIPfreeMemoryArrayNull(scip, &consdata->gaugecoefs);
11074  }
11075 
11076  if( SCIPgetStage(scip) != SCIP_STAGE_EXITSOLVE )
11077  {
11078  /* if called from consDisableQuadratic, then don't do below */
11079  return SCIP_OKAY;
11080  }
11081 
11082  if( conshdlrdata->newsoleventfilterpos >= 0 )
11083  {
11084  SCIP_EVENTHDLR* eventhdlr;
11085 
11086  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
11087  assert(eventhdlr != NULL);
11088 
11089  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11090  conshdlrdata->newsoleventfilterpos = -1;
11091  }
11092 
11093  return SCIP_OKAY;
11094 }
11095 
11096 /** frees specific constraint data */
11097 static
11098 SCIP_DECL_CONSDELETE(consDeleteQuadratic)
11100  assert(scip != NULL);
11101  assert(conshdlr != NULL);
11102  assert(cons != NULL);
11103  assert(consdata != NULL);
11104  assert(SCIPconsGetData(cons) == *consdata);
11105 
11106  SCIP_CALL( consdataFree(scip, consdata) );
11107 
11108  assert(*consdata == NULL);
11109 
11110  return SCIP_OKAY;
11111 }
11112 
11113 /** transforms constraint data into data belonging to the transformed problem */
11114 static
11115 SCIP_DECL_CONSTRANS(consTransQuadratic)
11116 {
11117  SCIP_CONSDATA* sourcedata;
11118  SCIP_CONSDATA* targetdata;
11119  int i;
11120 
11121  sourcedata = SCIPconsGetData(sourcecons);
11122  assert(sourcedata != NULL);
11123 
11124  SCIP_CALL( consdataCreate(scip, &targetdata,
11125  sourcedata->lhs, sourcedata->rhs,
11126  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
11127  sourcedata->nquadvars, sourcedata->quadvarterms,
11128  sourcedata->nbilinterms, sourcedata->bilinterms,
11129  FALSE) );
11130 
11131  for( i = 0; i < targetdata->nlinvars; ++i )
11132  {
11133  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
11134  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
11135  }
11136 
11137  for( i = 0; i < targetdata->nquadvars; ++i )
11138  {
11139  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->quadvarterms[i].var, &targetdata->quadvarterms[i].var) );
11140  SCIP_CALL( SCIPcaptureVar(scip, targetdata->quadvarterms[i].var) );
11141  }
11142 
11143  for( i = 0; i < targetdata->nbilinterms; ++i )
11144  {
11145  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var1, &targetdata->bilinterms[i].var1) );
11146  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var2, &targetdata->bilinterms[i].var2) );
11147 
11148  if( SCIPvarCompare(targetdata->bilinterms[i].var1, targetdata->bilinterms[i].var2) > 0 )
11149  {
11150  SCIP_VAR* tmp;
11151  tmp = targetdata->bilinterms[i].var2;
11152  targetdata->bilinterms[i].var2 = targetdata->bilinterms[i].var1;
11153  targetdata->bilinterms[i].var1 = tmp;
11154  }
11155  }
11156 
11157  /* create target constraint */
11158  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
11159  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11160  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
11161  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
11162  SCIPconsIsStickingAtNode(sourcecons)) );
11163 
11164  SCIPdebugMessage("created transformed quadratic constraint ");
11165  SCIPdebugPrintCons(scip, *targetcons, NULL);
11166 
11167  return SCIP_OKAY;
11168 }
11169 
11170 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11171 static
11172 SCIP_DECL_CONSINITLP(consInitlpQuadratic)
11174  SCIP_CONSHDLRDATA* conshdlrdata;
11175  SCIP_CONSDATA* consdata;
11176  SCIP_VAR* var;
11177  SCIP_ROW* row;
11178  SCIP_Real* x;
11179  int c;
11180  int i;
11181 
11182  assert(scip != NULL);
11183  assert(conshdlr != NULL);
11184  assert(conss != NULL || nconss == 0);
11185 
11186  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11187  assert(conshdlrdata != NULL);
11188 
11189  for( c = 0; c < nconss; ++c )
11190  {
11191  assert(conss[c] != NULL); /*lint !e613 */
11192 
11193  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11194 
11195  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
11196  assert(consdata != NULL);
11197 
11198  row = NULL;
11199 
11200  if( consdata->nquadvars == 0 )
11201  {
11202  SCIP_Bool infeasible;
11203 
11204  /* if we are actually linear, add the constraint as row to the LP */
11205  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
11206  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613 */
11207  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
11208  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
11209 #ifdef ASSERT_INITLP_FEASCUT
11210  assert( ! infeasible );
11211 #endif
11212  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11213  continue;
11214  }
11215 
11216  /* alloc memory for reference point */
11217  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nquadvars) );
11218 
11219  /* for convex parts, add linearizations in 5 points */
11220  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
11221  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
11222  {
11223  SCIP_Real lb;
11224  SCIP_Real ub;
11225  SCIP_Real lambda;
11226  int k;
11227 
11228  for( k = 0; k < 5; ++k )
11229  {
11230  lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
11231  for( i = 0; i < consdata->nquadvars; ++i )
11232  {
11233  var = consdata->quadvarterms[i].var;
11234  lb = SCIPvarGetLbGlobal(var);
11235  ub = SCIPvarGetUbGlobal(var);
11236 
11237  if( ub > -INITLPMAXVARVAL )
11238  lb = MAX(lb, -INITLPMAXVARVAL);
11239  if( lb < INITLPMAXVARVAL )
11240  ub = MIN(ub, INITLPMAXVARVAL);
11241 
11242  /* make bounds finite */
11243  if( SCIPisInfinity(scip, -lb) )
11244  lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
11245  if( SCIPisInfinity(scip, ub) )
11246  ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
11247 
11249  x[i] = lambda * ub + (1.0 - lambda) * lb;
11250  else
11251  x[i] = lambda * lb + (1.0 - lambda) * ub;
11252  }
11253 
11254  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, consdata->isconvex ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT, &row, NULL,
11255  FALSE, -SCIPinfinity(scip)) ); /*lint !e613 */
11256  if( row != NULL )
11257  {
11258  SCIP_Bool infeasible;
11259 
11260  SCIPdebugMessage("initlp adds row <%s> for lambda = %g of conss <%s>\n", SCIProwGetName(row), lambda, SCIPconsGetName(conss[c])); /*lint !e613 */
11261  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11262 
11263  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
11264 #ifdef ASSERT_INITLP_FEASCUT
11265  assert( ! infeasible );
11266 #endif
11267 
11268  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11269  }
11270  }
11271  }
11272 
11273  /* for concave parts, add underestimator w.r.t. at most 2 reference points */
11274  if( (! consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) || (! consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
11275  {
11276  SCIP_Bool unbounded;
11277  SCIP_Bool possquare;
11278  SCIP_Bool negsquare;
11279  SCIP_Real lb;
11280  SCIP_Real ub;
11281  SCIP_Real lambda;
11282  int k;
11283 
11284  unbounded = FALSE; /* whether there are unbounded variables */
11285  possquare = FALSE; /* whether there is a positive square term */
11286  negsquare = FALSE; /* whether there is a negative square term */
11287  for( k = 0; k < 2; ++k )
11288  {
11289  /* Set reference point to 0 projected on bounds for unbounded variables or in between lower and upper bound
11290  * for bounded variables in the first round, we set it closer to the best bound for one part of the
11291  * variables, in the second closer to the best bound for the other part of the variables.
11292  * Additionally, we use slightly different weights for each variable.
11293  * The reason for the latter is, that for a bilinear term with bounded variables, there are always two linear underestimators
11294  * if the same weight is used for both variables of a product, then rounding and luck decides which underestimator is chosen
11295  * of course, the possible number of cuts is something in the order of 2^nquadvars, and we choose two of them here.
11296  */
11297  for( i = 0; i < consdata->nquadvars; ++i )
11298  {
11299  var = consdata->quadvarterms[i].var;
11300  lb = SCIPvarGetLbGlobal(var);
11301  ub = SCIPvarGetUbGlobal(var);
11302 
11303  if( SCIPisInfinity(scip, -lb) )
11304  {
11305  if( SCIPisInfinity(scip, ub) )
11306  x[i] = 0.0;
11307  else
11308  x[i] = MIN(0.0, ub);
11309  unbounded = TRUE;
11310  }
11311  else
11312  {
11313  if( SCIPisInfinity(scip, ub) )
11314  {
11315  x[i] = MAX(0.0, lb);
11316  unbounded = TRUE;
11317  }
11318  else
11319  {
11320  lambda = 0.4 + 0.2 * ((i+k)%2) + 0.01 * i / (double)consdata->nquadvars;
11321  x[i] = lambda * SCIPvarGetBestBoundLocal(var) + (1.0-lambda) * SCIPvarGetWorstBoundLocal(var);
11322  }
11323  }
11324 
11325  possquare |= consdata->quadvarterms[i].sqrcoef > 0.0; /*lint !e514 */
11326  negsquare |= consdata->quadvarterms[i].sqrcoef < 0.0; /*lint !e514 */
11327  }
11328 
11329  if( !consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
11330  {
11331  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_RIGHT, &row, NULL,
11332  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
11333  if( row != NULL )
11334  {
11335  SCIP_Bool infeasible;
11336 
11337  SCIPdebugMessage("initlp adds row <%s> for rhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
11338  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11339 
11340  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
11341 #ifdef ASSERT_INITLP_FEASCUT
11342  assert( ! infeasible );
11343 #endif
11344 
11345  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11346  }
11347  }
11348  if( !consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
11349  {
11350  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_LEFT, &row, NULL,
11351  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
11352  if( row != NULL )
11353  {
11354  SCIP_Bool infeasible;
11355 
11356  SCIPdebugMessage("initlp adds row <%s> for lhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
11357  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11358 
11359  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
11360 #ifdef ASSERT_INITLP_FEASCUT
11361  assert( ! infeasible );
11362 #endif
11363 
11364  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11365  }
11366  }
11367 
11368  /* if there are unbounded variables, then there is typically only at most one possible underestimator, so don't try another round
11369  * 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 */
11370  if( unbounded ||
11371  (consdata->nbilinterms == 0 && (!possquare || SCIPisInfinity(scip, consdata->rhs))) ||
11372  (consdata->nbilinterms == 0 && (!negsquare || SCIPisInfinity(scip, -consdata->lhs))) )
11373  break;
11374  }
11375  }
11376 
11377  SCIPfreeBufferArray(scip, &x);
11378  }
11379 
11380  return SCIP_OKAY;
11381 }
11382 
11383 /** separation method of constraint handler for LP solutions */
11384 static
11385 SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
11386 {
11387  SCIP_CONSHDLRDATA* conshdlrdata;
11388  SCIP_CONS* maxviolcon;
11389 
11390  assert(scip != NULL);
11391  assert(conshdlr != NULL);
11392  assert(conss != NULL || nconss == 0);
11393  assert(result != NULL);
11394 
11395  *result = SCIP_DIDNOTFIND;
11396 
11397  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11398  assert(conshdlrdata != NULL);
11399 
11400  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
11401  if( maxviolcon == NULL )
11402  return SCIP_OKAY;
11403 
11404  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
11405  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
11406  */
11407  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
11408  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) ||
11409  (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
11410  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
11411  {
11412  SCIP_CONSDATA* consdata;
11413  SCIP_NLPSOLSTAT solstat;
11414  SCIP_Bool solvednlp;
11415  int c;
11416 
11417  solstat = SCIPgetNLPSolstat(scip);
11418  solvednlp = FALSE;
11419  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
11420  {
11421  /* NLP is not solved yet, so we might want to do this
11422  * but first check whether there is a violated constraint side which corresponds to a convex function
11423  */
11424  for( c = 0; c < nconss; ++c )
11425  {
11426  assert(conss[c] != NULL); /*lint !e613 */
11427 
11428  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
11429  assert(consdata != NULL);
11430 
11431  /* skip feasible constraints */
11432  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11433  continue;
11434 
11435  /* make sure curvature has been checked */
11436  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11437 
11438  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->isconvex) ||
11439  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->isconcave) )
11440  break;
11441  }
11442 
11443  if( c < nconss )
11444  {
11445  /* try to solve NLP and update solstat */
11446 
11447  /* ensure linear conss are in NLP */
11448  if( conshdlrdata->subnlpheur != NULL )
11449  {
11450  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
11451  }
11452 
11453  /* set LP solution as starting values, if available */
11455  {
11457  }
11458 
11459  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
11460  SCIP_CALL( SCIPsolveNLP(scip) );
11461 
11462  solstat = SCIPgetNLPSolstat(scip);
11463  SCIPdebugMessage("solved NLP relax, solution status: %d\n", solstat);
11464 
11465  solvednlp = TRUE;
11466  }
11467  }
11468 
11469  conshdlrdata->sepanlp = TRUE;
11470 
11471  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
11472  {
11473  SCIPdebugMessage("NLP relaxation is globally infeasible, thus can cutoff node\n");
11474  *result = SCIP_CUTOFF;
11475  return SCIP_OKAY;
11476  }
11477 
11478  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
11479  {
11480  /* if we have feasible NLP solution, generate linearization cuts there */
11481  SCIP_Bool lpsolseparated;
11482  SCIP_SOL* nlpsol;
11483 
11484  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
11485  assert(nlpsol != NULL);
11486 
11487  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
11488  if( solvednlp && conshdlrdata->trysolheur != NULL )
11489  {
11490  int nfracvars;
11491 
11492  nfracvars = 0;
11493  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
11494  {
11495  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
11496  }
11497 
11498  if( nfracvars == 0 )
11499  {
11500  SCIPdebugMessage("pass solution with obj. value %g to trysol\n", SCIPgetSolOrigObj(scip, nlpsol));
11501  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
11502  }
11503  }
11504 
11505  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, conshdlrdata->mincutefficacysepa) );
11506 
11507  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
11508 
11509  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
11510  if( lpsolseparated )
11511  {
11512  SCIPdebugMessage("linearization cuts separate LP solution\n");
11513  *result = SCIP_SEPARATED;
11514 
11515  return SCIP_OKAY;
11516  }
11517  }
11518  }
11519  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
11520  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
11521  */
11522 
11523  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
11524 
11525  return SCIP_OKAY;
11526 }
11527 
11528 /** separation method of constraint handler for arbitrary primal solutions */
11529 static
11530 SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
11532  SCIP_CONSHDLRDATA* conshdlrdata;
11533  SCIP_CONS* maxviolcon;
11534 
11535  assert(scip != NULL);
11536  assert(conshdlr != NULL);
11537  assert(conss != NULL || nconss == 0);
11538  assert(sol != NULL);
11539  assert(result != NULL);
11540 
11541  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11542  assert(conshdlrdata != NULL);
11543 
11544  *result = SCIP_DIDNOTFIND;
11545 
11546  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &maxviolcon) );
11547  if( maxviolcon == NULL )
11548  return SCIP_OKAY;
11549 
11550  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
11551 
11552  return SCIP_OKAY;
11553 }
11554 
11555 /** constraint enforcing method of constraint handler for LP solutions */
11556 static
11557 SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
11558 { /*lint --e{715}*/
11559  SCIP_CONSHDLRDATA* conshdlrdata;
11560  SCIP_CONSDATA* consdata;
11561  SCIP_CONS* maxviolcon;
11562  SCIP_Real maxviol;
11563  SCIP_RESULT propresult;
11564  SCIP_RESULT separateresult;
11565  int nchgbds;
11566  int nnotify;
11567  SCIP_Real sepaefficacy;
11568  SCIP_Real minefficacy;
11569  SCIP_Real leastpossibleefficacy;
11570 
11571  assert(scip != NULL);
11572  assert(conshdlr != NULL);
11573  assert(conss != NULL || nconss == 0);
11574 
11575  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11576  assert(conshdlrdata != NULL);
11577 
11578  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
11579  if( maxviolcon == NULL )
11580  {
11581  *result = SCIP_FEASIBLE;
11582  return SCIP_OKAY;
11583  }
11584 
11585  *result = SCIP_INFEASIBLE;
11586 
11587  consdata = SCIPconsGetData(maxviolcon);
11588  assert(consdata != NULL);
11589  maxviol = consdata->lhsviol + consdata->rhsviol;
11590  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
11591 
11592  SCIPdebugMessage("enfolp with max violation %g in cons <%s>\n", maxviol, SCIPconsGetName(maxviolcon));
11593 
11594  /* if we are above the 100'th enforcement round for this node, something is strange
11595  * (maybe the LP does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
11596  * 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
11597  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
11598  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
11599  * we only increment nenfolprounds until 101 to avoid an overflow
11600  */
11601  if( conshdlrdata->lastenfolpnode == SCIPgetCurrentNode(scip) )
11602  {
11603  if( conshdlrdata->nenfolprounds > 100 )
11604  {
11605  if( SCIPisStopped(scip) )
11606  {
11607  SCIP_NODE* child;
11608 
11609  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
11610  *result = SCIP_BRANCHED;
11611 
11612  return SCIP_OKAY;
11613  }
11614  }
11615 
11616  ++conshdlrdata->nenfolprounds;
11617 
11618  /* cut off the current subtree, if a limit on the enforcement rounds should be applied. At this point, feasible
11619  * solutions might get cut off; the enfolplimit parameter should therefore only be set if SCIP is used as a
11620  * heuristic solver and when the returned result (infeasible, optimal, the gap) can be ignored
11621  */
11622  if( conshdlrdata->enfolplimit != -1 && conshdlrdata->nenfolprounds > conshdlrdata->enfolplimit )
11623  {
11625  "cut off subtree because enforcement limit was reached; this might lead to incorrect results\n");
11626  *result = SCIP_CUTOFF;
11627  return SCIP_OKAY;
11628  }
11629  }
11630  else
11631  {
11632  conshdlrdata->lastenfolpnode = SCIPgetCurrentNode(scip);
11633  conshdlrdata->nenfolprounds = 0;
11634  }
11635 
11636  /* run domain propagation */
11637  nchgbds = 0;
11638  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
11639  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
11640  {
11641  SCIPdebugMessage("propagation succeeded (%s)\n", propresult == SCIP_CUTOFF ? "cutoff" : "reduceddom");
11642  *result = propresult;
11643  return SCIP_OKAY;
11644  }
11645 
11646  /* we would like a cut that is efficient enough that it is not redundant in the LP (>feastol)
11647  * however, if the maximal violation is very small, also the best cut efficacy cannot be large
11648  * thus, in the latter case, we are also happy if the efficacy is at least, say, 75% of the maximal violation
11649  * but in any case we need an efficacy that is at least feastol
11650  */
11651  minefficacy = MIN(0.75*maxviol, conshdlrdata->mincutefficacyenfofac * SCIPfeastol(scip)); /*lint !e666 */
11652  minefficacy = MAX(minefficacy, SCIPfeastol(scip)); /*lint !e666 */
11653  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, minefficacy, TRUE, &separateresult, &sepaefficacy) );
11654  if( separateresult == SCIP_CUTOFF )
11655  {
11656  SCIPdebugMessage("separation found cutoff\n");
11657  *result = SCIP_CUTOFF;
11658  return SCIP_OKAY;
11659  }
11660  if( separateresult == SCIP_SEPARATED )
11661  {
11662  SCIPdebugMessage("separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, minefficacy);
11663  *result = SCIP_SEPARATED;
11664  return SCIP_OKAY;
11665  }
11666 
11667  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
11668  * -> collect variables for branching
11669  */
11670 
11671  SCIPdebugMessage("separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, minefficacy, maxviol);
11672 
11673  /* find branching candidates */
11674  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &nnotify) );
11675 
11676  /* if sepastore can decrease LP feasibility tolerance, we can add cuts with efficacy in [eps, feastol] */
11677  leastpossibleefficacy = SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip);
11678  if( nnotify == 0 && !solinfeasible && minefficacy > leastpossibleefficacy )
11679  {
11680  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
11681  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, leastpossibleefficacy, TRUE, &separateresult, &sepaefficacy) );
11682  if( separateresult == SCIP_CUTOFF )
11683  {
11684  SCIPdebugMessage("separation found cutoff\n");
11685  *result = SCIP_CUTOFF;
11686  return SCIP_OKAY;
11687  }
11688  if( separateresult == SCIP_SEPARATED )
11689  {
11690  SCIPdebugMessage("separation fallback succeeded, efficacy = %g\n", sepaefficacy);
11691  *result = SCIP_SEPARATED;
11692  return SCIP_OKAY;
11693  }
11694  }
11695 
11696  if( nnotify == 0 && !solinfeasible )
11697  {
11698  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
11699  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
11700  */
11701  SCIP_VAR* brvar = NULL;
11702  SCIP_CALL( registerLargeLPValueVariableForBranching(scip, conss, nconss, &brvar) );
11703  if( brvar == NULL )
11704  {
11705  /* fallback 3: all quadratic variables seem to be fixed -> replace by linear constraint */
11706  SCIP_Bool addedcons;
11707  SCIP_Bool reduceddom;
11708  SCIP_Bool infeasible;
11709 
11710  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
11711  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
11712  * when it enforces the new constraints again and nothing resolves the infeasiblity that we declare here thus,
11713  * we only add them if considered violated, and otherwise claim the solution is feasible (but print a
11714  * warning) */
11715  if ( infeasible )
11716  *result = SCIP_CUTOFF;
11717  else if ( addedcons )
11718  *result = SCIP_CONSADDED;
11719  else if ( reduceddom )
11720  *result = SCIP_REDUCEDDOM;
11721  else
11722  {
11723  *result = SCIP_FEASIBLE;
11724  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
11725  assert(!SCIPisInfinity(scip, maxviol));
11726  }
11727  return SCIP_OKAY;
11728  }
11729  else
11730  {
11731  SCIPdebugMessage("Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
11732  SCIPvarGetName(brvar), SCIPgetSolVal(scip, NULL, brvar));
11733  nnotify = 1;
11734  }
11735  }
11736 
11737  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
11738  return SCIP_OKAY;
11739 }
11740 
11741 
11742 /** constraint enforcing method of constraint handler for pseudo solutions */
11743 static
11744 SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
11745 { /*lint --e{715}*/
11746  SCIP_CONS* maxviolcon;
11747  SCIP_CONSDATA* consdata;
11748  SCIP_RESULT propresult;
11749  SCIP_VAR* var;
11750  int c;
11751  int i;
11752  int nchgbds;
11753  int nnotify;
11754 
11755  assert(scip != NULL);
11756  assert(conss != NULL || nconss == 0);
11757 
11758  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
11759  if( maxviolcon == NULL )
11760  {
11761  *result = SCIP_FEASIBLE;
11762  return SCIP_OKAY;
11763  }
11764 
11765  *result = SCIP_INFEASIBLE;
11766 
11767  SCIPdebugMessage("enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcon));
11768 
11769  /* run domain propagation */
11770  nchgbds = 0;
11771  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
11772  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
11773  {
11774  *result = propresult;
11775  return SCIP_OKAY;
11776  }
11777 
11778  /* we are not feasible and we cannot proof that the whole node is infeasible
11779  * -> collect all variables in violated constraints for branching
11780  */
11781  nnotify = 0;
11782  for( c = 0; c < nconss; ++c )
11783  {
11784  assert(conss != NULL);
11785  consdata = SCIPconsGetData(conss[c]);
11786  assert(consdata != NULL);
11787 
11788  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11789  continue;
11790 
11791  for( i = 0; i < consdata->nlinvars; ++i )
11792  {
11793  var = consdata->linvars[i];
11794  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11795  {
11796  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
11797  ++nnotify;
11798  }
11799  }
11800 
11801  for( i = 0; i < consdata->nquadvars; ++i )
11802  {
11803  var = consdata->quadvarterms[i].var;
11804  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11805  {
11806  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
11807  ++nnotify;
11808  }
11809  }
11810  }
11811 
11812  if( nnotify == 0 )
11813  {
11814  SCIPdebugMessage("All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
11815  *result = SCIP_SOLVELP;
11816  }
11817 
11818  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
11819  return SCIP_OKAY;
11820 }
11821 
11822 /** domain propagation method of constraint handler */
11823 static
11824 SCIP_DECL_CONSPROP(consPropQuadratic)
11826  int nchgbds;
11827 
11828  assert(scip != NULL);
11829  assert(conshdlr != NULL);
11830  assert(conss != NULL || nconss == 0);
11831  assert(result != NULL);
11832 
11833  nchgbds = 0;
11834  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, result, &nchgbds) );
11835 
11836  return SCIP_OKAY;
11837 } /*lint !e715 */
11838 
11839 /** presolving method of constraint handler */
11840 static
11841 SCIP_DECL_CONSPRESOL(consPresolQuadratic)
11842 { /*lint --e{715,788}*/
11843  SCIP_CONSHDLRDATA* conshdlrdata;
11844  SCIP_CONSDATA* consdata;
11845  SCIP_RESULT solveresult;
11846  SCIP_Bool redundant;
11847  SCIP_Bool havechange;
11848  SCIP_Bool doreformulations;
11849  int c;
11850  int i;
11851 
11852  assert(scip != NULL);
11853  assert(conshdlr != NULL);
11854  assert(conss != NULL || nconss == 0);
11855  assert(result != NULL);
11856 
11857  *result = SCIP_DIDNOTFIND;
11858 
11859  /* if other presolvers did not find enough changes for another presolving round,
11860  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
11861  * otherwise, we wait with these
11862  * @todo first do all usual presolving steps, then check SCIPisPresolveFinished(scip), and if true then do reformulations (and usual steps again)
11863  */
11864  doreformulations = nrounds > 0 && ((presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 || SCIPisPresolveFinished(scip));
11865  SCIPdebugMessage("presolving will %swait with reformulation\n", doreformulations ? "not " : "");
11866 
11867  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11868  assert(conshdlrdata != NULL);
11869 
11870  for( c = 0; c < nconss; ++c )
11871  {
11872  assert(conss != NULL);
11873  consdata = SCIPconsGetData(conss[c]);
11874  assert(consdata != NULL);
11875 
11876  SCIPdebugMessage("process constraint <%s>\n", SCIPconsGetName(conss[c]));
11877  SCIPdebugPrintCons(scip, conss[c], NULL);
11878 
11879  if( !consdata->initialmerge )
11880  {
11881  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
11882  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
11883  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
11884  consdata->initialmerge = TRUE;
11885  }
11886 
11887  havechange = FALSE;
11888 #ifdef CHECKIMPLINBILINEAR
11889  if( consdata->isimpladded && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
11890  {
11891  int nbilinremoved;
11892  SCIP_CALL( presolveApplyImplications(scip, conss[c], &nbilinremoved) );
11893  if( nbilinremoved > 0 )
11894  {
11895  *nchgcoefs += nbilinremoved;
11896  havechange = TRUE;
11897  *result = SCIP_SUCCESS;
11898  }
11899  assert(!consdata->isimpladded);
11900  }
11901 #endif
11902  /* 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
11903  * we want to do this before (multi)aggregated variables are replaced, since that may change structure, e.g., introduce bilinear terms
11904  */
11905  if( !consdata->ispresolved || !consdata->ispropagated || nnewchgvartypes > 0 )
11906  {
11907  SCIP_Bool upgraded;
11908 
11909  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
11910  if( upgraded )
11911  {
11912  *result = SCIP_SUCCESS;
11913  continue;
11914  }
11915  }
11916 
11917  if( !consdata->isremovedfixings )
11918  {
11919  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
11920  assert(consdata->isremovedfixings);
11921  havechange = TRUE;
11922  }
11923 
11924  /* try to "solve" the constraint, e.g., reduce to a variable aggregation */
11925  SCIP_CALL( presolveSolve(scip, conss[c], &solveresult, &redundant, naggrvars) );
11926  if( solveresult == SCIP_CUTOFF )
11927  {
11928  SCIPdebugMessage("solving constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
11929  *result = SCIP_CUTOFF;
11930  return SCIP_OKAY;
11931  }
11932  if( redundant )
11933  {
11934  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
11935  ++*ndelconss;
11936  *result = SCIP_SUCCESS;
11937  break;
11938  }
11939  if( solveresult == SCIP_SUCCESS )
11940  {
11941  *result = SCIP_SUCCESS;
11942  havechange = TRUE;
11943  }
11944 
11945  /* @todo divide constraint by gcd of coefficients if all are integral */
11946 
11947  if( doreformulations )
11948  {
11949  int naddconss_old;
11950 
11951  naddconss_old = *naddconss;
11952 
11953  SCIP_CALL( presolveTryAddAND(scip, conshdlr, conss[c], naddconss) );
11954  assert(*naddconss >= naddconss_old);
11955 
11956  if( *naddconss == naddconss_old )
11957  {
11958  /* user not so empathic about AND, or we don't have products of two binaries, so try this more general reformulation */
11959  SCIP_CALL( presolveTryAddLinearReform(scip, conshdlr, conss[c], naddconss) );
11960  assert(*naddconss >= naddconss_old);
11961  }
11962 
11963  if( conshdlrdata->disaggregate )
11964  {
11965  /* try disaggregation, if enabled */
11966  SCIP_CALL( presolveDisaggregate(scip, conshdlr, conss[c], naddconss) );
11967  }
11968 
11969  if( *naddconss > naddconss_old )
11970  {
11971  /* if something happened, report success and cleanup constraint */
11972  *result = SCIP_SUCCESS;
11973  havechange = TRUE;
11974  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
11975  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
11976  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
11977  }
11978  }
11979 
11980  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
11981  {
11982  /* all variables fixed or removed, constraint function is 0.0 now */
11983  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
11984  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
11985  { /* left hand side positive or right hand side negative */
11986  SCIPdebugMessage("constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
11987  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
11988  ++*ndelconss;
11989  *result = SCIP_CUTOFF;
11990  return SCIP_OKAY;
11991  }
11992 
11993  /* left and right hand side are consistent */
11994  SCIPdebugMessage("constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
11995  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
11996  ++*ndelconss;
11997  *result = SCIP_SUCCESS;
11998  continue;
11999  }
12000 
12001  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 && !consdata->ispropagated )
12002  {
12003  /* try domain propagation if there were bound changes or constraint has changed (in which case, processVarEvents may have set ispropagated to false) */
12004  SCIP_RESULT propresult;
12005  int roundnr;
12006 
12007  roundnr = 0;
12008  do
12009  {
12010  ++roundnr;
12011 
12012  SCIPdebugMessage("starting domain propagation round %d of %d\n", roundnr, conshdlrdata->maxproproundspresolve);
12013 
12014  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
12015 
12016  if( propresult == SCIP_CUTOFF )
12017  {
12018  SCIPdebugMessage("propagation on constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
12019  *result = SCIP_CUTOFF;
12020  return SCIP_OKAY;
12021  }
12022 
12023  /* delete constraint if found redundant by bound tightening */
12024  if( redundant )
12025  {
12026  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12027  ++*ndelconss;
12028  *result = SCIP_SUCCESS;
12029  break;
12030  }
12031 
12032  if( propresult == SCIP_REDUCEDDOM )
12033  {
12034  *result = SCIP_SUCCESS;
12035  havechange = TRUE;
12036  }
12037 
12038  }
12039  while( !consdata->ispropagated && roundnr < conshdlrdata->maxproproundspresolve );
12040 
12041  if( redundant )
12042  continue;
12043  }
12044 
12045  /* check if we have a single linear continuous variable that we can make implicit integer */
12046  if( (nnewchgvartypes != 0 || havechange || !consdata->ispresolved)
12047  && (SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->lhs)) )
12048  {
12049  int ncontvar;
12050  SCIP_VAR* candidate;
12051  SCIP_Bool fail;
12052 
12053  fail = FALSE;
12054  candidate = NULL;
12055  ncontvar = 0;
12056 
12057  for( i = 0; !fail && i < consdata->nlinvars; ++i )
12058  {
12059  if( !SCIPisIntegral(scip, consdata->lincoefs[i]) )
12060  {
12061  fail = TRUE;
12062  }
12063  else if( SCIPvarGetType(consdata->linvars[i]) == SCIP_VARTYPE_CONTINUOUS )
12064  {
12065  if( ncontvar > 0 ) /* now at 2nd continuous variable */
12066  fail = TRUE;
12067  else if( SCIPisEQ(scip, ABS(consdata->lincoefs[i]), 1.0) )
12068  candidate = consdata->linvars[i];
12069  ++ncontvar;
12070  }
12071  }
12072  for( i = 0; !fail && i < consdata->nquadvars; ++i )
12073  fail = SCIPvarGetType(consdata->quadvarterms[i].var) == SCIP_VARTYPE_CONTINUOUS ||
12074  !SCIPisIntegral(scip, consdata->quadvarterms[i].lincoef) ||
12075  !SCIPisIntegral(scip, consdata->quadvarterms[i].sqrcoef);
12076  for( i = 0; !fail && i < consdata->nbilinterms; ++i )
12077  fail = !SCIPisIntegral(scip, consdata->bilinterms[i].coef);
12078 
12079  if( !fail && candidate != NULL )
12080  {
12081  SCIP_Bool infeasible;
12082 
12083  SCIPdebugMessage("make variable <%s> implicit integer due to constraint <%s>\n", SCIPvarGetName(candidate), SCIPconsGetName(conss[c]));
12084 
12085  SCIP_CALL( SCIPchgVarType(scip, candidate, SCIP_VARTYPE_IMPLINT, &infeasible) );
12086  if( infeasible )
12087  {
12088  SCIPdebugMessage("infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(candidate));
12089  *result = SCIP_CUTOFF;
12090 
12091  return SCIP_OKAY;
12092  }
12093 
12094  ++(*nchgvartypes);
12095  *result = SCIP_SUCCESS;
12096  havechange = TRUE;
12097  }
12098  }
12099 
12100  /* call upgrade methods again if constraint has been changed */
12101  if( havechange )
12102  {
12103  SCIP_Bool upgraded;
12104 
12105  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
12106  if( upgraded )
12107  {
12108  *result = SCIP_SUCCESS;
12109  continue;
12110  }
12111  }
12112 
12113  consdata->ispresolved = TRUE;
12114  }
12115 
12116  return SCIP_OKAY;
12117 }
12118 
12119 /** variable rounding lock method of constraint handler */
12120 static
12121 SCIP_DECL_CONSLOCK(consLockQuadratic)
12122 { /*lint --e{715}*/
12123  SCIP_CONSDATA* consdata;
12124  SCIP_Bool haslb;
12125  SCIP_Bool hasub;
12126  int i;
12127 
12128  assert(scip != NULL);
12129  assert(cons != NULL);
12130 
12131  consdata = SCIPconsGetData(cons);
12132  assert(consdata != NULL);
12133 
12134  haslb = !SCIPisInfinity(scip, -consdata->lhs);
12135  hasub = !SCIPisInfinity(scip, consdata->rhs);
12136 
12137  for( i = 0; i < consdata->nlinvars; ++i )
12138  {
12139  if( consdata->lincoefs[i] > 0 )
12140  {
12141  if( haslb )
12142  {
12143  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
12144  }
12145  if( hasub )
12146  {
12147  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
12148  }
12149  }
12150  else
12151  {
12152  if( haslb )
12153  {
12154  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
12155  }
12156  if( hasub )
12157  {
12158  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
12159  }
12160  }
12161  }
12162 
12163  for( i = 0; i < consdata->nquadvars; ++i )
12164  {
12165  /* @todo try to be more clever, but variable locks that depend on the bounds of other variables are not trival to maintain */
12166  SCIP_CALL( SCIPaddVarLocks(scip, consdata->quadvarterms[i].var, nlockspos+nlocksneg, nlockspos+nlocksneg) );
12167  }
12168 
12169  return SCIP_OKAY;
12170 }
12171 
12172 /** constraint enabling notification method of constraint handler */
12173 static
12174 SCIP_DECL_CONSENABLE(consEnableQuadratic)
12176  SCIP_CONSHDLRDATA* conshdlrdata;
12177 
12178  assert(scip != NULL);
12179  assert(conshdlr != NULL);
12180  assert(cons != NULL);
12181  assert(SCIPconsIsTransformed(cons));
12182  assert(SCIPconsIsActive(cons));
12183 
12184  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12185  assert(conshdlrdata != NULL);
12186 
12187  SCIPdebugMessage("enable cons <%s>\n", SCIPconsGetName(cons));
12188 
12189  if( SCIPgetStage(scip) >= SCIP_STAGE_EXITPRESOLVE )
12190  {
12191  /* merge duplicate bilinear terms, move quad terms that are linear to linear vars */
12192  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
12193  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
12194  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
12195  }
12196 
12197  /* catch variable events */
12198  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12199 
12200  /* initialize solving data */
12201  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
12202  {
12203  SCIP_CALL( consInitsolQuadratic(scip, conshdlr, &cons, 1) );
12204  }
12205 
12206  return SCIP_OKAY;
12207 }
12208 
12209 /** constraint disabling notification method of constraint handler */
12210 static
12211 SCIP_DECL_CONSDISABLE(consDisableQuadratic)
12212 { /*lint --e{715}*/
12213  SCIP_CONSHDLRDATA* conshdlrdata;
12214 
12215  assert(scip != NULL);
12216  assert(conshdlr != NULL);
12217  assert(cons != NULL);
12218  assert(SCIPconsIsTransformed(cons));
12219 
12220  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12221  assert(conshdlrdata != NULL);
12222 
12223  SCIPdebugMessage("disable cons <%s>\n", SCIPconsGetName(cons));
12224 
12225  /* free solving data */
12226  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
12227  {
12228  SCIP_CALL( consExitsolQuadratic(scip, conshdlr, &cons, 1, FALSE) );
12229  }
12230 
12231  /* drop variable events */
12232  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12233 
12234  return SCIP_OKAY;
12235 }
12236 
12237 /** constraint display method of constraint handler */
12238 static
12239 SCIP_DECL_CONSPRINT(consPrintQuadratic)
12240 { /*lint --e{715}*/
12241  SCIP_CONSDATA* consdata;
12242 
12243  assert(scip != NULL);
12244  assert(cons != NULL);
12245 
12246  consdata = SCIPconsGetData(cons);
12247  assert(consdata != NULL);
12248 
12249  /* print left hand side for ranged rows */
12250  if( !SCIPisInfinity(scip, -consdata->lhs)
12251  && !SCIPisInfinity(scip, consdata->rhs)
12252  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12253  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
12254 
12255  /* print coefficients and variables */
12256  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
12257  {
12258  SCIPinfoMessage(scip, file, "0 ");
12259  }
12260  else
12261  {
12262  SCIP_VAR*** monomialvars;
12263  SCIP_Real** monomialexps;
12264  SCIP_Real* monomialcoefs;
12265  int* monomialnvars;
12266  int nmonomials;
12267  int monomialssize;
12268  int j;
12269 
12270  monomialssize = consdata->nlinvars + 2 * consdata->nquadvars + consdata->nbilinterms;
12271  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, monomialssize) );
12272  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps, monomialssize) );
12273  SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, monomialssize) );
12274  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, monomialssize) );
12275 
12276  nmonomials = 0;
12277  for( j = 0; j < consdata->nlinvars; ++j )
12278  {
12279  assert(nmonomials < monomialssize);
12280 
12281  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
12282 
12283  monomialvars[nmonomials][0] = consdata->linvars[j];
12284  monomialexps[nmonomials] = NULL;
12285  monomialcoefs[nmonomials] = consdata->lincoefs[j];
12286  monomialnvars[nmonomials] = 1;
12287  ++nmonomials;
12288  }
12289 
12290  for( j = 0; j < consdata->nquadvars; ++j )
12291  {
12292  if( consdata->quadvarterms[j].lincoef != 0.0 )
12293  {
12294  assert(nmonomials < monomialssize);
12295 
12296  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
12297 
12298  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
12299  monomialexps[nmonomials] = NULL;
12300  monomialcoefs[nmonomials] = consdata->quadvarterms[j].lincoef;
12301  monomialnvars[nmonomials] = 1;
12302  ++nmonomials;
12303  }
12304 
12305  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
12306  {
12307  assert(nmonomials < monomialssize);
12308 
12309  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
12310  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps[nmonomials], 1) ); /*lint !e866 */
12311 
12312  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
12313  monomialexps[nmonomials][0] = 2.0;
12314  monomialcoefs[nmonomials] = consdata->quadvarterms[j].sqrcoef;
12315  monomialnvars[nmonomials] = 1;
12316  ++nmonomials;
12317  }
12318  }
12319 
12320  for( j = 0; j < consdata->nbilinterms; ++j )
12321  {
12322  assert(nmonomials < monomialssize);
12323 
12324  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 2) ); /*lint !e866 */
12325 
12326  monomialvars[nmonomials][0] = consdata->bilinterms[j].var1;
12327  monomialvars[nmonomials][1] = consdata->bilinterms[j].var2;
12328  monomialexps[nmonomials] = NULL;
12329  monomialcoefs[nmonomials] = consdata->bilinterms[j].coef;
12330  monomialnvars[nmonomials] = 2;
12331  ++nmonomials;
12332  }
12333 
12334  SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, monomialexps, monomialcoefs, monomialnvars, nmonomials, TRUE) );
12335 
12336  for( j = 0; j < nmonomials; ++j )
12337  {
12338  SCIPfreeBufferArray(scip, &monomialvars[j]);
12339  SCIPfreeBufferArrayNull(scip, &monomialexps[j]);
12340  }
12341 
12342  SCIPfreeBufferArray(scip, &monomialvars);
12343  SCIPfreeBufferArray(scip, &monomialexps);
12344  SCIPfreeBufferArray(scip, &monomialcoefs);
12345  SCIPfreeBufferArray(scip, &monomialnvars);
12346  }
12347 
12348  /* print right hand side */
12349  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12350  {
12351  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
12352  }
12353  else if( !SCIPisInfinity(scip, consdata->rhs) )
12354  {
12355  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
12356  }
12357  else if( !SCIPisInfinity(scip, -consdata->lhs) )
12358  {
12359  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
12360  }
12361  else
12362  {
12363  /* should be ignored by parser */
12364  SCIPinfoMessage(scip, file, " [free]");
12365  }
12366 
12367  return SCIP_OKAY;
12368 }
12369 
12370 /** feasibility check method of constraint handler for integral solutions */
12371 static
12372 SCIP_DECL_CONSCHECK(consCheckQuadratic)
12373 { /*lint --e{715}*/
12374  SCIP_CONSHDLRDATA* conshdlrdata;
12375  SCIP_CONSDATA* consdata;
12376  SCIP_Real maxviol;
12377  int c;
12378  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
12379 
12380  assert(scip != NULL);
12381  assert(conss != NULL || nconss == 0);
12382  assert(result != NULL);
12383 
12384  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12385  assert(conshdlrdata != NULL);
12386 
12387  *result = SCIP_FEASIBLE;
12388 
12389  maxviol = 0.0;
12390  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
12392  for( c = 0; c < nconss; ++c )
12393  {
12394  assert(conss != NULL);
12395  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
12396 
12397  consdata = SCIPconsGetData(conss[c]);
12398  assert(consdata != NULL);
12399 
12400  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12401  {
12402  *result = SCIP_INFEASIBLE;
12403  if( printreason )
12404  {
12405  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
12406  SCIPinfoMessage(scip, NULL, ";\n");
12407  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
12408  {
12409  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
12410  }
12411  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12412  {
12413  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
12414  }
12415  }
12416  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible )
12417  return SCIP_OKAY;
12418  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
12419  maxviol = consdata->lhsviol + consdata->rhsviol;
12420 
12421  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
12422  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
12423  maypropfeasible = FALSE;
12424 
12425  if( maypropfeasible )
12426  {
12427  /* update information on linear variables that may be in- or decreased */
12428  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
12429  consdataFindUnlockedLinearVar(scip, consdata);
12430 
12431  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
12432  {
12433  /* check if there is a variable which may help to get the left hand side satisfied
12434  * if there is no such var, then we cannot get feasible */
12435  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
12436  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
12437  maypropfeasible = FALSE;
12438  }
12439  else
12440  {
12441  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
12442  /* check if there is a variable which may help to get the right hand side satisfied
12443  * if there is no such var, then we cannot get feasible */
12444  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
12445  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
12446  maypropfeasible = FALSE;
12447  }
12448  }
12449  }
12450  }
12451 
12452  if( *result == SCIP_INFEASIBLE && maypropfeasible )
12453  {
12454  SCIP_Bool success;
12455 
12456  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
12457 
12458  /* do not pass solution to NLP heuristic if we made it feasible this way */
12459  if( success )
12460  return SCIP_OKAY;
12461  }
12462 
12463  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL )
12464  {
12465  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
12466  }
12467 
12468  return SCIP_OKAY;
12469 }
12470 
12471 /** constraint copying method of constraint handler */
12472 static
12473 SCIP_DECL_CONSCOPY(consCopyQuadratic)
12475  SCIP_CONSDATA* consdata;
12476  SCIP_CONSDATA* targetconsdata;
12477  SCIP_VAR** linvars;
12478  SCIP_QUADVARTERM* quadvarterms;
12479  SCIP_BILINTERM* bilinterms;
12480  int i;
12481  int j;
12482  int k;
12483 
12484  assert(scip != NULL);
12485  assert(cons != NULL);
12486  assert(sourcescip != NULL);
12487  assert(sourceconshdlr != NULL);
12488  assert(sourcecons != NULL);
12489  assert(varmap != NULL);
12490  assert(valid != NULL);
12491 
12492  consdata = SCIPconsGetData(sourcecons);
12493  assert(consdata != NULL);
12494 
12495  linvars = NULL;
12496  quadvarterms = NULL;
12497  bilinterms = NULL;
12498 
12499  *valid = TRUE;
12500 
12501  if( consdata->nlinvars != 0 )
12502  {
12503  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
12504  for( i = 0; i < consdata->nlinvars; ++i )
12505  {
12506  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
12507  assert(!(*valid) || linvars[i] != NULL);
12508 
12509  /* we do not copy, if a variable is missing */
12510  if( !(*valid) )
12511  goto TERMINATE;
12512  }
12513  }
12514 
12515  if( consdata->nbilinterms != 0 )
12516  {
12517  SCIP_CALL( SCIPallocBufferArray(sourcescip, &bilinterms, consdata->nbilinterms) );
12518  }
12519 
12520  if( consdata->nquadvars != 0 )
12521  {
12522  SCIP_CALL( SCIPallocBufferArray(sourcescip, &quadvarterms, consdata->nquadvars) );
12523  for( i = 0; i < consdata->nquadvars; ++i )
12524  {
12525  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->quadvarterms[i].var, &quadvarterms[i].var, varmap, consmap, global, valid) );
12526  assert(!(*valid) || quadvarterms[i].var != NULL);
12527 
12528  /* we do not copy, if a variable is missing */
12529  if( !(*valid) )
12530  goto TERMINATE;
12531 
12532  quadvarterms[i].lincoef = consdata->quadvarterms[i].lincoef;
12533  quadvarterms[i].sqrcoef = consdata->quadvarterms[i].sqrcoef;
12534  quadvarterms[i].eventdata = NULL;
12535  quadvarterms[i].nadjbilin = consdata->quadvarterms[i].nadjbilin;
12536  quadvarterms[i].adjbilin = consdata->quadvarterms[i].adjbilin;
12537 
12538  assert(consdata->nbilinterms != 0 || consdata->quadvarterms[i].nadjbilin == 0);
12539 
12540  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
12541  {
12542  assert(bilinterms != NULL);
12543 
12544  k = consdata->quadvarterms[i].adjbilin[j];
12545  assert(consdata->bilinterms[k].var1 != NULL);
12546  assert(consdata->bilinterms[k].var2 != NULL);
12547  if( consdata->bilinterms[k].var1 == consdata->quadvarterms[i].var )
12548  {
12549  assert(consdata->bilinterms[k].var2 != consdata->quadvarterms[i].var);
12550  bilinterms[k].var1 = quadvarterms[i].var;
12551  }
12552  else
12553  {
12554  assert(consdata->bilinterms[k].var2 == consdata->quadvarterms[i].var);
12555  bilinterms[k].var2 = quadvarterms[i].var;
12556  }
12557  bilinterms[k].coef = consdata->bilinterms[k].coef;
12558  }
12559  }
12560  }
12561 
12562  assert(stickingatnode == FALSE);
12563  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name ? name : SCIPconsGetName(sourcecons),
12564  consdata->nlinvars, linvars, consdata->lincoefs,
12565  consdata->nquadvars, quadvarterms,
12566  consdata->nbilinterms, bilinterms,
12567  consdata->lhs, consdata->rhs,
12568  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12569 
12570  /* copy information on curvature */
12571  targetconsdata = SCIPconsGetData(*cons);
12572  targetconsdata->isconvex = consdata->isconvex;
12573  targetconsdata->isconcave = consdata->isconcave;
12574  targetconsdata->iscurvchecked = consdata->iscurvchecked;
12575 
12576  TERMINATE:
12577  SCIPfreeBufferArrayNull(sourcescip, &quadvarterms);
12578  SCIPfreeBufferArrayNull(sourcescip, &bilinterms);
12579  SCIPfreeBufferArrayNull(sourcescip, &linvars);
12580 
12581  return SCIP_OKAY;
12582 }
12583 
12584 /** constraint parsing method of constraint handler */
12585 static
12586 SCIP_DECL_CONSPARSE(consParseQuadratic)
12587 { /*lint --e{715}*/
12588  SCIP_VAR*** monomialvars;
12589  SCIP_Real** monomialexps;
12590  SCIP_Real* monomialcoefs;
12591  char* endptr;
12592  int* monomialnvars;
12593  int nmonomials;
12594 
12595  SCIP_Real lhs;
12596  SCIP_Real rhs;
12597 
12598  assert(scip != NULL);
12599  assert(success != NULL);
12600  assert(str != NULL);
12601  assert(name != NULL);
12602  assert(cons != NULL);
12603 
12604  /* set left and right hand side to their default values */
12605  lhs = -SCIPinfinity(scip);
12606  rhs = SCIPinfinity(scip);
12607 
12608  (*success) = FALSE;
12609 
12610  /* return of string empty */
12611  if( !*str )
12612  return SCIP_OKAY;
12613 
12614  /* ignore whitespace */
12615  while( isspace((unsigned char)*str) )
12616  ++str;
12617 
12618  /* check for left hand side */
12619  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
12620  {
12621  /* there is a number coming, maybe it is a left-hand-side */
12622  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
12623  {
12624  SCIPerrorMessage("error parsing number from <%s>\n", str);
12625  return SCIP_OKAY;
12626  }
12627 
12628  /* ignore whitespace */
12629  while( isspace((unsigned char)*endptr) )
12630  ++endptr;
12631 
12632  if( endptr[0] != '<' || endptr[1] != '=' )
12633  {
12634  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
12635  lhs = -SCIPinfinity(scip);
12636  }
12637  else
12638  {
12639  /* it was indeed a left-hand-side, so continue parsing after it */
12640  str = endptr + 2;
12641 
12642  /* ignore whitespace */
12643  while( isspace((unsigned char)*str) )
12644  ++str;
12645  }
12646  }
12647 
12648  SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, &endptr, success) );
12649 
12650  if( *success )
12651  {
12652  /* check for right hand side */
12653  str = endptr;
12654 
12655  /* ignore whitespace */
12656  while( isspace((unsigned char)*str) )
12657  ++str;
12658 
12659  if( *str && str[0] == '<' && str[1] == '=' )
12660  {
12661  /* we seem to get a right-hand-side */
12662  str += 2;
12663 
12664  if( !SCIPstrToRealValue(str, &rhs, &endptr) )
12665  {
12666  SCIPerrorMessage("error parsing right-hand-side from %s\n", str);
12667  *success = FALSE;
12668  }
12669  }
12670  else if( *str && str[0] == '>' && str[1] == '=' )
12671  {
12672  /* we seem to get a left-hand-side */
12673  str += 2;
12674 
12675  /* we should not have a left-hand-side already */
12676  assert(SCIPisInfinity(scip, -lhs));
12677 
12678  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
12679  {
12680  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
12681  *success = FALSE;
12682  }
12683  }
12684  else if( *str && str[0] == '=' && str[1] == '=' )
12685  {
12686  /* we seem to get a left- and right-hand-side */
12687  str += 2;
12688 
12689  /* we should not have a left-hand-side already */
12690  assert(SCIPisInfinity(scip, -lhs));
12691 
12692  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
12693  {
12694  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
12695  *success = FALSE;
12696  }
12697  else
12698  {
12699  rhs = lhs;
12700  }
12701  }
12702  }
12703 
12704  if( *success )
12705  {
12706  int i;
12707 
12708  /* setup constraint */
12709  assert(stickingatnode == FALSE);
12710  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL,
12711  0, NULL, NULL, NULL, lhs, rhs,
12712  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12713 
12714  for( i = 0; i < nmonomials; ++i )
12715  {
12716  if( monomialnvars[i] == 0 )
12717  {
12718  /* constant monomial */
12719  SCIPaddConstantQuadratic(scip, *cons, monomialcoefs[i]);
12720  }
12721  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 1.0 )
12722  {
12723  /* linear monomial */
12724  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, *cons, monomialvars[i][0], monomialcoefs[i]) );
12725  }
12726  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 2.0 )
12727  {
12728  /* square monomial */
12729  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, monomialvars[i][0], 0.0, monomialcoefs[i]) );
12730  }
12731  else if( monomialnvars[i] == 2 && monomialexps[i][0] == 1.0 && monomialexps[i][1] == 1.0 )
12732  {
12733  /* bilinear term */
12734  SCIP_VAR* var1;
12735  SCIP_VAR* var2;
12736  int pos;
12737 
12738  var1 = monomialvars[i][0];
12739  var2 = monomialvars[i][1];
12740  if( var1 == var2 )
12741  {
12742  /* actually a square term */
12743  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, monomialcoefs[i]) );
12744  }
12745  else
12746  {
12747  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var1, &pos) );
12748  if( pos == -1 )
12749  {
12750  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, 0.0) );
12751  }
12752 
12753  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var2, &pos) );
12754  if( pos == -1 )
12755  {
12756  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var2, 0.0, 0.0) );
12757  }
12758  }
12759 
12760  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, *cons, var1, var2, monomialcoefs[i]) );
12761  }
12762  else
12763  {
12764  SCIPerrorMessage("polynomial in quadratic constraint does not have degree at most 2\n");
12765  *success = FALSE;
12766  SCIP_CALL( SCIPreleaseCons(scip, cons) );
12767  break;
12768  }
12769  }
12770  }
12771 
12772  SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
12773 
12774  return SCIP_OKAY;
12775 }
12776 
12777 /** constraint method of constraint handler which returns the variables (if possible) */
12778 static
12779 SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
12780 { /*lint --e{715}*/
12781  SCIP_CONSDATA* consdata;
12782 
12783  assert(cons != NULL);
12784  assert(success != NULL);
12785 
12786  consdata = SCIPconsGetData(cons);
12787  assert(consdata != NULL);
12788 
12789  if( varssize < consdata->nlinvars + consdata->nquadvars )
12790  (*success) = FALSE;
12791  else
12792  {
12793  int i;
12794 
12795  assert(vars != NULL);
12796 
12797  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
12798 
12799  for( i = 0; i < consdata->nquadvars; ++i )
12800  vars[consdata->nlinvars+i] = consdata->quadvarterms[i].var;
12801 
12802  (*success) = TRUE;
12803  }
12804 
12805  return SCIP_OKAY;
12806 }
12807 
12808 /** constraint method of constraint handler which returns the number of variables (if possible) */
12809 static
12810 SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
12811 { /*lint --e{715}*/
12812  SCIP_CONSDATA* consdata;
12813 
12814  assert(cons != NULL);
12815  assert(success != NULL);
12816 
12817  consdata = SCIPconsGetData(cons);
12818  assert(consdata != NULL);
12819 
12820  (*nvars) = consdata->nlinvars + consdata->nquadvars;
12821  (*success) = TRUE;
12822 
12823  return SCIP_OKAY;
12824 }
12825 
12826 
12827 /*
12828  * constraint specific interface methods
12829  */
12830 
12831 /** creates the handler for quadratic constraints and includes it in SCIP */
12833  SCIP* scip /**< SCIP data structure */
12834  )
12835 {
12836  SCIP_CONSHDLRDATA* conshdlrdata;
12837  SCIP_CONSHDLR* conshdlr;
12838 
12839  /* create quadratic constraint handler data */
12840  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
12841  BMSclearMemory(conshdlrdata);
12842 
12843  /* include constraint handler */
12846  consEnfolpQuadratic, consEnfopsQuadratic, consCheckQuadratic, consLockQuadratic,
12847  conshdlrdata) );
12848  assert(conshdlr != NULL);
12849 
12850 
12851  /* set non-fundamental callbacks via specific setter functions */
12852  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyQuadratic, consCopyQuadratic) );
12853  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteQuadratic) );
12854  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableQuadratic) );
12855  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableQuadratic) );
12856  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitQuadratic) );
12857  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreQuadratic) );
12858  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolQuadratic) );
12859  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeQuadratic) );
12860  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsQuadratic) );
12861  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsQuadratic) );
12862  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitQuadratic) );
12863  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolQuadratic) );
12864  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpQuadratic) );
12865  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseQuadratic) );
12866  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolQuadratic, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
12867  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintQuadratic) );
12868  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropQuadratic, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
12870  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpQuadratic, consSepasolQuadratic, CONSHDLR_SEPAFREQ,
12872  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransQuadratic) );
12873 
12874  /* add quadratic constraint handler parameters */
12875  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/replacebinaryprod",
12876  "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)",
12877  &conshdlrdata->replacebinaryprodlength, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12878 
12879  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/empathy4and",
12880  "empathy level for using the AND constraint handler: 0 always avoid using AND; 1 use AND sometimes; 2 use AND as often as possible",
12881  &conshdlrdata->empathy4and, FALSE, 0, 0, 2, NULL, NULL) );
12882 
12883  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreforminitial",
12884  "whether to make non-varbound linear constraints added due to replacing products with binary variables initial",
12885  &conshdlrdata->binreforminitial, TRUE, FALSE, NULL, NULL) );
12886 
12887  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/binreformmaxcoef",
12888  "limit (as factor on 1/feastol) on coefficients and coef. range in linear constraints created when replacing products with binary variables",
12889  &conshdlrdata->binreformmaxcoef, TRUE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
12890 
12891  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacysepa",
12892  "minimal efficacy for a cut to be added to the LP during separation; overwrites separating/efficacy",
12893  &conshdlrdata->mincutefficacysepa, TRUE, 0.0001, 0.0, SCIPinfinity(scip), NULL, NULL) );
12894 
12895  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacyenfofac",
12896  "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)",
12897  &conshdlrdata->mincutefficacyenfofac, TRUE, 2.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12898 
12899  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/scaling",
12900  "whether scaling of infeasibility is 'o'ff, by sup-norm of function 'g'radient, or by left/right hand 's'ide",
12901  &conshdlrdata->scaling, TRUE, 'o', "ogs", NULL, NULL) );
12902 
12903  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
12904  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
12905  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
12906 
12907  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12908  "whether linearizations of convex quadratic constraints should be added to cutpool in a solution found by some heuristic",
12909  &conshdlrdata->linearizeheursol, TRUE, TRUE, NULL, NULL) );
12910 
12911  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkcurvature",
12912  "whether multivariate quadratic functions should be checked for convexity/concavity",
12913  &conshdlrdata->checkcurvature, FALSE, TRUE, NULL, NULL) );
12914 
12915  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkfactorable",
12916  "whether constraint functions should be checked to be factorable",
12917  &conshdlrdata->checkfactorable, TRUE, TRUE, NULL, NULL) );
12918 
12919  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
12920  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
12921  &conshdlrdata->linfeasshift, TRUE, TRUE, NULL, NULL) );
12922 
12923  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/disaggregate",
12924  "whether to disaggregate quadratic parts that decompose into a sum of non-overlapping quadratic terms",
12925  &conshdlrdata->disaggregate, TRUE, FALSE, NULL, NULL) );
12926 
12927  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12928  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve",
12929  &conshdlrdata->maxproprounds, TRUE, 1, 0, INT_MAX, NULL, NULL) );
12930 
12931  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproproundspresolve",
12932  "limit on number of propagation rounds for a single constraint within one round of SCIP presolve",
12933  &conshdlrdata->maxproproundspresolve, TRUE, 10, 0, INT_MAX, NULL, NULL) );
12934 
12935  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/enfolplimit",
12936  "maximum number of enforcement rounds before declaring the LP relaxation infeasible (-1: no limit); WARNING: changing this parameter might lead to incorrect results!",
12937  &conshdlrdata->enfolplimit, TRUE, -1, -1, INT_MAX, NULL, NULL) );
12938 
12939  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
12940  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
12941  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
12942 
12943  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
12944  "are cuts added during enforcement removable from the LP in the same node?",
12945  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
12946 
12947  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/gaugecuts",
12948  "should convex quadratics generated strong cuts via gauge function?",
12949  &conshdlrdata->gaugecuts, FALSE, TRUE, NULL, NULL) );
12950 
12951  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/interiorcomputation",
12952  "how the interior point should be computed: 'a'ny point per constraint, 'm'ost interior per constraint",
12953  &conshdlrdata->interiorcomputation, TRUE, 'a', "am", NULL, NULL) );
12954 
12955  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchscoring",
12956  "which score to give branching candidates: convexification 'g'ap, constraint 'v'iolation, 'c'entrality of variable value in domain",
12957  &conshdlrdata->branchscoring, TRUE, 'g', "cgv", NULL, NULL) );
12958 
12959  conshdlrdata->eventhdlr = NULL;
12960  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr),CONSHDLR_NAME"_boundchange", "signals a bound change to a quadratic constraint",
12961  processVarEvent, NULL) );
12962  assert(conshdlrdata->eventhdlr != NULL);
12963 
12964  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
12965  processNewSolutionEvent, NULL) );
12966 
12967  /* include the quadratic constraint upgrade in the nonlinear constraint handler */
12969 
12970  return SCIP_OKAY;
12971 }
12972 
12973 /** includes a quadratic constraint update method into the quadratic constraint handler */
12975  SCIP* scip, /**< SCIP data structure */
12976  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
12977  int priority, /**< priority of upgrading method */
12978  SCIP_Bool active, /**< should the upgrading method be active by default? */
12979  const char* conshdlrname /**< name of the constraint handler */
12980  )
12981 {
12982  SCIP_CONSHDLR* conshdlr;
12983  SCIP_CONSHDLRDATA* conshdlrdata;
12984  SCIP_QUADCONSUPGRADE* quadconsupgrade;
12985  char paramname[SCIP_MAXSTRLEN];
12986  char paramdesc[SCIP_MAXSTRLEN];
12987  int i;
12988 
12989  assert(quadconsupgd != NULL);
12990  assert(conshdlrname != NULL );
12991 
12992  /* find the quadratic constraint handler */
12993  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12994  if( conshdlr == NULL )
12995  {
12996  SCIPerrorMessage("quadratic constraint handler not found\n");
12997  return SCIP_PLUGINNOTFOUND;
12998  }
12999 
13000  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13001  assert(conshdlrdata != NULL);
13002 
13003  if( !conshdlrdataHasUpgrade(scip, conshdlrdata, quadconsupgd, conshdlrname) )
13004  {
13005  /* create a quadratic constraint upgrade data object */
13006  SCIP_CALL( SCIPallocMemory(scip, &quadconsupgrade) );
13007  quadconsupgrade->quadconsupgd = quadconsupgd;
13008  quadconsupgrade->priority = priority;
13009  quadconsupgrade->active = active;
13010 
13011  /* insert quadratic constraint upgrade method into constraint handler data */
13012  assert(conshdlrdata->nquadconsupgrades <= conshdlrdata->quadconsupgradessize);
13013  if( conshdlrdata->nquadconsupgrades+1 > conshdlrdata->quadconsupgradessize )
13014  {
13015  int newsize;
13016 
13017  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nquadconsupgrades+1);
13018  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->quadconsupgrades, newsize) );
13019  conshdlrdata->quadconsupgradessize = newsize;
13020  }
13021  assert(conshdlrdata->nquadconsupgrades+1 <= conshdlrdata->quadconsupgradessize);
13022 
13023  for( i = conshdlrdata->nquadconsupgrades; i > 0 && conshdlrdata->quadconsupgrades[i-1]->priority < quadconsupgrade->priority; --i )
13024  conshdlrdata->quadconsupgrades[i] = conshdlrdata->quadconsupgrades[i-1];
13025  assert(0 <= i && i <= conshdlrdata->nquadconsupgrades);
13026  conshdlrdata->quadconsupgrades[i] = quadconsupgrade;
13027  conshdlrdata->nquadconsupgrades++;
13028 
13029  /* adds parameter to turn on and off the upgrading step */
13030  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
13031  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable quadratic upgrading for constraint handler <%s>", conshdlrname);
13033  paramname, paramdesc,
13034  &quadconsupgrade->active, FALSE, active, NULL, NULL) );
13035  }
13036 
13037  return SCIP_OKAY;
13038 }
13039 
13040 /** Creates and captures a quadratic constraint.
13041  *
13042  * The constraint should be given in the form
13043  * \f[
13044  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
13045  * \f]
13046  * where \f$x_i = y_j = z_k\f$ is possible.
13047  *
13048  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13049  */
13051  SCIP* scip, /**< SCIP data structure */
13052  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13053  const char* name, /**< name of constraint */
13054  int nlinvars, /**< number of linear terms (n) */
13055  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13056  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13057  int nquadterms, /**< number of quadratic terms (m) */
13058  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
13059  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
13060  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
13061  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
13062  SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
13063  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13064  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13065  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13066  * Usually set to TRUE. */
13067  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13068  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13069  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13070  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13071  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13072  * Usually set to TRUE. */
13073  SCIP_Bool local, /**< is constraint only valid locally?
13074  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13075  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13076  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13077  * adds coefficients to this constraint. */
13078  SCIP_Bool dynamic, /**< is constraint subject to aging?
13079  * Usually set to FALSE. Set to TRUE for own cuts which
13080  * are separated as constraints. */
13081  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
13082  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13083  )
13084 {
13085  SCIP_CONSHDLR* conshdlr;
13086  SCIP_CONSDATA* consdata;
13087  SCIP_HASHMAP* quadvaridxs;
13088  SCIP_Real sqrcoef;
13089  int i;
13090  int var1pos;
13091  int var2pos;
13092 
13093  int nbilinterms;
13094 
13095  assert(modifiable == FALSE); /* we do not support column generation */
13096 
13097  /* find the quadratic constraint handler */
13098  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13099  if( conshdlr == NULL )
13100  {
13101  SCIPerrorMessage("quadratic constraint handler not found\n");
13102  return SCIP_PLUGINNOTFOUND;
13103  }
13104 
13105  /* create constraint data and constraint */
13106  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
13107 
13108  consdata->lhs = lhs;
13109  consdata->rhs = rhs;
13110 
13111  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13112  local, modifiable, dynamic, removable, FALSE) );
13113 
13114  /* add quadratic variables and remember their indices */
13115  SCIP_CALL( SCIPhashmapCreate(&quadvaridxs, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * nquadterms)) );
13116  nbilinterms = 0;
13117  for( i = 0; i < nquadterms; ++i )
13118  {
13119  if( SCIPisZero(scip, quadcoefs[i]) )
13120  continue;
13121 
13122  /* if it is actually a square term, remember it's coefficient */
13123  if( quadvars1[i] == quadvars2[i] )
13124  sqrcoef = quadcoefs[i];
13125  else
13126  sqrcoef = 0.0;
13127 
13128  /* add quadvars1[i], if not in there already */
13129  if( !SCIPhashmapExists(quadvaridxs, quadvars1[i]) )
13130  {
13131  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars1[i], 0.0, sqrcoef) );
13132  assert(consdata->nquadvars >= 0);
13133  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars1[i]);
13134 
13135  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars1[i], (void*)(size_t)(consdata->nquadvars-1)) );
13136  }
13137  else if( !SCIPisZero(scip, sqrcoef) )
13138  {
13139  /* if it's there already, but we got a square coefficient, add it to the previous one */
13140  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]);
13141  assert(consdata->quadvarterms[var1pos].var == quadvars1[i]);
13142  consdata->quadvarterms[var1pos].sqrcoef += sqrcoef;
13143  }
13144 
13145  if( quadvars1[i] == quadvars2[i] )
13146  continue;
13147 
13148  /* add quadvars2[i], if not in there already */
13149  if( !SCIPhashmapExists(quadvaridxs, quadvars2[i]) )
13150  {
13151  assert(sqrcoef == 0.0);
13152  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars2[i], 0.0, 0.0) );
13153  assert(consdata->nquadvars >= 0);
13154  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars2[i]);
13155 
13156  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars2[i], (void*)(size_t)(consdata->nquadvars-1)) );
13157  }
13158 
13159  ++nbilinterms;
13160  }
13161 
13162  /* add bilinear terms, if we saw any */
13163  if( nbilinterms > 0 )
13164  {
13165  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, nbilinterms) );
13166  for( i = 0; i < nquadterms; ++i )
13167  {
13168  if( SCIPisZero(scip, quadcoefs[i]) )
13169  continue;
13170 
13171  /* square terms have been taken care of already */
13172  if( quadvars1[i] == quadvars2[i] )
13173  continue;
13174 
13175  assert(SCIPhashmapExists(quadvaridxs, quadvars1[i]));
13176  assert(SCIPhashmapExists(quadvaridxs, quadvars2[i]));
13177 
13178  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]);
13179  var2pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars2[i]);
13180 
13181  SCIP_CALL( addBilinearTerm(scip, *cons, var1pos, var2pos, quadcoefs[i]) );
13182  }
13183  }
13184 
13185  /* add linear variables */
13186  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
13187  for( i = 0; i < nlinvars; ++i )
13188  {
13189  if( SCIPisZero(scip, lincoefs[i]) )
13190  continue;
13191 
13192  /* if it's a linear coefficient for a quadratic variable, add it there, otherwise add as linear variable */
13193  if( SCIPhashmapExists(quadvaridxs, linvars[i]) )
13194  {
13195  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, linvars[i]);
13196  assert(consdata->quadvarterms[var1pos].var == linvars[i]);
13197  consdata->quadvarterms[var1pos].lincoef += lincoefs[i];
13198  }
13199  else
13200  {
13201  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) );
13202  }
13203  }
13204 
13205  SCIPhashmapFree(&quadvaridxs);
13206 
13207  SCIPdebugMessage("created quadratic constraint ");
13208  SCIPdebugPrintCons(scip, *cons, NULL);
13209 
13210  return SCIP_OKAY;
13211 }
13212 
13213 /** creates and captures a quadratic constraint with all its
13214  * flags set to their default values.
13215  *
13216  * The constraint should be given in the form
13217  * \f[
13218  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
13219  * \f]
13220  * where \f$x_i = y_j = z_k\f$ is possible.
13221  *
13222  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13223  */
13225  SCIP* scip, /**< SCIP data structure */
13226  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13227  const char* name, /**< name of constraint */
13228  int nlinvars, /**< number of linear terms (n) */
13229  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13230  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13231  int nquadterms, /**< number of quadratic terms (m) */
13232  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
13233  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
13234  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
13235  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
13236  SCIP_Real rhs /**< right hand side of quadratic equation (u) */
13237  )
13238 {
13239  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, nlinvars, linvars, lincoefs,
13240  nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
13241  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
13242 
13243  return SCIP_OKAY;
13244 }
13245 
13246 /** Creates and captures a quadratic constraint.
13247  *
13248  * The constraint should be given in the form
13249  * \f[
13250  * \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.
13251  * \f]
13252  *
13253  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13254  */
13256  SCIP* scip, /**< SCIP data structure */
13257  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13258  const char* name, /**< name of constraint */
13259  int nlinvars, /**< number of linear terms (n) */
13260  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13261  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13262  int nquadvarterms, /**< number of quadratic terms (m) */
13263  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
13264  int nbilinterms, /**< number of bilinear terms (p) */
13265  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
13266  SCIP_Real lhs, /**< constraint left hand side (ell) */
13267  SCIP_Real rhs, /**< constraint right hand side (u) */
13268  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
13269  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
13270  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
13271  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
13272  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
13273  SCIP_Bool local, /**< is constraint only valid locally? */
13274  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
13275  SCIP_Bool dynamic, /**< is constraint dynamic? */
13276  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
13277  )
13278 {
13279  SCIP_CONSHDLR* conshdlr;
13280  SCIP_CONSDATA* consdata;
13281 
13282  assert(modifiable == FALSE); /* we do not support column generation */
13283  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
13284  assert(nquadvarterms == 0 || quadvarterms != NULL);
13285  assert(nbilinterms == 0 || bilinterms != NULL);
13286 
13287  /* find the quadratic constraint handler */
13288  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13289  if( conshdlr == NULL )
13290  {
13291  SCIPerrorMessage("quadratic constraint handler not found\n");
13292  return SCIP_PLUGINNOTFOUND;
13293  }
13294 
13295  /* create constraint data */
13296  SCIP_CALL( consdataCreate(scip, &consdata, lhs, rhs,
13297  nlinvars, linvars, lincoefs, nquadvarterms, quadvarterms, nbilinterms, bilinterms,
13298  TRUE) );
13299 
13300  /* create constraint */
13301  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13302  local, modifiable, dynamic, removable, FALSE) );
13303 
13304  return SCIP_OKAY;
13305 }
13306 
13307 /** creates and captures a quadratic constraint in its most basic version, i.e.,
13308  * all constraint flags are set to their default values.
13309  *
13310  * The constraint should be given in the form
13311  * \f[
13312  * \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.
13313  * \f]
13314  *
13315  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13316  */
13318  SCIP* scip, /**< SCIP data structure */
13319  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13320  const char* name, /**< name of constraint */
13321  int nlinvars, /**< number of linear terms (n) */
13322  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13323  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13324  int nquadvarterms, /**< number of quadratic terms (m) */
13325  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
13326  int nbilinterms, /**< number of bilinear terms (p) */
13327  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
13328  SCIP_Real lhs, /**< constraint left hand side (ell) */
13329  SCIP_Real rhs /**< constraint right hand side (u) */
13330  )
13331 {
13332  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name, nlinvars, linvars, lincoefs,
13333  nquadvarterms, quadvarterms, nbilinterms, bilinterms, lhs, rhs,
13334  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
13335 
13336  return SCIP_OKAY;
13337 }
13338 
13339 
13340 /** Adds a constant to the constraint function, that is, subtracts a constant from both sides */
13342  SCIP* scip, /**< SCIP data structure */
13343  SCIP_CONS* cons, /**< constraint */
13344  SCIP_Real constant /**< constant to subtract from both sides */
13345  )
13346 {
13347  SCIP_CONSDATA* consdata;
13348 
13349  assert(scip != NULL);
13350  assert(cons != NULL);
13351  assert(!SCIPisInfinity(scip, REALABS(constant)));
13352 
13353  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13354  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13355  {
13356  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13357  SCIPABORT();
13358  }
13359 
13360  consdata = SCIPconsGetData(cons);
13361  assert(consdata != NULL);
13362  assert(consdata->lhs <= consdata->rhs);
13363 
13364  if( !SCIPisInfinity(scip, -consdata->lhs) )
13365  consdata->lhs -= constant;
13366  if( !SCIPisInfinity(scip, consdata->rhs) )
13367  consdata->rhs -= constant;
13368 
13369  if( consdata->lhs > consdata->rhs )
13370  {
13371  assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
13372  consdata->lhs = consdata->rhs;
13373  }
13374 }
13375 
13376 /** Adds a linear variable with coefficient to a quadratic constraint. */
13378  SCIP* scip, /**< SCIP data structure */
13379  SCIP_CONS* cons, /**< constraint */
13380  SCIP_VAR* var, /**< variable */
13381  SCIP_Real coef /**< coefficient of variable */
13382  )
13383 {
13384  assert(scip != NULL);
13385  assert(cons != NULL);
13386  assert(var != NULL);
13387  assert(!SCIPisInfinity(scip, REALABS(coef)));
13388 
13389  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13390  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13391  {
13392  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13393  return SCIP_INVALIDCALL;
13394  }
13395 
13396  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
13397 
13398  return SCIP_OKAY;
13399 }
13400 
13401 /** Adds a quadratic variable with linear and square coefficient to a quadratic constraint. */
13403  SCIP* scip, /**< SCIP data structure */
13404  SCIP_CONS* cons, /**< constraint */
13405  SCIP_VAR* var, /**< variable */
13406  SCIP_Real lincoef, /**< linear coefficient of variable */
13407  SCIP_Real sqrcoef /**< square coefficient of variable */
13408  )
13409 {
13410  assert(scip != NULL);
13411  assert(cons != NULL);
13412  assert(var != NULL);
13413  assert(!SCIPisInfinity(scip, REALABS(lincoef)));
13414  assert(!SCIPisInfinity(scip, REALABS(sqrcoef)));
13415 
13416  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13417  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13418  {
13419  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13420  return SCIP_INVALIDCALL;
13421  }
13422 
13423  SCIP_CALL( addQuadVarTerm(scip, cons, var, lincoef, sqrcoef) );
13424 
13425  return SCIP_OKAY;
13426 }
13427 
13428 /** Adds a linear coefficient for a quadratic variable.
13429  *
13430  * Variable will be added with square coefficient 0.0 if not existing yet.
13431  */
13433  SCIP* scip, /**< SCIP data structure */
13434  SCIP_CONS* cons, /**< constraint */
13435  SCIP_VAR* var, /**< variable */
13436  SCIP_Real coef /**< value to add to linear coefficient of variable */
13437  )
13438 {
13439  SCIP_CONSDATA* consdata;
13440  int pos;
13441 
13442  assert(scip != NULL);
13443  assert(cons != NULL);
13444  assert(var != NULL);
13445  assert(!SCIPisInfinity(scip, REALABS(coef)));
13446 
13447  if( SCIPisZero(scip, coef) )
13448  return SCIP_OKAY;
13449 
13450  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13451  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13452  {
13453  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13454  return SCIP_INVALIDCALL;
13455  }
13456 
13457  consdata = SCIPconsGetData(cons);
13458  assert(consdata != NULL);
13459 
13460  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
13461  if( pos < 0 )
13462  {
13463  SCIP_CALL( addQuadVarTerm(scip, cons, var, coef, 0.0) );
13464  return SCIP_OKAY;
13465  }
13466  assert(pos < consdata->nquadvars);
13467  assert(consdata->quadvarterms[pos].var == var);
13468 
13469  consdata->quadvarterms[pos].lincoef += coef;
13470 
13471  /* update flags and invalid activities */
13472  consdata->ispropagated = FALSE;
13473  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].lincoef);
13474 
13475  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
13476  consdata->activity = SCIP_INVALID;
13477 
13478  return SCIP_OKAY;
13479 }
13480 
13481 /** Adds a square coefficient for a quadratic variable.
13482  *
13483  * Variable will be added with linear coefficient 0.0 if not existing yet.
13484  */
13486  SCIP* scip, /**< SCIP data structure */
13487  SCIP_CONS* cons, /**< constraint */
13488  SCIP_VAR* var, /**< variable */
13489  SCIP_Real coef /**< value to add to square coefficient of variable */
13490  )
13491 {
13492  SCIP_CONSDATA* consdata;
13493  int pos;
13494 
13495  assert(scip != NULL);
13496  assert(cons != NULL);
13497  assert(var != NULL);
13498  assert(!SCIPisInfinity(scip, REALABS(coef)));
13499 
13500  if( SCIPisZero(scip, coef) )
13501  return SCIP_OKAY;
13502 
13503  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13504  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13505  {
13506  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13507  return SCIP_INVALIDCALL;
13508  }
13509 
13510  consdata = SCIPconsGetData(cons);
13511  assert(consdata != NULL);
13512 
13513  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
13514  if( pos < 0 )
13515  {
13516  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
13517  return SCIP_OKAY;
13518  }
13519  assert(pos < consdata->nquadvars);
13520  assert(consdata->quadvarterms[pos].var == var);
13521 
13522  consdata->quadvarterms[pos].sqrcoef += coef;
13523 
13524  /* update flags and invalid activities */
13525  consdata->isconvex = FALSE;
13526  consdata->isconcave = FALSE;
13527  consdata->iscurvchecked = FALSE;
13528  consdata->ispropagated = FALSE;
13529  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].sqrcoef);
13530 
13531  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
13532  consdata->activity = SCIP_INVALID;
13533 
13534  return SCIP_OKAY;
13535 }
13536 
13537 /** Adds a bilinear term to a quadratic constraint.
13538  *
13539  * Variables will be added with linear and square coefficient 0.0 if not existing yet.
13540  * If variables are equal, only the square coefficient of the variable is updated.
13541  */
13543  SCIP* scip, /**< SCIP data structure */
13544  SCIP_CONS* cons, /**< constraint */
13545  SCIP_VAR* var1, /**< first variable */
13546  SCIP_VAR* var2, /**< second variable */
13547  SCIP_Real coef /**< coefficient of bilinear term */
13548  )
13549 {
13550  SCIP_CONSDATA* consdata;
13551  int var1pos;
13552  int var2pos;
13553 
13554  assert(scip != NULL);
13555  assert(cons != NULL);
13556  assert(var1 != NULL);
13557  assert(var2 != NULL);
13558  assert(!SCIPisInfinity(scip, REALABS(coef)));
13559 
13560  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13561  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13562  {
13563  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13564  return SCIP_INVALIDCALL;
13565  }
13566 
13567  if( var1 == var2 )
13568  {
13569  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, cons, var1, coef) );
13570  return SCIP_OKAY;
13571  }
13572 
13573  consdata = SCIPconsGetData(cons);
13574  assert(consdata != NULL);
13575 
13576  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
13577  if( var1pos < 0 )
13578  {
13579  SCIP_CALL( addQuadVarTerm(scip, cons, var1, 0.0, 0.0) );
13580  var1pos = consdata->nquadvars-1;
13581  }
13582 
13583  if( !consdata->quadvarssorted )
13584  {
13585  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
13586  /* sorting may change the position of var1 */
13587  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
13588  assert(var1pos >= 0);
13589  }
13590 
13591  assert(consdata->quadvarssorted);
13592  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var2, &var2pos) );
13593  if( var2pos < 0 )
13594  {
13595  SCIP_CALL( addQuadVarTerm(scip, cons, var2, 0.0, 0.0) );
13596  var2pos = consdata->nquadvars-1;
13597  }
13598 
13599  assert(consdata->quadvarterms[var1pos].var == var1);
13600  assert(consdata->quadvarterms[var2pos].var == var2);
13601 
13602  SCIP_CALL( addBilinearTerm(scip, cons, var1pos, var2pos, coef) );
13603 
13604  return SCIP_OKAY;
13605 }
13606 
13607 /** Gets the quadratic constraint as a nonlinear row representation. */
13609  SCIP* scip, /**< SCIP data structure */
13610  SCIP_CONS* cons, /**< constraint */
13611  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
13612  )
13613 {
13614  SCIP_CONSDATA* consdata;
13615 
13616  assert(cons != NULL);
13617  assert(nlrow != NULL);
13618 
13619  consdata = SCIPconsGetData(cons);
13620  assert(consdata != NULL);
13621 
13622  if( consdata->nlrow == NULL )
13623  {
13624  SCIP_CALL( createNlRow(scip, cons) );
13625  }
13626  assert(consdata->nlrow != NULL);
13627  *nlrow = consdata->nlrow;
13628 
13629  return SCIP_OKAY;
13630 }
13631 
13632 /** Gets the number of variables in the linear term of a quadratic constraint. */
13634  SCIP* scip, /**< SCIP data structure */
13635  SCIP_CONS* cons /**< constraint */
13636  )
13637 {
13638  assert(cons != NULL);
13639  assert(SCIPconsGetData(cons) != NULL);
13640 
13641  return SCIPconsGetData(cons)->nlinvars;
13642 }
13643 
13644 /** Gets the variables in the linear part of a quadratic constraint.
13645  * Length is given by SCIPgetNLinearVarsQuadratic.
13646  */
13648  SCIP* scip, /**< SCIP data structure */
13649  SCIP_CONS* cons /**< constraint */
13650  )
13651 {
13652  assert(cons != NULL);
13653  assert(SCIPconsGetData(cons) != NULL);
13654 
13655  return SCIPconsGetData(cons)->linvars;
13656 }
13657 
13658 /** Gets the coefficients in the linear part of a quadratic constraint.
13659  * Length is given by SCIPgetNLinearVarsQuadratic.
13660  */
13662  SCIP* scip, /**< SCIP data structure */
13663  SCIP_CONS* cons /**< constraint */
13664  )
13665 {
13666  assert(cons != NULL);
13667  assert(SCIPconsGetData(cons) != NULL);
13668 
13669  return SCIPconsGetData(cons)->lincoefs;
13670 }
13671 
13672 /** Gets the number of quadratic variable terms of a quadratic constraint.
13673  */
13675  SCIP* scip, /**< SCIP data structure */
13676  SCIP_CONS* cons /**< constraint */
13677  )
13678 {
13679  assert(cons != NULL);
13680  assert(SCIPconsGetData(cons) != NULL);
13681 
13682  return SCIPconsGetData(cons)->nquadvars;
13683 }
13684 
13685 /** Gets the quadratic variable terms of a quadratic constraint.
13686  * Length is given by SCIPgetNQuadVarTermsQuadratic.
13687  */
13689  SCIP* scip, /**< SCIP data structure */
13690  SCIP_CONS* cons /**< constraint */
13691  )
13692 {
13693  assert(cons != NULL);
13694  assert(SCIPconsGetData(cons) != NULL);
13695 
13696  return SCIPconsGetData(cons)->quadvarterms;
13697 }
13698 
13699 /** Ensures that quadratic variable terms are sorted. */
13701  SCIP* scip, /**< SCIP data structure */
13702  SCIP_CONS* cons /**< constraint */
13703  )
13704 {
13705  assert(cons != NULL);
13706  assert(SCIPconsGetData(cons) != NULL);
13707 
13709 
13710  return SCIP_OKAY;
13711 }
13712 
13713 /** Finds the position of a quadratic variable term for a given variable.
13714  *
13715  * @note If the quadratic variable terms have not been sorted before, then a search may reorder the current order of the terms.
13716  */
13718  SCIP* scip, /**< SCIP data structure */
13719  SCIP_CONS* cons, /**< constraint */
13720  SCIP_VAR* var, /**< variable to search for */
13721  int* pos /**< buffer to store position of quadvarterm for var, or -1 if not found */
13722  )
13723 {
13724  assert(cons != NULL);
13725  assert(SCIPconsGetData(cons) != NULL);
13726  assert(var != NULL);
13727  assert(pos != NULL);
13728 
13729  SCIP_CALL( consdataFindQuadVarTerm(scip, SCIPconsGetData(cons), var, pos) );
13730 
13731  return SCIP_OKAY;
13732 }
13733 
13734 /** Gets the number of bilinear terms of a quadratic constraint. */
13736  SCIP* scip, /**< SCIP data structure */
13737  SCIP_CONS* cons /**< constraint */
13738  )
13739 {
13740  assert(cons != NULL);
13741  assert(SCIPconsGetData(cons) != NULL);
13742 
13743  return SCIPconsGetData(cons)->nbilinterms;
13744 }
13745 
13746 /** Gets the bilinear terms of a quadratic constraint.
13747  * Length is given by SCIPgetNBilinTermQuadratic.
13748  */
13750  SCIP* scip, /**< SCIP data structure */
13751  SCIP_CONS* cons /**< constraint */
13752  )
13753 {
13754  assert(cons != NULL);
13755  assert(SCIPconsGetData(cons) != NULL);
13756 
13757  return SCIPconsGetData(cons)->bilinterms;
13758 }
13759 
13760 /** Gets the left hand side of a quadratic constraint. */
13762  SCIP* scip, /**< SCIP data structure */
13763  SCIP_CONS* cons /**< constraint */
13764  )
13765 {
13766  assert(cons != NULL);
13767  assert(SCIPconsGetData(cons) != NULL);
13768 
13769  return SCIPconsGetData(cons)->lhs;
13770 }
13771 
13772 /** Gets the right hand side of a quadratic constraint. */
13774  SCIP* scip, /**< SCIP data structure */
13775  SCIP_CONS* cons /**< constraint */
13776  )
13777 {
13778  assert(cons != NULL);
13779  assert(SCIPconsGetData(cons) != NULL);
13780 
13781  return SCIPconsGetData(cons)->rhs;
13782 }
13783 
13784 /** Check the quadratic function of a quadratic constraint for its semi-definiteness, if not done yet. */
13786  SCIP* scip, /**< SCIP data structure */
13787  SCIP_CONS* cons /**< constraint */
13788  )
13789 {
13790  assert(cons != NULL);
13791 
13792  SCIP_CALL( checkCurvature(scip, cons, TRUE) );
13793 
13794  return SCIP_OKAY;
13795 }
13796 
13797 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) convex. */
13799  SCIP* scip, /**< SCIP data structure */
13800  SCIP_CONS* cons /**< constraint */
13801  )
13802 {
13803  SCIP_Bool determined;
13804 
13805  assert(cons != NULL);
13806  assert(SCIPconsGetData(cons) != NULL);
13807 
13808  checkCurvatureEasy(scip, cons, &determined, FALSE);
13809  assert(determined);
13810 
13811  return (SCIPconsGetData(cons)->isconvex);
13812 }
13813 
13814 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) concave. */
13816  SCIP* scip, /**< SCIP data structure */
13817  SCIP_CONS* cons /**< constraint */
13818  )
13819 {
13820  SCIP_Bool determined;
13821 
13822  assert(cons != NULL);
13823  assert(SCIPconsGetData(cons) != NULL);
13824 
13825  checkCurvatureEasy(scip, cons, &determined, FALSE);
13826  assert(determined);
13827 
13828  return (SCIPconsGetData(cons)->isconcave);
13829 }
13830 
13831 /** Computes the violation of a constraint by a solution */
13833  SCIP* scip, /**< SCIP data structure */
13834  SCIP_CONS* cons, /**< constraint */
13835  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
13836  SCIP_Real* violation /**< pointer to store violation of constraint */
13837  )
13838 {
13839  SCIP_CONSHDLR* conshdlr;
13840  SCIP_CONSDATA* consdata;
13841 
13842  assert(scip != NULL);
13843  assert(cons != NULL);
13844  assert(violation != NULL);
13845 
13846  conshdlr = SCIPconsGetHdlr(cons);
13847  assert(conshdlr != NULL);
13848 
13849  SCIP_CALL( computeViolation(scip, conshdlr, cons, sol) );
13850 
13851  consdata = SCIPconsGetData(cons);
13852  assert(consdata != NULL);
13853 
13854  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
13855 
13856  return SCIP_OKAY;
13857 }
13858 
13859 /** Indicates whether the quadratic constraint is local w.r.t. the current local bounds.
13860  *
13861  * That is, checks whether each variable with a square term is fixed and for each bilinear term at least one variable is fixed.
13862  */
13864  SCIP* scip, /**< SCIP data structure */
13865  SCIP_CONS* cons /**< constraint */
13866  )
13867 {
13868  SCIP_CONSDATA* consdata;
13869  SCIP_VAR* var1;
13870  SCIP_VAR* var2;
13871  int i;
13872 
13873  assert(scip != NULL);
13874  assert(cons != NULL);
13875 
13876  consdata = SCIPconsGetData(cons);
13877  assert(consdata != NULL);
13878 
13879  /* check all square terms */
13880  for( i = 0; i < consdata->nquadvars; ++i )
13881  {
13882  if( consdata->quadvarterms[i].sqrcoef == 0.0 )
13883  continue;
13884 
13885  var1 = consdata->quadvarterms[i].var;
13886  assert(var1 != NULL);
13887 
13888  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) )
13889  return FALSE;
13890  }
13891 
13892  for( i = 0; i < consdata->nbilinterms; ++i )
13893  {
13894  var1 = consdata->bilinterms[i].var1;
13895  var2 = consdata->bilinterms[i].var2;
13896 
13897  assert(var1 != NULL);
13898  assert(var2 != NULL);
13899 
13900  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) &&
13901  ! SCIPisRelEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
13902  return FALSE;
13903  }
13904 
13905  return TRUE;
13906 }
13907 
13908 /** Adds the constraint to an NLPI problem. */
13910  SCIP* scip, /**< SCIP data structure */
13911  SCIP_CONS* cons, /**< constraint */
13912  SCIP_NLPI* nlpi, /**< interface to NLP solver */
13913  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
13914  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
13915  SCIP_Bool names /**< whether to pass constraint names to NLPI */
13916  )
13917 {
13918  SCIP_CONSDATA* consdata;
13919  int nlininds;
13920  int* lininds;
13921  SCIP_Real* linvals;
13922  int nquadelems;
13923  SCIP_QUADELEM* quadelems;
13924  SCIP_VAR* othervar;
13925  const char* name;
13926  int j;
13927  int l;
13928  int lincnt;
13929  int quadcnt;
13930  int idx1;
13931  int idx2;
13932 
13933  assert(scip != NULL);
13934  assert(cons != NULL);
13935  assert(nlpi != NULL);
13936  assert(nlpiprob != NULL);
13937  assert(scipvar2nlpivar != NULL);
13938 
13939  consdata = SCIPconsGetData(cons);
13940  assert(consdata != NULL);
13941 
13942  /* count nonzeros in quadratic part */
13943  nlininds = consdata->nlinvars;
13944  nquadelems = consdata->nbilinterms;
13945  for( j = 0; j < consdata->nquadvars; ++j )
13946  {
13947  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
13948  ++nquadelems;
13949  if( consdata->quadvarterms[j].lincoef != 0.0 )
13950  ++nlininds;
13951  }
13952 
13953  /* setup linear part */
13954  lininds = NULL;
13955  linvals = NULL;
13956  lincnt = 0;
13957  if( nlininds > 0 )
13958  {
13959  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
13960  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
13961 
13962  for( j = 0; j < consdata->nlinvars; ++j )
13963  {
13964  linvals[j] = consdata->lincoefs[j];
13965  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->linvars[j]));
13966  lininds[j] = (int) (size_t) SCIPhashmapGetImage(scipvar2nlpivar, consdata->linvars[j]);
13967  }
13968 
13969  lincnt = consdata->nlinvars;
13970  }
13971 
13972  /* setup quadratic part */
13973  quadelems = NULL;
13974  if( nquadelems > 0 )
13975  {
13976  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
13977  }
13978  quadcnt = 0;
13979 
13980  for( j = 0; j < consdata->nquadvars; ++j )
13981  {
13982  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->quadvarterms[j].var));
13983  idx1 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, consdata->quadvarterms[j].var);
13984  if( consdata->quadvarterms[j].lincoef != 0.0 )
13985  {
13986  assert(lininds != NULL);
13987  assert(linvals != NULL);
13988  lininds[lincnt] = idx1;
13989  linvals[lincnt] = consdata->quadvarterms[j].lincoef;
13990  ++lincnt;
13991  }
13992 
13993  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
13994  {
13995  assert(quadcnt < nquadelems);
13996  assert(quadelems != NULL);
13997  quadelems[quadcnt].idx1 = idx1;
13998  quadelems[quadcnt].idx2 = idx1;
13999  quadelems[quadcnt].coef = consdata->quadvarterms[j].sqrcoef;
14000  ++quadcnt;
14001  }
14002 
14003  for( l = 0; l < consdata->quadvarterms[j].nadjbilin; ++l )
14004  {
14005  othervar = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].var2;
14006  /* if othervar is on position 2, then we process this bilinear term later (or it was processed already) */
14007  if( othervar == consdata->quadvarterms[j].var )
14008  continue;
14009 
14010  assert(quadcnt < nquadelems);
14011  assert(quadelems != NULL);
14012  assert(SCIPhashmapExists(scipvar2nlpivar, othervar));
14013  idx2 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, othervar);
14014  quadelems[quadcnt].idx1 = MIN(idx1, idx2);
14015  quadelems[quadcnt].idx2 = MAX(idx1, idx2);
14016  quadelems[quadcnt].coef = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].coef;
14017  ++quadcnt;
14018  }
14019  }
14020 
14021  assert(quadcnt == nquadelems);
14022  assert(lincnt == nlininds);
14023 
14024  name = names ? SCIPconsGetName(cons) : NULL;
14025 
14026  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
14027  &consdata->lhs, &consdata->rhs,
14028  &nlininds, &lininds, &linvals ,
14029  &nquadelems, &quadelems,
14030  NULL, NULL, &name) );
14031 
14032  SCIPfreeBufferArrayNull(scip, &quadelems);
14033  SCIPfreeBufferArrayNull(scip, &lininds);
14034  SCIPfreeBufferArrayNull(scip, &linvals);
14035 
14036  return SCIP_OKAY;
14037 }
14038 
14039 
14040 /** sets the left hand side of a quadratic constraint
14041  *
14042  * @note This method may only be called during problem creation stage for an original constraint.
14043  */
14045  SCIP* scip, /**< SCIP data structure */
14046  SCIP_CONS* cons, /**< constraint data */
14047  SCIP_Real lhs /**< new left hand side */
14048  )
14049 {
14050  SCIP_CONSDATA* consdata;
14051 
14052  assert(scip != NULL);
14053  assert(cons != NULL);
14054  assert(!SCIPisInfinity(scip, lhs));
14055 
14056  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14057  {
14058  SCIPerrorMessage("constraint is not quadratic\n");
14059  return SCIP_INVALIDDATA;
14060  }
14061 
14062  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
14063  {
14064  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
14065  return SCIP_INVALIDDATA;
14066  }
14067 
14068  consdata = SCIPconsGetData(cons);
14069  assert(consdata != NULL);
14070  assert(!SCIPisInfinity(scip, consdata->lhs));
14071 
14072  /* adjust value to not be smaller than -inf */
14073  if( SCIPisInfinity(scip, -lhs) )
14074  lhs = -SCIPinfinity(scip);
14075 
14076  /* check for lhs <= rhs */
14077  if( !SCIPisLE(scip, lhs, consdata->rhs) )
14078  return SCIP_INVALIDDATA;
14079 
14080  consdata->lhs = lhs;
14081 
14082  return SCIP_OKAY;
14083 }
14084 
14085 /** sets the right hand side of a quadratic constraint
14086  *
14087  * @note This method may only be called during problem creation stage for an original constraint.
14088  */
14090  SCIP* scip, /**< SCIP data structure */
14091  SCIP_CONS* cons, /**< constraint data */
14092  SCIP_Real rhs /**< new right hand side */
14093  )
14094 {
14095  SCIP_CONSDATA* consdata;
14096 
14097  assert(scip != NULL);
14098  assert(cons != NULL);
14099  assert(!SCIPisInfinity(scip, -rhs));
14100 
14101  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14102  {
14103  SCIPerrorMessage("constraint is not quadratic\n");
14104  return SCIP_INVALIDDATA;
14105  }
14106 
14107  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
14108  {
14109  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
14110  return SCIP_INVALIDDATA;
14111  }
14112 
14113  consdata = SCIPconsGetData(cons);
14114  assert(consdata != NULL);
14115  assert(!SCIPisInfinity(scip, -consdata->rhs));
14116 
14117  /* adjust value to not be greater than inf */
14118  if( SCIPisInfinity(scip, rhs) )
14119  rhs = SCIPinfinity(scip);
14120 
14121  /* check for lhs <= rhs */
14122  if( !SCIPisLE(scip, consdata->lhs, rhs) )
14123  return SCIP_INVALIDDATA;
14124 
14125  consdata->rhs = rhs;
14126 
14127  return SCIP_OKAY;
14128 }
14129 
14130 /** gets the feasibility of the quadratic constraint in the given solution */
14132  SCIP* scip, /**< SCIP data structure */
14133  SCIP_CONS* cons, /**< constraint data */
14134  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
14135  SCIP_Real* feasibility /**< pointer to store the feasibility */
14136  )
14137 {
14138  SCIP_CONSDATA* consdata;
14139 
14140  assert(scip != NULL);
14141  assert(cons != NULL);
14142  assert(feasibility != NULL);
14143 
14144  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14145  {
14146  SCIPerrorMessage("constraint is not quadratic\n");
14147  SCIPABORT();
14148  }
14149 
14150  SCIP_CALL( computeViolation(scip, SCIPconsGetHdlr(cons), cons, sol) );
14151 
14152  consdata = SCIPconsGetData(cons);
14153  assert(consdata != NULL);
14154 
14155  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
14156  *feasibility = SCIPinfinity(scip);
14157  else if( SCIPisInfinity(scip, -consdata->lhs) )
14158  *feasibility = (consdata->rhs - consdata->activity);
14159  else if( SCIPisInfinity(scip, consdata->rhs) )
14160  *feasibility = (consdata->activity - consdata->lhs);
14161  else
14162  {
14163  assert(!SCIPisInfinity(scip, -consdata->rhs));
14164  assert(!SCIPisInfinity(scip, consdata->lhs));
14165  *feasibility = MIN( consdata->rhs - consdata->activity, consdata->activity - consdata->lhs );
14166  }
14167 
14168  return SCIP_OKAY;
14169 }
14170 
14171 /** gets the activity of the quadratic constraint in the given solution */
14173  SCIP* scip, /**< SCIP data structure */
14174  SCIP_CONS* cons, /**< constraint data */
14175  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
14176  SCIP_Real* activity /**< pointer to store the activity */
14177  )
14178 {
14179  SCIP_CONSDATA* consdata;
14180 
14181  assert(scip != NULL);
14182  assert(cons != NULL);
14183  assert(activity != NULL);
14184 
14185  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14186  {
14187  SCIPerrorMessage("constraint is not quadratic\n");
14188  SCIPABORT();
14189  }
14190 
14191  SCIP_CALL( computeViolation(scip, SCIPconsGetHdlr(cons), cons, sol) );
14192 
14193  consdata = SCIPconsGetData(cons);
14194  assert(consdata != NULL);
14195 
14196  *activity = consdata->activity;
14197 
14198  return SCIP_OKAY;
14199 }
14200 
14201 /** changes the linear coefficient value for a given quadratic variable in a quadratic constraint data; if not
14202  * available, it adds it
14203  *
14204  * @note this is only allowed for original constraints and variables in problem creation stage
14205  */
14207  SCIP* scip, /**< SCIP data structure */
14208  SCIP_CONS* cons, /**< constraint data */
14209  SCIP_VAR* var, /**< quadratic variable */
14210  SCIP_Real coef /**< new coefficient */
14211  )
14212 {
14213  SCIP_CONSDATA* consdata;
14214  SCIP_Bool found;
14215  int i;
14216 
14217  assert(scip != NULL);
14218  assert(cons != NULL);
14219  assert(var != NULL);
14220 
14221  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14222  {
14223  SCIPerrorMessage("constraint is not quadratic\n");
14224  return SCIP_INVALIDDATA;
14225  }
14226 
14227  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
14228  {
14229  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
14230  return SCIP_INVALIDDATA;
14231  }
14232 
14233  consdata = SCIPconsGetData(cons);
14234  assert(consdata != NULL);
14235 
14236  /* check all quadratic variables */
14237  found = FALSE;
14238  for( i = 0; i < consdata->nquadvars; ++i )
14239  {
14240  if( var == consdata->quadvarterms[i].var )
14241  {
14242  if( found || SCIPisZero(scip, coef) )
14243  {
14244  consdata->quadvarterms[i].lincoef = 0.0;
14245 
14246  /* remember to merge quadratic variable terms */
14247  consdata->quadvarsmerged = FALSE;
14248  }
14249  else
14250  consdata->quadvarterms[i].lincoef = coef;
14251 
14252  found = TRUE;
14253  }
14254  }
14255 
14256  /* check all linear variables */
14257  i = 0;
14258  while( i < consdata->nlinvars )
14259  {
14260  if( var == consdata->linvars[i] )
14261  {
14262  if( found || SCIPisZero(scip, coef) )
14263  {
14264  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
14265 
14266  /* decrease i by one since otherwise we would skip the coefficient which has been switched to position i */
14267  i--;
14268  }
14269  else
14270  {
14271  SCIP_CALL( chgLinearCoefPos(scip, cons, i, coef) );
14272  }
14273 
14274  found = TRUE;
14275  }
14276  i++;
14277  }
14278 
14279  /* add linear term if necessary */
14280  if( !found && !SCIPisZero(scip, coef) )
14281  {
14282  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
14283  }
14284 
14285  consdata->ispropagated = FALSE;
14286  consdata->ispresolved = FALSE;
14287 
14288  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14289  consdata->activity = SCIP_INVALID;
14290 
14291  return SCIP_OKAY;
14292 }
14293 
14294 /** changes the square coefficient value for a given quadratic variable in a quadratic constraint data; if not
14295  * available, it adds it
14296  *
14297  * @note this is only allowed for original constraints and variables in problem creation stage
14298  */
14300  SCIP* scip, /**< SCIP data structure */
14301  SCIP_CONS* cons, /**< constraint data */
14302  SCIP_VAR* var, /**< quadratic variable */
14303  SCIP_Real coef /**< new coefficient */
14304  )
14305 {
14306  SCIP_CONSDATA* consdata;
14307  SCIP_Bool found;
14308  int i;
14309 
14310  assert(scip != NULL);
14311  assert(cons != NULL);
14312  assert(var != NULL);
14313  assert(!SCIPisInfinity(scip, REALABS(coef)));
14314 
14315  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14316  {
14317  SCIPerrorMessage("constraint is not quadratic\n");
14318  return SCIP_INVALIDDATA;
14319  }
14320 
14321  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
14322  {
14323  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
14324  return SCIP_INVALIDDATA;
14325  }
14326 
14327  consdata = SCIPconsGetData(cons);
14328  assert(consdata != NULL);
14329 
14330  /* find the quadratic variable and change its quadratic coefficient */
14331  found = FALSE;
14332  for( i = 0; i < consdata->nquadvars; ++i )
14333  {
14334  if( var == consdata->quadvarterms[i].var )
14335  {
14336  consdata->quadvarterms[i].sqrcoef = (found || SCIPisZero(scip, coef)) ? 0.0 : coef;
14337  found = TRUE;
14338  }
14339  }
14340 
14341  /* add bilinear term if necessary */
14342  if( !found && !SCIPisZero(scip, coef) )
14343  {
14344  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
14345  }
14346 
14347  /* update flags and invalidate activities */
14348  consdata->isconvex = FALSE;
14349  consdata->isconcave = FALSE;
14350  consdata->iscurvchecked = FALSE;
14351  consdata->ispropagated = FALSE;
14352  consdata->ispresolved = FALSE;
14353 
14354  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14355  consdata->activity = SCIP_INVALID;
14356 
14357  /* remember to merge quadratic variable terms */
14358  consdata->quadvarsmerged = FALSE;
14359 
14360  return SCIP_OKAY;
14361 }
14362 
14363 /** changes the bilinear coefficient value for a given quadratic variable in a quadratic constraint data; if not
14364  * available, it adds it
14365  *
14366  * @note this is only allowed for original constraints and variables in problem creation stage
14367  */
14369  SCIP* scip, /**< SCIP data structure */
14370  SCIP_CONS* cons, /**< constraint */
14371  SCIP_VAR* var1, /**< first variable */
14372  SCIP_VAR* var2, /**< second variable */
14373  SCIP_Real coef /**< coefficient of bilinear term */
14374  )
14375 {
14376  SCIP_CONSDATA* consdata;
14377  SCIP_Bool found;
14378  int i;
14379 
14380  assert(scip != NULL);
14381  assert(cons != NULL);
14382  assert(var1 != NULL);
14383  assert(var2 != NULL);
14384  assert(!SCIPisInfinity(scip, REALABS(coef)));
14385 
14386  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14387  {
14388  SCIPerrorMessage("constraint is not quadratic\n");
14389  return SCIP_INVALIDDATA;
14390  }
14391 
14392  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var1) || !SCIPvarIsOriginal(var2) )
14393  {
14394  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
14395  return SCIP_INVALIDDATA;
14396  }
14397 
14398  if( var1 == var2 )
14399  {
14400  SCIP_CALL( SCIPchgSquareCoefQuadratic(scip, cons, var1, coef) );
14401  return SCIP_OKAY;
14402  }
14403 
14404  consdata = SCIPconsGetData(cons);
14405  assert(consdata != NULL);
14406 
14407  /* search array of bilinear terms */
14408  found = FALSE;
14409  for( i = 0; i < consdata->nbilinterms; ++i )
14410  {
14411  if( (consdata->bilinterms[i].var1 == var1 && consdata->bilinterms[i].var2 == var2) ||
14412  (consdata->bilinterms[i].var1 == var2 && consdata->bilinterms[i].var2 == var1) )
14413  {
14414  if( found || SCIPisZero(scip, coef) )
14415  {
14416  consdata->bilinterms[i].coef = 0.0;
14417 
14418  /* remember to merge bilinear terms */
14419  consdata->bilinmerged = FALSE;
14420  }
14421  else
14422  consdata->bilinterms[i].coef = coef;
14423  found = TRUE;
14424  }
14425  }
14426 
14427  /* add bilinear term if necessary */
14428  if( !found )
14429  {
14430  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, cons, var1, var2, coef) );
14431  }
14432 
14433  /* update flags and invalidate activities */
14434  consdata->isconvex = FALSE;
14435  consdata->isconcave = FALSE;
14436  consdata->iscurvchecked = FALSE;
14437  consdata->ispropagated = FALSE;
14438  consdata->ispresolved = FALSE;
14439 
14440  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14441  consdata->activity = SCIP_INVALID;
14442 
14443  return SCIP_OKAY;
14444 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:51
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17250
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:34422
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41180
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:16759
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:41293
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:10735
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:5847
static SCIP_RETCODE propagateBoundsQuadVar(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real a, SCIP_INTERVAL b, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
SCIP_Bool SCIPconsIsLocked(SCIP_CONS *cons)
Definition: cons.c:7943
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:5557
static SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:25575
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:2193
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:16341
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:22873
static SCIP_RETCODE consdataEnsureQuadVarTermsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
Constraint handler for variable bound constraints .
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:41256
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1147
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20402
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:33682
SCIP_RETCODE SCIPgetViolationQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12716
SCIP_QUADVARTERM * SCIPgetQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:10415
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11577
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16521
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1220
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:15823
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:7903
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip.c:3174
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41528
static SCIP_DECL_SORTINDCOMP(quadVarTermComp)
SCIP_Real SCIPgetRelaxFeastolFactor(SCIP *scip)
Definition: scip.c:31157
#define SCIP_MAXSTRLEN
Definition: def.h:198
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:5215
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4292
void SCIPaddBilinLinearization(SCIP *scip, SCIP_Real bilincoef, SCIP_Real refpointx, SCIP_Real refpointy, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
SCIP_RETCODE 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:17011
#define CONSHDLR_PROPFREQ
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4262
#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:29352
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:940
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:7853
static SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:18914
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:18860
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:7685
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5303
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:16965
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:17512
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:5787
static void consdataUpdateLinearActivityLbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
static SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
#define CONSHDLR_MAXPREROUNDS
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip.c:5672
static SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip.c:7362
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:7913
#define FALSE
Definition: def.h:53
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:34723
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2052
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:16113
void SCIPaddSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
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:17067
int SCIPgetNBinVars(SCIP *scip)
Definition: scip.c:10780
#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:7747
#define CONSHDLR_SEPAPRIORITY
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:8169
#define TRUE
Definition: def.h:52
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7644
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:33006
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:28754
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip.c:28777
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:5764
static void consdataFindUnlockedLinearVar(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41580
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:30559
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:27875
static SCIP_RETCODE removeBilinearTermsPos(SCIP *scip, SCIP_CONS *cons, int nterms, int *termposs)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20385
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:26426
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)
SCIP_DECL_QUADCONSUPGD((*quadconsupgd))
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:34593
SCIP_Real SCIPselectSimpleValue(SCIP_Real lb, SCIP_Real ub, SCIP_Longint maxdnom)
Definition: misc.c:7615
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)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:20414
static SCIP_RETCODE presolveTryAddAND(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
Constraint handler for "and" constraints, .
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:16803
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:2111
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:10915
static SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:7843
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:7783
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:26224
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:30577
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:24936
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
static SCIP_RETCODE dropQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:99
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:20418
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty)
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28050
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:28897
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:5328
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:7773
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:34676
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip.c:7877
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:95
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip.c:28645
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:5352
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:3516
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16460
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2154
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:3542
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16532
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:12776
static SCIP_RETCODE consdataSortQuadVarTerms(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3921
#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:36232
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
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:41193
SCIP_Bool SCIPvarIsOriginal(SCIP_VAR *var)
Definition: var.c:16470
static SCIP_RETCODE checkCurvature(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkmultivariate)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16483
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:1750
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:20383
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:41592
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:41317
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip.c:17159
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:7883
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:20355
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)
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)
SCIP_Real SCIPgetPrimalRayVal(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:36126
#define SCIPerrorMessage
Definition: pub_message.h:45
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:20426
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:18924
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:20403
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:19592
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:15786
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:41604
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:25857
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:3901
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:1152
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:40692
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:16542
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip.c:28394
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41206
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:5496
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28138
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip.c:19783
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30672
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:40927
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:7624
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16552
#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:41366
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:19023
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:2070
constraint handler for quadratic constraints
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:5472
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:20391
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:17265
#define REALABS(x)
Definition: def.h:148
SCIP_Bool SCIPisConcaveQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_NLPI ** SCIPgetNlpis(SCIP *scip)
Definition: scip.c:8641
SCIP_RETCODE SCIPaddLinearVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPenableNLP(SCIP *scip)
Definition: scip.c:28379
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:16735
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:41245
struct SCIP_QuadVarEventData SCIP_QUADVAREVENTDATA
#define SCIP_CALL(x)
Definition: def.h:263
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:5261
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:5161
#define CONSHDLR_ENFOPRIORITY
SCIP_Real sup
Definition: intervalarith.h:39
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:37045
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:2224
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:18973
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:31741
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41554
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:246
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:97
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7654
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:16968
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
Definition: scip.c:41268
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:5695
static SCIP_RETCODE consdataEnsureAdjBilinSize(SCIP *scip, SCIP_QUADVARTERM *quadvarterm, int num)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12117
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:38120
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41219
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12879
Ipopt NLP interface.
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip.c:22668
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:20259
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:16934
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:17021
SCIP_RETCODE SCIPaddLinearCoefsToNlRow(SCIP *scip, SCIP_NLROW *nlrow, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:29574
#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:24759
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41427
static SCIP_DECL_CONSINITLP(consInitlpQuadratic)
#define SCIP_Bool
Definition: def.h:50
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:14365
#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:17233
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:17041
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:801
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:7863
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:22152
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 SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:20427
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:8240
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:33881
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:7873
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:7973
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:16723
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:5580
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28014
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
#define SCIPreallocMemoryArray(scip, ptr, newnum)
Definition: scip.h:20363
#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:16747
#define infty2infty(infty1, infty2, val)
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip.h:20357
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
Constraint handler for linear constraints in their most general form, .
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_NAME
#define BMSclearMemory(ptr)
Definition: memory.h:84
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:20400
SCIP_Real SCIPvarGetWorstBoundLocal(SCIP_VAR *var)
Definition: var.c:17054
static SCIP_Bool consdataCheckBilinTermsSort(SCIP_CONSDATA *consdata)
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip.c:36389
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip.c:34550
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7046
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:37750
SCIP_Bool SCIPhasPrimalRay(SCIP *scip)
Definition: scip.c:36108
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12808
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:16526
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:20359
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1270
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:12891
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41232
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:36278
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:5534
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11514
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16506
SCIP_QUADVAREVENTDATA * eventdata
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip.c:5400
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2258
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:41378
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:20371
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:16955
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:36198
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:5741
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:3824
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:29459
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1253
#define CONSHDLR_DESC
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
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)
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNIntVars(SCIP *scip)
Definition: scip.c:10825
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:41329
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:18870
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:5424
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:41541
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:19519
void SCIPfreeParseVarsPolynomialData(SCIP *scip, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int nmonomials)
Definition: scip.c:16878
#define SCIP_Real
Definition: def.h:124
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:7803
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:3626
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20365
#define MIN(x, y)
Definition: memory.c:63
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:27587
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:33654
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:28321
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41567
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:20397
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:12726
#define SCIP_INVALID
Definition: def.h:144
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:40720
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
const char * SCIPgetProbName(SCIP *scip)
Definition: scip.c:9978
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:27725
void SCIPsortInt(int *intarray, int len)
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:28722
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:109
static SCIP_RETCODE consdataEnsureBilinSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
int SCIPgetNNlpis(SCIP *scip)
Definition: scip.c:8654
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip.c:19751
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:917
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:245
static SCIP_DECL_CONSLOCK(consLockQuadratic)
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:5376
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
Definition: scip.c:41390
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:19465
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:41891
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:18835
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
static SCIP_DECL_EVENTEXEC(processVarEvent)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16628
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip.c:33311
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:12036
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17279
#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:40996
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2089
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
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:12915
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:18684
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41305
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:3598
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:5810
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:7711
#define SCIPfreeMemoryArrayNull(scip, ptr)
Definition: scip.h:20374
#define SCIPABORT()
Definition: def.h:235
static SCIP_RETCODE consdataFindQuadVarTerm(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR *var, int *pos)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:7793
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:7078
static SCIP_RETCODE mergeAndCleanQuadVarTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:7823
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:36164
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:34217
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:12903