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-2014 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_ix_j + \sum_{i=1}^n b_i x_i \leq \textrm{rhs}\f$
18  * @author Stefan Vigerske
19  *
20  * @todo SCIP might fix linear variables on +/- infinity; remove them in presolve and take care later
21  * @todo round constraint sides to integers if all coefficients and variables are (impl.) integer
22  * @todo constraints in one variable should be replaced by linear or bounddisjunction constraint
23  * @todo check if some quadratic terms appear in several constraints and try to simplify (e.g., nous1)
24  * @todo skip separation in enfolp if for current LP (check LP id) was already separated
25  * @todo watch unbounded variables to enable/disable propagation
26  * @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
27  * @todo catch/drop events in consEnable/consDisable, do initsol/exitsol stuff also when a constraint is enabled/disabled during solve
28  * @todo underestimate for multivariate concave quadratic terms as in cons_nonlinear
29  */
30 
31 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32 
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_DELAYPRESOL FALSE /**< should presolving method be delayed, if other presolvers found reductions? */
65 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
66 
67 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
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 /*
84  * Data structures
85  */
86 
87 /** eventdata for variable bound change events in quadratic constraints */
88 struct SCIP_QuadVarEventData
89 {
90  SCIP_CONSDATA* consdata; /**< the constraint data */
91  int varidx; /**< the index of the variable which bound change is caught, positive for linear variables, negative for quadratic variables */
92  int filterpos; /**< position of eventdata in SCIP's event filter */
93 };
94 
95 /** Data of a quadratic constraint. */
96 struct SCIP_ConsData
97 {
98  SCIP_Real lhs; /**< left hand side of constraint */
99  SCIP_Real rhs; /**< right hand side of constraint */
100 
101  int nlinvars; /**< number of linear variables */
102  int linvarssize; /**< length of linear variable arrays */
103  SCIP_VAR** linvars; /**< linear variables */
104  SCIP_Real* lincoefs; /**< coefficients of linear variables */
105  SCIP_QUADVAREVENTDATA** lineventdata; /**< eventdata for bound change of linear variable */
106 
107  int nquadvars; /**< number of variables in quadratic terms */
108  int quadvarssize; /**< length of quadratic variable terms arrays */
109  SCIP_QUADVARTERM* quadvarterms; /**< array with quadratic variable terms */
110 
111  int nbilinterms; /**< number of bilinear terms */
112  int bilintermssize; /**< length of bilinear term arrays */
113  SCIP_BILINTERM* bilinterms; /**< bilinear terms array */
114 
115  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
116 
117  unsigned int linvarssorted:1; /**< are the linear variables already sorted? */
118  unsigned int linvarsmerged:1; /**< are equal linear variables already merged? */
119  unsigned int quadvarssorted:1; /**< are the quadratic variables already sorted? */
120  unsigned int quadvarsmerged:1; /**< are equal quadratic variables already merged? */
121  unsigned int bilinsorted:1; /**< are the bilinear terms already sorted? */
122  unsigned int bilinmerged:1; /**< are equal bilinear terms already merged? */
123 
124  unsigned int isconvex:1; /**< is quadratic function is convex ? */
125  unsigned int isconcave:1; /**< is quadratic function is concave ? */
126  unsigned int iscurvchecked:1; /**< is quadratic function checked on convexity or concavity ? */
127  unsigned int isremovedfixings:1; /**< did we removed fixed/aggr/multiaggr variables ? */
128  unsigned int ispropagated:1; /**< was the constraint propagated with respect to the current bounds ? */
129  unsigned int ispresolved:1; /**< did we checked for possibilities of upgrading or implicit integer variables ? */
130  unsigned int initialmerge:1; /**< did we perform an initial merge and clean in presolving yet ? */
131 #ifdef CHECKIMPLINBILINEAR
132  unsigned int isimpladded:1; /**< has there been an implication added for a binary variable in a bilinear term? */
133 #endif
134 
135  SCIP_Real minlinactivity; /**< sum of minimal activities of all linear terms with finite minimal activity */
136  SCIP_Real maxlinactivity; /**< sum of maximal activities of all linear terms with finite maximal activity */
137  int minlinactivityinf; /**< number of linear terms with infinite minimal activity */
138  int maxlinactivityinf; /**< number of linear terms with infinity maximal activity */
139  SCIP_INTERVAL quadactivitybounds; /**< bounds on the activity of the quadratic term, if up to date, otherwise empty interval */
140  SCIP_Real activity; /**< activity of quadratic function w.r.t. current solution */
141  SCIP_Real lhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
142  SCIP_Real rhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
143 
144  int linvar_maydecrease; /**< index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
145  int linvar_mayincrease; /**< index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
146 
147  SCIP_VAR** sepaquadvars; /**< variables corresponding to quadvarterms to use in separation, only available in solving stage */
148  int* sepabilinvar2pos; /**< position of second variable in bilinear terms to use in separation, only available in solving stage */
149  SCIP_Real lincoefsmin; /**< minimal absolute value of coefficients in linear part, only available in solving stage */
150  SCIP_Real lincoefsmax; /**< maximal absolute value of coefficients in linear part, only available in solving stage */
151 
152  SCIP_Real* factorleft; /**< coefficients of left factor if constraint function is factorable */
153  SCIP_Real* factorright; /**< coefficients of right factor if constraint function is factorable */
154 };
155 
156 /** quadratic constraint update method */
158 {
159  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)); /**< method to call for upgrading quadratic constraint */
160  int priority; /**< priority of upgrading method */
161  SCIP_Bool active; /**< is upgrading enabled */
162 };
163 typedef struct SCIP_QuadConsUpgrade SCIP_QUADCONSUPGRADE; /**< quadratic constraint update method */
164 
165 /** constraint handler data */
166 struct SCIP_ConshdlrData
167 {
168  int replacebinaryprodlength; /**< length of linear term which when multiplied with a binary variable is replaced by an auxiliary variable and an equivalent linear formulation */
169  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 */
170  SCIP_Bool binreforminitial; /**< whether to make constraints added due to replacing products with binary variables initial */
171  SCIP_Real binreformmaxcoef; /**< factor on 1/feastol to limit coefficients and coef range in linear constraints created by binary reformulation */
172  SCIP_Real mincutefficacysepa; /**< minimal efficacy of a cut in order to add it to relaxation during separation */
173  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) */
174  char scaling; /**< scaling method of constraints in feasibility check */
175  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
176  SCIP_Bool linearizeheursol; /**< whether linearizations of convex quadratic constraints should be added to cutpool when some heuristics finds a new solution */
177  SCIP_Bool checkcurvature; /**< whether functions should be checked for convexity/concavity */
178  SCIP_Bool checkfactorable; /**< whether functions should be checked to be factorable */
179  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
180  SCIP_Bool disaggregate; /**< whether to disaggregate quadratic constraints */
181  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve */
182  int maxproproundspresolve; /**< limit on number of propagation rounds for a single constraint within one presolving round */
183  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
184  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
185  int enfolplimit; /**< maximum number of enforcement round before declaring the LP relaxation
186  * infeasible (-1: no limit); WARNING: if this parameter is not set to -1,
187  * SCIP might declare sub-optimal solutions optimal or feasible instances
188  * infeasible; thus, the result returned by SCIP might be incorrect!
189  */
190  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
191  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
192  SCIP_EVENTHDLR* eventhdlr; /**< our handler for variable bound change events */
193  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
194  SCIP_Bool sepanlp; /**< where linearization of the NLP relaxation solution added? */
195  SCIP_NODE* lastenfolpnode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
196  int nenfolprounds; /**< counter on number of enforcement rounds for the current node */
197  SCIP_QUADCONSUPGRADE** quadconsupgrades; /**< quadratic constraint upgrade methods for specializing quadratic constraints */
198  int quadconsupgradessize; /**< size of quadconsupgrade array */
199  int nquadconsupgrades; /**< number of quadratic constraint upgrade methods */
200 };
201 
202 
203 /*
204  * local methods for managing quadratic constraint update methods
205  */
206 
207 
208 /** checks whether a quadratic constraint upgrade method has already be registered */
209 static
211  SCIP* scip, /**< SCIP data structure */
212  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
213  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
214  const char* conshdlrname /**< name of the constraint handler */
215  )
216 {
217  int i;
218 
219  assert(scip != NULL);
220  assert(conshdlrdata != NULL);
221  assert(quadconsupgd != NULL);
222  assert(conshdlrname != NULL);
223 
224  for( i = conshdlrdata->nquadconsupgrades - 1; i >= 0; --i )
225  {
226  if( conshdlrdata->quadconsupgrades[i]->quadconsupgd == quadconsupgd )
227  {
228  SCIPwarningMessage(scip, "Try to add already known upgrade message for constraint handler <%s>.\n", conshdlrname);
229  return TRUE;
230  }
231  }
232 
233  return FALSE;
234 }
235 
236 /*
237  * Local methods
238  */
239 
240 /** translate from one value of infinity to another
241  *
242  * if val is >= infty1, then give infty2, else give val
243  */
244 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
245 
246 /* catches variable bound change events on a linear variable in a quadratic constraint */
247 static
249  SCIP* scip, /**< SCIP data structure */
250  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
251  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
252  int linvarpos /**< position of variable in linear variables array */
253  )
254 {
255  SCIP_CONSDATA* consdata;
256  SCIP_QUADVAREVENTDATA* eventdata;
257  SCIP_EVENTTYPE eventtype;
258 
259  assert(scip != NULL);
260  assert(eventhdlr != NULL);
261  assert(cons != NULL);
262 
263  consdata = SCIPconsGetData(cons);
264  assert(consdata != NULL);
265 
266  assert(linvarpos >= 0);
267  assert(linvarpos < consdata->nlinvars);
268  assert(consdata->lineventdata != NULL);
269 
270  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
271 
272  eventdata->consdata = consdata;
273  eventdata->varidx = linvarpos;
274 
275  eventtype = SCIP_EVENTTYPE_VARFIXED;
276  if( !SCIPisInfinity(scip, consdata->rhs) )
277  {
278  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
279  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
280  if( consdata->lincoefs[linvarpos] > 0.0 )
281  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
282  else
283  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
284  }
285  if( !SCIPisInfinity(scip, -consdata->lhs) )
286  {
287  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
288  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
289  if( consdata->lincoefs[linvarpos] > 0.0 )
290  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
291  else
292  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
293  }
294 
295  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
296 
297  consdata->lineventdata[linvarpos] = eventdata;
298 
299  return SCIP_OKAY;
300 }
301 
302 /* drops variable bound change events on a linear variable in a quadratic constraint */
303 static
305  SCIP* scip, /**< SCIP data structure */
306  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
307  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
308  int linvarpos /**< position of variable in linear variables array */
309  )
310 {
311  SCIP_CONSDATA* consdata;
312  SCIP_EVENTTYPE eventtype;
313 
314  assert(scip != NULL);
315  assert(eventhdlr != NULL);
316  assert(cons != NULL);
317 
318  consdata = SCIPconsGetData(cons);
319  assert(consdata != NULL);
320 
321  assert(linvarpos >= 0);
322  assert(linvarpos < consdata->nlinvars);
323  assert(consdata->lineventdata != NULL);
324  assert(consdata->lineventdata[linvarpos] != NULL);
325  assert(consdata->lineventdata[linvarpos]->consdata == consdata);
326  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
327  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
328 
329  eventtype = SCIP_EVENTTYPE_VARFIXED;
330  if( !SCIPisInfinity(scip, consdata->rhs) )
331  {
332  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
333  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
334  if( consdata->lincoefs[linvarpos] > 0.0 )
335  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
336  else
337  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
338  }
339  if( !SCIPisInfinity(scip, -consdata->lhs) )
340  {
341  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
342  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
343  if( consdata->lincoefs[linvarpos] > 0.0 )
344  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
345  else
346  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
347  }
348 
349  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
350 
351  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866 */
352 
353  return SCIP_OKAY;
354 }
355 
356 /* catches variable bound change events on a quadratic variable in a quadratic constraint */
357 static
359  SCIP* scip, /**< SCIP data structure */
360  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
361  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
362  int quadvarpos /**< position of variable in quadratic variables array */
363  )
364 {
365  SCIP_CONSDATA* consdata;
366  SCIP_QUADVAREVENTDATA* eventdata;
367  SCIP_EVENTTYPE eventtype;
368 
369  assert(scip != NULL);
370  assert(eventhdlr != NULL);
371  assert(cons != NULL);
372 
373  consdata = SCIPconsGetData(cons);
374  assert(consdata != NULL);
375 
376  assert(quadvarpos >= 0);
377  assert(quadvarpos < consdata->nquadvars);
378  assert(consdata->quadvarterms[quadvarpos].eventdata == NULL);
379 
380  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
381 
383 #ifdef CHECKIMPLINBILINEAR
384  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
385 #endif
386  eventdata->consdata = consdata;
387  eventdata->varidx = -quadvarpos-1;
388  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
389 
390  consdata->quadvarterms[quadvarpos].eventdata = eventdata;
391 
392  return SCIP_OKAY;
393 }
394 
395 /* catches variable bound change events on a quadratic variable in a quadratic constraint */
396 static
398  SCIP* scip, /**< SCIP data structure */
399  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
400  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
401  int quadvarpos /**< position of variable in quadratic variables array */
402  )
403 {
404  SCIP_CONSDATA* consdata;
405  SCIP_EVENTTYPE eventtype;
406 
407  assert(scip != NULL);
408  assert(eventhdlr != NULL);
409  assert(cons != NULL);
410 
411  consdata = SCIPconsGetData(cons);
412  assert(consdata != NULL);
413 
414  assert(quadvarpos >= 0);
415  assert(quadvarpos < consdata->nquadvars);
416  assert(consdata->quadvarterms[quadvarpos].eventdata != NULL);
417  assert(consdata->quadvarterms[quadvarpos].eventdata->consdata == consdata);
418  assert(consdata->quadvarterms[quadvarpos].eventdata->varidx == -quadvarpos-1);
419  assert(consdata->quadvarterms[quadvarpos].eventdata->filterpos >= 0);
420 
422 #ifdef CHECKIMPLINBILINEAR
423  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
424 #endif
425 
426  SCIP_CALL( SCIPdropVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->quadvarterms[quadvarpos].eventdata, consdata->quadvarterms[quadvarpos].eventdata->filterpos) );
427 
428  SCIPfreeBlockMemory(scip, &consdata->quadvarterms[quadvarpos].eventdata);
429 
430  return SCIP_OKAY;
431 }
432 
433 /** catch variable events */
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  )
440 {
441  SCIP_CONSDATA* consdata;
442  int i;
443 
444  assert(scip != NULL);
445  assert(cons != NULL);
446  assert(eventhdlr != NULL);
447 
448  consdata = SCIPconsGetData(cons);
449  assert(consdata != NULL);
450  assert(consdata->lineventdata == NULL);
451 
452  /* we will update isremovedfixings, so reset it to TRUE first */
453  consdata->isremovedfixings = TRUE;
454 
455  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
456  for( i = 0; i < consdata->nlinvars; ++i )
457  {
458  SCIP_CALL( catchLinearVarEvents(scip, eventhdlr, cons, i) );
459 
460  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(consdata->linvars[i]);
461  }
462 
463  for( i = 0; i < consdata->nquadvars; ++i )
464  {
465  assert(consdata->quadvarterms[i].eventdata == NULL);
466 
467  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, i) );
468 
469  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(consdata->quadvarterms[i].var);
470  }
471 
472  consdata->ispropagated = FALSE;
473 
474  return SCIP_OKAY;
475 }
476 
477 /** drop variable events */
478 static
480  SCIP* scip, /**< SCIP data structure */
481  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
482  SCIP_CONS* cons /**< constraint for which to drop bound change events */
483  )
484 {
485  SCIP_CONSDATA* consdata;
486  int i;
487 
488  assert(scip != NULL);
489  assert(eventhdlr != NULL);
490  assert(cons != NULL);
491 
492  consdata = SCIPconsGetData(cons);
493  assert(consdata != NULL);
494 
495  if( consdata->lineventdata != NULL )
496  {
497  for( i = 0; i < consdata->nlinvars; ++i )
498  {
499  if( consdata->lineventdata[i] != NULL )
500  {
501  SCIP_CALL( dropLinearVarEvents(scip, eventhdlr, cons, i) );
502  }
503  }
504  SCIPfreeBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize);
505  }
506 
507  for( i = 0; i < consdata->nquadvars; ++i )
508  {
509  if( consdata->quadvarterms[i].eventdata != NULL )
510  {
511  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, i) );
512  }
513  }
514 
515  return SCIP_OKAY;
516 }
517 
518 /** locks a linear variable in a constraint */
519 static
521  SCIP* scip, /**< SCIP data structure */
522  SCIP_CONS* cons, /**< constraint where to lock a variable */
523  SCIP_VAR* var, /**< variable to lock */
524  SCIP_Real coef /**< coefficient of variable in constraint */
525  )
526 {
527  SCIP_CONSDATA* consdata;
528 
529  assert(scip != NULL);
530  assert(cons != NULL);
531  assert(var != NULL);
532  assert(coef != 0.0);
533 
534  consdata = SCIPconsGetData(cons);
535  assert(consdata != NULL);
536 
537  if( coef > 0.0 )
538  {
539  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
540  }
541  else
542  {
543  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
544  }
545 
546  return SCIP_OKAY;
547 }
548 
549 /** unlocks a linear variable in a constraint */
550 static
552  SCIP* scip, /**< SCIP data structure */
553  SCIP_CONS* cons, /**< constraint where to unlock a variable */
554  SCIP_VAR* var, /**< variable to unlock */
555  SCIP_Real coef /**< coefficient of variable in constraint */
556  )
557 {
558  SCIP_CONSDATA* consdata;
559 
560  assert(scip != NULL);
561  assert(cons != NULL);
562  assert(var != NULL);
563  assert(coef != 0.0);
564 
565  consdata = SCIPconsGetData(cons);
566  assert(consdata != NULL);
567 
568  if( coef > 0.0 )
569  {
570  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
571  }
572  else
573  {
574  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
575  }
576 
577  return SCIP_OKAY;
578 }
579 
580 /** locks a quadratic variable in a constraint */
581 static
583  SCIP* scip, /**< SCIP data structure */
584  SCIP_CONS* cons, /**< constraint where to lock a variable */
585  SCIP_VAR* var /**< variable to lock */
586  )
587 {
588  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
589 
590  return SCIP_OKAY;
591 }
592 
593 /** unlocks a quadratic variable in a constraint */
594 static
596  SCIP* scip, /**< SCIP data structure */
597  SCIP_CONS* cons, /**< constraint where to unlock a variable */
598  SCIP_VAR* var /**< variable to unlock */
599  )
600 {
601  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
602 
603  return SCIP_OKAY;
604 }
605 
606 /** computes the minimal and maximal activity for the linear part in a constraint data
607  * only sums up terms that contribute finite values
608  * gives the number of terms that contribute infinite values
609  * only computes those activities where the corresponding side of the constraint is finite
610  */
611 static
613  SCIP* scip, /**< SCIP data structure */
614  SCIP_CONSDATA* consdata, /**< constraint data */
615  SCIP_Real intervalinfty /**< infinity value used in interval operations */
616  )
617 { /*lint --e{666}*/
618  SCIP_ROUNDMODE prevroundmode;
619  int i;
620  SCIP_Real bnd;
621 
622  assert(scip != NULL);
623  assert(consdata != NULL);
624 
625  /* if variable bounds are not strictly consistent, then the activity update methods may yield inconsistent activities
626  * in this case, we also recompute the activities
627  */
628  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID && /*lint !e777 */
629  (consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity) )
630  {
631  /* activities should be up-to-date */
632  assert(consdata->minlinactivityinf >= 0);
633  assert(consdata->maxlinactivityinf >= 0);
634  return;
635  }
636 
637  consdata->minlinactivityinf = 0;
638  consdata->maxlinactivityinf = 0;
639 
640  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
641  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
642  */
643  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
644  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
645 
646  if( consdata->nlinvars == 0 )
647  return;
648 
649  /* if the activities computed here should be still up-to-date after bound changes,
650  * variable events need to be caught */
651  assert(consdata->lineventdata != NULL);
652 
653  prevroundmode = SCIPintervalGetRoundingMode();
654 
655  if( !SCIPisInfinity(scip, consdata->rhs) )
656  {
657  /* compute minimal activity only if there is a finite right hand side */
659 
660  for( i = 0; i < consdata->nlinvars; ++i )
661  {
662  assert(consdata->lineventdata[i] != NULL);
663  if( consdata->lincoefs[i] >= 0.0 )
664  {
665  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
666  if( SCIPisInfinity(scip, -bnd) )
667  {
668  ++consdata->minlinactivityinf;
669  continue;
670  }
671  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
672  }
673  else
674  {
675  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
676  if( SCIPisInfinity(scip, bnd) )
677  {
678  ++consdata->minlinactivityinf;
679  continue;
680  }
681  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
682  }
683  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
684  }
685  }
686 
687  if( !SCIPisInfinity(scip, -consdata->lhs) )
688  {
689  /* compute maximal activity only if there is a finite left hand side */
691 
692  for( i = 0; i < consdata->nlinvars; ++i )
693  {
694  assert(consdata->lineventdata[i] != NULL);
695  if( consdata->lincoefs[i] >= 0.0 )
696  {
697  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
698  if( SCIPisInfinity(scip, bnd) )
699  {
700  ++consdata->maxlinactivityinf;
701  continue;
702  }
703  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
704  }
705  else
706  {
707  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
708  if( SCIPisInfinity(scip, -bnd) )
709  {
710  ++consdata->maxlinactivityinf;
711  continue;
712  }
713  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
714  }
715  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
716  }
717  }
718 
719  SCIPintervalSetRoundingMode(prevroundmode);
720 
721  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
722 }
723 
724 /** update the linear activities after a change in the lower bound of a variable */
725 static
727  SCIP* scip, /**< SCIP data structure */
728  SCIP_CONSDATA* consdata, /**< constraint data */
729  SCIP_Real coef, /**< coefficient of variable in constraint */
730  SCIP_Real oldbnd, /**< previous lower bound of variable */
731  SCIP_Real newbnd /**< new lower bound of variable */
732  )
733 {
734  SCIP_ROUNDMODE prevroundmode;
735 
736  assert(scip != NULL);
737  assert(consdata != NULL);
738  /* we can't deal with lower bounds at infinity */
739  assert(!SCIPisInfinity(scip, oldbnd));
740  assert(!SCIPisInfinity(scip, newbnd));
741 
742  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
743 
744  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
745  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
746  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
747  */
748 
749  if( coef > 0.0 )
750  {
751  /* we should only be called if rhs is finite */
752  assert(!SCIPisInfinity(scip, consdata->rhs));
753 
754  /* we have no min activities computed so far, so cannot update */
755  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
756  return;
757 
758  assert(!SCIPisInfinity(scip, -consdata->minlinactivity));
759 
760  prevroundmode = SCIPintervalGetRoundingMode();
762 
763  /* update min activity */
764  if( SCIPisInfinity(scip, -oldbnd) )
765  {
766  --consdata->minlinactivityinf;
767  assert(consdata->minlinactivityinf >= 0);
768  }
769  else
770  {
771  SCIP_Real minuscoef;
772  minuscoef = -coef;
773  consdata->minlinactivity += minuscoef * oldbnd;
774  }
775 
776  if( SCIPisInfinity(scip, -newbnd) )
777  {
778  ++consdata->minlinactivityinf;
779  }
780  else
781  {
782  consdata->minlinactivity += coef * newbnd;
783  }
784 
785  SCIPintervalSetRoundingMode(prevroundmode);
786  }
787  else
788  {
789  /* we should only be called if lhs is finite */
790  assert(!SCIPisInfinity(scip, -consdata->lhs));
791 
792  /* we have no max activities computed so far, so cannot update */
793  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
794  return;
795 
796  assert(!SCIPisInfinity(scip, consdata->maxlinactivity));
797 
798  prevroundmode = SCIPintervalGetRoundingMode();
800 
801  /* update max activity */
802  if( SCIPisInfinity(scip, -oldbnd) )
803  {
804  --consdata->maxlinactivityinf;
805  assert(consdata->maxlinactivityinf >= 0);
806  }
807  else
808  {
809  SCIP_Real minuscoef;
810  minuscoef = -coef;
811  consdata->maxlinactivity += minuscoef * oldbnd;
812  }
813 
814  if( SCIPisInfinity(scip, -newbnd) )
815  {
816  ++consdata->maxlinactivityinf;
817  }
818  else
819  {
820  consdata->maxlinactivity += coef * newbnd;
821  }
822 
823  SCIPintervalSetRoundingMode(prevroundmode);
824  }
825 }
826 
827 /** update the linear activities after a change in the upper bound of a variable */
828 static
830  SCIP* scip, /**< SCIP data structure */
831  SCIP_CONSDATA* consdata, /**< constraint data */
832  SCIP_Real coef, /**< coefficient of variable in constraint */
833  SCIP_Real oldbnd, /**< previous lower bound of variable */
834  SCIP_Real newbnd /**< new lower bound of variable */
835  )
836 {
837  SCIP_ROUNDMODE prevroundmode;
838 
839  assert(scip != NULL);
840  assert(consdata != NULL);
841  /* we can't deal with upper bounds at -infinity */
842  assert(!SCIPisInfinity(scip, -oldbnd));
843  assert(!SCIPisInfinity(scip, -newbnd));
844 
845  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
846 
847  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
848  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
849  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
850  */
851 
852  if( coef > 0.0 )
853  {
854  /* we should only be called if lhs is finite */
855  assert(!SCIPisInfinity(scip, -consdata->lhs));
856 
857  /* we have no max activities computed so far, so cannot update */
858  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
859  return;
860 
861  assert(!SCIPisInfinity(scip, consdata->maxlinactivity));
862 
863  prevroundmode = SCIPintervalGetRoundingMode();
865 
866  /* update max activity */
867  if( SCIPisInfinity(scip, oldbnd) )
868  {
869  --consdata->maxlinactivityinf;
870  assert(consdata->maxlinactivityinf >= 0);
871  }
872  else
873  {
874  SCIP_Real minuscoef;
875  minuscoef = -coef;
876  consdata->maxlinactivity += minuscoef * oldbnd;
877  }
878 
879  if( SCIPisInfinity(scip, newbnd) )
880  {
881  ++consdata->maxlinactivityinf;
882  }
883  else
884  {
885  consdata->maxlinactivity += coef * newbnd;
886  }
887 
888  SCIPintervalSetRoundingMode(prevroundmode);
889  }
890  else
891  {
892  /* we should only be called if rhs is finite */
893  assert(!SCIPisInfinity(scip, consdata->rhs));
894 
895  /* we have no min activities computed so far, so cannot update */
896  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
897  return;
898 
899  assert(!SCIPisInfinity(scip, -consdata->minlinactivity));
900 
901  prevroundmode = SCIPintervalGetRoundingMode();
903 
904  /* update min activity */
905  if( SCIPisInfinity(scip, oldbnd) )
906  {
907  --consdata->minlinactivityinf;
908  assert(consdata->minlinactivityinf >= 0);
909  }
910  else
911  {
912  SCIP_Real minuscoef;
913  minuscoef = -coef;
914  consdata->minlinactivity += minuscoef * oldbnd;
915  }
916 
917  if( SCIPisInfinity(scip, newbnd) )
918  {
919  ++consdata->minlinactivityinf;
920  }
921  else
922  {
923  consdata->minlinactivity += coef * newbnd;
924  }
925 
926  SCIPintervalSetRoundingMode(prevroundmode);
927  }
928 }
929 
930 /** processes variable fixing or bound change event */
931 static
932 SCIP_DECL_EVENTEXEC(processVarEvent)
933 {
934  SCIP_CONSDATA* consdata;
935  SCIP_EVENTTYPE eventtype;
936  int varidx;
937 
938  assert(scip != NULL);
939  assert(event != NULL);
940  assert(eventdata != NULL);
941  assert(eventhdlr != NULL);
942 
943  consdata = ((SCIP_QUADVAREVENTDATA*)eventdata)->consdata;
944  assert(consdata != NULL);
945 
946  varidx = ((SCIP_QUADVAREVENTDATA*)eventdata)->varidx;
947  assert(varidx < 0 || varidx < consdata->nlinvars);
948  assert(varidx >= 0 || -varidx-1 < consdata->nquadvars);
949 
950  eventtype = SCIPeventGetType(event);
951 
952  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
953  {
954  if( varidx < 0 )
955  {
956  /* mark activity bounds for quad term as not up to date anymore */
957  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
958  }
959  else
960  {
961  /* update activity bounds for linear terms */
962  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
963  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
964  else
965  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
966  }
967 
968  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
969  consdata->ispropagated = FALSE;
970  }
971 
972  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
973  {
974  consdata->isremovedfixings = FALSE;
975  }
976 
977 #ifdef CHECKIMPLINBILINEAR
978  if( eventtype & SCIP_EVENTTYPE_IMPLADDED )
979  {
980  assert(varidx < 0); /* we catch impladded events only for quadratic variables */
981  /* 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 */
982  if( SCIPvarIsBinary(SCIPeventGetVar(event)) && consdata->quadvarterms[-varidx-1].nadjbilin > 0 )
983  consdata->isimpladded = TRUE;
984  }
985 #endif
986 
987  return SCIP_OKAY;
988 }
989 
990 /** ensures, that linear vars and coefs arrays can store at least num entries */
991 static
993  SCIP* scip, /**< SCIP data structure */
994  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
995  int num /**< minimum number of entries to store */
996  )
997 {
998  assert(scip != NULL);
999  assert(consdata != NULL);
1000  assert(consdata->nlinvars <= consdata->linvarssize);
1001 
1002  if( num > consdata->linvarssize )
1003  {
1004  int newsize;
1005 
1006  newsize = SCIPcalcMemGrowSize(scip, num);
1007  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1008  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1009  if( consdata->lineventdata != NULL )
1010  {
1011  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1012  }
1013  consdata->linvarssize = newsize;
1014  }
1015  assert(num <= consdata->linvarssize);
1016 
1017  return SCIP_OKAY;
1018 }
1019 
1020 /** ensures, that quadratic variable terms array can store at least num entries */
1021 static
1023  SCIP* scip, /**< SCIP data structure */
1024  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1025  int num /**< minimum number of entries to store */
1026  )
1027 {
1028  assert(scip != NULL);
1029  assert(consdata != NULL);
1030  assert(consdata->nquadvars <= consdata->quadvarssize);
1031 
1032  if( num > consdata->quadvarssize )
1033  {
1034  int newsize;
1035 
1036  newsize = SCIPcalcMemGrowSize(scip, num);
1037  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->quadvarterms, consdata->quadvarssize, newsize) );
1038  consdata->quadvarssize = newsize;
1039  }
1040  assert(num <= consdata->quadvarssize);
1041 
1042  return SCIP_OKAY;
1043 }
1044 
1045 /** ensures, that adjacency array can store at least num entries */
1046 static
1048  SCIP* scip, /**< SCIP data structure */
1049  SCIP_QUADVARTERM* quadvarterm, /**< quadratic variable term */
1050  int num /**< minimum number of entries to store */
1051  )
1052 {
1053  assert(scip != NULL);
1054  assert(quadvarterm != NULL);
1055  assert(quadvarterm->nadjbilin <= quadvarterm->adjbilinsize);
1056 
1057  if( num > quadvarterm->adjbilinsize )
1058  {
1059  int newsize;
1060 
1061  newsize = SCIPcalcMemGrowSize(scip, num);
1062  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvarterm->adjbilin, quadvarterm->adjbilinsize, newsize) );
1063  quadvarterm->adjbilinsize = newsize;
1064  }
1065  assert(num <= quadvarterm->adjbilinsize);
1066 
1067  return SCIP_OKAY;
1068 }
1069 
1070 /** ensures, that bilinear term arrays can store at least num entries */
1071 static
1073  SCIP* scip, /**< SCIP data structure */
1074  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1075  int num /**< minimum number of entries to store */
1076  )
1077 {
1078  assert(scip != NULL);
1079  assert(consdata != NULL);
1080  assert(consdata->nbilinterms <= consdata->bilintermssize);
1081 
1082  if( num > consdata->bilintermssize )
1083  {
1084  int newsize;
1085 
1086  newsize = SCIPcalcMemGrowSize(scip, num);
1087  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize, newsize) );
1088  consdata->bilintermssize = newsize;
1089  }
1090  assert(num <= consdata->bilintermssize);
1091 
1092  return SCIP_OKAY;
1093 }
1094 
1095 /** creates empty constraint data structure */
1096 static
1098  SCIP* scip, /**< SCIP data structure */
1099  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1100  )
1101 {
1102  assert(scip != NULL);
1103  assert(consdata != NULL);
1104 
1105  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1106  BMSclearMemory(*consdata);
1107 
1108  (*consdata)->lhs = -SCIPinfinity(scip);
1109  (*consdata)->rhs = SCIPinfinity(scip);
1110 
1111  (*consdata)->linvarssorted = TRUE;
1112  (*consdata)->linvarsmerged = TRUE;
1113  (*consdata)->quadvarssorted = TRUE;
1114  (*consdata)->quadvarsmerged = TRUE;
1115  (*consdata)->bilinsorted = TRUE;
1116  (*consdata)->bilinmerged = TRUE;
1117 
1118  (*consdata)->isremovedfixings = TRUE;
1119  (*consdata)->ispropagated = TRUE;
1120  (*consdata)->initialmerge = FALSE;
1121 
1122  (*consdata)->linvar_maydecrease = -1;
1123  (*consdata)->linvar_mayincrease = -1;
1124 
1125  (*consdata)->minlinactivity = SCIP_INVALID;
1126  (*consdata)->maxlinactivity = SCIP_INVALID;
1127  (*consdata)->minlinactivityinf = -1;
1128  (*consdata)->maxlinactivityinf = -1;
1129 
1130  return SCIP_OKAY;
1131 }
1132 
1133 /** creates constraint data structure */
1134 static
1136  SCIP* scip, /**< SCIP data structure */
1137  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1138  SCIP_Real lhs, /**< left hand side of constraint */
1139  SCIP_Real rhs, /**< right hand side of constraint */
1140  int nlinvars, /**< number of linear variables */
1141  SCIP_VAR** linvars, /**< array of linear variables */
1142  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1143  int nquadvars, /**< number of quadratic variables */
1144  SCIP_QUADVARTERM* quadvarterms, /**< array of quadratic variable terms */
1145  int nbilinterms, /**< number of bilinear terms */
1146  SCIP_BILINTERM* bilinterms, /**< array of bilinear terms */
1147  SCIP_Bool capturevars /**< whether we should capture variables */
1148  )
1149 {
1150  int i;
1151 
1152  assert(scip != NULL);
1153  assert(consdata != NULL);
1154 
1155  assert(nlinvars == 0 || linvars != NULL);
1156  assert(nlinvars == 0 || lincoefs != NULL);
1157  assert(nquadvars == 0 || quadvarterms != NULL);
1158  assert(nbilinterms == 0 || bilinterms != NULL);
1159 
1160  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1161  BMSclearMemory(*consdata);
1162 
1163  (*consdata)->minlinactivity = SCIP_INVALID;
1164  (*consdata)->maxlinactivity = SCIP_INVALID;
1165  (*consdata)->minlinactivityinf = -1;
1166  (*consdata)->maxlinactivityinf = -1;
1167 
1168  (*consdata)->lhs = lhs;
1169  (*consdata)->rhs = rhs;
1170 
1171  if( nlinvars > 0 )
1172  {
1173  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1174  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1175  (*consdata)->nlinvars = nlinvars;
1176  (*consdata)->linvarssize = nlinvars;
1177 
1178  if( capturevars )
1179  for( i = 0; i < nlinvars; ++i )
1180  {
1181  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1182  }
1183  }
1184  else
1185  {
1186  (*consdata)->linvarssorted = TRUE;
1187  (*consdata)->linvarsmerged = TRUE;
1188  (*consdata)->minlinactivity = 0.0;
1189  (*consdata)->maxlinactivity = 0.0;
1190  (*consdata)->minlinactivityinf = 0;
1191  (*consdata)->maxlinactivityinf = 0;
1192  }
1193 
1194  if( nquadvars > 0 )
1195  {
1196  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms, quadvarterms, nquadvars) );
1197 
1198  for( i = 0; i < nquadvars; ++i )
1199  {
1200  (*consdata)->quadvarterms[i].eventdata = NULL;
1201  if( quadvarterms[i].nadjbilin )
1202  {
1203  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms[i].adjbilin, quadvarterms[i].adjbilin, quadvarterms[i].nadjbilin) );
1204  (*consdata)->quadvarterms[i].adjbilinsize = quadvarterms[i].nadjbilin;
1205  }
1206  else
1207  {
1208  assert((*consdata)->quadvarterms[i].nadjbilin == 0);
1209  (*consdata)->quadvarterms[i].adjbilin = NULL;
1210  (*consdata)->quadvarterms[i].adjbilinsize = 0;
1211  }
1212  if( capturevars )
1213  {
1214  SCIP_CALL( SCIPcaptureVar(scip, quadvarterms[i].var) );
1215  }
1216  }
1217 
1218  (*consdata)->nquadvars = nquadvars;
1219  (*consdata)->quadvarssize = nquadvars;
1220  SCIPintervalSetEmpty(&(*consdata)->quadactivitybounds);
1221  }
1222  else
1223  {
1224  (*consdata)->quadvarssorted = TRUE;
1225  (*consdata)->quadvarsmerged = TRUE;
1226  SCIPintervalSet(&(*consdata)->quadactivitybounds, 0.0);
1227  }
1228 
1229  if( nbilinterms > 0 )
1230  {
1231  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->bilinterms, bilinterms, nbilinterms) );
1232  (*consdata)->nbilinterms = nbilinterms;
1233  (*consdata)->bilintermssize = nbilinterms;
1234  }
1235  else
1236  {
1237  (*consdata)->bilinsorted = TRUE;
1238  (*consdata)->bilinmerged = TRUE;
1239  }
1240 
1241  (*consdata)->linvar_maydecrease = -1;
1242  (*consdata)->linvar_mayincrease = -1;
1243 
1244  (*consdata)->activity = SCIP_INVALID;
1245  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1246  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1247 
1248  return SCIP_OKAY;
1249 }
1250 
1251 /** frees constraint data structure */
1252 static
1254  SCIP* scip, /**< SCIP data structure */
1255  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1256  )
1257 {
1258  int i;
1259 
1260  assert(scip != NULL);
1261  assert(consdata != NULL);
1262  assert(*consdata != NULL);
1263 
1264  /* free sepa arrays, may exists if constraint is deleted in solving stage */
1265  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepaquadvars, (*consdata)->nquadvars);
1266  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepabilinvar2pos, (*consdata)->nbilinterms);
1267 
1268  /* release linear variables and free linear part */
1269  if( (*consdata)->linvarssize > 0 )
1270  {
1271  for( i = 0; i < (*consdata)->nlinvars; ++i )
1272  {
1273  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1274  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1275  }
1276  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1277  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1278  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1279  }
1280  assert((*consdata)->linvars == NULL);
1281  assert((*consdata)->lincoefs == NULL);
1282  assert((*consdata)->lineventdata == NULL);
1283 
1284  /* release quadratic variables and free quadratic variable term part */
1285  for( i = 0; i < (*consdata)->nquadvars; ++i )
1286  {
1287  assert((*consdata)->quadvarterms[i].eventdata == NULL); /* variable events should have been dropped earlier */
1288  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms[i].adjbilin, (*consdata)->quadvarterms[i].adjbilinsize);
1289  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->quadvarterms[i].var) );
1290  }
1291  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms, (*consdata)->quadvarssize);
1292 
1293  /* free bilinear terms */
1294  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilinterms, (*consdata)->bilintermssize);
1295 
1296  /* free nonlinear row representation */
1297  if( (*consdata)->nlrow != NULL )
1298  {
1299  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1300  }
1301 
1302  SCIPfreeBlockMemory(scip, consdata);
1303  *consdata = NULL;
1304 
1305  return SCIP_OKAY;
1306 }
1307 
1308 /** sorts linear part of constraint data */
1309 static
1311  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1312  )
1313 {
1314  assert(consdata != NULL);
1315 
1316  if( consdata->linvarssorted )
1317  return;
1318 
1319  if( consdata->nlinvars <= 1 )
1320  {
1321  consdata->linvarssorted = TRUE;
1322  return;
1323  }
1324 
1325  if( consdata->lineventdata == NULL )
1326  {
1327  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1328  }
1329  else
1330  {
1331  int i;
1332 
1333  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1334 
1335  /* update variable indices in event data */
1336  for( i = 0; i < consdata->nlinvars; ++i )
1337  if( consdata->lineventdata[i] != NULL )
1338  consdata->lineventdata[i]->varidx = i;
1339  }
1340 
1341  consdata->linvarssorted = TRUE;
1342 }
1343 
1344 #if 0 /* no-one needs this routine currently */
1345 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1346 static
1347 int consdataFindLinearVar(
1348  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1349  SCIP_VAR* var /**< variable to search for */
1350  )
1351 {
1352  int pos;
1353 
1354  assert(consdata != NULL);
1355  assert(var != NULL);
1356 
1357  if( consdata->nlinvars == 0 )
1358  return -1;
1359 
1360  consdataSortLinearVars(consdata);
1361 
1362  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1363  pos = -1;
1364 
1365  return pos;
1366 }
1367 #endif
1368 
1369 /** index comparison method for quadratic variable terms: compares two indices of the quadratic variable set in the quadratic constraint */
1370 static
1371 SCIP_DECL_SORTINDCOMP(quadVarTermComp)
1372 { /*lint --e{715}*/
1373  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1374 
1375  assert(consdata != NULL);
1376  assert(0 <= ind1 && ind1 < consdata->nquadvars);
1377  assert(0 <= ind2 && ind2 < consdata->nquadvars);
1378 
1379  return SCIPvarCompare(consdata->quadvarterms[ind1].var, consdata->quadvarterms[ind2].var);
1380 }
1381 
1382 /** sorting of quadratic variable terms */
1383 static
1385  SCIP* scip, /**< SCIP data structure */
1386  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1387  )
1388 {
1389  int* perm;
1390  int i;
1391  int nexti;
1392  int v;
1393  SCIP_QUADVARTERM quadterm;
1394 
1395  assert(scip != NULL);
1396  assert(consdata != NULL);
1397 
1398  if( consdata->quadvarssorted )
1399  return SCIP_OKAY;
1400 
1401  if( consdata->nquadvars == 0 )
1402  {
1403  consdata->quadvarssorted = TRUE;
1404  return SCIP_OKAY;
1405  }
1406 
1407  /* get temporary memory to store the sorted permutation */
1408  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nquadvars) );
1409 
1410  /* call bubble sort */
1411  SCIPsort(perm, quadVarTermComp, (void*)consdata, consdata->nquadvars);
1412 
1413  /* permute the quadratic variable terms according to the resulting permutation */
1414  for( v = 0; v < consdata->nquadvars; ++v )
1415  {
1416  if( perm[v] != v )
1417  {
1418  quadterm = consdata->quadvarterms[v];
1419 
1420  i = v;
1421  do
1422  {
1423  assert(0 <= perm[i] && perm[i] < consdata->nquadvars);
1424  assert(perm[i] != i);
1425  consdata->quadvarterms[i] = consdata->quadvarterms[perm[i]];
1426  if( consdata->quadvarterms[i].eventdata != NULL )
1427  {
1428  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1429  }
1430  nexti = perm[i];
1431  perm[i] = i;
1432  i = nexti;
1433  }
1434  while( perm[i] != v );
1435  consdata->quadvarterms[i] = quadterm;
1436  if( consdata->quadvarterms[i].eventdata != NULL )
1437  {
1438  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1439  }
1440  perm[i] = i;
1441  }
1442  }
1443  consdata->quadvarssorted = TRUE;
1444 
1445  /* free temporary memory */
1446  SCIPfreeBufferArray(scip, &perm);
1447 
1448  return SCIP_OKAY;
1449 }
1450 
1451 /** returns the position of variable in the quadratic variable terms array of a constraint, or -1 if not found */
1452 static
1454  SCIP* scip, /**< SCIP data structure */
1455  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1456  SCIP_VAR* var, /**< variable to search for */
1457  int* pos /**< buffer where to store position of var in quadvarterms array, or -1 if not found */
1458  )
1459 {
1460  int left;
1461  int right;
1462  int cmpres;
1463 
1464  assert(consdata != NULL);
1465  assert(var != NULL);
1466  assert(pos != NULL);
1467 
1468  if( consdata->nquadvars == 0 )
1469  {
1470  *pos = -1;
1471  return SCIP_OKAY;
1472  }
1473 
1474  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
1475 
1476  left = 0;
1477  right = consdata->nquadvars - 1;
1478  while( left <= right )
1479  {
1480  int middle;
1481 
1482  middle = (left+right)/2;
1483  assert(0 <= middle && middle < consdata->nquadvars);
1484 
1485  cmpres = SCIPvarCompare(var, consdata->quadvarterms[middle].var);
1486 
1487  if( cmpres < 0 )
1488  right = middle - 1;
1489  else if( cmpres > 0 )
1490  left = middle + 1;
1491  else
1492  {
1493  *pos = middle;
1494  return SCIP_OKAY;
1495  }
1496  }
1497  assert(left == right+1);
1498 
1499  *pos = -1;
1500 
1501  return SCIP_OKAY;
1502 }
1503 
1504 /** index comparison method for bilinear terms: compares two index pairs of the bilinear term set in the quadratic constraint */
1505 static
1507 { /*lint --e{715}*/
1508  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1509  int var1cmp;
1510 
1511  assert(consdata != NULL);
1512  assert(0 <= ind1 && ind1 < consdata->nbilinterms);
1513  assert(0 <= ind2 && ind2 < consdata->nbilinterms);
1514 
1515  var1cmp = SCIPvarCompare(consdata->bilinterms[ind1].var1, consdata->bilinterms[ind2].var1);
1516  if( var1cmp != 0 )
1517  return var1cmp;
1518 
1519  return SCIPvarCompare(consdata->bilinterms[ind1].var2, consdata->bilinterms[ind2].var2);
1520 }
1521 
1522 /** sorting of bilinear terms */
1523 static
1525  SCIP* scip, /**< SCIP data structure */
1526  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1527  )
1528 {
1529  int* perm;
1530  int* invperm;
1531  int i;
1532  int nexti;
1533  int v;
1534  SCIP_BILINTERM bilinterm;
1535 
1536  assert(scip != NULL);
1537  assert(consdata != NULL);
1538 
1539  if( consdata->bilinsorted )
1540  return SCIP_OKAY;
1541 
1542  if( consdata->nbilinterms == 0 )
1543  {
1544  consdata->bilinsorted = TRUE;
1545  return SCIP_OKAY;
1546  }
1547 
1548  /* get temporary memory to store the sorted permutation and the inverse permutation */
1549  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nbilinterms) );
1550  SCIP_CALL( SCIPallocBufferArray(scip, &invperm, consdata->nbilinterms) );
1551 
1552  /* call bubble sort */
1553  SCIPsort(perm, bilinTermComp, (void*)consdata, consdata->nbilinterms);
1554 
1555  /* compute inverted permutation */
1556  for( v = 0; v < consdata->nbilinterms; ++v )
1557  {
1558  assert(0 <= perm[v] && perm[v] < consdata->nbilinterms);
1559  invperm[perm[v]] = v;
1560  }
1561 
1562  /* permute the bilinear terms according to the resulting permutation */
1563  for( v = 0; v < consdata->nbilinterms; ++v )
1564  {
1565  if( perm[v] != v )
1566  {
1567  bilinterm = consdata->bilinterms[v];
1568 
1569  i = v;
1570  do
1571  {
1572  assert(0 <= perm[i] && perm[i] < consdata->nbilinterms);
1573  assert(perm[i] != i);
1574  consdata->bilinterms[i] = consdata->bilinterms[perm[i]];
1575  nexti = perm[i];
1576  perm[i] = i;
1577  i = nexti;
1578  }
1579  while( perm[i] != v );
1580  consdata->bilinterms[i] = bilinterm;
1581  perm[i] = i;
1582  }
1583  }
1584 
1585  /* update the adjacency information in the quadratic variable terms */
1586  for( v = 0; v < consdata->nquadvars; ++v )
1587  for( i = 0; i < consdata->quadvarterms[v].nadjbilin; ++i )
1588  consdata->quadvarterms[v].adjbilin[i] = invperm[consdata->quadvarterms[v].adjbilin[i]];
1589 
1590  consdata->bilinsorted = TRUE;
1591 
1592  /* free temporary memory */
1593  SCIPfreeBufferArray(scip, &perm);
1594  SCIPfreeBufferArray(scip, &invperm);
1595 
1596  return SCIP_OKAY;
1597 }
1598 
1599 /** moves a linear variable from one position to another */
1600 static
1602  SCIP_CONSDATA* consdata, /**< constraint data */
1603  int oldpos, /**< position of variable that shall be moved */
1604  int newpos /**< new position of variable */
1605  )
1606 {
1607  assert(consdata != NULL);
1608  assert(oldpos >= 0);
1609  assert(oldpos < consdata->nlinvars);
1610  assert(newpos >= 0);
1611  assert(newpos < consdata->linvarssize);
1612 
1613  if( newpos == oldpos )
1614  return;
1615 
1616  consdata->linvars [newpos] = consdata->linvars [oldpos];
1617  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1618 
1619  if( consdata->lineventdata != NULL )
1620  {
1621  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1622 
1623  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1624  consdata->lineventdata[newpos]->varidx = newpos;
1625 
1626  consdata->lineventdata[oldpos] = NULL;
1627  }
1628 
1629  consdata->linvarssorted = FALSE;
1630 }
1631 
1632 /** moves a quadratic variable from one position to another */
1633 static
1635  SCIP_CONSDATA* consdata, /**< constraint data */
1636  int oldpos, /**< position of variable that shall be moved */
1637  int newpos /**< new position of variable */
1638  )
1639 {
1640  assert(consdata != NULL);
1641  assert(oldpos >= 0);
1642  assert(oldpos < consdata->nquadvars);
1643  assert(newpos >= 0);
1644  assert(newpos < consdata->quadvarssize);
1645 
1646  if( newpos == oldpos )
1647  return;
1648 
1649  assert(newpos >= consdata->nquadvars || consdata->quadvarterms[newpos].eventdata == NULL);
1650 
1651  consdata->quadvarterms[newpos] = consdata->quadvarterms[oldpos];
1652 
1653  if( consdata->quadvarterms[newpos].eventdata != NULL )
1654  {
1655  consdata->quadvarterms[newpos].eventdata->varidx = -newpos-1;
1656  consdata->quadvarterms[oldpos].eventdata = NULL;
1657  }
1658 
1659  consdata->quadvarssorted = FALSE;
1660 }
1661 
1662 /** adds linear coefficient in quadratic constraint */
1663 static
1665  SCIP* scip, /**< SCIP data structure */
1666  SCIP_CONS* cons, /**< quadratic constraint */
1667  SCIP_VAR* var, /**< variable of constraint entry */
1668  SCIP_Real coef /**< coefficient of constraint entry */
1669  )
1670 {
1671  SCIP_CONSDATA* consdata;
1672  SCIP_Bool transformed;
1673 
1674  assert(scip != NULL);
1675  assert(cons != NULL);
1676  assert(var != NULL);
1677 
1678  /* ignore coefficient if it is nearly zero */
1679  if( SCIPisZero(scip, coef) )
1680  return SCIP_OKAY;
1681 
1682  consdata = SCIPconsGetData(cons);
1683  assert(consdata != NULL);
1684 
1685  /* are we in the transformed problem? */
1686  transformed = SCIPconsIsTransformed(cons);
1687 
1688  /* always use transformed variables in transformed constraints */
1689  if( transformed )
1690  {
1691  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1692  }
1693  assert(var != NULL);
1694  assert(transformed == SCIPvarIsTransformed(var));
1695 
1696  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1697  consdata->linvars [consdata->nlinvars] = var;
1698  consdata->lincoefs[consdata->nlinvars] = coef;
1699 
1700  ++consdata->nlinvars;
1701 
1702  /* catch variable events */
1703  if( consdata->lineventdata != NULL )
1704  {
1705  SCIP_CONSHDLR* conshdlr;
1706  SCIP_CONSHDLRDATA* conshdlrdata;
1707 
1708  /* get event handler */
1709  conshdlr = SCIPconsGetHdlr(cons);
1710  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1711  assert(conshdlrdata != NULL);
1712  assert(conshdlrdata->eventhdlr != NULL);
1713 
1714  consdata->lineventdata[consdata->nlinvars-1] = NULL;
1715 
1716  /* catch bound change events of variable */
1717  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nlinvars-1) );
1718  }
1719 
1720  /* invalidate activity information */
1721  consdata->activity = SCIP_INVALID;
1722  consdata->minlinactivity = SCIP_INVALID;
1723  consdata->maxlinactivity = SCIP_INVALID;
1724  consdata->minlinactivityinf = -1;
1725  consdata->maxlinactivityinf = -1;
1726 
1727  /* invalidate nonlinear row */
1728  if( consdata->nlrow != NULL )
1729  {
1730  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1731  }
1732 
1733  /* install rounding locks for new variable */
1734  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1735 
1736  /* capture new variable */
1737  SCIP_CALL( SCIPcaptureVar(scip, var) );
1738 
1739  consdata->ispropagated = FALSE;
1740  consdata->ispresolved = FALSE;
1741  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
1742  if( consdata->nlinvars == 1 )
1743  consdata->linvarssorted = TRUE;
1744  else
1745  consdata->linvarssorted = consdata->linvarssorted && (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1746  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1747  consdata->linvarsmerged = FALSE;
1748 
1749  return SCIP_OKAY;
1750 }
1751 
1752 /** deletes linear coefficient at given position from quadratic constraint data */
1753 static
1755  SCIP* scip, /**< SCIP data structure */
1756  SCIP_CONS* cons, /**< quadratic constraint */
1757  int pos /**< position of coefficient to delete */
1758  )
1759 {
1760  SCIP_CONSDATA* consdata;
1761  SCIP_VAR* var;
1762  SCIP_Real coef;
1763 
1764  assert(scip != NULL);
1765  assert(cons != NULL);
1766 
1767  consdata = SCIPconsGetData(cons);
1768  assert(consdata != NULL);
1769  assert(0 <= pos && pos < consdata->nlinvars);
1770 
1771  var = consdata->linvars[pos];
1772  coef = consdata->lincoefs[pos];
1773  assert(var != NULL);
1774 
1775  /* remove rounding locks for deleted variable */
1776  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1777 
1778  /* if we catch variable events, drop the events on the variable */
1779  if( consdata->lineventdata != NULL )
1780  {
1781  SCIP_CONSHDLR* conshdlr;
1782  SCIP_CONSHDLRDATA* conshdlrdata;
1783 
1784  /* get event handler */
1785  conshdlr = SCIPconsGetHdlr(cons);
1786  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1787  assert(conshdlrdata != NULL);
1788  assert(conshdlrdata->eventhdlr != NULL);
1789 
1790  /* drop bound change events of variable */
1791  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1792  }
1793 
1794  /* release variable */
1795  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
1796 
1797  /* move the last variable to the free slot */
1798  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
1799 
1800  --consdata->nlinvars;
1801 
1802  /* invalidate activity */
1803  consdata->activity = SCIP_INVALID;
1804  consdata->minlinactivity = SCIP_INVALID;
1805  consdata->maxlinactivity = SCIP_INVALID;
1806  consdata->minlinactivityinf = -1;
1807  consdata->maxlinactivityinf = -1;
1808 
1809  /* invalidate nonlinear row */
1810  if( consdata->nlrow != NULL )
1811  {
1812  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1813  }
1814 
1815  consdata->ispropagated = FALSE;
1816  consdata->ispresolved = FALSE;
1817 
1818  return SCIP_OKAY;
1819 }
1820 
1821 /** changes linear coefficient value at given position of quadratic constraint */
1822 static
1824  SCIP* scip, /**< SCIP data structure */
1825  SCIP_CONS* cons, /**< quadratic constraint */
1826  int pos, /**< position of linear coefficient to change */
1827  SCIP_Real newcoef /**< new value of linear coefficient */
1828  )
1829 {
1830  SCIP_CONSHDLR* conshdlr;
1831  SCIP_CONSHDLRDATA* conshdlrdata;
1832  SCIP_CONSDATA* consdata;
1833  SCIP_VAR* var;
1834  SCIP_Real coef;
1835 
1836  assert(scip != NULL);
1837  assert(cons != NULL);
1838  assert(!SCIPisZero(scip, newcoef));
1839 
1840  conshdlrdata = NULL;
1841 
1842  consdata = SCIPconsGetData(cons);
1843  assert(consdata != NULL);
1844  assert(0 <= pos);
1845  assert(pos < consdata->nlinvars);
1846  assert(!SCIPisZero(scip, newcoef));
1847 
1848  var = consdata->linvars[pos];
1849  coef = consdata->lincoefs[pos];
1850  assert(var != NULL);
1851  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
1852 
1853  /* invalidate activity */
1854  consdata->activity = SCIP_INVALID;
1855  consdata->minlinactivity = SCIP_INVALID;
1856  consdata->maxlinactivity = SCIP_INVALID;
1857  consdata->minlinactivityinf = -1;
1858  consdata->maxlinactivityinf = -1;
1859 
1860  /* invalidate nonlinear row */
1861  if( consdata->nlrow != NULL )
1862  {
1863  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1864  }
1865 
1866  /* if necessary, remove the rounding locks and event catching of the variable */
1867  if( newcoef * coef < 0.0 )
1868  {
1869  if( SCIPconsIsLocked(cons) )
1870  {
1871  assert(SCIPconsIsTransformed(cons));
1872 
1873  /* remove rounding locks for variable with old coefficient */
1874  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1875  }
1876 
1877  if( consdata->lineventdata[pos] != NULL )
1878  {
1879  /* get event handler */
1880  conshdlr = SCIPconsGetHdlr(cons);
1881  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1882  assert(conshdlrdata != NULL);
1883  assert(conshdlrdata->eventhdlr != NULL);
1884 
1885  /* drop bound change events of variable */
1886  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1887  }
1888  }
1889 
1890  /* change the coefficient */
1891  consdata->lincoefs[pos] = newcoef;
1892 
1893  /* if necessary, install the rounding locks and event catching of the variable again */
1894  if( newcoef * coef < 0.0 )
1895  {
1896  if( SCIPconsIsLocked(cons) )
1897  {
1898  /* install rounding locks for variable with new coefficient */
1899  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
1900  }
1901 
1902  if( conshdlrdata != NULL )
1903  {
1904  /* catch bound change events of variable */
1905  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1906  }
1907  }
1908 
1909  consdata->ispropagated = FALSE;
1910  consdata->ispresolved = FALSE;
1911 
1912  return SCIP_OKAY;
1913 }
1914 
1915 /** adds quadratic variable term to quadratic constraint */
1916 static
1918  SCIP* scip, /**< SCIP data structure */
1919  SCIP_CONS* cons, /**< quadratic constraint */
1920  SCIP_VAR* var, /**< variable to add */
1921  SCIP_Real lincoef, /**< linear coefficient of variable */
1922  SCIP_Real sqrcoef, /**< square coefficient of variable */
1923  SCIP_Bool catchevents /**< whether we should catch variable events */
1924  )
1925 {
1926  SCIP_CONSDATA* consdata;
1927  SCIP_Bool transformed;
1928  SCIP_QUADVARTERM* quadvarterm;
1929 
1930  assert(scip != NULL);
1931  assert(cons != NULL);
1932  assert(var != NULL);
1933 
1934  consdata = SCIPconsGetData(cons);
1935  assert(consdata != NULL);
1936 
1937  /* are we in the transformed problem? */
1938  transformed = SCIPconsIsTransformed(cons);
1939 
1940  /* always use transformed variables in transformed constraints */
1941  if( transformed )
1942  {
1943  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1944  }
1945  assert(var != NULL);
1946  assert(transformed == SCIPvarIsTransformed(var));
1947 
1948  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars+1) );
1949 
1950  quadvarterm = &consdata->quadvarterms[consdata->nquadvars];
1951  quadvarterm->var = var;
1952  quadvarterm->lincoef = lincoef;
1953  quadvarterm->sqrcoef = sqrcoef;
1954  quadvarterm->adjbilinsize = 0;
1955  quadvarterm->nadjbilin = 0;
1956  quadvarterm->adjbilin = NULL;
1957  quadvarterm->eventdata = NULL;
1958 
1959  ++consdata->nquadvars;
1960 
1961  /* capture variable */
1962  SCIP_CALL( SCIPcaptureVar(scip, var) );
1963 
1964  /* catch variable events, if we do so */
1965  if( catchevents )
1966  {
1967  SCIP_CONSHDLR* conshdlr;
1968  SCIP_CONSHDLRDATA* conshdlrdata;
1969 
1970  /* get event handler */
1971  conshdlr = SCIPconsGetHdlr(cons);
1972  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1973  assert(conshdlrdata != NULL);
1974  assert(conshdlrdata->eventhdlr != NULL);
1975 
1976  /* catch bound change events of variable */
1977  SCIP_CALL( catchQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nquadvars-1) );
1978  }
1979 
1980  /* invalidate activity information */
1981  consdata->activity = SCIP_INVALID;
1982  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
1983 
1984  /* invalidate nonlinear row */
1985  if( consdata->nlrow != NULL )
1986  {
1987  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1988  }
1989 
1990  /* install rounding locks for new variable */
1991  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
1992 
1993  consdata->ispropagated = FALSE;
1994  consdata->ispresolved = FALSE;
1995  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
1996  if( consdata->nquadvars == 1 )
1997  consdata->quadvarssorted = TRUE;
1998  else
1999  consdata->quadvarssorted = consdata->quadvarssorted && (SCIPvarCompare(consdata->quadvarterms[consdata->nquadvars-2].var, consdata->quadvarterms[consdata->nquadvars-1].var) == -1);
2000  /* also set to FALSE if nquadvars == 1, since the new variable should be checked for linearity and other stuff in mergeAndClean ... */
2001  consdata->quadvarsmerged = FALSE;
2002 
2003  consdata->iscurvchecked = FALSE;
2004 
2005  return SCIP_OKAY;
2006 }
2007 
2008 /** deletes quadratic variable term at given position from quadratic constraint data */
2009 static
2011  SCIP* scip, /**< SCIP data structure */
2012  SCIP_CONS* cons, /**< quadratic constraint */
2013  int pos /**< position of term to delete */
2014  )
2015 {
2016  SCIP_CONSDATA* consdata;
2017  SCIP_VAR* var;
2018 
2019  assert(scip != NULL);
2020  assert(cons != NULL);
2021 
2022  consdata = SCIPconsGetData(cons);
2023  assert(consdata != NULL);
2024  assert(0 <= pos && pos < consdata->nquadvars);
2025 
2026  var = consdata->quadvarterms[pos].var;
2027  assert(var != NULL);
2028  assert(consdata->quadvarterms[pos].nadjbilin == 0);
2029 
2030  /* remove rounding locks for deleted variable */
2031  SCIP_CALL( unlockQuadraticVariable(scip, cons, var) );
2032 
2033  /* if we catch variable events, drop the events on the variable */
2034  if( consdata->quadvarterms[pos].eventdata != NULL )
2035  {
2036  SCIP_CONSHDLR* conshdlr;
2037  SCIP_CONSHDLRDATA* conshdlrdata;
2038 
2039  /* get event handler */
2040  conshdlr = SCIPconsGetHdlr(cons);
2041  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2042  assert(conshdlrdata != NULL);
2043  assert(conshdlrdata->eventhdlr != NULL);
2044 
2045  /* drop bound change events of variable */
2046  SCIP_CALL( dropQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2047  }
2048 
2049  /* release variable */
2050  SCIP_CALL( SCIPreleaseVar(scip, &consdata->quadvarterms[pos].var) );
2051 
2052  /* free adjacency array */
2053  SCIPfreeBlockMemoryArrayNull(scip, &consdata->quadvarterms[pos].adjbilin, consdata->quadvarterms[pos].adjbilinsize);
2054 
2055  /* move the last variable term to the free slot */
2056  consdataMoveQuadVarTerm(consdata, consdata->nquadvars-1, pos);
2057 
2058  --consdata->nquadvars;
2059 
2060  /* invalidate activity */
2061  consdata->activity = SCIP_INVALID;
2062  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2063 
2064  /* invalidate nonlinear row */
2065  if( consdata->nlrow != NULL )
2066  {
2067  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2068  }
2069 
2070  consdata->ispropagated = FALSE;
2071  consdata->ispresolved = FALSE;
2072  consdata->iscurvchecked = FALSE;
2073 
2074  return SCIP_OKAY;
2075 }
2076 
2077 /** replace variable in quadratic variable term at given position of quadratic constraint data
2078  * allows to replace x by coef*y+offset, thereby maintaining linear and square coefficients and bilinear terms */
2079 static
2081  SCIP* scip, /**< SCIP data structure */
2082  SCIP_CONS* cons, /**< quadratic constraint */
2083  int pos, /**< position of term to replace */
2084  SCIP_VAR* var, /**< new variable */
2085  SCIP_Real coef, /**< linear coefficient of new variable */
2086  SCIP_Real offset /**< offset of new variable */
2087  )
2088 {
2089  SCIP_CONSDATA* consdata;
2090  SCIP_QUADVARTERM* quadvarterm;
2091  SCIP_EVENTHDLR* eventhdlr;
2092  SCIP_BILINTERM* bilinterm;
2093  SCIP_Real constant;
2094 
2095  int i;
2096  SCIP_VAR* var2;
2097 
2098  consdata = SCIPconsGetData(cons);
2099  assert(consdata != NULL);
2100  assert(pos >= 0);
2101  assert(pos < consdata->nquadvars);
2102 
2103  quadvarterm = &consdata->quadvarterms[pos];
2104 
2105  /* remove rounding locks for old variable */
2106  SCIP_CALL( unlockQuadraticVariable(scip, cons, quadvarterm->var) );
2107 
2108  /* if we catch variable events, drop the events on the old variable */
2109  if( quadvarterm->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  eventhdlr = conshdlrdata->eventhdlr;
2121 
2122  /* drop bound change events of variable */
2123  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, pos) );
2124  }
2125  else
2126  {
2127  eventhdlr = NULL;
2128  }
2129 
2130  /* compute constant and put into lhs/rhs */
2131  constant = quadvarterm->lincoef * offset + quadvarterm->sqrcoef * offset * offset;
2132  if( constant != 0.0 )
2133  {
2134  /* maintain constant part */
2135  if( !SCIPisInfinity(scip, -consdata->lhs) )
2136  consdata->lhs -= constant;
2137  if( !SCIPisInfinity(scip, consdata->rhs) )
2138  consdata->rhs -= constant;
2139  }
2140 
2141  /* update linear and square coefficient */
2142  quadvarterm->lincoef *= coef;
2143  quadvarterm->lincoef += 2.0 * quadvarterm->sqrcoef * coef * offset;
2144  quadvarterm->sqrcoef *= coef * coef;
2145 
2146  /* update bilinear terms */
2147  for( i = 0; i < quadvarterm->nadjbilin; ++i )
2148  {
2149  bilinterm = &consdata->bilinterms[quadvarterm->adjbilin[i]];
2150 
2151  if( bilinterm->var1 == quadvarterm->var )
2152  {
2153  bilinterm->var1 = var;
2154  var2 = bilinterm->var2;
2155  }
2156  else
2157  {
2158  assert(bilinterm->var2 == quadvarterm->var);
2159  bilinterm->var2 = var;
2160  var2 = bilinterm->var1;
2161  }
2162 
2163  if( var == var2 )
2164  {
2165  /* looks like we actually have a square term here */
2166  quadvarterm->lincoef += bilinterm->coef * offset;
2167  quadvarterm->sqrcoef += bilinterm->coef * coef;
2168  /* deleting bilinear terms is expensive, since it requires updating adjacency information
2169  * thus, for now we just set the coefficient to 0.0 and clear in later when the bilinear terms are merged */
2170  bilinterm->coef = 0.0;
2171  continue;
2172  }
2173 
2174  /* swap var1 and var2 if they are in wrong order */
2175  if( SCIPvarCompare(bilinterm->var1, bilinterm->var2) > 0 )
2176  {
2177  SCIP_VAR* tmp;
2178  tmp = bilinterm->var1;
2179  bilinterm->var1 = bilinterm->var2;
2180  bilinterm->var2 = tmp;
2181  }
2182  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2183 
2184  if( offset != 0.0 )
2185  {
2186  /* need to find var2 and add offset*bilinterm->coef to linear coefficient */
2187  int var2pos;
2188 
2189  var2pos = 0;
2190  while( consdata->quadvarterms[var2pos].var != var2 )
2191  {
2192  ++var2pos;
2193  assert(var2pos < consdata->nquadvars);
2194  }
2195 
2196  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2197  }
2198 
2199  bilinterm->coef *= coef;
2200  }
2201 
2202  /* release old variable */
2203  SCIP_CALL( SCIPreleaseVar(scip, &quadvarterm->var) );
2204 
2205  /* set new variable */
2206  quadvarterm->var = var;
2207 
2208  /* capture new variable */
2209  SCIP_CALL( SCIPcaptureVar(scip, quadvarterm->var) );
2210 
2211  /* catch variable events, if we do so */
2212  if( eventhdlr != NULL )
2213  {
2214  /* catch bound change events of variable */
2215  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, pos) );
2216  }
2217 
2218  /* invalidate activity information */
2219  consdata->activity = SCIP_INVALID;
2220  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2221 
2222  /* invalidate nonlinear row */
2223  if( consdata->nlrow != NULL )
2224  {
2225  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2226  }
2227 
2228  /* install rounding locks for new variable */
2229  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2230 
2231  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
2232  consdata->quadvarssorted = (consdata->nquadvars == 1);
2233  consdata->quadvarsmerged = FALSE;
2234  consdata->bilinsorted &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2235  consdata->bilinmerged &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2236 
2237  consdata->ispropagated = FALSE;
2238  consdata->ispresolved = FALSE;
2239  consdata->iscurvchecked = FALSE;
2240 
2241  return SCIP_OKAY;
2242 }
2243 
2244 /** adds a bilinear term to quadratic constraint */
2245 static
2247  SCIP* scip, /**< SCIP data structure */
2248  SCIP_CONS* cons, /**< quadratic constraint */
2249  int var1pos, /**< position of first variable in quadratic variables array */
2250  int var2pos, /**< position of second variable in quadratic variables array */
2251  SCIP_Real coef /**< coefficient of bilinear term */
2252  )
2253 {
2254  SCIP_CONSDATA* consdata;
2255  SCIP_BILINTERM* bilinterm;
2256 
2257  assert(scip != NULL);
2258  assert(cons != NULL);
2259 
2260  if( var1pos == var2pos )
2261  {
2262  SCIPerrorMessage("tried to add bilinear term where both variables are the same\n");
2263  return SCIP_INVALIDDATA;
2264  }
2265 
2266  consdata = SCIPconsGetData(cons);
2267  assert(consdata != NULL);
2268 
2269  assert(var1pos >= 0);
2270  assert(var1pos < consdata->nquadvars);
2271  assert(var2pos >= 0);
2272  assert(var2pos < consdata->nquadvars);
2273 
2274  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nbilinterms + 1) );
2275 
2276  bilinterm = &consdata->bilinterms[consdata->nbilinterms];
2277  if( SCIPvarCompare(consdata->quadvarterms[var1pos].var, consdata->quadvarterms[var2pos].var) < 0 )
2278  {
2279  bilinterm->var1 = consdata->quadvarterms[var1pos].var;
2280  bilinterm->var2 = consdata->quadvarterms[var2pos].var;
2281  }
2282  else
2283  {
2284  bilinterm->var1 = consdata->quadvarterms[var2pos].var;
2285  bilinterm->var2 = consdata->quadvarterms[var1pos].var;
2286  }
2287  bilinterm->coef = coef;
2288 
2289  if( bilinterm->var1 == bilinterm->var2 )
2290  {
2291  SCIPerrorMessage("tried to add bilinear term where both variables are the same, but appear at different positions in quadvarterms array\n");
2292  return SCIP_INVALIDDATA;
2293  }
2294  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2295 
2296  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var1pos], consdata->quadvarterms[var1pos].nadjbilin + 1) );
2297  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var2pos], consdata->quadvarterms[var2pos].nadjbilin + 1) );
2298 
2299  consdata->quadvarterms[var1pos].adjbilin[consdata->quadvarterms[var1pos].nadjbilin] = consdata->nbilinterms;
2300  consdata->quadvarterms[var2pos].adjbilin[consdata->quadvarterms[var2pos].nadjbilin] = consdata->nbilinterms;
2301  ++consdata->quadvarterms[var1pos].nadjbilin;
2302  ++consdata->quadvarterms[var2pos].nadjbilin;
2303 
2304  ++consdata->nbilinterms;
2305 
2306  /* invalidate activity information */
2307  consdata->activity = SCIP_INVALID;
2308  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2309 
2310  /* invalidate nonlinear row */
2311  if( consdata->nlrow != NULL )
2312  {
2313  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2314  }
2315 
2316  consdata->ispropagated = FALSE;
2317  consdata->ispresolved = FALSE;
2318  if( consdata->nbilinterms == 1 )
2319  {
2320  consdata->bilinsorted = TRUE;
2321  consdata->bilinmerged = TRUE;
2322  }
2323  else
2324  {
2325  consdata->bilinsorted = consdata->bilinsorted
2326  && (bilinTermComp(consdata, consdata->nbilinterms-2, consdata->nbilinterms-1) >= 0);
2327  consdata->bilinmerged = FALSE;
2328  }
2329 
2330  consdata->iscurvchecked = FALSE;
2331 
2332  return SCIP_OKAY;
2333 }
2334 
2335 /** removes a set of bilinear terms and updates adjacency information in quad var terms
2336  * Note: this function sorts the given array termposs */
2337 static
2339  SCIP* scip, /**< SCIP data structure */
2340  SCIP_CONS* cons, /**< quadratic constraint */
2341  int nterms, /**< number of terms to delete */
2342  int* termposs /**< indices of terms to delete */
2343  )
2344 {
2345  SCIP_CONSDATA* consdata;
2346  int* newpos;
2347  int i;
2348  int j;
2349  int offset;
2350 
2351  assert(scip != NULL);
2352  assert(cons != NULL);
2353  assert(nterms == 0 || termposs != NULL);
2354 
2355  if( nterms == 0 )
2356  return SCIP_OKAY;
2357 
2358  consdata = SCIPconsGetData(cons);
2359  assert(consdata != NULL);
2360 
2361  SCIPsortInt(termposs, nterms);
2362 
2363  SCIP_CALL( SCIPallocBufferArray(scip, &newpos, consdata->nbilinterms) );
2364 
2365  i = 0;
2366  offset = 0;
2367  for( j = 0; j < consdata->nbilinterms; ++j )
2368  {
2369  /* if j'th term is deleted, increase offset and continue */
2370  if( i < nterms && j == termposs[i] )
2371  {
2372  ++offset;
2373  ++i;
2374  newpos[j] = -1;
2375  continue;
2376  }
2377 
2378  /* otherwise, move it forward and remember new position */
2379  if( offset > 0 )
2380  consdata->bilinterms[j-offset] = consdata->bilinterms[j];
2381  newpos[j] = j - offset;
2382  }
2383  assert(offset == nterms);
2384 
2385  /* update adjacency and activity information in quad var terms */
2386  for( i = 0; i < consdata->nquadvars; ++i )
2387  {
2388  offset = 0;
2389  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2390  {
2391  assert(consdata->quadvarterms[i].adjbilin[j] < consdata->nbilinterms);
2392  if( newpos[consdata->quadvarterms[i].adjbilin[j]] == -1 )
2393  {
2394  /* corresponding bilinear term was deleted, thus increase offset */
2395  ++offset;
2396  }
2397  else
2398  {
2399  /* update index of j'th bilinear term and store at position j-offset */
2400  consdata->quadvarterms[i].adjbilin[j-offset] = newpos[consdata->quadvarterms[i].adjbilin[j]];
2401  }
2402  }
2403  consdata->quadvarterms[i].nadjbilin -= offset;
2404  /* some bilinear term was removed, so invalidate activity bounds */
2405  }
2406 
2407  consdata->nbilinterms -= nterms;
2408 
2409  SCIPfreeBufferArray(scip, &newpos);
2410 
2411  /* some quad vars may be linear now */
2412  consdata->quadvarsmerged = FALSE;
2413 
2414  consdata->ispropagated = FALSE;
2415  consdata->ispresolved = FALSE;
2416  consdata->iscurvchecked = FALSE;
2417 
2418  /* invalidate activity */
2419  consdata->activity = SCIP_INVALID;
2420  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2421 
2422  /* invalidate nonlinear row */
2423  if( consdata->nlrow != NULL )
2424  {
2425  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2426  }
2427 
2428  return SCIP_OKAY;
2429 }
2430 
2431 /* merges quad var terms that correspond to the same variable and does additional cleanup
2432  * if a quadratic variable terms is actually linear, makes a linear term out of it
2433  * also replaces squares of binary variables by the binary variables, i.e., adds sqrcoef to lincoef
2434  */
2435 static
2437  SCIP* scip, /**< SCIP data structure */
2438  SCIP_CONS* cons /**< quadratic constraint */
2439  )
2440 {
2441  SCIP_QUADVARTERM* quadvarterm;
2442  SCIP_CONSDATA* consdata;
2443  int i;
2444  int j;
2445 
2446  assert(scip != NULL);
2447  assert(cons != NULL);
2448 
2449  consdata = SCIPconsGetData(cons);
2450 
2451  if( consdata->quadvarsmerged )
2452  return SCIP_OKAY;
2453 
2454  if( consdata->nquadvars == 0 )
2455  {
2456  consdata->quadvarsmerged = TRUE;
2457  return SCIP_OKAY;
2458  }
2459 
2460  i = 0;
2461  while( i < consdata->nquadvars )
2462  {
2463  /* make sure quad var terms are sorted (do this in every round, since we may move variables around) */
2464  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
2465 
2466  quadvarterm = &consdata->quadvarterms[i];
2467 
2468  for( j = i+1; j < consdata->nquadvars && consdata->quadvarterms[j].var == quadvarterm->var; ++j )
2469  {
2470  /* add quad var term j to current term i */
2471  quadvarterm->lincoef += consdata->quadvarterms[j].lincoef;
2472  quadvarterm->sqrcoef += consdata->quadvarterms[j].sqrcoef;
2473  if( consdata->quadvarterms[j].nadjbilin > 0 )
2474  {
2475  /* move adjacency information from j to i */
2476  SCIP_CALL( consdataEnsureAdjBilinSize(scip, quadvarterm, quadvarterm->nadjbilin + consdata->quadvarterms[j].nadjbilin) );
2477  BMScopyMemoryArray(&quadvarterm->adjbilin[quadvarterm->nadjbilin], consdata->quadvarterms[j].adjbilin, consdata->quadvarterms[j].nadjbilin); /*lint !e866*/
2478  quadvarterm->nadjbilin += consdata->quadvarterms[j].nadjbilin;
2479  consdata->quadvarterms[j].nadjbilin = 0;
2480  }
2481  consdata->quadvarterms[j].lincoef = 0.0;
2482  consdata->quadvarterms[j].sqrcoef = 0.0;
2483  /* mark that activity information in quadvarterm is not up to date anymore */
2484  }
2485 
2486  /* remove quad var terms i+1..j-1 backwards */
2487  for( j = j-1; j > i; --j )
2488  {
2489  SCIP_CALL( delQuadVarTermPos(scip, cons, j) );
2490  }
2491 
2492  /* for binary variables, x^2 = x
2493  * however, we may destroy convexity of a quadratic term that involves also bilinear terms
2494  * thus, we do this step only if the variable does not appear in any bilinear term */
2495  if( quadvarterm->sqrcoef != 0.0 && SCIPvarIsBinary(quadvarterm->var) && quadvarterm->nadjbilin == 0 )
2496  {
2497  SCIPdebugMessage("replace square of binary variable by itself: <%s>^2 --> <%s>\n", SCIPvarGetName(quadvarterm->var), SCIPvarGetName(quadvarterm->var));
2498  quadvarterm->lincoef += quadvarterm->sqrcoef;
2499  quadvarterm->sqrcoef = 0.0;
2500 
2501  /* invalidate nonlinear row */
2502  if( consdata->nlrow != NULL )
2503  {
2504  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2505  }
2506  }
2507 
2508  /* if its 0.0 or linear, get rid of it */
2509  if( SCIPisZero(scip, quadvarterm->sqrcoef) && quadvarterm->nadjbilin == 0 )
2510  {
2511  if( !SCIPisZero(scip, quadvarterm->lincoef) )
2512  {
2513  /* seem to be a linear term now, thus add as linear term */
2514  SCIP_CALL( addLinearCoef(scip, cons, quadvarterm->var, quadvarterm->lincoef) );
2515  }
2516  /* remove term at pos i */
2517  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2518  }
2519  else
2520  {
2521  ++i;
2522  }
2523  }
2524 
2525  consdata->quadvarsmerged = TRUE;
2526  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2527 
2528  return SCIP_OKAY;
2529 }
2530 
2531 /* merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
2532 static
2534  SCIP* scip, /**< SCIP data structure */
2535  SCIP_CONS* cons /**< quadratic constraint */
2536  )
2537 {
2538  SCIP_CONSDATA* consdata;
2539  SCIP_Real newcoef;
2540  int i;
2541  int j;
2542  int qvarpos;
2543 
2544  assert(scip != NULL);
2545  assert(cons != NULL);
2546 
2547  consdata = SCIPconsGetData(cons);
2548 
2549  if( consdata->linvarsmerged )
2550  return SCIP_OKAY;
2551 
2552  if( consdata->nlinvars == 0 )
2553  {
2554  consdata->linvarsmerged = TRUE;
2555  return SCIP_OKAY;
2556  }
2557 
2558  i = 0;
2559  while( i < consdata->nlinvars )
2560  {
2561  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
2562  consdataSortLinearVars(consdata);
2563 
2564  /* sum up coefficients that correspond to variable i */
2565  newcoef = consdata->lincoefs[i];
2566  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
2567  newcoef += consdata->lincoefs[j];
2568  /* delete the additional variables in backward order */
2569  for( j = j-1; j > i; --j )
2570  {
2571  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
2572  }
2573 
2574  /* check if there is already a quadratic variable term with this variable */
2575  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->linvars[i], &qvarpos) );
2576  if( qvarpos >= 0)
2577  {
2578  /* add newcoef to linear coefficient of quadratic variable and mark linear variable as to delete */
2579  assert(qvarpos < consdata->nquadvars);
2580  assert(consdata->quadvarterms[qvarpos].var == consdata->linvars[i]);
2581  consdata->quadvarterms[qvarpos].lincoef += newcoef;
2582  newcoef = 0.0;
2583  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2584  }
2585 
2586  /* delete also entry at position i, if it became zero (or was zero before) */
2587  if( SCIPisZero(scip, newcoef) )
2588  {
2589  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2590  }
2591  else
2592  {
2593  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
2594  ++i;
2595  }
2596  }
2597 
2598  consdata->linvarsmerged = TRUE;
2599 
2600  return SCIP_OKAY;
2601 }
2602 
2603 /* merges bilinear terms with same variables into a single term, removes bilinear terms with coefficient 0.0 */
2604 static
2606  SCIP* scip, /**< SCIP data structure */
2607  SCIP_CONS* cons /**< quadratic constraint */
2608  )
2609 {
2610  SCIP_CONSDATA* consdata;
2611  SCIP_BILINTERM* bilinterm;
2612  int i;
2613  int j;
2614  int* todelete;
2615  int ntodelete;
2616 
2617  assert(scip != NULL);
2618  assert(cons != NULL);
2619 
2620  consdata = SCIPconsGetData(cons);
2621 
2622  if( consdata->bilinmerged )
2623  return SCIP_OKAY;
2624 
2625  if( consdata->nbilinterms == 0 )
2626  {
2627  consdata->bilinmerged = TRUE;
2628  return SCIP_OKAY;
2629  }
2630 
2631  /* alloc memory for array of terms that need to be deleted finally */
2632  ntodelete = 0;
2633  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
2634 
2635  /* make sure bilinear terms are sorted */
2636  SCIP_CALL( consdataSortBilinTerms(scip, consdata) );
2637 
2638  i = 0;
2639  while( i < consdata->nbilinterms )
2640  {
2641  bilinterm = &consdata->bilinterms[i];
2642 
2643  /* sum up coefficients that correspond to same variables as term i */
2644  for( j = i+1; j < consdata->nbilinterms && bilinterm->var1 == consdata->bilinterms[j].var1 && bilinterm->var2 == consdata->bilinterms[j].var2; ++j )
2645  {
2646  bilinterm->coef += consdata->bilinterms[j].coef;
2647  todelete[ntodelete++] = j;
2648  }
2649 
2650  /* delete also entry at position i, if it became zero (or was zero before) */
2651  if( SCIPisZero(scip, bilinterm->coef) )
2652  {
2653  todelete[ntodelete++] = i;
2654  }
2655 
2656  /* continue with term after the current series */
2657  i = j;
2658  }
2659 
2660  /* delete bilinear terms */
2661  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
2662 
2663  SCIPfreeBufferArray(scip, &todelete);
2664 
2665  consdata->bilinmerged = TRUE;
2666 
2667  return SCIP_OKAY;
2668 }
2669 
2670 /** removes fixes (or aggregated) variables from a quadratic constraint */
2671 static
2673  SCIP* scip, /**< SCIP data structure */
2674  SCIP_CONS* cons /**< quadratic constraint */
2675  )
2676 {
2677  SCIP_CONSDATA* consdata;
2678  SCIP_BILINTERM* bilinterm;
2679  SCIP_Real coef;
2680  SCIP_Real offset;
2681  SCIP_VAR* var;
2682  SCIP_VAR* var2;
2683  int var2pos;
2684  int i;
2685  int j;
2686  int k;
2687 
2688  SCIP_Bool have_change;
2689 
2690  assert(scip != NULL);
2691  assert(cons != NULL);
2692 
2693  consdata = SCIPconsGetData(cons);
2694 
2695  have_change = FALSE;
2696  i = 0;
2697  while( i < consdata->nlinvars )
2698  {
2699  var = consdata->linvars[i];
2700 
2701  if( SCIPvarIsActive(var) )
2702  {
2703  ++i;
2704  continue;
2705  }
2706 
2707  have_change = TRUE;
2708 
2709  coef = consdata->lincoefs[i];
2710  offset = 0.0;
2711 
2712  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2713 
2714  SCIPdebugMessage(" linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]), coef, SCIPvarGetName(var), offset);
2715 
2716  /* delete previous variable (this will move another variable to position i) */
2717  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2718 
2719  /* put constant part into bounds */
2720  if( offset != 0.0 )
2721  {
2722  if( !SCIPisInfinity(scip, -consdata->lhs) )
2723  consdata->lhs -= offset;
2724  if( !SCIPisInfinity(scip, consdata->rhs) )
2725  consdata->rhs -= offset;
2726  }
2727 
2728  /* nothing left to do if variable had been fixed */
2729  if( coef == 0.0 )
2730  continue;
2731 
2732  /* if GetProbvar gave a linear variable, just add it
2733  * if it's a multilinear variable, add it's disaggregated variables */
2734  if( SCIPvarIsActive(var) )
2735  {
2736  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
2737  }
2738  else
2739  {
2740  int naggrs;
2741  SCIP_VAR** aggrvars;
2742  SCIP_Real* aggrscalars;
2743  SCIP_Real aggrconstant;
2744 
2745  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2746 
2747  naggrs = SCIPvarGetMultaggrNVars(var);
2748  aggrvars = SCIPvarGetMultaggrVars(var);
2749  aggrscalars = SCIPvarGetMultaggrScalars(var);
2750  aggrconstant = SCIPvarGetMultaggrConstant(var);
2751 
2752  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
2753 
2754  for( j = 0; j < naggrs; ++j )
2755  {
2756  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
2757  }
2758 
2759  if( aggrconstant != 0.0 )
2760  {
2761  if( !SCIPisInfinity(scip, -consdata->lhs) )
2762  consdata->lhs -= coef * aggrconstant;
2763  if( !SCIPisInfinity(scip, consdata->rhs) )
2764  consdata->rhs -= coef * aggrconstant;
2765  }
2766  }
2767  }
2768 
2769  i = 0;
2770  while( i < consdata->nquadvars )
2771  {
2772  var = consdata->quadvarterms[i].var;
2773 
2774  if( SCIPvarIsActive(var) )
2775  {
2776  ++i;
2777  continue;
2778  }
2779 
2780  have_change = TRUE;
2781 
2782  coef = 1.0;
2783  offset = 0.0;
2784  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2785 
2786  SCIPdebugMessage(" quadratic variable <%s> with status %d is replaced by %g * <%s> + %g\n", SCIPvarGetName(consdata->quadvarterms[i].var), SCIPvarGetStatus(consdata->quadvarterms[i].var), coef, SCIPvarGetName(var), offset);
2787 
2788  /* handle fixed variable */
2789  if( coef == 0.0 )
2790  {
2791  /* if not fixed to 0.0, add to linear coefs of vars in bilinear terms, and deal with linear and square term as constant */
2792  if( offset != 0.0 )
2793  {
2794  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2795  {
2796  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
2797 
2798  var2 = bilinterm->var1 == consdata->quadvarterms[i].var ? bilinterm->var2 : bilinterm->var1;
2799  assert(var2 != consdata->quadvarterms[i].var);
2800 
2801  var2pos = 0;
2802  while( consdata->quadvarterms[var2pos].var != var2 )
2803  {
2804  ++var2pos;
2805  assert(var2pos < consdata->nquadvars);
2806  }
2807  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2808  }
2809 
2810  offset = consdata->quadvarterms[i].lincoef * offset + consdata->quadvarterms[i].sqrcoef * offset * offset;
2811  if( !SCIPisInfinity(scip, -consdata->lhs) )
2812  consdata->lhs -= offset;
2813  if( !SCIPisInfinity(scip, consdata->rhs) )
2814  consdata->rhs -= offset;
2815  }
2816 
2817  /* remove bilinear terms */
2818  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
2819 
2820  /* delete quad. var term i */
2821  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2822 
2823  continue;
2824  }
2825 
2826  assert(var != NULL);
2827 
2828  /* if GetProbvar gave an active variable, replace the quad var term so that it uses the new variable */
2829  if( SCIPvarIsActive(var) )
2830  {
2831  /* replace x by coef*y+offset */
2832  SCIP_CALL( replaceQuadVarTermPos(scip, cons, i, var, coef, offset) );
2833 
2834  continue;
2835  }
2836  else
2837  {
2838  /* if GetProbVar gave a multi-aggregated variable, add new quad var terms and new bilinear terms
2839  * x is replaced by coef * (sum_i a_ix_i + b) + offset
2840  * lcoef * x + scoef * x^2 + bcoef * x * y ->
2841  * (b*coef + offset) * (lcoef + (b*coef + offset) * scoef)
2842  * + sum_i a_i*coef * (lcoef + 2 (b*coef + offset) * scoef) x_i
2843  * + sum_i (a_i*coef)^2 * scoef * x_i^2
2844  * + 2 sum_{i,j, i<j} (a_i a_j coef^2 scoef) x_i x_j
2845  * + bcoef * (b*coef + offset + coef * sum_i a_ix_i) y
2846  */
2847  int naggrs;
2848  SCIP_VAR** aggrvars; /* x_i */
2849  SCIP_Real* aggrscalars; /* a_i */
2850  SCIP_Real aggrconstant; /* b */
2851  int nquadtermsold;
2852 
2853  SCIP_Real lcoef;
2854  SCIP_Real scoef;
2855 
2856  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2857 
2858  naggrs = SCIPvarGetMultaggrNVars(var);
2859  aggrvars = SCIPvarGetMultaggrVars(var);
2860  aggrscalars = SCIPvarGetMultaggrScalars(var);
2861  aggrconstant = SCIPvarGetMultaggrConstant(var);
2862 
2863  lcoef = consdata->quadvarterms[i].lincoef;
2864  scoef = consdata->quadvarterms[i].sqrcoef;
2865 
2866  nquadtermsold = consdata->nquadvars;
2867 
2868  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars + naggrs) );
2869 
2870  /* take care of constant part */
2871  if( aggrconstant != 0.0 || offset != 0.0 )
2872  {
2873  SCIP_Real constant;
2874  constant = (aggrconstant * coef + offset) * (lcoef + (aggrconstant * coef + offset) * scoef);
2875  if( !SCIPisInfinity(scip, -consdata->lhs) )
2876  consdata->lhs -= constant;
2877  if( !SCIPisInfinity(scip, consdata->rhs) )
2878  consdata->rhs -= constant;
2879  }
2880 
2881  /* add x_i's with linear and square coefficients */
2882  for( j = 0; j < naggrs; ++j )
2883  {
2884  SCIP_CALL( addQuadVarTerm(scip, cons, aggrvars[j],
2885  coef * aggrscalars[j] * (lcoef + 2.0 * scoef * (coef * aggrconstant + offset)),
2886  coef * coef * aggrscalars[j] * aggrscalars[j] * scoef,
2887  TRUE) );
2888  }
2889 
2890  /* ensure space for bilinear terms */
2891  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nquadvars + (scoef != 0.0 ? (naggrs * (naggrs-1))/2 : 0) + consdata->quadvarterms[j].nadjbilin * naggrs) );
2892 
2893  /* add x_j*x_k's */
2894  if( scoef != 0.0 )
2895  {
2896  for( j = 0; j < naggrs; ++j )
2897  for( k = 0; k < j; ++k )
2898  {
2899  assert(aggrvars[j] != aggrvars[k]);
2900  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, nquadtermsold + k,
2901  2.0 * aggrscalars[j] * aggrscalars[k] * coef * coef * scoef) );
2902  }
2903  }
2904 
2905  /* add x_i*y's */
2906  for( k = 0; k < consdata->quadvarterms[i].nadjbilin; ++k )
2907  {
2908  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[k]];
2909  var2 = (bilinterm->var1 == consdata->quadvarterms[i].var) ? bilinterm->var2 : bilinterm->var1;
2910  assert(var2 != consdata->quadvarterms[i].var);
2911 
2912  /* this is not efficient, but we cannot sort the quadratic terms here, since we currently iterate over them */
2913  var2pos = 0;
2914  while( consdata->quadvarterms[var2pos].var != var2 )
2915  {
2916  ++var2pos;
2917  assert(var2pos < consdata->nquadvars);
2918  }
2919 
2920  for( j = 0; j < naggrs; ++j )
2921  {
2922  if( aggrvars[j] == var2 )
2923  { /* x_i == y, so we have a square term here */
2924  consdata->quadvarterms[var2pos].sqrcoef += bilinterm->coef * coef * aggrscalars[j];
2925  }
2926  else
2927  { /* x_i != y, so we need to add a bilinear term here */
2928  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, var2pos,
2929  bilinterm->coef * coef * aggrscalars[j]) );
2930  }
2931  }
2932 
2933  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * (aggrconstant * coef + offset);
2934  }
2935 
2936  /* remove bilinear terms */
2937  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
2938 
2939  /* delete quad. var term i */
2940  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2941  }
2942  }
2943 
2944  consdata->isremovedfixings = TRUE;
2945 
2946  SCIPdebugMessage("removed fixations from <%s>\n -> ", SCIPconsGetName(cons));
2947  SCIPdebugPrintCons(scip, cons, NULL);
2948 
2949 #ifndef NDEBUG
2950  for( i = 0; i < consdata->nlinvars; ++i )
2951  assert(SCIPvarIsActive(consdata->linvars[i]));
2952 
2953  for( i = 0; i < consdata->nquadvars; ++i )
2954  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
2955 #endif
2956 
2957  if( !have_change )
2958  return SCIP_OKAY;
2959 
2960  /* some quadratic variable may have been replaced by an already existing linear variable
2961  * in this case, we want the linear variable to be removed, which happens in mergeAndCleanLinearVars
2962  */
2963  consdata->linvarsmerged = FALSE;
2964 
2965  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
2966  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
2967  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
2968 
2969 #ifndef NDEBUG
2970  for( i = 0; i < consdata->nbilinterms; ++i )
2971  {
2972  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
2973  assert(consdata->bilinterms[i].coef != 0.0);
2974  assert(SCIPvarCompare(consdata->bilinterms[i].var1, consdata->bilinterms[i].var2) < 0);
2975  }
2976 #endif
2977 
2978  return SCIP_OKAY;
2979 }
2980 
2981 /** create a nonlinear row representation of the constraint and stores them in consdata */
2982 static
2984  SCIP* scip, /**< SCIP data structure */
2985  SCIP_CONS* cons /**< quadratic constraint */
2986  )
2987 {
2988  SCIP_CONSDATA* consdata;
2989  int nquadvars; /* number of variables in quadratic terms */
2990  SCIP_VAR** quadvars; /* variables in quadratic terms */
2991  int nquadelems; /* number of quadratic elements (square and bilinear terms) */
2992  SCIP_QUADELEM* quadelems; /* quadratic elements (square and bilinear terms) */
2993  int nquadlinterms; /* number of linear terms using variables that are in quadratic terms */
2994  SCIP_VAR** quadlinvars; /* variables of linear terms using variables that are in quadratic terms */
2995  SCIP_Real* quadlincoefs; /* coefficients of linear terms using variables that are in quadratic terms */
2996  int i;
2997  int idx1;
2998  int idx2;
2999  int lincnt;
3000  int elcnt;
3001  SCIP_VAR* lastvar;
3002  int lastvaridx;
3003 
3004  assert(scip != NULL);
3005  assert(cons != NULL);
3006 
3007  consdata = SCIPconsGetData(cons);
3008  assert(consdata != NULL);
3009 
3010  if( consdata->nlrow != NULL )
3011  {
3012  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3013  }
3014 
3015  nquadvars = consdata->nquadvars;
3016  nquadelems = consdata->nbilinterms;
3017  nquadlinterms = 0;
3018  for( i = 0; i < nquadvars; ++i )
3019  {
3020  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3021  ++nquadelems;
3022  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3023  ++nquadlinterms;
3024  }
3025 
3026  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, nquadvars) );
3027  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
3028  SCIP_CALL( SCIPallocBufferArray(scip, &quadlinvars, nquadlinterms) );
3029  SCIP_CALL( SCIPallocBufferArray(scip, &quadlincoefs, nquadlinterms) );
3030 
3031  lincnt = 0;
3032  elcnt = 0;
3033  for( i = 0; i < nquadvars; ++i )
3034  {
3035  quadvars[i] = consdata->quadvarterms[i].var;
3036 
3037  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3038  {
3039  assert(elcnt < nquadelems);
3040  quadelems[elcnt].idx1 = i;
3041  quadelems[elcnt].idx2 = i;
3042  quadelems[elcnt].coef = consdata->quadvarterms[i].sqrcoef;
3043  ++elcnt;
3044  }
3045 
3046  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3047  {
3048  assert(lincnt < nquadlinterms);
3049  quadlinvars [lincnt] = consdata->quadvarterms[i].var;
3050  quadlincoefs[lincnt] = consdata->quadvarterms[i].lincoef;
3051  ++lincnt;
3052  }
3053  }
3054  assert(lincnt == nquadlinterms);
3055 
3056  /* bilinear terms are sorted first by first variable, then by second variable
3057  * 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 */
3058  lastvar = NULL;
3059  lastvaridx = -1;
3060  for( i = 0; i < consdata->nbilinterms; ++i )
3061  {
3062  if( lastvar == consdata->bilinterms[i].var1 )
3063  {
3064  assert(lastvaridx >= 0);
3065  assert(consdata->quadvarterms[lastvaridx].var == consdata->bilinterms[i].var1);
3066  }
3067  else
3068  {
3069  lastvar = consdata->bilinterms[i].var1;
3070  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, lastvar, &lastvaridx) );
3071  }
3072  idx1 = lastvaridx;
3073 
3074  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &idx2) );
3075 
3076  assert(elcnt < nquadelems);
3077  quadelems[elcnt].idx1 = MIN(idx1, idx2);
3078  quadelems[elcnt].idx2 = MAX(idx1, idx2);
3079  quadelems[elcnt].coef = consdata->bilinterms[i].coef;
3080  ++elcnt;
3081  }
3082  assert(elcnt == nquadelems);
3083 
3084  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3085  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
3086  nquadvars, quadvars, nquadelems, quadelems,
3087  NULL, consdata->lhs, consdata->rhs) );
3088 
3089  SCIP_CALL( SCIPaddLinearCoefsToNlRow(scip, consdata->nlrow, nquadlinterms, quadlinvars, quadlincoefs) );
3090 
3091  SCIPfreeBufferArray(scip, &quadvars);
3092  SCIPfreeBufferArray(scip, &quadelems);
3093  SCIPfreeBufferArray(scip, &quadlinvars);
3094  SCIPfreeBufferArray(scip, &quadlincoefs);
3095 
3096  return SCIP_OKAY;
3097 }
3098 
3099 static
3101  SCIP* scip, /**< SCIP data structure */
3102  SCIP_CONS* cons, /**< constraint */
3103  SCIP_RESULT* result, /**< to store result of solve: cutoff, success, or do-not-find */
3104  SCIP_Bool* redundant, /**< to store whether constraint is redundant now (should be deleted) */
3105  int* naggrvars /**< counter on number of variable aggregations */
3106  )
3107 {
3108  SCIP_CONSDATA* consdata;
3109 
3110  assert(scip != NULL);
3111  assert(cons != NULL);
3112  assert(result != NULL);
3113  assert(redundant != NULL);
3114 
3115  *result = SCIP_DIDNOTFIND;
3116  *redundant = FALSE;
3117 
3118  consdata = SCIPconsGetData(cons);
3119  assert(consdata != NULL);
3120 
3121  /* if constraint is an equality with two variables, at least one of them binary,
3122  * and linear after fixing the binary, then we can aggregate the variables */
3123  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && consdata->nlinvars == 0 && consdata->nquadvars == 2 &&
3124  ((SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ||
3125  (SCIPvarIsBinary(consdata->quadvarterms[1].var) && consdata->quadvarterms[0].sqrcoef == 0.0)) )
3126  {
3127  SCIP_Bool infeasible;
3128  SCIP_Bool aggregated;
3129  SCIP_Real a;
3130  SCIP_Real b;
3131  SCIP_Real c;
3132  SCIP_VAR* x;
3133  SCIP_VAR* y;
3134  int binvaridx;
3135 
3136  /* constraint is a*(x+x^2) + b*y + c*x*y = rhs, with x binary variable
3137  * x = 0 -> b*y == rhs
3138  * x = 1 -> (b+c)*y == rhs - a
3139  *
3140  * 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
3141  */
3142 
3143  binvaridx = (SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ? 0 : 1;
3144 
3145  x = consdata->quadvarterms[binvaridx].var;
3146  a = consdata->quadvarterms[binvaridx].sqrcoef + consdata->quadvarterms[binvaridx].lincoef;
3147 
3148  y = consdata->quadvarterms[1-binvaridx].var;
3149  b = consdata->quadvarterms[1-binvaridx].lincoef;
3150 
3151  assert(consdata->nbilinterms <= 1); /* should actually be 1, since constraint is otherwise linear */
3152  c = (consdata->nbilinterms == 1) ? consdata->bilinterms[0].coef : 0.0;
3153 
3154  if( !SCIPisZero(scip, b) && !SCIPisZero(scip, b+c) )
3155  {
3156  SCIPdebugMessage("<%s> = 0 -> %g*<%s> = %g and <%s> = 1 -> %g*<%s> = %g\n", SCIPvarGetName(x), b, SCIPvarGetName(y), consdata->rhs, SCIPvarGetName(x), b+c, SCIPvarGetName(y), consdata->rhs - a);
3157  SCIPdebugMessage("=> attempt aggregation <%s> = %g*<%s> + %g\n", SCIPvarGetName(y), (consdata->rhs-a)/(b+c) - consdata->rhs/b, SCIPvarGetName(x), consdata->rhs/b);
3158 
3159  SCIP_CALL( SCIPaggregateVars(scip, x, y, (consdata->rhs-a)/(b+c) - consdata->rhs/b, -1.0, -consdata->rhs/b, &infeasible, redundant, &aggregated) );
3160  if( infeasible )
3161  *result = SCIP_CUTOFF;
3162  else if( *redundant || aggregated )
3163  {
3164  /* aggregated (or were already aggregated), so constraint is now redundant */
3165  *result = SCIP_SUCCESS;
3166  *redundant = TRUE;
3167 
3168  if( aggregated )
3169  ++*naggrvars;
3170  }
3171  }
3172 
3173  /* @todo if b is 0 or b+c is 0, or lhs != rhs, then could replace by varbound constraint */
3174  }
3175 
3176  return SCIP_OKAY;
3177 }
3178 
3179 
3180 /** reformulates products of binary variables as AND constraint
3181  * 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.
3182  */
3183 static
3185  SCIP* scip, /**< SCIP data structure */
3186  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3187  SCIP_CONS* cons, /**< constraint */
3188  int* naddconss /**< buffer where to add the number of AND constraints added */
3189  )
3190 {
3191  SCIP_CONSHDLRDATA* conshdlrdata;
3192  SCIP_CONSDATA* consdata;
3193  char name[SCIP_MAXSTRLEN];
3194  SCIP_VAR* vars[2];
3195  SCIP_VAR* auxvar;
3196  SCIP_CONS* andcons;
3197  int i;
3198  int ntodelete;
3199  int* todelete;
3200 
3201  assert(scip != NULL);
3202  assert(conshdlr != NULL);
3203  assert(cons != NULL);
3204  assert(naddconss != NULL);
3205 
3206  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3207  assert(conshdlrdata != NULL);
3208 
3209  /* if user does not like AND very much, then return */
3210  if( conshdlrdata->empathy4and < 2 )
3211  return SCIP_OKAY;
3212 
3213  consdata = SCIPconsGetData(cons);
3214  assert(consdata != NULL);
3215 
3216  if( consdata->nbilinterms == 0 )
3217  return SCIP_OKAY;
3218 
3219  /* get array to store indices of bilinear terms that shall be deleted */
3220  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
3221  ntodelete = 0;
3222 
3223  for( i = 0; i < consdata->nbilinterms; ++i )
3224  {
3225  vars[0] = consdata->bilinterms[i].var1;
3226  if( !SCIPvarIsBinary(vars[0]) )
3227  continue;
3228 
3229  vars[1] = consdata->bilinterms[i].var2;
3230  if( !SCIPvarIsBinary(vars[1]) )
3231  continue;
3232 
3233  /* create auxiliary variable */
3234  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]), SCIPconsGetName(cons));
3235  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
3236  SCIPvarIsInitial(vars[0]) || SCIPvarIsInitial(vars[1]), SCIPvarIsRemovable(vars[0]) && SCIPvarIsRemovable(vars[1]), NULL, NULL, NULL, NULL, NULL) );
3237  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3238 #ifdef SCIP_DEBUG_SOLUTION
3239  if( SCIPdebugIsMainscip(scip) )
3240  {
3241  SCIP_Real var0val;
3242  SCIP_Real var1val;
3243  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[0], &var0val) );
3244  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[1], &var1val) );
3245  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3246  }
3247 #endif
3248 
3249  /* create and constraint auxvar = x and y */
3250  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3251  SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, auxvar, 2, vars,
3252  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3256  SCIP_CALL( SCIPaddCons(scip, andcons) );
3257  SCIPdebugMessage("added AND constraint: ");
3258  SCIPdebugPrintCons(scip, andcons, NULL);
3259  SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
3260  ++*naddconss;
3261 
3262  /* add bilincoef * auxvar to linear terms */
3263  SCIP_CALL( addLinearCoef(scip, cons, auxvar, consdata->bilinterms[i].coef) );
3264  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3265 
3266  /* remember that we have to delete this bilinear term */
3267  assert(ntodelete < consdata->nbilinterms);
3268  todelete[ntodelete++] = i;
3269  }
3270 
3271  /* remove bilinear terms that have been replaced */
3272  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3273  SCIPfreeBufferArray(scip, &todelete);
3274 
3275  return SCIP_OKAY;
3276 }
3277 
3278 /** gets bounds of variable y if x takes a certain value
3279  * checks whether x = xval has implications on y
3280  */
3281 static
3283  SCIP_VAR* x, /**< variable which implications to check */
3284  SCIP_Bool xval, /**< value of x to check for (TRUE for 1, FALSE for 0) */
3285  SCIP_VAR* y, /**< variable to check if bounds can be reduced */
3286  SCIP_INTERVAL* resultant /**< buffer to store bounds on y */
3287  )
3288 {
3289  int nimpls;
3290  int nbinimpls;
3291  SCIP_VAR** implvars;
3292  SCIP_BOUNDTYPE* impltypes;
3293  SCIP_Real* implbounds;
3294  int pos;
3295 
3296  assert(x != NULL);
3297  assert(y != NULL);
3298  assert(resultant != NULL);
3299 
3301 
3302  if( !SCIPvarIsBinary(x) || !SCIPvarIsActive(x) )
3303  return;
3304 
3305  /* analyze implications for x = xval */
3306  nimpls = SCIPvarGetNImpls(x, xval);
3307  if( nimpls == 0 )
3308  return;
3309 
3310  nbinimpls = SCIPvarGetNBinImpls (x, xval);
3311  implvars = SCIPvarGetImplVars (x, xval);
3312  impltypes = SCIPvarGetImplTypes (x, xval);
3313  implbounds = SCIPvarGetImplBounds(x, xval);
3314 
3315  assert(implvars != NULL);
3316  assert(impltypes != NULL);
3317  assert(implbounds != NULL);
3318 
3320  {
3321  if( !SCIPsortedvecFindPtr((void**)implvars, SCIPvarComp, (void*)y, nbinimpls, &pos) )
3322  return;
3323  }
3324  else if( nbinimpls < nimpls )
3325  {
3326  if( !SCIPsortedvecFindPtr((void**)&implvars[nbinimpls], SCIPvarComp, (void*)y, nimpls - nbinimpls, &pos) )
3327  return;
3328  }
3329  else
3330  return;
3331 
3332  /* if there are several implications on y, go to the first one */
3333  while( pos > 0 && implvars[pos-1] == y )
3334  --pos;
3335 
3336  /* update implied lower and upper bounds on y
3337  * but make sure that resultant will not be empty, due to tolerances
3338  */
3339  while( pos < nimpls && implvars[pos] == y )
3340  {
3341  if( impltypes[pos] == SCIP_BOUNDTYPE_LOWER )
3342  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, implbounds[pos]));
3343  else
3344  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, implbounds[pos]));
3345  ++pos;
3346  }
3347 
3348  assert(!SCIPintervalIsEmpty(*resultant));
3349 }
3350 
3351 /** Reformulates products of binary times bounded continuous variables as system of linear inequalities (plus auxiliary variable).
3352  *
3353  * For a product x*y, with y a binary variable and x a continous variable with finite bounds,
3354  * 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.
3355  *
3356  * 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.
3357  * For each product of linear term of length at most maxnrvar with y, an auxiliary z and linear inequalities are added.
3358  *
3359  * If y is a binary variable, the AND constraint \f$ z = x \wedge y \f$ may be added instead of linear constraints.
3360  */
3361 static
3363  SCIP* scip, /**< SCIP data structure */
3364  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3365  SCIP_CONS* cons, /**< constraint */
3366  int* naddconss /**< buffer where to add the number of auxiliary constraints added */
3367  )
3368 { /*lint --e{666} */
3369  SCIP_CONSHDLRDATA* conshdlrdata;
3370  SCIP_CONSDATA* consdata;
3371  SCIP_VAR** xvars;
3372  SCIP_Real* xcoef;
3373  SCIP_INTERVAL xbndszero;
3374  SCIP_INTERVAL xbndsone;
3375  SCIP_INTERVAL act0;
3376  SCIP_INTERVAL act1;
3377  int nxvars;
3378  SCIP_VAR* y;
3379  SCIP_VAR* bvar;
3380  char name[SCIP_MAXSTRLEN];
3381  int nbilinterms;
3382  SCIP_VAR* auxvar;
3383  SCIP_CONS* auxcons;
3384  int i;
3385  int j;
3386  int k;
3387  int bilinidx;
3388  SCIP_Real bilincoef;
3389  SCIP_Real mincoef;
3390  SCIP_Real maxcoef;
3391  int* todelete;
3392  int ntodelete;
3393  int maxnrvar;
3394  SCIP_Bool integral;
3395  SCIP_Longint gcd;
3396  SCIP_Bool auxvarinitial;
3397  SCIP_Bool auxvarremovable;
3398 
3399  assert(scip != NULL);
3400  assert(conshdlr != NULL);
3401  assert(cons != NULL);
3402  assert(naddconss != NULL);
3403 
3404  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3405  assert(conshdlrdata != NULL);
3406 
3407  maxnrvar = conshdlrdata->replacebinaryprodlength;
3408  if( maxnrvar == 0 )
3409  return SCIP_OKAY;
3410 
3411  consdata = SCIPconsGetData(cons);
3412  assert(consdata != NULL);
3413 
3414  xvars = NULL;
3415  xcoef = NULL;
3416  todelete = NULL;
3417  gcd = 0;
3418 
3419  for( i = 0; i < consdata->nquadvars; ++i )
3420  {
3421  y = consdata->quadvarterms[i].var;
3422  if( !SCIPvarIsBinary(y) )
3423  continue;
3424 
3425  nbilinterms = consdata->quadvarterms[i].nadjbilin;
3426  if( nbilinterms == 0 )
3427  continue;
3428 
3429  SCIP_CALL( SCIPreallocBufferArray(scip, &xvars, MIN(maxnrvar, nbilinterms)+2) ); /* add 2 for later use when creating linear constraints */
3430  SCIP_CALL( SCIPreallocBufferArray(scip, &xcoef, MIN(maxnrvar, nbilinterms)+2) );
3431 
3432  /* alloc array to store indices of bilinear terms that shall be deleted */
3433  SCIP_CALL( SCIPreallocBufferArray(scip, &todelete, nbilinterms) );
3434  ntodelete = 0;
3435 
3436  auxvarinitial = SCIPvarIsInitial(y);
3437  auxvarremovable = SCIPvarIsRemovable(y);
3438 
3439  /* 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)
3440  * and compute range of sum_i a_i*x_i for the cases y = 0 and y = 1
3441  * we may need several rounds of maxnrvar < nbilinterms
3442  */
3443  j = 0;
3444  do
3445  {
3446  nxvars = 0;
3447  SCIPintervalSet(&xbndszero, 0.0);
3448  SCIPintervalSet(&xbndsone, 0.0);
3449 
3450  mincoef = SCIPinfinity(scip);
3451  maxcoef = 0.0;
3452  integral = TRUE;
3453 
3454  /* collect at most maxnrvar variables for x term */
3455  for( ; j < nbilinterms && nxvars < maxnrvar; ++j )
3456  {
3457  bilinidx = consdata->quadvarterms[i].adjbilin[j];
3458  assert(bilinidx >= 0);
3459  assert(bilinidx < consdata->nbilinterms);
3460 
3461  bvar = consdata->bilinterms[bilinidx].var1;
3462  if( bvar == y )
3463  bvar = consdata->bilinterms[bilinidx].var2;
3464  assert(bvar != y);
3465 
3466  /* skip products with unbounded variables */
3467  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(bvar)) || SCIPisInfinity(scip, SCIPvarGetUbGlobal(bvar)) )
3468  {
3469  SCIPdebugMessage("skip reform of <%s><%s> due to unbounded second variable [%g,%g]\n",
3471  continue;
3472  }
3473 
3474  bilincoef = consdata->bilinterms[bilinidx].coef;
3475  assert(bilincoef != 0.0);
3476 
3477  /* get activity of bilincoef * x if y = 0 */
3478  getImpliedBounds(y, FALSE, bvar, &act0);
3479  SCIPintervalMulScalar(SCIPinfinity(scip), &act0, act0, bilincoef);
3480 
3481  /* get activity of bilincoef * x if y = 1 */
3482  getImpliedBounds(y, TRUE, bvar, &act1);
3483  SCIPintervalMulScalar(SCIPinfinity(scip), &act1, act1, bilincoef);
3484 
3485  /* skip products that give rise to very large coefficients (big big-M's) */
3486  if( SCIPfeastol(scip) * REALABS(act0.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act0.sup) >= conshdlrdata->binreformmaxcoef )
3487  {
3488  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 0.0\n",
3489  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act0), SCIPintervalGetSup(act0), SCIPvarGetName(y));
3490  continue;
3491  }
3492  if( SCIPfeastol(scip) * REALABS(act1.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act1.sup) >= conshdlrdata->binreformmaxcoef )
3493  {
3494  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 1.0\n",
3495  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act1), SCIPintervalGetSup(act1), SCIPvarGetName(y));
3496  continue;
3497  }
3498  if( !SCIPisZero(scip, MIN(REALABS(act0.inf), REALABS(act0.sup))) &&
3499  SCIPfeastol(scip) * MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)) >= conshdlrdata->binreformmaxcoef )
3500  {
3501  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n",
3502  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)), SCIPvarGetName(y));
3503  continue;
3504  }
3505  if( !SCIPisZero(scip, MIN(REALABS(act1.inf), REALABS(act1.sup))) &&
3506  SCIPfeastol(scip) * MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)) >= conshdlrdata->binreformmaxcoef )
3507  {
3508  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n",
3509  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)), SCIPvarGetName(y));
3510  continue;
3511  }
3512 
3513  /* add bvar to x term */
3514  xvars[nxvars] = bvar;
3515  xcoef[nxvars] = bilincoef;
3516  ++nxvars;
3517 
3518  /* update bounds on x term */
3519  SCIPintervalAdd(SCIPinfinity(scip), &xbndszero, xbndszero, act0);
3520  SCIPintervalAdd(SCIPinfinity(scip), &xbndsone, xbndsone, act1);
3521 
3522  if( REALABS(bilincoef) < mincoef )
3523  mincoef = ABS(bilincoef);
3524  if( REALABS(bilincoef) > maxcoef )
3525  maxcoef = ABS(bilincoef);
3526 
3527  /* update whether all coefficients will be integral and if so, compute their gcd */
3528  integral &= (SCIPvarGetType(bvar) < SCIP_VARTYPE_CONTINUOUS) && SCIPisIntegral(scip, bilincoef); /*lint !e514 */
3529  if( integral )
3530  {
3531  if( nxvars == 1 )
3532  gcd = (SCIP_Longint)SCIPround(scip, REALABS(bilincoef));
3533  else
3534  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)SCIPround(scip, REALABS(bilincoef)));
3535  }
3536 
3537  /* if bvar is initial, then also the auxiliary variable should be initial
3538  * if bvar is not removable, then also the auxiliary variable should not be removable
3539  */
3540  auxvarinitial |= SCIPvarIsInitial(bvar);
3541  auxvarremovable &= SCIPvarIsRemovable(bvar);
3542 
3543  /* remember that we have to remove this bilinear term later */
3544  assert(ntodelete < nbilinterms);
3545  todelete[ntodelete++] = bilinidx;
3546  }
3547 
3548  if( nxvars == 0 ) /* all (remaining) x_j seem to be unbounded */
3549  break;
3550 
3551  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndszero)));
3552  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndszero)));
3553  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndsone)));
3554  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndsone)));
3555 
3556 #ifdef SCIP_DEBUG
3557  if( SCIPintervalGetInf(xbndszero) != SCIPintervalGetInf(xbndsone) || /*lint !e777*/
3558  +SCIPintervalGetSup(xbndszero) != SCIPintervalGetSup(xbndsone) ) /*lint !e777*/
3559  {
3560  SCIPdebugMessage("got different bounds for y = 0: [%g, %g] and y = 1: [%g, %g]\n", xbndszero.inf, xbndszero.sup, xbndsone.inf, xbndsone.sup);
3561  }
3562 #endif
3563 
3564  if( nxvars == 1 && conshdlrdata->empathy4and >= 1 && SCIPvarIsBinary(xvars[0]) )
3565  {
3566  /* product of two binary variables, replace by auxvar and AND constraint */
3567  /* add auxiliary variable z */
3568  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3569  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT,
3570  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3571  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3572 
3573 #ifdef SCIP_DEBUG_SOLUTION
3574  if( SCIPdebugIsMainscip(scip) )
3575  {
3576  SCIP_Real var0val;
3577  SCIP_Real var1val;
3578  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[0], &var0val) );
3579  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &var1val) );
3580  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3581  }
3582 #endif
3583 
3584  /* add constraint z = x and y */
3585  xvars[1] = y;
3586  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3587  SCIP_CALL( SCIPcreateConsAnd(scip, &auxcons, name, auxvar, 2, xvars,
3588  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3592  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3593  SCIPdebugMessage("added AND constraint: ");
3594  SCIPdebugPrintCons(scip, auxcons, NULL);
3595  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3596  ++*naddconss;
3597 
3598  /* add linear term coef*auxvar */
3599  SCIP_CALL( addLinearCoef(scip, cons, auxvar, xcoef[0]) );
3600 
3601  /* forget about auxvar */
3602  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3603  }
3604  else
3605  {
3606  /* product of binary variable with more than one binary or with continuous variables or with binary and user did not like AND -> replace by auxvar and linear constraints */
3607  SCIP_Real scale;
3608 
3609  /* scale auxiliary constraint by some nice value,
3610  * if all coefficients are integral, take a value that preserves integrality (-> gcd), so we can make the auxiliary variable impl. integer
3611  */
3612  if( integral )
3613  {
3614  scale = (SCIP_Real)gcd;
3615  assert(scale >= 1.0);
3616  }
3617  else if( nxvars == 1 )
3618  {
3619  /* scaling by the only coefficient gives auxiliary variable = x * y, which thus will be implicit integral provided y is not continuous */
3620  assert(mincoef == maxcoef); /*lint !e777 */
3621  scale = mincoef;
3622  integral = SCIPvarGetType(xvars[0]) < SCIP_VARTYPE_CONTINUOUS;
3623  }
3624  else
3625  {
3626  scale = 1.0;
3627  if( maxcoef < 0.5 )
3628  scale = maxcoef;
3629  if( mincoef > 2.0 )
3630  scale = mincoef;
3631  if( scale != 1.0 )
3632  scale = SCIPselectSimpleValue(scale / 2.0, 1.5 * scale, MAXDNOM);
3633  }
3634  assert(scale > 0.0);
3635  assert(!SCIPisInfinity(scip, scale));
3636 
3637  /* if x-term is always negative for y = 1, negate scale so we get a positive auxiliary variable; maybe this is better sometimes? */
3638  if( !SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3639  scale = -scale;
3640 
3641  SCIPdebugMessage("binary reformulation using scale %g, nxvars = %d, integral = %u\n", scale, nxvars, integral);
3642  if( scale != 1.0 )
3643  {
3644  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndszero, xbndszero, scale);
3645  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndsone, xbndsone, scale);
3646  for( k = 0; k < nxvars; ++k )
3647  xcoef[k] /= scale;
3648  }
3649 
3650  /* add auxiliary variable z */
3651  if( nxvars == 1 )
3652  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3653  else
3654  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_more_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3655  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, MIN(0., SCIPintervalGetInf(xbndsone)), MAX(0., SCIPintervalGetSup(xbndsone)),
3657  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3658  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3659 
3660  /* compute value of auxvar in debug solution */
3661 #ifdef SCIP_DEBUG_SOLUTION
3662  if( SCIPdebugIsMainscip(scip) )
3663  {
3664  SCIP_Real debugval;
3665  SCIP_Real varval;
3666 
3667  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &varval) );
3668  if( SCIPisZero(scip, varval) )
3669  {
3670  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, 0.0) );
3671  }
3672  else
3673  {
3674  assert(SCIPisEQ(scip, varval, 1.0));
3675 
3676  debugval = 0.0;
3677  for( k = 0; k < nxvars; ++k )
3678  {
3679  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[k], &varval) );
3680  debugval += xcoef[k] * varval;
3681  }
3682  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
3683  }
3684  }
3685 #endif
3686 
3687  /* add auxiliary constraints
3688  * it seems to be advantageous to make the varbound constraints initial and the linear constraints not initial
3689  * maybe because it is more likely that a binary variable takes value 0 instead of 1, and thus the varbound constraints
3690  * are more often active, compared to the linear constraints added below
3691  * also, the varbound constraints are more sparse than the linear cons
3692  */
3693  if( SCIPisNegative(scip, SCIPintervalGetInf(xbndsone)) )
3694  {
3695  /* add 0 <= z - xbndsone.inf * y constraint (as varbound constraint) */
3696  if( nxvars == 1 )
3697  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3698  else
3699  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3700  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetInf(xbndsone), 0.0, SCIPinfinity(scip),
3701  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3705  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3706  SCIPdebugMessage("added varbound constraint: ");
3707  SCIPdebugPrintCons(scip, auxcons, NULL);
3708  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3709  ++*naddconss;
3710  }
3711  if( SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3712  {
3713  /* add z - xbndsone.sup * y <= 0 constraint (as varbound constraint) */
3714  if( nxvars == 1 )
3715  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3716  else
3717  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3718  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetSup(xbndsone), -SCIPinfinity(scip), 0.0,
3719  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3723  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3724  SCIPdebugMessage("added varbound constraint: ");
3725  SCIPdebugPrintCons(scip, auxcons, NULL);
3726  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3727  ++*naddconss;
3728  }
3729 
3730  /* add xbndszero.inf <= sum_i a_i*x_i + xbndszero.inf * y - z constraint */
3731  xvars[nxvars] = y;
3732  xvars[nxvars+1] = auxvar;
3733  xcoef[nxvars] = SCIPintervalGetInf(xbndszero);
3734  xcoef[nxvars+1] = -1;
3735 
3736  if( nxvars == 1 )
3737  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3738  else
3739  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3740  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, SCIPintervalGetInf(xbndszero), SCIPinfinity(scip),
3741  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3745  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3746  SCIPdebugMessage("added linear constraint: ");
3747  SCIPdebugPrintCons(scip, auxcons, NULL);
3748  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3749  ++*naddconss;
3750 
3751  /* add sum_i a_i*x_i + xbndszero.sup * y - z <= xbndszero.sup constraint */
3752  xcoef[nxvars] = SCIPintervalGetSup(xbndszero);
3753 
3754  if( nxvars == 1 )
3755  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3756  else
3757  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3758  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, -SCIPinfinity(scip), SCIPintervalGetSup(xbndszero),
3759  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3763  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3764  SCIPdebugMessage("added linear constraint: ");
3765  SCIPdebugPrintCons(scip, auxcons, NULL);
3766  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3767  ++*naddconss;
3768 
3769  /* add linear term scale*auxvar to this constraint */
3770  SCIP_CALL( addLinearCoef(scip, cons, auxvar, scale) );
3771 
3772  /* forget about auxvar */
3773  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3774  }
3775  }
3776  while( j < nbilinterms );
3777 
3778  /* remove bilinear terms that have been replaced */
3779  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3780  }
3781  SCIPdebugMessage("resulting quadratic constraint: ");
3782  SCIPdebugPrintCons(scip, cons, NULL);
3783 
3784  SCIPfreeBufferArrayNull(scip, &xvars);
3785  SCIPfreeBufferArrayNull(scip, &xcoef);
3786  SCIPfreeBufferArrayNull(scip, &todelete);
3787 
3788  return SCIP_OKAY;
3789 }
3790 
3791 /** tries to automatically convert a quadratic constraint (or a part of it) into a more specific and more specialized constraint */
3792 static
3794  SCIP* scip, /**< SCIP data structure */
3795  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
3796  SCIP_CONS* cons, /**< source constraint to try to convert */
3797  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
3798  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
3799  int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
3800  )
3801 {
3802  SCIP_CONSHDLRDATA* conshdlrdata;
3803  SCIP_CONSDATA* consdata;
3804  SCIP_VAR* var;
3805  SCIP_Real lincoef;
3806  SCIP_Real quadcoef;
3807  SCIP_Real lb;
3808  SCIP_Real ub;
3809  int nbinlin;
3810  int nbinquad;
3811  int nintlin;
3812  int nintquad;
3813  int nimpllin;
3814  int nimplquad;
3815  int ncontlin;
3816  int ncontquad;
3817  SCIP_Bool integral;
3818  int i;
3819  int j;
3820  SCIP_CONS** upgdconss;
3821  int upgdconsssize;
3822  int nupgdconss_;
3823 
3824  assert(scip != NULL);
3825  assert(conshdlr != NULL);
3826  assert(cons != NULL);
3827  assert(!SCIPconsIsModifiable(cons));
3828  assert(upgraded != NULL);
3829  assert(nupgdconss != NULL);
3830  assert(naddconss != NULL);
3831 
3832  *upgraded = FALSE;
3833 
3834  nupgdconss_ = 0;
3835 
3836  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3837  assert(conshdlrdata != NULL);
3838 
3839  /* if there are no upgrade methods, we can also stop */
3840  if( conshdlrdata->nquadconsupgrades == 0 )
3841  return SCIP_OKAY;
3842 
3843  upgdconsssize = 2;
3844  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
3845 
3846  consdata = SCIPconsGetData(cons);
3847  assert(consdata != NULL);
3848 
3849  /* calculate some statistics on quadratic constraint */
3850  nbinlin = 0;
3851  nbinquad = 0;
3852  nintlin = 0;
3853  nintquad = 0;
3854  nimpllin = 0;
3855  nimplquad = 0;
3856  ncontlin = 0;
3857  ncontquad = 0;
3858  integral = TRUE;
3859  for( i = 0; i < consdata->nlinvars; ++i )
3860  {
3861  var = consdata->linvars[i];
3862  lincoef = consdata->lincoefs[i];
3863  lb = SCIPvarGetLbLocal(var);
3864  ub = SCIPvarGetUbLocal(var);
3865  assert(!SCIPisZero(scip, lincoef));
3866 
3867  switch( SCIPvarGetType(var) )
3868  {
3869  case SCIP_VARTYPE_BINARY:
3870  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3871  integral = integral && SCIPisIntegral(scip, lincoef);
3872  nbinlin++;
3873  break;
3874  case SCIP_VARTYPE_INTEGER:
3875  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3876  integral = integral && SCIPisIntegral(scip, lincoef);
3877  nintlin++;
3878  break;
3879  case SCIP_VARTYPE_IMPLINT:
3880  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3881  integral = integral && SCIPisIntegral(scip, lincoef);
3882  nimpllin++;
3883  break;
3885  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb);
3886  ncontlin++;
3887  break;
3888  default:
3889  SCIPerrorMessage("unknown variable type\n");
3890  return SCIP_INVALIDDATA;
3891  }
3892  }
3893 
3894  for( i = 0; i < consdata->nquadvars; ++i )
3895  {
3896  var = consdata->quadvarterms[i].var;
3897  lincoef = consdata->quadvarterms[i].lincoef;
3898  quadcoef = consdata->quadvarterms[i].sqrcoef;
3899  lb = SCIPvarGetLbLocal(var);
3900  ub = SCIPvarGetUbLocal(var);
3901 
3902  switch( SCIPvarGetType(var) )
3903  {
3904  case SCIP_VARTYPE_BINARY:
3905  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3906  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
3907  nbinquad++;
3908  break;
3909  case SCIP_VARTYPE_INTEGER:
3910  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3911  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
3912  nintquad++;
3913  break;
3914  case SCIP_VARTYPE_IMPLINT:
3915  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3916  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
3917  nimplquad++;
3918  break;
3920  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb + quadcoef * lb * lb);
3921  ncontquad++;
3922  break;
3923  default:
3924  SCIPerrorMessage("unknown variable type\n");
3925  return SCIP_INVALIDDATA;
3926  }
3927  }
3928 
3929  if( integral )
3930  {
3931  for( i = 0; i < consdata->nbilinterms && integral; ++i )
3932  {
3933  if( SCIPvarGetType(consdata->bilinterms[i].var1) < SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->bilinterms[i].var2) < SCIP_VARTYPE_CONTINUOUS )
3934  integral = integral && SCIPisIntegral(scip, consdata->bilinterms[i].coef);
3935  else
3936  integral = FALSE;
3937  }
3938  }
3939 
3940  /* call the upgrading methods */
3941 
3942  SCIPdebugMessage("upgrading quadratic constraint <%s> (%d upgrade methods):\n",
3943  SCIPconsGetName(cons), conshdlrdata->nquadconsupgrades);
3944  SCIPdebugMessage(" binlin=%d binquad=%d intlin=%d intquad=%d impllin=%d implquad=%d contlin=%d contquad=%d integral=%u\n",
3945  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral);
3946  SCIPdebugPrintCons(scip, cons, NULL);
3947 
3948  /* try all upgrading methods in priority order in case the upgrading step is enable */
3949  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
3950  {
3951  if( !conshdlrdata->quadconsupgrades[i]->active )
3952  continue;
3953 
3954  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
3955  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
3956  &nupgdconss_, upgdconss, upgdconsssize) );
3957 
3958  while( nupgdconss_ < 0 )
3959  {
3960  /* upgrade function requires more memory: resize upgdconss and call again */
3961  assert(-nupgdconss_ > upgdconsssize);
3962  upgdconsssize = -nupgdconss_;
3963  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
3964 
3965  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
3966  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
3967  &nupgdconss_, upgdconss, upgdconsssize) );
3968 
3969  assert(nupgdconss_ != 0);
3970  }
3971 
3972  if( nupgdconss_ > 0 )
3973  {
3974  /* got upgrade */
3975  SCIPdebugPrintCons(scip, cons, NULL);
3976  SCIPdebugMessage(" -> upgraded to %d constraints:\n", nupgdconss_);
3977 
3978  /* add the upgraded constraints to the problem and forget them */
3979  for( j = 0; j < nupgdconss_; ++j )
3980  {
3981  SCIPdebugPrintf("\t");
3982  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
3983 
3984  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
3985  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
3986  }
3987 
3988  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
3989  *nupgdconss += 1;
3990  *naddconss += nupgdconss_ - 1;
3991  *upgraded = TRUE;
3992 
3993  /* delete upgraded constraint */
3994  SCIPdebugMessage("delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
3995  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
3996  SCIP_CALL( SCIPdelCons(scip, cons) );
3997 
3998  break;
3999  }
4000  }
4001 
4002  SCIPfreeBufferArray(scip, &upgdconss);
4003 
4004  return SCIP_OKAY;
4005 }
4006 
4007 /** helper function for presolveDisaggregate */
4008 static
4010  SCIP* scip, /**< SCIP data structure */
4011  SCIP_CONSDATA* consdata, /**< constraint data */
4012  int quadvaridx, /**< index of quadratic variable to mark */
4013  SCIP_HASHMAP* var2component, /**< variables to components mapping */
4014  int componentnr /**< the component number to mark to */
4015  )
4016 {
4017  SCIP_QUADVARTERM* quadvarterm;
4018  SCIP_VAR* othervar;
4019  int othervaridx;
4020  int i;
4021 
4022  assert(consdata != NULL);
4023  assert(quadvaridx >= 0);
4024  assert(quadvaridx < consdata->nquadvars);
4025  assert(var2component != NULL);
4026  assert(componentnr >= 0);
4027 
4028  quadvarterm = &consdata->quadvarterms[quadvaridx];
4029 
4030  if( SCIPhashmapExists(var2component, quadvarterm->var) )
4031  {
4032  /* if we saw the variable before, then it should have the same component number */
4033  assert((int)(size_t)SCIPhashmapGetImage(var2component, quadvarterm->var) == componentnr);
4034  return SCIP_OKAY;
4035  }
4036 
4037  /* assign component number to variable */
4038  SCIP_CALL( SCIPhashmapInsert(var2component, quadvarterm->var, (void*)(size_t)componentnr) );
4039 
4040  /* assign same component number to all variables this variable is multiplied with */
4041  for( i = 0; i < quadvarterm->nadjbilin; ++i )
4042  {
4043  othervar = consdata->bilinterms[quadvarterm->adjbilin[i]].var1 == quadvarterm->var ?
4044  consdata->bilinterms[quadvarterm->adjbilin[i]].var2 : consdata->bilinterms[quadvarterm->adjbilin[i]].var1;
4045  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, othervar, &othervaridx) );
4046  assert(othervaridx >= 0);
4047  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, othervaridx, var2component, componentnr) );
4048  }
4049 
4050  return SCIP_OKAY;
4051 }
4052 
4053 /** for quadratic constraints that consists of a sum of quadratic terms, disaggregates the sum into a set of constraints by introducing auxiliary variables */
4054 static
4056  SCIP* scip, /**< SCIP data structure */
4057  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4058  SCIP_CONS* cons, /**< source constraint to try to convert */
4059  int* naddconss /**< pointer to counter of added constraints */
4060  )
4061 {
4062  SCIP_CONSDATA* consdata;
4063  SCIP_HASHMAP* var2component;
4064  int ncomponents;
4065  int i;
4066  int comp;
4067  SCIP_CONS** auxconss;
4068  SCIP_VAR** auxvars;
4069  SCIP_Real* auxcoefs;
4070  char name[SCIP_MAXSTRLEN];
4071 
4072  assert(scip != NULL);
4073  assert(conshdlr != NULL);
4074  assert(cons != NULL);
4075  assert(naddconss != NULL);
4076 
4077  consdata = SCIPconsGetData(cons);
4078  assert(consdata != NULL);
4079 
4080  /* make sure there are no quadratic variables without coefficients */
4081  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4082  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
4083 
4084  if( consdata->nquadvars <= 1 )
4085  return SCIP_OKAY;
4086 
4087  /* sort quadratic variable terms here, so we can later search in it without reordering the array */
4088  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4089 
4090  /* check how many quadratic terms with non-overlapping variables we have
4091  * in other words, the number of components in the sparsity graph of the quadratic term matrix */
4092  ncomponents = 0;
4093  SCIP_CALL( SCIPhashmapCreate(&var2component, SCIPblkmem(scip), SCIPcalcHashtableSize(consdata->nquadvars)) );
4094  for( i = 0; i < consdata->nquadvars; ++i )
4095  {
4096  /* if variable was marked already, skip it */
4097  if( SCIPhashmapExists(var2component, (void*)consdata->quadvarterms[i].var) )
4098  continue;
4099 
4100  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, i, var2component, ncomponents) );
4101  ++ncomponents;
4102  }
4103  assert(ncomponents >= 1);
4104 
4105  /* if there is only one component, we cannot disaggregate
4106  * @todo we could still split the constraint into several while keeping the number of variables sharing several constraints as small as possible
4107  */
4108  if( ncomponents == 1 )
4109  {
4110  SCIPhashmapFree(&var2component);
4111  return SCIP_OKAY;
4112  }
4113 
4114  SCIP_CALL( SCIPallocBufferArray(scip, &auxconss, ncomponents) );
4115  SCIP_CALL( SCIPallocBufferArray(scip, &auxvars, ncomponents) );
4116  SCIP_CALL( SCIPallocBufferArray(scip, &auxcoefs, ncomponents) );
4117 
4118  /* create auxiliary variables and empty constraints for each component */
4119  for( comp = 0; comp < ncomponents; ++comp )
4120  {
4121  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp%d", SCIPconsGetName(cons), comp);
4122 
4123  SCIP_CALL( SCIPcreateVar(scip, &auxvars[comp], name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
4125 
4126  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &auxconss[comp], name, 0, NULL, NULL, 0, NULL, 0, NULL,
4127  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : 0.0),
4128  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : 0.0),
4131  SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons)) );
4132 
4133  auxcoefs[comp] = SCIPinfinity(scip);
4134  }
4135 
4136  /* add quadratic variables to each component constraint
4137  * delete adjacency information */
4138  for( i = 0; i < consdata->nquadvars; ++i )
4139  {
4140  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->quadvarterms[i].var);
4141  assert(comp >= 0);
4142  assert(comp < ncomponents);
4143 
4144  /* add variable term to corresponding constraint */
4145  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, auxconss[comp], consdata->quadvarterms[i].var, consdata->quadvarterms[i].lincoef, consdata->quadvarterms[i].sqrcoef) );
4146 
4147  /* reduce coefficient of aux variable */
4148  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) && ABS(consdata->quadvarterms[i].lincoef) < auxcoefs[comp] )
4149  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].lincoef);
4150  if( !SCIPisZero(scip, consdata->quadvarterms[i].sqrcoef) && ABS(consdata->quadvarterms[i].sqrcoef) < auxcoefs[comp] )
4151  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].sqrcoef);
4152 
4153  SCIPfreeBlockMemoryArray(scip, &consdata->quadvarterms[i].adjbilin, consdata->quadvarterms[i].adjbilinsize);
4154  consdata->quadvarterms[i].nadjbilin = 0;
4155  consdata->quadvarterms[i].adjbilinsize = 0;
4156  }
4157 
4158  /* add bilinear terms to each component constraint */
4159  for( i = 0; i < consdata->nbilinterms; ++i )
4160  {
4161  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var1);
4162  assert(comp == (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var2));
4163  assert(!SCIPisZero(scip, consdata->bilinterms[i].coef));
4164 
4165  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, auxconss[comp],
4166  consdata->bilinterms[i].var1, consdata->bilinterms[i].var2, consdata->bilinterms[i].coef) );
4167 
4168  if( ABS(consdata->bilinterms[i].coef) < auxcoefs[comp] )
4169  auxcoefs[comp] = ABS(consdata->bilinterms[i].coef);
4170  }
4171 
4172  /* forget about bilinear terms in cons */
4173  SCIPfreeBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize);
4174  consdata->nbilinterms = 0;
4175  consdata->bilintermssize = 0;
4176 
4177  /* remove quadratic variable terms from cons */
4178  for( i = consdata->nquadvars - 1; i >= 0; --i )
4179  {
4180  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
4181  }
4182  assert(consdata->nquadvars == 0);
4183 
4184  /* add auxiliary variables to auxiliary constraints
4185  * add aux vars and constraints to SCIP
4186  * add aux vars to this constraint
4187  * @todo compute debug solution values and set for auxvars
4188  */
4189  SCIPdebugMessage("add %d constraints for disaggregation of quadratic constraint <%s>\n", ncomponents, SCIPconsGetName(cons));
4190  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + ncomponents) );
4191  for( comp = 0; comp < ncomponents; ++comp )
4192  {
4193  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, auxconss[comp], auxvars[comp], -auxcoefs[comp]) );
4194 
4195  SCIP_CALL( SCIPaddVar(scip, auxvars[comp]) );
4196 
4197  SCIP_CALL( SCIPaddCons(scip, auxconss[comp]) );
4198  SCIPdebugPrintCons(scip, auxconss[comp], NULL);
4199 
4200  SCIP_CALL( addLinearCoef(scip, cons, auxvars[comp], auxcoefs[comp]) );
4201 
4202  SCIP_CALL( SCIPreleaseCons(scip, &auxconss[comp]) );
4203  SCIP_CALL( SCIPreleaseVar(scip, &auxvars[comp]) );
4204  }
4205  *naddconss += ncomponents;
4206 
4207  SCIPdebugPrintCons(scip, cons, NULL);
4208 
4209  SCIPfreeBufferArray(scip, &auxconss);
4210  SCIPfreeBufferArray(scip, &auxvars);
4211  SCIPfreeBufferArray(scip, &auxcoefs);
4212  SCIPhashmapFree(&var2component);
4213 
4214  return SCIP_OKAY;
4215 }
4216 
4217 #ifdef CHECKIMPLINBILINEAR
4218 /** checks if there are bilinear terms x*y with a binary variable x and an implication x = {0,1} -> y = 0
4219  * in this case, the bilinear term can be removed (x=0 case) or replaced by y (x=1 case)
4220  */
4221 static
4222 SCIP_RETCODE presolveApplyImplications(
4223  SCIP* scip, /**< SCIP data structure */
4224  SCIP_CONS* cons, /**< quadratic constraint */
4225  int* nbilinremoved /**< buffer to store number of removed bilinear terms */
4226  )
4227 {
4228  SCIP_CONSDATA* consdata;
4229  SCIP_VAR* x;
4230  SCIP_VAR* y;
4231  SCIP_INTERVAL implbnds;
4232  int i;
4233  int j;
4234  int k;
4235 
4236  assert(scip != NULL);
4237  assert(cons != NULL);
4238  assert(nbilinremoved != NULL);
4239 
4240  *nbilinremoved = 0;
4241 
4242  consdata = SCIPconsGetData(cons);
4243  assert(consdata != NULL);
4244 
4245  SCIPdebugMessage("apply implications in <%s>\n", SCIPconsGetName(cons));
4246 
4247  /* sort quadvarterms in case we need to search */
4248  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4249 
4250  for( i = 0; i < consdata->nquadvars; ++i )
4251  {
4252  x = consdata->quadvarterms[i].var;
4253  assert(x != NULL);
4254 
4255  if( consdata->quadvarterms[i].nadjbilin == 0 )
4256  continue;
4257 
4258  if( !SCIPvarIsBinary(x) )
4259  continue;
4260 
4261  if( !SCIPvarIsActive(x) )
4262  continue;
4263 
4264  if( SCIPvarGetNImpls(x, TRUE) == 0 && SCIPvarGetNImpls(x, FALSE) == 0 )
4265  continue;
4266 
4267  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4268  {
4269  k = consdata->quadvarterms[i].adjbilin[j];
4270  assert(k >= 0);
4271  assert(k < consdata->nbilinterms);
4272 
4273  if( consdata->bilinterms[k].coef == 0.0 )
4274  continue;
4275 
4276  y = consdata->bilinterms[k].var1 == x ? consdata->bilinterms[k].var2 : consdata->bilinterms[k].var1;
4277  assert(x != y);
4278 
4279  getImpliedBounds(x, TRUE, y, &implbnds);
4280  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4281  {
4282  /* if x = 1 implies y = 0, then we can remove the bilinear term x*y, since it is always 0
4283  * we only set the coefficient to 0.0 here and mark the bilinterms as not merged */
4284  SCIPdebugMessage("remove bilinear term %g<%s><%s> from <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), SCIPconsGetName(cons));
4285  consdata->bilinterms[k].coef = 0.0;
4286  consdata->bilinmerged = FALSE;
4287  ++*nbilinremoved;
4288  continue;
4289  }
4290 
4291  getImpliedBounds(x, FALSE, y, &implbnds);
4292  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4293  {
4294  /* if x = 0 implies y = 0, then we can replace the bilinear term x*y by y
4295  * we only move the coefficient to the linear coef of y here and mark the bilinterms as not merged */
4296  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));
4297  assert(consdata->quadvarssorted);
4298  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, cons, y, consdata->bilinterms[k].coef) );
4299  consdata->bilinterms[k].coef = 0.0;
4300  consdata->bilinmerged = FALSE;
4301  ++*nbilinremoved;
4302  }
4303  }
4304  }
4305 
4306  if( *nbilinremoved > 0 )
4307  {
4308  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4309 
4310  /* invalidate nonlinear row */
4311  if( consdata->nlrow != NULL )
4312  {
4313  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4314  }
4315 
4316  consdata->ispropagated = FALSE;
4317  consdata->ispresolved = FALSE;
4318  consdata->iscurvchecked = FALSE;
4319  }
4320 
4321  consdata->isimpladded = FALSE;
4322 
4323  return SCIP_OKAY;
4324 }
4325 #endif
4326 
4327 /** checks a quadratic constraint for convexity and/or concavity without checking multivariate functions */
4328 static
4330  SCIP* scip, /**< SCIP data structure */
4331  SCIP_CONS* cons, /**< quadratic constraint */
4332  SCIP_Bool* determined, /**< pointer to store whether the curvature could be determined */
4333  SCIP_Bool checkmultivariate /**< whether curvature will be checked later on for multivariate functions */
4334  )
4335 {
4336  SCIP_CONSDATA* consdata;
4337  int nquadvars;
4338 
4339  assert(scip != NULL);
4340  assert(cons != NULL);
4341  assert(determined != NULL);
4342 
4343  consdata = SCIPconsGetData(cons);
4344  assert(consdata != NULL);
4345 
4346  nquadvars = consdata->nquadvars;
4347  *determined = TRUE;
4348 
4349  if( consdata->iscurvchecked )
4350  return;
4351 
4352  SCIPdebugMessage("Checking curvature of constraint <%s> without multivariate functions\n", SCIPconsGetName(cons));
4353 
4354  if( nquadvars == 1 )
4355  {
4356  assert(consdata->nbilinterms == 0);
4357  consdata->isconvex = !SCIPisNegative(scip, consdata->quadvarterms[0].sqrcoef);
4358  consdata->isconcave = !SCIPisPositive(scip, consdata->quadvarterms[0].sqrcoef);
4359  consdata->iscurvchecked = TRUE;
4360  }
4361  else if( nquadvars == 0 )
4362  {
4363  consdata->isconvex = TRUE;
4364  consdata->isconcave = TRUE;
4365  consdata->iscurvchecked = TRUE;
4366  }
4367  else if( consdata->nbilinterms == 0 )
4368  {
4369  int v;
4370 
4371  consdata->isconvex = TRUE;
4372  consdata->isconcave = TRUE;
4373 
4374  for( v = nquadvars - 1; v >= 0; --v )
4375  {
4376  consdata->isconvex = consdata->isconvex && !SCIPisNegative(scip, consdata->quadvarterms[v].sqrcoef);
4377  consdata->isconcave = consdata->isconcave && !SCIPisPositive(scip, consdata->quadvarterms[v].sqrcoef);
4378  }
4379 
4380  consdata->iscurvchecked = TRUE;
4381  }
4382  else if( !checkmultivariate )
4383  {
4384  consdata->isconvex = FALSE;
4385  consdata->isconcave = FALSE;
4386  consdata->iscurvchecked = TRUE;
4387  }
4388  else
4389  *determined = FALSE;
4390 }
4391 
4392 /** checks a quadratic constraint for convexity and/or concavity */
4393 static
4395  SCIP* scip, /**< SCIP data structure */
4396  SCIP_CONS* cons, /**< quadratic constraint */
4397  SCIP_Bool checkmultivariate /**< whether curvature should also be checked for multivariate functions */
4398  )
4399 {
4400  SCIP_CONSDATA* consdata;
4401  double* matrix;
4402  SCIP_HASHMAP* var2index;
4403  int i;
4404  int n;
4405  int nn;
4406  int row;
4407  int col;
4408  double* alleigval;
4409  SCIP_Bool determined;
4410 
4411  assert(scip != NULL);
4412  assert(cons != NULL);
4413 
4414  consdata = SCIPconsGetData(cons);
4415  assert(consdata != NULL);
4416 
4417  n = consdata->nquadvars;
4418 
4419  if( consdata->iscurvchecked )
4420  return SCIP_OKAY;
4421 
4422  /* easy checks for curvature detection */
4423  checkCurvatureEasy(scip, cons, &determined, checkmultivariate);
4424 
4425  /* if curvature was already detected stop */
4426  if( determined )
4427  return SCIP_OKAY;
4428 
4429  SCIPdebugMessage("Checking curvature of constraint <%s> with multivariate functions\n", SCIPconsGetName(cons));
4430 
4431  if( n == 2 )
4432  {
4433  /* compute eigenvalues by hand */
4434  assert(consdata->nbilinterms == 1);
4435  consdata->isconvex =
4436  consdata->quadvarterms[0].sqrcoef >= 0 &&
4437  consdata->quadvarterms[1].sqrcoef >= 0 &&
4438  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4439  consdata->isconcave =
4440  consdata->quadvarterms[0].sqrcoef <= 0 &&
4441  consdata->quadvarterms[1].sqrcoef <= 0 &&
4442  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4443  consdata->iscurvchecked = TRUE;
4444  return SCIP_OKAY;
4445  }
4446 
4447  /* lower triangular of quadratic term matrix */
4448  nn = n * n;
4449  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, nn) );
4450  BMSclearMemoryArray(matrix, nn);
4451 
4452  consdata->isconvex = TRUE;
4453  consdata->isconcave = TRUE;
4454 
4455  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * n)) );
4456  for( i = 0; i < n; ++i )
4457  {
4458  if( consdata->quadvarterms[i].nadjbilin > 0 )
4459  {
4460  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
4461  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4462  }
4463  /* nonzero elements on diagonal tell a lot about convexity/concavity */
4464  if( SCIPisNegative(scip, consdata->quadvarterms[i].sqrcoef) )
4465  consdata->isconvex = FALSE;
4466  if( SCIPisPositive(scip, consdata->quadvarterms[i].sqrcoef) )
4467  consdata->isconcave = FALSE;
4468  }
4469 
4470  if( !consdata->isconvex && !consdata->isconcave )
4471  {
4472  SCIPfreeBufferArray(scip, &matrix);
4473  SCIPhashmapFree(&var2index);
4474  consdata->iscurvchecked = TRUE;
4475  return SCIP_OKAY;
4476  }
4477 
4479  {
4480  for( i = 0; i < consdata->nbilinterms; ++i )
4481  {
4482  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
4483  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
4484  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
4485  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
4486  if( row < col )
4487  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
4488  else
4489  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
4490  }
4491 
4492  SCIP_CALL( SCIPallocBufferArray(scip, &alleigval, n) );
4493  /* @todo Can we compute only min and max eigen value?
4494  * @todo Can we estimate the numerical error?
4495  * @todo Trying a cholesky factorization may be much faster.
4496  */
4497  if( LapackDsyev(FALSE, n, matrix, alleigval) != SCIP_OKAY )
4498  {
4499  SCIPwarningMessage(scip, "Failed to compute eigenvalues of quadratic coefficient matrix of constraint %s. Assuming matrix is indefinite.\n", SCIPconsGetName(cons));
4500  consdata->isconvex = FALSE;
4501  consdata->isconcave = FALSE;
4502  }
4503  else
4504  {
4505  /* deconvexification reformulates a stricly convex quadratic function in binaries such that it becomes not-strictly convex
4506  * by adding the -lambda*(x^2-x) terms for lambda the smallest eigenvalue of the matrix
4507  * 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
4508  */
4509 #ifdef DECONVEXIFY
4510  SCIP_Bool allbinary;
4511  printf("cons <%s>[%g,%g] spectrum = [%g,%g]\n", SCIPconsGetName(cons), consdata->lhs, consdata->rhs, alleigval[0], alleigval[n-1]);
4512 #endif
4513  consdata->isconvex &= !SCIPisNegative(scip, alleigval[0]); /*lint !e514*/
4514  consdata->isconcave &= !SCIPisPositive(scip, alleigval[n-1]); /*lint !e514*/
4515  consdata->iscurvchecked = TRUE;
4516 #ifdef DECONVEXIFY
4517  for( i = 0; i < consdata->nquadvars; ++i )
4518  if( !SCIPvarIsBinary(consdata->quadvarterms[i].var) )
4519  break;
4520  allbinary = i == consdata->nquadvars;
4521 
4522  if( !SCIPisInfinity(scip, consdata->rhs) && alleigval[0] > 0.1 && allbinary )
4523  {
4524  printf("deconvexify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[0]);
4525  for( i = 0; i < consdata->nquadvars; ++i )
4526  {
4527  consdata->quadvarterms[i].sqrcoef -= alleigval[0];
4528  consdata->quadvarterms[i].lincoef += alleigval[0];
4529  }
4530  }
4531 
4532  if( !SCIPisInfinity(scip, consdata->lhs) && alleigval[n-1] < -0.1 && allbinary )
4533  {
4534  printf("deconcavify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[n-1]);
4535  for( i = 0; i < consdata->nquadvars; ++i )
4536  {
4537  consdata->quadvarterms[i].sqrcoef -= alleigval[n-1];
4538  consdata->quadvarterms[i].lincoef += alleigval[n-1];
4539  }
4540  }
4541 #endif
4542  }
4543 
4544  SCIPfreeBufferArray(scip, &alleigval);
4545  }
4546  else
4547  {
4548  consdata->isconvex = FALSE;
4549  consdata->isconcave = FALSE;
4550  consdata->iscurvchecked = TRUE; /* set to TRUE since it does not help to repeat this procedure again and again (that will not bring Ipopt in) */
4551  }
4552 
4553  SCIPhashmapFree(&var2index);
4554  SCIPfreeBufferArray(scip, &matrix);
4555 
4556  return SCIP_OKAY;
4557 }
4558 
4559 /** check whether indefinite constraint function is factorable and store corresponding coefficients */
4560 static
4562  SCIP* scip, /**< SCIP data structure */
4563  SCIP_CONS* cons /**< constraint */
4564  )
4565 {
4566  SCIP_BILINTERM* bilinterm;
4567  SCIP_CONSDATA* consdata;
4568  SCIP_Real* a;
4569  SCIP_Real* eigvals;
4570  SCIP_Real sigma1;
4571  SCIP_Real sigma2;
4572  int n;
4573  int i;
4574  int idx1;
4575  int idx2;
4576  int posidx;
4577  int negidx;
4578 
4579  assert(scip != NULL);
4580  assert(cons != NULL);
4581 
4582  consdata = SCIPconsGetData(cons);
4583  assert(consdata != NULL);
4584  assert(consdata->factorleft == NULL);
4585  assert(consdata->factorright == NULL);
4586 
4587  /* we don't need this if there are no bilinear terms */
4588  if( consdata->nbilinterms == 0 )
4589  return SCIP_OKAY;
4590 
4591  /* write constraint as lhs <= linear + x'^T A x' <= rhs where x' = (x,1) and
4592  * A = ( Q b/2 )
4593  * ( b^T/2 0 )
4594  * compute an eigenvalue factorization of A and check if there are one positive and one negative eigenvalue
4595  * 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
4596  * thus, x'^T A x' = sigma1^2 (v1^T x')^2 - sigma2^2 (v2^T x')^2
4597  * = (sigma1 (v1^T x') - sigma2 (v2^T x')) * (sigma1 (v1^T x') + sigma2 (v2^T x'))
4598  * we then store sigma1 v1^T - sigma2 v2^T as left factor coef, and sigma1 v1^T + sigma2 v2^T as right factor coef
4599  */
4600 
4601  /* if we already know that there are only positive or only negative eigenvalues, then don't try */
4602  if( consdata->iscurvchecked && (consdata->isconvex || consdata->isconcave) )
4603  return SCIP_OKAY;
4604 
4605  n = consdata->nquadvars + 1;
4606 
4607  /* @todo handle case n=3 explicitly */
4608 
4609  /* skip too large matrices */
4610  if( n > 50 )
4611  return SCIP_OKAY;
4612 
4613  /* need routine to compute eigenvalues/eigenvectors */
4614  if( !SCIPisIpoptAvailableIpopt() )
4615  return SCIP_OKAY;
4616 
4617  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4618 
4619  SCIP_CALL( SCIPallocBufferArray(scip, &a, n*n) );
4620  BMSclearMemoryArray(a, n*n);
4621 
4622  /* set lower triangular entries of A corresponding to bilinear terms */
4623  for( i = 0; i < consdata->nbilinterms; ++i )
4624  {
4625  bilinterm = &consdata->bilinterms[i];
4626 
4627  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4628  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4629  assert(idx1 >= 0);
4630  assert(idx2 >= 0);
4631  assert(idx1 != idx2);
4632 
4633  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
4634  }
4635 
4636  /* set lower triangular entries of A corresponding to square and linear terms */
4637  for( i = 0; i < consdata->nquadvars; ++i )
4638  {
4639  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4640  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
4641  }
4642 
4643  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, n) );
4644  if( LapackDsyev(TRUE, n, a, eigvals) != SCIP_OKAY )
4645  {
4646  SCIPdebugMessage("Failed to compute eigenvalues and eigenvectors of augmented quadratic form matrix for constraint <%s>.\n", SCIPconsGetName(cons));
4647  goto CLEANUP;
4648  }
4649 
4650  /* check if there is exactly one positive and one negative eigenvalue */
4651  posidx = -1;
4652  negidx = -1;
4653  for( i = 0; i < n; ++i )
4654  {
4655  if( SCIPisPositive(scip, eigvals[i]) )
4656  {
4657  if( posidx == -1 )
4658  posidx = i;
4659  else
4660  break;
4661  }
4662  else if( SCIPisNegative(scip, eigvals[i]) )
4663  {
4664  if( negidx == -1 )
4665  negidx = i;
4666  else
4667  break;
4668  }
4669  }
4670  if( i < n || posidx == -1 || negidx == -1 )
4671  {
4672  SCIPdebugMessage("Augmented quadratic form of constraint <%s> is not factorable.\n", SCIPconsGetName(cons));
4673  goto CLEANUP;
4674  }
4675  assert(SCIPisPositive(scip, eigvals[posidx]));
4676  assert(SCIPisNegative(scip, eigvals[negidx]));
4677 
4678  /* compute factorleft and factorright */
4679  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1) );
4680  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1) );
4681 
4682  /* eigenvectors are stored in a, inverse eigenvector matrix is transposed of a
4683  * it seems that v1 and v2 are at &a[posidx*n] and &a[negidx*n]
4684  */
4685  sigma1 = sqrt( eigvals[posidx]);
4686  sigma2 = sqrt(-eigvals[negidx]);
4687  for( i = 0; i < n; ++i )
4688  {
4689  consdata->factorleft[i] = sigma1 * a[posidx * n + i] - sigma2 * a[negidx * n + i];
4690  consdata->factorright[i] = sigma1 * a[posidx * n + i] + sigma2 * a[negidx * n + i];
4691  if( SCIPisZero(scip, consdata->factorleft[i]) )
4692  consdata->factorleft[i] = 0.0;
4693  if( SCIPisZero(scip, consdata->factorright[i]) )
4694  consdata->factorright[i] = 0.0;
4695  }
4696 
4697  SCIPdebugMessage("constraint <%s> has factorable quadratic form: (%g", SCIPconsGetName(cons), consdata->factorleft[n-1]);
4698  for( i = 0; i < consdata->nquadvars; ++i )
4699  {
4700  if( consdata->factorleft[i] != 0.0 )
4701  SCIPdebugPrintf(" %+g<%s>", consdata->factorleft[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4702  }
4703  SCIPdebugPrintf(") * (%g", consdata->factorright[n-1]);
4704  for( i = 0; i < consdata->nquadvars; ++i )
4705  {
4706  if( consdata->factorright[i] != 0.0 )
4707  SCIPdebugPrintf(" %+g<%s>", consdata->factorright[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4708  }
4709  SCIPdebugPrintf(")\n");
4710 
4711 #ifndef NDEBUG
4712  /* check whether factorleft * factorright^T is matrix of augmented quadratic form */
4713  BMSclearMemoryArray(a, n*n);
4714 
4715  /* set lower triangular entries of A corresponding to bilinear terms */
4716  for( i = 0; i < consdata->nbilinterms; ++i )
4717  {
4718  bilinterm = &consdata->bilinterms[i];
4719 
4720  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4721  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4722  assert(idx1 >= 0);
4723  assert(idx2 >= 0);
4724  assert(idx1 != idx2);
4725 
4726  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
4727  }
4728 
4729  /* set lower triangular entries of A corresponding to square and linear terms */
4730  for( i = 0; i < consdata->nquadvars; ++i )
4731  {
4732  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4733  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
4734  }
4735 
4736  /* compare matrix entries */
4737  for( i = 0; i < n; ++i )
4738  {
4739  int j;
4740 
4741  /* on off-diagonal elements, only the sum of corresponding entries need to coincide */
4742  for( j = 0; j < i; ++j )
4743  assert(SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[j] + consdata->factorleft[j] * consdata->factorright[i], 2*a[j*n+i]));
4744 
4745  /* check diagonal elements */
4746  assert(SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[i], a[i*n+i]));
4747  }
4748 #endif
4749 
4750  CLEANUP:
4751  SCIPfreeBufferArray(scip, &a);
4752  SCIPfreeBufferArray(scip, &eigvals);
4753 
4754  return SCIP_OKAY;
4755 }
4756 
4757 /** gets maximal absolute value in gradient of quadratic function */
4758 static
4760  SCIP* scip, /**< SCIP data structure */
4761  SCIP_CONS* cons, /**< constraint */
4762  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
4763  )
4764 {
4765  SCIP_CONSDATA* consdata;
4766  SCIP_Real maxelem;
4767  SCIP_Real g;
4768  int i, j, k;
4769  SCIP_VAR* var;
4770 
4771  assert(scip != NULL);
4772  assert(cons != NULL);
4773 
4774  consdata = SCIPconsGetData(cons);
4775  assert(consdata != NULL);
4776 
4777  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
4778  {
4779  maxelem = 0.0;
4780  for( i = 0; i < consdata->nlinvars; ++i )
4781  if( REALABS(consdata->lincoefs[i]) > maxelem )
4782  maxelem = REALABS(consdata->lincoefs[i]);
4783  }
4784  else
4785  {
4786  maxelem = consdata->lincoefsmax;
4787  }
4788 
4789  for( i = 0; i < consdata->nquadvars; ++i )
4790  {
4791  var = consdata->quadvarterms[i].var;
4792  assert(!SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)));
4793  assert(!SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)));
4794  g = consdata->quadvarterms[i].lincoef;
4795  g += 2.0 * consdata->quadvarterms[i].sqrcoef * SCIPgetSolVal(scip, sol, var);
4796  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4797  {
4798  k = consdata->quadvarterms[i].adjbilin[j];
4799  if( consdata->bilinterms[k].var1 == var )
4800  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var2);
4801  else
4802  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var1);
4803  }
4804  if( REALABS(g) > maxelem )
4805  maxelem = REALABS(g);
4806  }
4807 
4808  return maxelem;
4809 }
4810 
4811 /** computes activity and violation of a constraint */
4812 static
4814  SCIP* scip, /**< SCIP data structure */
4815  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4816  SCIP_CONS* cons, /**< constraint */
4817  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
4818  )
4819 { /*lint --e{666}*/
4820  SCIP_CONSHDLRDATA* conshdlrdata;
4821  SCIP_CONSDATA* consdata;
4822  SCIP_Real varval;
4823  SCIP_Real varval2;
4824  SCIP_VAR* var;
4825  SCIP_VAR* var2;
4826  int i;
4827  int j;
4828 
4829  assert(scip != NULL);
4830  assert(cons != NULL);
4831 
4832  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4833  assert(conshdlrdata != NULL);
4834 
4835  consdata = SCIPconsGetData(cons);
4836  assert(consdata != NULL);
4837 
4838  consdata->activity = 0.0;
4839  varval = 0.0;
4840 
4841  /* @todo Take better care of variables at +/- infinity: e.g., run instance waste in debug mode with a short timelimit (30s). */
4842  for( i = 0; i < consdata->nlinvars; ++i )
4843  {
4844  var = consdata->linvars[i];
4845  varval = SCIPgetSolVal(scip, sol, var);
4846 
4847  if( SCIPisInfinity(scip, REALABS(varval)) )
4848  {
4849  consdata->activity = SCIPinfinity(scip);
4850  if( !SCIPisInfinity(scip, -consdata->lhs) )
4851  consdata->lhsviol = SCIPinfinity(scip);
4852  if( !SCIPisInfinity(scip, consdata->rhs) )
4853  consdata->rhsviol = SCIPinfinity(scip);
4854  return SCIP_OKAY;
4855  }
4856 
4857  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
4858  if( sol == NULL )
4859  {
4860 #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 */
4861  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
4862  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
4863 #endif
4864  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
4865  }
4866 
4867  consdata->activity += consdata->lincoefs[i] * varval;
4868  }
4869 
4870  for( j = 0; j < consdata->nquadvars; ++j )
4871  {
4872  var = consdata->quadvarterms[j].var;
4873  varval = SCIPgetSolVal(scip, sol, var);
4874  if( SCIPisInfinity(scip, REALABS(varval)) )
4875  {
4876  consdata->activity = SCIPinfinity(scip);
4877  if( !SCIPisInfinity(scip, -consdata->lhs) )
4878  consdata->lhsviol = SCIPinfinity(scip);
4879  if( !SCIPisInfinity(scip, consdata->rhs) )
4880  consdata->rhsviol = SCIPinfinity(scip);
4881  return SCIP_OKAY;
4882  }
4883 
4884  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
4885  if( sol == NULL )
4886  {
4887 #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 */
4888  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
4889  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
4890 #endif
4891  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
4892  }
4893 
4894  consdata->activity += (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
4895  }
4896 
4897  for( j = 0; j < consdata->nbilinterms; ++j )
4898  {
4899  var = consdata->bilinterms[j].var1;
4900  var2 = consdata->bilinterms[j].var2;
4901  varval = SCIPgetSolVal(scip, sol, var);
4902  varval2 = SCIPgetSolVal(scip, sol, var2);
4903 
4904  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
4905  if( sol == NULL )
4906  {
4907 #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 */
4908  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
4909  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
4910 #endif
4911  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
4912 
4913 #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 */
4914  assert(SCIPisFeasGE(scip, varval2, SCIPvarGetLbLocal(var2)));
4915  assert(SCIPisFeasLE(scip, varval2, SCIPvarGetUbLocal(var2)));
4916 #endif
4917  varval2 = MAX(SCIPvarGetLbLocal(var2), MIN(SCIPvarGetUbLocal(var2), varval2));
4918  }
4919 
4920  consdata->activity += consdata->bilinterms[j].coef * varval * varval2;
4921  }
4922 
4923  /* compute absolute violation left hand side */
4924  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
4925  consdata->lhsviol = consdata->lhs - consdata->activity;
4926  else
4927  consdata->lhsviol = 0.0;
4928 
4929  /* compute absolute violation right hand side */
4930  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
4931  consdata->rhsviol = consdata->activity - consdata->rhs;
4932  else
4933  consdata->rhsviol = 0.0;
4934 
4935  switch( conshdlrdata->scaling )
4936  {
4937  case 'o' :
4938  /* no scaling */
4939  break;
4940 
4941  case 'g' :
4942  /* scale by sup-norm of gradient in current point */
4943  if( consdata->lhsviol > 0.0 || consdata->rhsviol > 0.0 )
4944  {
4945  SCIP_Real norm;
4946  norm = getGradientMaxElement(scip, cons, sol);
4947  if( norm > 1.0 )
4948  {
4949  consdata->lhsviol /= norm;
4950  consdata->rhsviol /= norm;
4951  }
4952  }
4953  break;
4954 
4955  case 's' :
4956  /* scale by left/right hand side of constraint */
4957  if( consdata->lhsviol > 0.0 )
4958  consdata->lhsviol /= MAX(1.0, REALABS(consdata->lhs));
4959 
4960  if( consdata->rhsviol > 0.0 )
4961  consdata->rhsviol /= MAX(1.0, REALABS(consdata->rhs));
4962 
4963  break;
4964 
4965  default :
4966  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
4967  SCIPABORT();
4968  return SCIP_INVALIDDATA; /*lint !e527*/
4969  }
4970 
4971  return SCIP_OKAY;
4972 }
4973 
4974 /** computes violation of a set of constraints */
4975 static
4977  SCIP* scip, /**< SCIP data structure */
4978  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4979  SCIP_CONS** conss, /**< constraints */
4980  int nconss, /**< number of constraints */
4981  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
4982  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
4983  )
4984 {
4985  SCIP_CONSDATA* consdata;
4986  SCIP_Real viol;
4987  SCIP_Real maxviol;
4988  int c;
4989 
4990  assert(scip != NULL);
4991  assert(conss != NULL || nconss == 0);
4992  assert(maxviolcon != NULL);
4993 
4994  *maxviolcon = NULL;
4995 
4996  maxviol = 0.0;
4997 
4998  for( c = 0; c < nconss; ++c )
4999  {
5000  assert(conss != NULL);
5001  assert(conss[c] != NULL);
5002 
5003  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
5004 
5005  consdata = SCIPconsGetData(conss[c]);
5006  assert(consdata != NULL);
5007 
5008  viol = MAX(consdata->lhsviol, consdata->rhsviol);
5009  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
5010  {
5011  maxviol = viol;
5012  *maxviolcon = conss[c];
5013  }
5014  }
5015 
5016  return SCIP_OKAY;
5017 }
5018 
5019 /** tries to compute cut for multleft * <coefleft, x'> * multright <= rhs / (multright * <coefright, x'>) where x'=(x,1) */
5020 static
5022  SCIP* scip, /**< SCIP data structure */
5023  SCIP_CONS* cons, /**< constraint */
5024  SCIP_Real* ref, /**< reference solution where to generate the cut */
5025  SCIP_Real multleft, /**< multiplicator on lhs */
5026  SCIP_Real* coefleft, /**< coefficient for factor on lhs */
5027  SCIP_Real multright, /**< multiplicator on both sides */
5028  SCIP_Real* coefright, /**< coefficient for factor that goes to rhs */
5029  SCIP_Real rightminactivity, /**< minimal activity of <coefright, x> */
5030  SCIP_Real rightmaxactivity, /**< maximal activity of <coefright, x> */
5031  SCIP_Real rhs, /**< denominator on rhs */
5032  SCIP_Real* cutcoef, /**< array to store cut coefficients for quadratic variables */
5033  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5034  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5035  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5036  char* name /**< buffer to store name of cut */
5037  )
5038 {
5039  SCIP_CONSDATA* consdata;
5040  SCIP_Real constant;
5041  int i;
5042 
5043  assert(cutcoef != NULL);
5044  assert(rightminactivity * multright > 0.0);
5045  assert(rightmaxactivity * multright > 0.0);
5046  assert(multright == 1.0 || multright == -1.0);
5047 
5048  consdata = SCIPconsGetData(cons);
5049  assert(consdata != NULL);
5050 
5051  if( rhs > 0.0 )
5052  {
5053  /* if rhs > 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need secant:
5054  * 1 / multright*<coefright, x'> <= 1/minact + 1/maxact - 1/(minact * maxact) multright*<coefright, x'>
5055  * where [minact, maxact] = multright * [rightminactivity, rightmaxactivity]
5056  *
5057  * assuming multright is either -1 or 1, and substituting gives
5058  * multright/rightminactivity + multright/rightmaxactivity - multright/(rightminactivity * rightmaxactivity) *<coefright, x'>
5059  *
5060  * multiplying by rhs, gives the estimate
5061  * rhs / (multright * <coefright, x'>) <= rhs * multright * (1/rightminactivity + 1/rightmaxactivity - 1/(rightminactivity * rightmaxactivity) * <coefright, x'>)
5062  */
5063 
5064  /* cannot do if unbounded */
5065  if( SCIPisInfinity(scip, rightmaxactivity) )
5066  {
5067  *success = FALSE;
5068  return;
5069  }
5070 
5071  assert(SCIPisFeasLE(scip, rightminactivity, rightmaxactivity));
5072 
5073  constant = multleft * multright * coefleft[consdata->nquadvars];
5074  constant -= rhs * multright * (1.0 / rightminactivity + 1.0 / rightmaxactivity);
5075  constant += rhs * multright * coefright[consdata->nquadvars] / (rightminactivity * rightmaxactivity);
5076 
5077  for( i = 0; i < consdata->nquadvars; ++i )
5078  {
5079  cutcoef[i] = multleft * multright * coefleft[i];
5080  cutcoef[i] += rhs * multright / (rightminactivity * rightmaxactivity) * coefright[i];
5081  }
5082 
5083  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_factorablesecant_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5084  }
5085  else
5086  {
5087  SCIP_Real refvalue;
5088 
5089  /* if rhs < 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need linearization:
5090  * rhs / (multright * <coefright, x'>)
5091  * <= rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'> - multright * <coefright, ref'>)
5092  * = 2*rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'>)
5093  *
5094  * where ref' = (ref, 1)
5095  */
5096 
5097  /* compute <coefright, ref'> */
5098  refvalue = coefright[consdata->nquadvars];
5099  for( i = 0; i < consdata->nquadvars; ++i )
5100  refvalue += coefright[i] * ref[i];
5101 
5102  /* should not happen, since we checked activity of <coefright,x> before, and assume ref within bounds */
5103  assert(!SCIPisZero(scip, refvalue));
5104 
5105  constant = multleft * multright * coefleft[consdata->nquadvars];
5106  constant -= 2.0 * rhs / (multright * refvalue);
5107  constant += rhs / (refvalue * refvalue) * multright * coefright[consdata->nquadvars];
5108 
5109  for( i = 0; i < consdata->nquadvars; ++i )
5110  {
5111  cutcoef[i] = multleft * multright * coefleft[i];
5112  cutcoef[i] += rhs / (refvalue * refvalue) * multright * coefright[i];
5113  }
5114 
5115  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_factorablelinearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5116  }
5117 
5118  *cutrhs = -constant;
5119 
5120  /* @todo does not always need to be local */
5121  *islocal = TRUE;
5122  *success = TRUE;
5123 }
5124 
5125 /** tries to generate a cut if constraint quadratic function is factorable and there are no linear variables
5126  * (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
5127  */
5128 static
5130  SCIP* scip, /**< SCIP data structure */
5131  SCIP_CONS* cons, /**< constraint */
5132  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
5133  SCIP_Real* ref, /**< reference solution where to generate the cut */
5134  SCIP_Real* cutcoef, /**< array to store cut coefficients for quadratic variables */
5135  SCIP_Real* cutlhs, /**< buffer to store cut lhs */
5136  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5137  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5138  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5139  char* name /**< buffer to store name of cut */
5140  )
5141 {
5142  SCIP_CONSDATA* consdata;
5143  SCIP_Real leftminactivity;
5144  SCIP_Real leftmaxactivity;
5145  SCIP_Real rightminactivity;
5146  SCIP_Real rightmaxactivity;
5147  SCIP_Real multleft;
5148  SCIP_Real multright;
5149  SCIP_Real rhs;
5150  int i;
5151 
5152  assert(scip != NULL);
5153  assert(cons != NULL);
5154  assert(ref != NULL);
5155  assert(cutcoef != NULL);
5156  assert(cutlhs != NULL);
5157  assert(cutrhs != NULL);
5158  assert(islocal != NULL);
5159  assert(success != NULL);
5160  assert(name != NULL);
5161 
5162  consdata = SCIPconsGetData(cons);
5163  assert(consdata != NULL);
5164  assert(consdata->nlinvars == 0);
5165  assert(consdata->factorleft != NULL);
5166  assert(consdata->factorright != NULL);
5167 
5168  *success = FALSE;
5169  *cutlhs = -SCIPinfinity(scip);
5170 
5171  leftminactivity = consdata->factorleft[consdata->nquadvars];
5172  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
5173  rightminactivity = consdata->factorright[consdata->nquadvars];
5174  rightmaxactivity = consdata->factorright[consdata->nquadvars];
5175  for( i = 0; i < consdata->nquadvars; ++i )
5176  {
5177  if( !SCIPisInfinity(scip, -leftminactivity) )
5178  {
5179  if( consdata->factorleft[i] > 0.0 )
5180  {
5181  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5182  leftminactivity = -SCIPinfinity(scip);
5183  else
5184  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5185  }
5186  else if( consdata->factorleft[i] < 0.0 )
5187  {
5188  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5189  leftminactivity = -SCIPinfinity(scip);
5190  else
5191  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5192  }
5193  }
5194  if( !SCIPisInfinity(scip, leftmaxactivity) )
5195  {
5196  if( consdata->factorleft[i] > 0.0 )
5197  {
5198  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5199  leftmaxactivity = SCIPinfinity(scip);
5200  else
5201  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5202  }
5203  else if( consdata->factorleft[i] < 0.0 )
5204  {
5205  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5206  leftmaxactivity = SCIPinfinity(scip);
5207  else
5208  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5209  }
5210  }
5211 
5212  if( !SCIPisInfinity(scip, -rightminactivity) )
5213  {
5214  if( consdata->factorright[i] > 0.0 )
5215  {
5216  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5217  rightminactivity = -SCIPinfinity(scip);
5218  else
5219  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5220  }
5221  else if( consdata->factorright[i] < 0.0 )
5222  {
5223  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5224  rightminactivity = -SCIPinfinity(scip);
5225  else
5226  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5227  }
5228  }
5229  if( !SCIPisInfinity(scip, rightmaxactivity) )
5230  {
5231  if( consdata->factorright[i] > 0.0 )
5232  {
5233  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5234  rightmaxactivity = SCIPinfinity(scip);
5235  else
5236  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5237  }
5238  else if( consdata->factorright[i] < 0.0 )
5239  {
5240  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5241  rightmaxactivity = SCIPinfinity(scip);
5242  else
5243  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5244  }
5245  }
5246  }
5247 
5248  /* write violated constraints as multleft * factorleft * factorright <= rhs */
5249  if( violside == SCIP_SIDETYPE_RIGHT )
5250  {
5251  rhs = consdata->rhs;
5252  multleft = 1.0;
5253  }
5254  else
5255  {
5256  rhs = -consdata->lhs;
5257  multleft = -1.0;
5258  }
5259 
5260  if( SCIPisZero(scip, rhs) )
5261  {
5262  /* @todo do something for rhs == 0.0? */
5263  return SCIP_OKAY;
5264  }
5265 
5266  if( !SCIPisFeasPositive(scip, leftminactivity) && !SCIPisFeasNegative(scip, leftmaxactivity) )
5267  {
5268  /* left factor has 0 within activity bounds, or is very close, at least */
5269  if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5270  {
5271  /* right factor also has 0 within activity bounds, or is very close, at least
5272  * -> cannot separate
5273  */
5274  return SCIP_OKAY;
5275  }
5276 
5277  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5278  * such that multright * factorright > 0.0
5279  */
5280  if( rightminactivity < 0.0 )
5281  multright = -1.0;
5282  else
5283  multright = 1.0;
5284 
5285  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5286  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5287  }
5288  else if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5289  {
5290  /* left factor is bounded away from 0
5291  * right factor has 0 within activity bounds, or is very close, at least
5292  * -> so divide by left factor
5293  */
5294 
5295  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5296  * such that multright * factorleft > 0.0
5297  */
5298  if( leftminactivity < 0.0 )
5299  multright = -1.0;
5300  else
5301  multright = 1.0;
5302 
5303  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5304  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5305  }
5306  else if( SCIPisInfinity(scip, -leftminactivity) || SCIPisInfinity(scip, leftmaxactivity) ||
5307  (!SCIPisInfinity(scip, -rightminactivity) && !SCIPisInfinity(scip, rightmaxactivity) && rightmaxactivity - rightminactivity < leftmaxactivity - leftminactivity) )
5308  {
5309  /* both factors are bounded away from 0, but the right one has a smaller activity range, so divide by that one */
5310 
5311  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5312  * such that multright * factorright > 0.0
5313  */
5314  if( rightminactivity < 0.0 )
5315  multright = -1.0;
5316  else
5317  multright = 1.0;
5318 
5319  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5320  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5321  }
5322  else
5323  {
5324  /* both factors are bounded away from 0, but the left one has a smaller activity range, so divide by that one */
5325 
5326  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5327  * such that multright * factorleft > 0.0
5328  */
5329  if( leftminactivity < 0.0 )
5330  multright = -1.0;
5331  else
5332  multright = 1.0;
5333 
5334  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5335  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5336  }
5337 
5338  return SCIP_OKAY;
5339 }
5340 
5341 /* finds intersections of a parametric line (x,y) = (x0,y0) + t [(x1,y1) - (x0,y0)] on curves x*y = wl and x*y = wu
5342  * returns TRUE if unsuccessful and FALSE otherwise
5343  */
5344 static
5346  SCIP* scip,
5347  SCIP_Real x0,
5348  SCIP_Real y0_,
5349  SCIP_Real x1,
5350  SCIP_Real y1_,
5351  SCIP_Real wl,
5352  SCIP_Real wu,
5353  SCIP_Real* xl,
5354  SCIP_Real* yl,
5355  SCIP_Real* xu,
5356  SCIP_Real* yu
5357  )
5358 {
5359  SCIP_Real a;
5360  SCIP_Real b;
5361  SCIP_Real c;
5362  SCIP_Real tl;
5363  SCIP_Real tu;
5364 
5365  assert(wl == SCIP_INVALID || (xl != NULL && yl != NULL)); /*lint !e777 */
5366  assert(wu == SCIP_INVALID || (xu != NULL && yu != NULL)); /*lint !e777 */
5367 
5368  /* The parametric line is of the form
5369  *
5370  * x = x0 + t (x1-x0)
5371  * y = y0 + t (y1-y0)
5372  *
5373  * and for that to satisfy xy = wl and xy = wu we must have
5374  *
5375  * x0 y0 + t [x0 (y1-y0) + y0 (x1-x0)] + t^2 (x1-x0) (y1-y0) = wl
5376  * = wu
5377  *
5378  * or a t^2 + b t + c - wl = 0 for proper values of a,b,c.
5379  * a t^2 + b t + c - wu = 0
5380  *
5381  * Because of the way this procedure will be used, one of the two
5382  * solutions found we must always use the minimum nonnegative one
5383  */
5384 
5385  a = (x1 - x0) * (y1_ - y0_);
5386  c = x0 * y0_;
5387  b = x0 * y1_ + y0_ * x1 - 2.0 * c;
5388 
5389  tl = 0.0;
5390  tu = 0.0;
5391 
5392  if( !SCIPisZero(scip, (SCIP_Real)a) )
5393  {
5394  if( wl != SCIP_INVALID ) /*lint !e777 */
5395  {
5396  SCIP_Real tl1;
5397  SCIP_Real tl2;
5398  SCIP_Real denom;
5399 
5400  assert(b * b - 4.0 * a * (c - wl) >= 0.0);
5401  denom = sqrt(b * b - 4.0 * a * (c - wl));
5402  tl1 = (-b - denom) / (2.0 * a);
5403  tl2 = (-b + denom) / (2.0 * a);
5404  tl = (tl1 < 0.0) ? tl2 : tl1;
5405  }
5406 
5407  if( wu != SCIP_INVALID ) /*lint !e777 */
5408  {
5409  SCIP_Real tu1;
5410  SCIP_Real tu2;
5411  SCIP_Real denom;
5412 
5413  assert(b * b - 4.0 * a * (c - wu) >= 0.0);
5414  denom = sqrt(b * b - 4.0 * a * (c - wu));
5415  tu1 = (-b - denom) / (2.0 * a);
5416  tu2 = (-b + denom) / (2.0 * a);
5417  tu = (tu1 < 0.0) ? tu2 : tu1;
5418  }
5419  }
5420  else if( !SCIPisZero(scip, (SCIP_Real)b) )
5421  {
5422  if( wl != SCIP_INVALID ) /*lint !e777 */
5423  tl = (wl - c) / b;
5424  if( wu != SCIP_INVALID ) /*lint !e777 */
5425  tu = (wu - c) / b;
5426  }
5427  else
5428  {
5429  /* no or infinitely many solutions */
5430  return TRUE;
5431  }
5432 
5433  if( wl != SCIP_INVALID ) /*lint !e777 */
5434  {
5435  *xl = (SCIP_Real)(x0 + tl * (x1 - x0 ));
5436  *yl = (SCIP_Real)(y0_ + tl * (y1_ - y0_));
5437 
5438  if( !SCIPisRelEQ(scip, *xl * *yl, wl) )
5439  {
5440  SCIPdebugMessage("probable numerical difficulties, give up\n");
5441  return TRUE;
5442  }
5443  }
5444 
5445  if( wu != SCIP_INVALID ) /*lint !e777 */
5446  {
5447  *xu = (SCIP_Real)(x0 + tu * (x1 - x0));
5448  *yu = (SCIP_Real)(y0_ + tu * (y1_ - y0_));
5449 
5450  if( !SCIPisRelEQ(scip, *xu * *yu, wu) )
5451  {
5452  SCIPdebugMessage("probable numerical difficulties, give up\n");
5453  return TRUE;
5454  }
5455  }
5456 
5457  return FALSE;
5458 }
5459 
5460 /* generate coefficients for a plane through points (x1, y1_, x1*y1) and (x2, y2, x2*y2)
5461  * such that intersecting it with one of them (the first if whichuse is FALSE, the second otherwise)
5462  * gives a tangent to the curve x*y = k
5463  *
5464  * returns TRUE on error and FALSE on success
5465  */
5466 static
5468  SCIP* scip,
5469  SCIP_Real x1,
5470  SCIP_Real y1_,
5471  SCIP_Real x2,
5472  SCIP_Real y2,
5473  SCIP_Bool whichuse,
5474  SCIP_Real* cx,
5475  SCIP_Real* cy,
5476  SCIP_Real* cw
5477  )
5478 {
5479  SCIP_Real xd;
5480  SCIP_Real yd;
5481  SCIP_Real xo;
5482  SCIP_Real yo;
5483 
5484  assert(cx != NULL);
5485  assert(cy != NULL);
5486  assert(cw != NULL);
5487 
5488  /* the x-y slope of this constraint must be tangent to a curve x*y = k at (xD,yD) */
5489  if( !whichuse )
5490  {
5491  xd = x1;
5492  xo = x2;
5493  yd = y1_;
5494  yo = y2;
5495  }
5496  else
5497  {
5498  xd = x2;
5499  xo = x1;
5500  yd = y2;
5501  yo = y1_;
5502  }
5503 
5504  *cx = yd;
5505  *cy = xd;
5506 
5507  /* lift it so that it touches the other curve */
5508 
5509  /* if the two points are on the same curve, then no cut */
5510  if( SCIPisZero(scip, xo * yo - xd * yd) )
5511  return TRUE;
5512 
5513  /* should ALWAYS be negative */
5514  *cw = (2.0 * xd * yd - (*cx * xo + *cy * yo)) / (xo * yo - xd * yd);
5515 
5516  return FALSE;
5517 }
5518 
5519 /** computes coefficients of a lifted-tangent inequality for x*y = w
5520  * The code is an adaptation of the methods in exprMul-upperHull.cpp in Couenne/stable/0.4 rev773,
5521  * written by P. Belotti and licensed under Eclipse Public License.
5522  */
5523 static
5525  SCIP* scip, /**< SCIP data structure */
5526  SCIP_Real xl, /**< lower bound on x */
5527  SCIP_Real xu, /**< upper bound on x */
5528  SCIP_Real x0, /**< reference point for x */
5529  SCIP_Real yl, /**< lower bound on y */
5530  SCIP_Real yu, /**< upper bound on y */
5531  SCIP_Real y0_, /**< reference point for y */
5532  SCIP_Real wl, /**< lower bound on w */
5533  SCIP_Real wu, /**< upper bound on w */
5534  SCIP_Real w0, /**< reference point for w */
5535  SCIP_Real* cx, /**< buffer where to store cut coefficient for x */
5536  SCIP_Real* cy, /**< buffer where to store cut coefficient for y */
5537  SCIP_Real* cw, /**< buffer where to store cut coefficient for w */
5538  SCIP_Real* c0, /**< buffer where to store cut left-hand-side */
5539  SCIP_Bool* success /**< buffer where to indicate whether cut coefficients were computed */
5540  )
5541 {
5542  SCIP_Bool flipx;
5543  SCIP_Bool flipy;
5544  SCIP_Bool flipw;
5545  SCIP_Real tmp;
5546  SCIP_Real xlow;
5547  SCIP_Real ylow;
5548  SCIP_Real xupp;
5549  SCIP_Real yupp;
5550  SCIP_Real c0x;
5551  SCIP_Real c0y;
5552  SCIP_Real c0w;
5553 
5554  assert(scip != NULL);
5555  assert(cx != NULL);
5556  assert(cy != NULL);
5557  assert(cw != NULL);
5558  assert(c0 != NULL);
5559  assert(success != NULL);
5560 
5561  *success = FALSE;
5562  *cx = 0.0;
5563  *cy = 0.0;
5564  *cw = 0.0;
5565  *c0 = 0.0;
5566 
5567  SCIPdebugMessage("entering points:\n");
5568  SCIPdebugMessage("x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5569  SCIPdebugMessage("y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5570  SCIPdebugMessage("w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5571 
5572  /* generateCutLTI should have recognized these */
5573  assert(wl >= 0.0 || wu <= 0.0);
5574  assert(!SCIPisInfinity(scip, -wl));
5575  assert(!SCIPisInfinity(scip, wu));
5576 
5577  assert(SCIPisFeasGE(scip, x0, xl));
5578  assert(SCIPisFeasLE(scip, x0, xu));
5579  assert(SCIPisFeasGE(scip, y0_, yl));
5580  assert(SCIPisFeasLE(scip, y0_, yu));
5581 
5582  /* preliminary bound tightening */
5583  if( wl >= 0.0 )
5584  {
5585  if( xl >= 0.0 || yl >= 0.0 || SCIPisLT(scip, xl * yl, wl) )
5586  {
5587  xl = MAX(xl, 0.0);
5588  yl = MAX(yl, 0.0);
5589  }
5590  else if( xu <= 0.0 || yu <= 0.0 || SCIPisLT(scip, xu * yu, wl) )
5591  {
5592  xu = MIN(xu, 0.0);
5593  yu = MIN(yu, 0.0);
5594  }
5595  else
5596  {
5597  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yl and xu*yu are feasible
5598  * cannot generate cut for this
5599  */
5600  return;
5601  }
5602  }
5603  else
5604  {
5605  if( xl >= 0.0 || yu <= 0.0 || SCIPisGT(scip, xl * yu, wu) )
5606  {
5607  xl = MAX(xl, 0.0);
5608  yu = MIN(yu, 0.0);
5609  }
5610  else if( xu <= 0.0 || yl >= 0.0 || SCIPisGT(scip, xu * yl, wu))
5611  {
5612  xu = MIN(xu, 0.0);
5613  yl = MAX(yl, 0.0);
5614  }
5615  else
5616  {
5617  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yu and xu*yl are feasible
5618  * cannot generate cut for this
5619  */
5620  return;
5621  }
5622  }
5623 
5624  /* if x or y is fixed now or even infeasible, then do not think about a cut */
5625  if( SCIPisGE(scip, xl, xu) || SCIPisGE(scip, yl, yu) )
5626  return;
5627 
5628  /* reduce to positive orthant by flipping variables */
5629  if( xl < 0.0 )
5630  {
5631  flipx = TRUE;
5632  tmp = xu;
5633  xu = -xl;
5634  xl = -tmp;
5635  x0 = -x0;
5636  }
5637  else
5638  flipx = FALSE;
5639 
5640  if( yl < 0.0 )
5641  {
5642  flipy = TRUE;
5643  tmp = yu;
5644  yu = -yl;
5645  yl = -tmp;
5646  y0_ = -y0_;
5647  }
5648  else
5649  flipy = FALSE;
5650 
5651  if( flipx ^ flipy )
5652  {
5653  flipw = TRUE;
5654  tmp = wu;
5655  wu = -wl;
5656  wl = -tmp;
5657  w0 = -w0;
5658  }
5659  else
5660  flipw = FALSE;
5661 
5662  /* project refpoint into box not only for numerical reasons, but also due to preliminary bound tightening above */
5663  x0 = MIN(xu, MAX(x0, xl));
5664  y0_ = MIN(yu, MAX(y0_, yl));
5665  w0 = MIN(wu, MAX(w0, wl));
5666 
5667  SCIPdebugMessage("reduced points:\n");
5668  SCIPdebugMessage("x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5669  SCIPdebugMessage("y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5670  SCIPdebugMessage("w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5671 
5672  if( SCIPisGE(scip, xl * yl, wl) && SCIPisLE(scip, xu * yu, wu) )
5673  {
5674  SCIPdebugMessage("box for x and y inside feasible region -> nothing to separate\n");
5675  return;
5676  }
5677  if( SCIPisGE(scip, x0 * y0_, w0) )
5678  {
5679  SCIPdebugMessage("point to separate not below curve -> cannot separate\n");
5680  return;
5681  }
5682 
5683  /* find intersections of halfline from origin
5684  * return if no proper point could be found
5685  */
5686  if( generateCutLTIfindIntersection(scip, 0.0, 0.0, x0, y0_, wl, wu, &xlow, &ylow, &xupp, &yupp) )
5687  return;
5688 
5689  SCIPdebugMessage("intersections:\n");
5690  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5691  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5692 
5693  /* Case 1: If both are outside of bounding box, either NW or SE, then McCormick is sufficient, so return */
5694  if( (xlow <= xl && yupp >= yu) || (ylow <= yl && xupp >= xu) )
5695  return;
5696 
5697  /* There will be at least one cut. Define coefficients and rhs ---will have to change them back if (flipX || flipY) */
5698  if( xlow >= xl && xupp <= xu && ylow >= yl && yupp <= yu )
5699  {
5700  /* Case 2: both are inside. Easy lifting... */
5701  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5702  return;
5703 
5704  c0x = *cx * xlow;
5705  c0y = *cy * ylow;
5706  c0w = *cw * wl;
5707  }
5708  else if( xlow >= xl && ylow >= yl && (xupp > xu || yupp > yu) )
5709  {
5710  /* Case 3a and 3b: through lower curve, but not upper. */
5711  if( yupp > yu )
5712  {
5713  /* upper intersect is North; place it within box */
5714  assert(!SCIPisInfinity(scip, yu));
5715  yupp = yu;
5716  xupp = wu / yu;
5717  }
5718  else
5719  {
5720  /* upper intersect is East; place it within box */
5721  assert(!SCIPisInfinity(scip, xu));
5722  xupp = xu;
5723  yupp = wu / xu;
5724  }
5725 
5726  /* find intersection on low curve on half line through new point and (x0,y0_) */
5727  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow, &ylow, NULL, NULL) )
5728  return;
5729 
5730  /* check whether McCormick is sufficient */
5731  if( xlow < xl || ylow < yl )
5732  return;
5733 
5734  /* lift inequality on lower point */
5735  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5736  return;
5737 
5738  c0x = *cx * xlow;
5739  c0y = *cy * ylow;
5740  c0w = *cw * wl;
5741  }
5742  else if( xupp <= xu && yupp <= yu && (xlow < xl || ylow < yl) )
5743  {
5744  /* Case 4a and 4b: viceversa (lift for validity) */
5745  if( ylow < yl )
5746  {
5747  /* upper intersect is South; place it within box */
5748  assert(!SCIPisZero(scip, yl));
5749  ylow = yl;
5750  xlow = wl / yl;
5751  }
5752  else
5753  {
5754  /* upper intersect is West; place it within box */
5755  assert(!SCIPisZero(scip, xl));
5756  xlow = xl;
5757  ylow = wl / xl;
5758  }
5759 
5760  /* find intersection on low curve on half line through new point and (x0,y0) */
5761  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp, &yupp) )
5762  return;
5763 
5764  /* check whether McCormick is sufficient */
5765  if( xupp > xu || yupp > yu )
5766  return;
5767 
5768  /* lift inequality on UPPER point */
5769  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
5770  return;
5771 
5772  c0x = *cx * xupp;
5773  c0y = *cy * yupp;
5774  c0w = *cw * wu;
5775  }
5776  else if( (xlow < xl && xupp > xu) || (ylow < yl && yupp > yu) )
5777  {
5778  /* Case 5: both outside of bounding box, N and S or W and E. */
5779 #if 0
5780  SCIP_Real xlow2;
5781  SCIP_Real ylow2;
5782  SCIP_Real xupp2;
5783  SCIP_Real yupp2;
5784 #endif
5785 
5786  if( ylow < yl )
5787  {
5788  /* upper intersect is South; place it within box */
5789  assert(!SCIPisZero(scip, yl));
5790  assert(!SCIPisZero(scip, yu));
5791  ylow = yl;
5792  yupp = yu;
5793  xlow = wl / yl;
5794  xupp = wu / yu;
5795  }
5796  else
5797  {
5798  /* upper intersect is West; place it within box */
5799  assert(!SCIPisZero(scip, xl));
5800  assert(!SCIPisZero(scip, xu));
5801  xlow = xl;
5802  xupp = xu;
5803  ylow = wl / xl;
5804  yupp = wu / xu;
5805  }
5806 
5807  SCIPdebugMessage("New intersections:\n");
5808  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5809  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5810 
5811 #if 1
5812  /* Nothing to find. Just separate two inequalities at the same point, just using different support */
5813  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5814  {
5815  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
5816  return;
5817 
5818  c0x = *cx * xupp;
5819  c0y = *cy * yupp;
5820  c0w = *cw * wu;
5821  }
5822  else
5823  {
5824  c0x = *cx * xlow;
5825  c0y = *cy * ylow;
5826  c0w = *cw * wl;
5827  }
5828 
5829 #else
5830  /* find the intersection on the lower (upper) curve on the line through xLP and the upper (lower) point
5831  * this does not seem to work (cuts off solution at nous2), so it is disabled for now
5832  */
5833  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp2, &yupp2) ||
5834  generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp2, yupp2, FALSE, cx, cx, cw) )
5835  {
5836  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow2, &ylow2, NULL, NULL) ||
5837  generateCutLTIgenMulCoeff(scip, xlow2, ylow2, xupp, yupp, TRUE, cx, cy, cw) )
5838  return;
5839 
5840  c0x = *cx * xupp;
5841  c0y = *cy * yupp;
5842  c0w = *cw * wu;
5843  }
5844  else
5845  {
5846  c0x = *cx * xlow;
5847  c0y = *cy * ylow;
5848  c0w = *cw * wl;
5849  }
5850 #endif
5851  }
5852  else
5853  {
5854  SCIPdebugMessage("points are in a weird position:\n");
5855  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5856  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5857 
5858  return;
5859  }
5860 
5861  SCIPdebugMessage("cut w.r.t. reduced points: %gx-%g %+gy-%g %+gw-%g >= 0\n",
5862  *cx, c0x, *cy, c0y, *cw, c0w);
5863 
5864  /* re-transform back into original variables */
5865  if( flipx )
5866  *cx = -*cx;
5867  if( flipy )
5868  *cy = -*cy;
5869  if( flipw )
5870  *cw = -*cw;
5871 
5872  *c0 = c0x + c0y + c0w;
5873 
5874  *success = TRUE;
5875 }
5876 
5877 /** tries to generate a cut if constraint quadratic function is factorable and there are linear variables
5878  * computes what is called a lifted tangent inequality described in
5879  * Belotti, Miller, Namazifar, Lifted inequalities for bounded products of variables, SIAG/OPT Views-and-News 22:1, 2011
5880  */
5881 static
5883  SCIP* scip, /**< SCIP data structure */
5884  SCIP_CONS* cons, /**< constraint */
5885  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
5886  SCIP_Real* ref, /**< reference solution where to generate the cut */
5887  SCIP_SOL* sol, /**< solution that shall be cutoff, NULL for LP solution */
5888  SCIP_Real** cutcoeflin, /**< buffer to store pointer to array with coefficients for linear variables */
5889  SCIP_Real* cutcoefquad, /**< array to store cut coefficients for quadratic variables */
5890  SCIP_Real* cutlhs, /**< buffer to store cut lhs */
5891  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5892  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5893  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5894  char* name /**< buffer to store name of cut */
5895  )
5896 {
5897  SCIP_CONSDATA* consdata;
5898  SCIP_Real leftminactivity;
5899  SCIP_Real leftmaxactivity;
5900  SCIP_Real leftrefactivity;
5901  SCIP_Real rightminactivity;
5902  SCIP_Real rightmaxactivity;
5903  SCIP_Real rightrefactivity;
5904  SCIP_Real rhsminactivity;
5905  SCIP_Real rhsmaxactivity;
5906  SCIP_Real rhsrefactivity;
5907  SCIP_Real coefleft;
5908  SCIP_Real coefright;
5909  SCIP_Real coefrhs;
5910  int i;
5911 
5912  assert(scip != NULL);
5913  assert(cons != NULL);
5914  assert(ref != NULL);
5915  assert(cutcoeflin != NULL);
5916  assert(cutcoefquad != NULL);
5917  assert(cutlhs != NULL);
5918  assert(cutrhs != NULL);
5919  assert(islocal != NULL);
5920  assert(success != NULL);
5921  assert(name != NULL);
5922  /* currently only separate LP solution or solutions given as SCIP_SOL, i.e., no cutgeneration during initlp */
5923  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
5924 
5925  consdata = SCIPconsGetData(cons);
5926  assert(consdata != NULL);
5927  assert(consdata->nlinvars > 0);
5928  assert(consdata->factorleft != NULL);
5929  assert(consdata->factorright != NULL);
5930 
5931  *success = FALSE;
5932  *cutlhs = -SCIPinfinity(scip); /* for compiler */
5933 
5934  /* write violated constraints as factorleft * factorright '==' rhs
5935  * where rhs are constraint sides - activity bound of linear part
5936  */
5937  rhsminactivity = consdata->lhs;
5938  rhsmaxactivity = consdata->rhs;
5939  rhsrefactivity = (violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
5940 
5941  for( i = 0; i < consdata->nlinvars; ++i )
5942  {
5943  if( !SCIPisInfinity(scip, -rhsminactivity) )
5944  {
5945  if( consdata->lincoefs[i] < 0.0 )
5946  {
5947  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
5948  rhsminactivity = -SCIPinfinity(scip);
5949  else
5950  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
5951  }
5952  else
5953  {
5954  assert(consdata->lincoefs[i] > 0.0);
5955  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
5956  rhsminactivity = -SCIPinfinity(scip);
5957  else
5958  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
5959  }
5960  }
5961  if( !SCIPisInfinity(scip, rhsmaxactivity) )
5962  {
5963  if( consdata->lincoefs[i] < 0.0 )
5964  {
5965  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
5966  rhsmaxactivity = SCIPinfinity(scip);
5967  else
5968  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
5969  }
5970  else
5971  {
5972  assert(consdata->lincoefs[i] > 0.0);
5973  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
5974  rhsmaxactivity = SCIPinfinity(scip);
5975  else
5976  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
5977  }
5978  }
5979  rhsrefactivity -= consdata->lincoefs[i] * SCIPgetSolVal(scip, sol, consdata->linvars[i]);
5980  }
5981 
5982  if( SCIPisInfinity(scip, -rhsminactivity) || SCIPisInfinity(scip, rhsmaxactivity) )
5983  {
5984  /* if right hand side is unbounded, then cannot do LTI */
5985  return SCIP_OKAY;
5986  }
5987 
5988  if( !SCIPisFeasPositive(scip, rhsminactivity) && !SCIPisFeasNegative(scip, rhsmaxactivity) )
5989  {
5990  /* if right hand side has 0 inside activity, then cannot do anything
5991  * if it has 0.0 as min or max activity, then a usual McCormick should be sufficient, too
5992  */
5993  return SCIP_OKAY;
5994  }
5995 
5996  leftminactivity = consdata->factorleft[consdata->nquadvars];
5997  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
5998  leftrefactivity = consdata->factorleft[consdata->nquadvars];
5999  rightminactivity = consdata->factorright[consdata->nquadvars];
6000  rightmaxactivity = consdata->factorright[consdata->nquadvars];
6001  rightrefactivity = consdata->factorright[consdata->nquadvars];
6002  for( i = 0; i < consdata->nquadvars; ++i )
6003  {
6004  if( !SCIPisInfinity(scip, -leftminactivity) )
6005  {
6006  if( consdata->factorleft[i] > 0.0 )
6007  {
6008  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6009  leftminactivity = -SCIPinfinity(scip);
6010  else
6011  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6012  }
6013  else if( consdata->factorleft[i] < 0.0 )
6014  {
6015  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6016  leftminactivity = -SCIPinfinity(scip);
6017  else
6018  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6019  }
6020  }
6021  if( !SCIPisInfinity(scip, leftmaxactivity) )
6022  {
6023  if( consdata->factorleft[i] > 0.0 )
6024  {
6025  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6026  leftmaxactivity = SCIPinfinity(scip);
6027  else
6028  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6029  }
6030  else if( consdata->factorleft[i] < 0.0 )
6031  {
6032  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6033  leftmaxactivity = SCIPinfinity(scip);
6034  else
6035  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6036  }
6037  }
6038  leftrefactivity += consdata->factorleft[i] * ref[i];
6039 
6040  if( !SCIPisInfinity(scip, -rightminactivity) )
6041  {
6042  if( consdata->factorright[i] > 0.0 )
6043  {
6044  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6045  rightminactivity = -SCIPinfinity(scip);
6046  else
6047  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6048  }
6049  else if( consdata->factorright[i] < 0.0 )
6050  {
6051  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6052  rightminactivity = -SCIPinfinity(scip);
6053  else
6054  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6055  }
6056  }
6057  if( !SCIPisInfinity(scip, rightmaxactivity) )
6058  {
6059  if( consdata->factorright[i] > 0.0 )
6060  {
6061  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6062  rightmaxactivity = SCIPinfinity(scip);
6063  else
6064  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6065  }
6066  else if( consdata->factorright[i] < 0.0 )
6067  {
6068  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6069  rightmaxactivity = SCIPinfinity(scip);
6070  else
6071  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6072  }
6073  }
6074  rightrefactivity += consdata->factorright[i] * ref[i];
6075  }
6076 
6077  /* if any of the factors is essentially fixed, give up and do usual method (numerically less sensitive, I hope) */
6078  if( SCIPisRelEQ(scip, leftminactivity, leftmaxactivity) || SCIPisRelEQ(scip, rightminactivity, rightmaxactivity) )
6079  return SCIP_OKAY;
6080 
6081  /* success can only be expected for separation of violated x*y <= w, assuming x>=0, y>=0
6082  * @todo we should check this early? */
6083 
6084  /* call Couenne magic */
6086  leftminactivity, leftmaxactivity, leftrefactivity,
6087  rightminactivity, rightmaxactivity, rightrefactivity,
6088  rhsminactivity, rhsmaxactivity, rhsrefactivity,
6089  &coefleft, &coefright, &coefrhs, cutlhs,
6090  success);
6091 
6092  if( !*success )
6093  return SCIP_OKAY;
6094 
6095  SCIPdebugMessage("LTI for x[%g,%g] * y[%g,%g] = w[%g,%g]: %gx %+gy %+gw >= %g; feas: %g\n",
6096  leftminactivity, leftmaxactivity, rightminactivity, rightmaxactivity, rhsminactivity, rhsmaxactivity,
6097  coefleft, coefright, coefrhs, *cutlhs,
6098  coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity - *cutlhs
6099  );
6100 
6101  if( coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity >= *cutlhs )
6102  {
6103  SCIPdebugMessage("does not cutoff point? :-(\n");
6104  *success = FALSE;
6105  return SCIP_OKAY;
6106  }
6107 
6108  /* setup cut coefs for
6109  * coefleft * leftfactor + coefright * rightfactor + coefrhs * w >= cutlhs, where conslhs - lincoefs <= w <= consrhs - lincoefs
6110  */
6111  for( i = 0; i < consdata->nquadvars; ++i )
6112  cutcoefquad[i] = coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i];
6113  assert(i == consdata->nquadvars);
6114  *cutlhs -= coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i];
6115 
6116  SCIP_CALL( SCIPallocBufferArray(scip, cutcoeflin, consdata->nlinvars) );
6117  for( i = 0; i < consdata->nlinvars; ++i )
6118  (*cutcoeflin)[i] = -coefrhs * consdata->lincoefs[i];
6119  if( coefrhs > 0.0 )
6120  {
6121  /* use coefrhs * w <= coefrhs * (consrhs - lincoefs) */
6122  assert(!SCIPisInfinity(scip, consdata->rhs));
6123  *cutlhs -= coefrhs * consdata->rhs;
6124  }
6125  else
6126  {
6127  /* use coefrhs * w <= coeflhs * (conslhs - lincoefs) */
6128  assert(!SCIPisInfinity(scip, -consdata->lhs));
6129  *cutlhs -= coefrhs * consdata->lhs;
6130  }
6131 
6132  *cutrhs = SCIPinfinity(scip);
6133  *islocal = TRUE;
6134 
6135  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_lti_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6136 
6137  *success = TRUE;
6138 
6139  return SCIP_OKAY;
6140 }
6141 
6142 /** computes coefficients of linearization of a square term in a reference point */
6143 static
6145  SCIP* scip, /**< SCIP data structure */
6146  SCIP_Real sqrcoef, /**< coefficient of square term */
6147  SCIP_Real refpoint, /**< point where to linearize */
6148  SCIP_Bool isint, /**< whether corresponding variable is a discrete variable, and thus linearization could be moved */
6149  SCIP_Real* lincoef, /**< buffer to add coefficient of linearization */
6150  SCIP_Real* linconstant, /**< buffer to add constant of linearization */
6151  SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
6152  )
6153 {
6154  assert(scip != NULL);
6155  assert(lincoef != NULL);
6156  assert(linconstant != NULL);
6157  assert(success != NULL);
6158 
6159  if( sqrcoef == 0.0 )
6160  return;
6161 
6162  if( SCIPisInfinity(scip, REALABS(refpoint)) )
6163  {
6164  *success = FALSE;
6165  return;
6166  }
6167 
6168  if( !isint || SCIPisIntegral(scip, refpoint) )
6169  {
6170  SCIP_Real tmp;
6171 
6172  /* sqrcoef * x^2 -> tangent in refpoint = sqrcoef * 2 * refpoint * (x - refpoint) */
6173 
6174  tmp = sqrcoef * refpoint;
6175 
6176  if( SCIPisInfinity(scip, 2.0 * REALABS(tmp)) )
6177  {
6178  *success = FALSE;
6179  return;
6180  }
6181 
6182  *lincoef += 2.0 * tmp;
6183  tmp *= refpoint;
6184  *linconstant -= tmp;
6185  }
6186  else
6187  {
6188  /* 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) */
6189  SCIP_Real f;
6190  SCIP_Real coef;
6191  SCIP_Real constant;
6192 
6193  f = SCIPfloor(scip, refpoint);
6194 
6195  coef = sqrcoef * (2.0 * f + 1.0);
6196  constant = -sqrcoef * f * (f + 1.0);
6197 
6198  if( SCIPisInfinity(scip, REALABS(coef)) || SCIPisInfinity(scip, REALABS(constant)) )
6199  {
6200  *success = FALSE;
6201  return;
6202  }
6203 
6204  *lincoef += coef;
6205  *linconstant += constant;
6206  }
6207 }
6208 
6209 /** computes coefficients of secant of a square term */
6210 static
6212  SCIP* scip, /**< SCIP data structure */
6213  SCIP_Real sqrcoef, /**< coefficient of square term */
6214  SCIP_Real lb, /**< lower bound on variable */
6215  SCIP_Real ub, /**< upper bound on variable */
6216  SCIP_Real refpoint, /**< point for which to compute value of linearization */
6217  SCIP_Real* lincoef, /**< buffer to add coefficient of secant */
6218  SCIP_Real* linconstant, /**< buffer to add constant of secant */
6219  SCIP_Bool* success /**< buffer to set to FALSE if secant has failed due to large numbers or unboundedness */
6220  )
6221 {
6222  SCIP_Real coef;
6223  SCIP_Real constant;
6224 
6225  assert(scip != NULL);
6226  assert(!SCIPisInfinity(scip, lb));
6227  assert(!SCIPisInfinity(scip, -ub));
6228  assert(SCIPisLE(scip, lb, ub));
6229  assert(SCIPisLE(scip, lb, refpoint));
6230  assert(SCIPisGE(scip, ub, refpoint));
6231  assert(lincoef != NULL);
6232  assert(linconstant != NULL);
6233  assert(success != NULL);
6234 
6235  if( sqrcoef == 0.0 )
6236  return;
6237 
6238  if( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
6239  {
6240  /* unboundedness */
6241  *success = FALSE;
6242  return;
6243  }
6244 
6245  /* 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) */
6246 
6247  coef = sqrcoef * (lb + ub);
6248  constant = -sqrcoef * lb * ub;
6249  if( SCIPisInfinity(scip, REALABS(coef)) || SCIPisInfinity(scip, REALABS(constant)) )
6250  {
6251  *success = FALSE;
6252  return;
6253  }
6254 
6255  *lincoef += coef;
6256  *linconstant += constant;
6257 }
6258 
6259 /** computes coefficients of linearization of a bilinear term in a reference point */
6260 static
6262  SCIP* scip, /**< SCIP data structure */
6263  SCIP_Real bilincoef, /**< coefficient of bilinear term */
6264  SCIP_Real refpointx, /**< point where to linearize first variable */
6265  SCIP_Real refpointy, /**< point where to linearize second variable */
6266  SCIP_Real* lincoefx, /**< buffer to add coefficient of first variable in linearization */
6267  SCIP_Real* lincoefy, /**< buffer to add coefficient of second variable in linearization */
6268  SCIP_Real* linconstant, /**< buffer to add constant of linearization */
6269  SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
6270  )
6271 {
6272  SCIP_Real constant;
6273 
6274  assert(scip != NULL);
6275  assert(lincoefx != NULL);
6276  assert(lincoefy != NULL);
6277  assert(linconstant != NULL);
6278  assert(success != NULL);
6279 
6280  if( bilincoef == 0.0 )
6281  return;
6282 
6283  if( SCIPisInfinity(scip, REALABS(refpointx)) || SCIPisInfinity(scip, REALABS(refpointy)) )
6284  {
6285  *success = FALSE;
6286  return;
6287  }
6288 
6289  /* bilincoef * x * y -> bilincoef * (refpointx * refpointy + refpointy * (x - refpointx) + refpointx * (y - refpointy))
6290  * = -bilincoef * refpointx * refpointy + bilincoef * refpointy * x + bilincoef * refpointx * y
6291  */
6292 
6293  constant = -bilincoef * refpointx * refpointy;
6294 
6295  if( SCIPisInfinity(scip, REALABS(bilincoef * refpointx)) || SCIPisInfinity(scip, REALABS(bilincoef * refpointy)) || SCIPisInfinity(scip, REALABS(constant)) )
6296  {
6297  *success = FALSE;
6298  return;
6299  }
6300 
6301  *lincoefx += bilincoef * refpointy;
6302  *lincoefy += bilincoef * refpointx;
6303  *linconstant += constant;
6304 }
6305 
6306 /** computes coefficients of McCormick under- or overestimation of a bilinear term */
6307 static
6309  SCIP* scip, /**< SCIP data structure */
6310  SCIP_Real bilincoef, /**< coefficient of bilinear term */
6311  SCIP_Real lbx, /**< lower bound on first variable */
6312  SCIP_Real ubx, /**< upper bound on first variable */
6313  SCIP_Real refpointx, /**< reference point for first variable */
6314  SCIP_Real lby, /**< lower bound on second variable */
6315  SCIP_Real uby, /**< upper bound on second variable */
6316  SCIP_Real refpointy, /**< reference point for second variable */
6317  SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
6318  SCIP_Real* lincoefx, /**< buffer to add coefficient of first variable in linearization */
6319  SCIP_Real* lincoefy, /**< buffer to add coefficient of second variable in linearization */
6320  SCIP_Real* linconstant, /**< buffer to add constant of linearization */
6321  SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
6322  )
6323 {
6324  SCIP_Real constant;
6325  SCIP_Real coefx;
6326  SCIP_Real coefy;
6327 
6328  assert(scip != NULL);
6329  assert(!SCIPisInfinity(scip, lbx));
6330  assert(!SCIPisInfinity(scip, -ubx));
6331  assert(!SCIPisInfinity(scip, lby));
6332  assert(!SCIPisInfinity(scip, -uby));
6333  assert(SCIPisLE(scip, lbx, ubx));
6334  assert(SCIPisLE(scip, lby, uby));
6335  assert(SCIPisLE(scip, lbx, refpointx));
6336  assert(SCIPisGE(scip, ubx, refpointx));
6337  assert(SCIPisLE(scip, lby, refpointy));
6338  assert(SCIPisGE(scip, uby, refpointy));
6339  assert(lincoefx != NULL);
6340  assert(lincoefy != NULL);
6341  assert(linconstant != NULL);
6342  assert(success != NULL);
6343 
6344  if( bilincoef == 0.0 )
6345  return;
6346 
6347  if( overestimate )
6348  bilincoef = -bilincoef;
6349 
6350  if( SCIPisRelEQ(scip, lbx, ubx) && SCIPisRelEQ(scip, lby, uby) )
6351  {
6352  /* both x and y are mostly fixed */
6353  SCIP_Real cand1;
6354  SCIP_Real cand2;
6355  SCIP_Real cand3;
6356  SCIP_Real cand4;
6357 
6358  coefx = 0.0;
6359  coefy = 0.0;
6360 
6361  /* estimate x * y by constant */
6362  cand1 = lbx * lby;
6363  cand2 = lbx * uby;
6364  cand3 = ubx * lby;
6365  cand4 = ubx * uby;
6366 
6367  if( bilincoef > 0.0 )
6368  constant = bilincoef * MAX( MAX(cand1, cand2), MAX(cand3, cand4) );
6369  else
6370  constant = bilincoef * MIN( MIN(cand1, cand2), MIN(cand3, cand4) );
6371  }
6372  else if( bilincoef > 0.0 )
6373  {
6374  /* either x or y is not fixed and coef > 0.0 */
6375  if( !SCIPisInfinity(scip, -lbx) && !SCIPisInfinity(scip, -lby) &&
6376  (SCIPisInfinity(scip, ubx) || SCIPisInfinity(scip, uby) || (uby - refpointy) * (ubx - refpointx) >= (refpointy - lby) * (refpointx - lbx)) )
6377  {
6378  if( SCIPisRelEQ(scip, lbx, ubx) )
6379  {
6380  /* x*y = lbx * y + (x-lbx) * y >= lbx * y + (x-lbx) * lby >= lbx * y + min{(ubx-lbx) * lby, 0 * lby} */
6381  coefx = 0.0;
6382  coefy = bilincoef * lbx;
6383  constant = bilincoef * (lby < 0.0 ? (ubx-lbx) * lby : 0.0);
6384  }
6385  else if( SCIPisRelEQ(scip, lby, uby) )
6386  {
6387  /* x*y = lby * x + (y-lby) * x >= lby * x + (y-lby) * lbx >= lby * x + min{(uby-lby) * lbx, 0 * lbx} */
6388  coefx = bilincoef * lby;
6389  coefy = 0.0;
6390  constant = bilincoef * (lbx < 0.0 ? (uby-lby) * lbx : 0.0);
6391  }
6392  else
6393  {
6394  coefx = bilincoef * lby;
6395  coefy = bilincoef * lbx;
6396  constant = -bilincoef * lbx * lby;
6397  }
6398  }
6399  else if( !SCIPisInfinity(scip, ubx) && !SCIPisInfinity(scip, uby) )
6400  {
6401  if( SCIPisRelEQ(scip, lbx, ubx) )
6402  {
6403  /* x*y = ubx * y + (x-ubx) * y >= ubx * y + (x-ubx) * uby >= ubx * y + min{(lbx-ubx) * uby, 0 * uby} */
6404  coefx = 0.0;
6405  coefy = bilincoef * ubx;
6406  constant = bilincoef * (uby > 0.0 ? (lbx-ubx) * uby : 0.0);
6407  }
6408  else if( SCIPisRelEQ(scip, lby, uby) )
6409  {
6410  /* x*y = uby * x + (y-uby) * x >= uby * x + (y-uby) * ubx >= uby * x + min{(lby-uby) * ubx, 0 * ubx} */
6411  coefx = bilincoef * uby;
6412  coefy = 0.0;
6413  constant = bilincoef * (ubx > 0.0 ? (lby-uby) * ubx : 0.0);
6414  }
6415  else
6416  {
6417  coefx = bilincoef * uby;
6418  coefy = bilincoef * ubx;
6419  constant = -bilincoef * ubx * uby;
6420  }
6421  }
6422  else
6423  {
6424  *success = FALSE;
6425  return;
6426  }
6427  }
6428  else
6429  {
6430  /* either x or y is not fixed and coef < 0.0 */
6431  if( !SCIPisInfinity(scip, ubx) && !SCIPisInfinity(scip, -lby) &&
6432  (SCIPisInfinity(scip, -lbx) || SCIPisInfinity(scip, uby) || (ubx - lbx) * (refpointy - lby) <= (uby - lby) * (refpointx - lbx)) )
6433  {
6434  if( SCIPisRelEQ(scip, lbx, ubx) )
6435  {
6436  /* x*y = ubx * y + (x-ubx) * y <= ubx * y + (x-ubx) * lby <= ubx * y + max{(lbx-ubx) * lby, 0 * lby} */
6437  coefx = 0.0;
6438  coefy = bilincoef * ubx;
6439  constant = bilincoef * (lby < 0.0 ? (lbx - ubx) * lby : 0.0);
6440  }
6441  else if( SCIPisRelEQ(scip, lby, uby) )
6442  {
6443  /* x*y = lby * x + (y-lby) * x <= lby * x + (y-lby) * ubx <= lby * x + max{(uby-lby) * ubx, 0 * ubx} */
6444  coefx = bilincoef * lby;
6445  coefy = 0.0;
6446  constant = bilincoef * (ubx > 0.0 ? (uby - lby) * ubx : 0.0);
6447  }
6448  else
6449  {
6450  coefx = bilincoef * lby;
6451  coefy = bilincoef * ubx;
6452  constant = -bilincoef * ubx * lby;
6453  }
6454  }
6455  else if( !SCIPisInfinity(scip, -lbx) && !SCIPisInfinity(scip, uby) )
6456  {
6457  if( SCIPisRelEQ(scip, lbx, ubx) )
6458  {
6459  /* x*y = lbx * y + (x-lbx) * y <= lbx * y + (x-lbx) * uby <= lbx * y + max{(ubx-lbx) * uby, 0 * uby} */
6460  coefx = 0.0;
6461  coefy = bilincoef * lbx;
6462  constant = bilincoef * (uby > 0.0 ? (ubx-lbx) * uby : 0.0);
6463  }
6464  else if( SCIPisRelEQ(scip, lby, uby) )
6465  {
6466  /* x*y = uby * x + (y-uby) * x <= uby * x + (y-uby) * lbx <= uby * x + max{(lby-uby) * lbx, 0 * lbx} */
6467  coefx = bilincoef * uby;
6468  coefy = 0.0;
6469  constant = bilincoef * (lbx < 0.0 ? (lby-uby) * lbx : 0.0);
6470  }
6471  else
6472  {
6473  coefx = bilincoef * uby;
6474  coefy = bilincoef * lbx;
6475  constant = -bilincoef * lbx * uby;
6476  }
6477  }
6478  else
6479  {
6480  *success = FALSE;
6481  return;
6482  }
6483  }
6484 
6485  if( SCIPisInfinity(scip, REALABS(coefx)) || SCIPisInfinity(scip, REALABS(coefy)) || SCIPisInfinity(scip, REALABS(constant)) )
6486  {
6487  *success = FALSE;
6488  return;
6489  }
6490 
6491  if( overestimate )
6492  {
6493  coefx = -coefx;
6494  coefy = -coefy;
6495  constant = -constant;
6496  }
6497 
6498  /* SCIPdebugMessage("%.20g * x[%.20g,%.20g] * y[%.20g,%.20g] %c= %.20g * x %+.20g * y %+.20g\n", bilincoef, lbx, ubx, lby, uby, overestimate ? '<' : '>', coefx, coefy, constant); */
6499 
6500  *lincoefx += coefx;
6501  *lincoefy += coefy;
6502  *linconstant += constant;
6503 }
6504 
6505 /** computes cut coefficients by linearizing a quadratic function */
6506 static
6508  SCIP* scip, /**< SCIP data structure */
6509  SCIP_CONS* cons, /**< constraint */
6510  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6511  SCIP_Real* ref, /**< reference solution where to generate the cut */
6512  SCIP_Real* coef, /**< array to store cut coefficients w.r.t. quadratic variables */
6513  SCIP_Real* lhs, /**< buffer to store left-hand-side of cut */
6514  SCIP_Real* rhs, /**< buffer to store right-hand-side of cut */
6515  SCIP_Bool* islocal, /**< buffer to set to TRUE if local bounds were used */
6516  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6517  char* name /**< buffer to store name for cut */
6518  )
6519 {
6520  SCIP_CONSDATA* consdata;
6521  SCIP_BILINTERM* bilinterm;
6522  SCIP_Real constant;
6523  SCIP_VAR* var;
6524  int var2pos;
6525  int j;
6526  int k;
6527 
6528  assert(scip != NULL);
6529  assert(cons != NULL);
6530  assert(ref != NULL);
6531  assert(coef != NULL);
6532  assert(lhs != NULL);
6533  assert(rhs != NULL);
6534  assert(islocal != NULL);
6535  assert(success != NULL);
6536 
6537  consdata = SCIPconsGetData(cons);
6538  assert(consdata != NULL);
6539 
6540  constant = 0.0;
6541  BMSclearMemoryArray(coef, consdata->nquadvars);
6542  *success = TRUE;
6543 
6544  /* do first-order Taylor for each term */
6545  for( j = 0; j < consdata->nquadvars && *success; ++j )
6546  {
6547  /* initialize coefficients to linear coefficients of quadratic variables */
6548  coef[j] += consdata->quadvarterms[j].lincoef;
6549 
6550  /* add linearization of square term */
6551  var = consdata->quadvarterms[j].var;
6552  addSquareLinearization(scip, consdata->quadvarterms[j].sqrcoef, ref[j], consdata->quadvarterms[j].nadjbilin == 0 && SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef[j], &constant, success);
6553 
6554  /* add linearization of bilinear terms that have var as first variable */
6555  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6556  {
6557  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6558  if( bilinterm->var1 != var )
6559  continue;
6560  assert(bilinterm->var2 != var);
6561  assert(consdata->sepabilinvar2pos != NULL);
6562 
6563  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6564  assert(var2pos >= 0);
6565  assert(var2pos < consdata->nquadvars);
6566  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6567 
6568  addBilinLinearization(scip, bilinterm->coef, ref[j], ref[var2pos], &coef[j], &coef[var2pos], &constant, success);
6569  }
6570  }
6571 
6572  if( !*success )
6573  {
6574  SCIPdebugMessage("no success in linearization of <%s> in reference point\n", SCIPconsGetName(cons));
6575  return SCIP_OKAY;
6576  }
6577 
6578  if( violside == SCIP_SIDETYPE_LEFT )
6579  {
6580  *lhs = consdata->lhs - constant;
6581  *rhs = SCIPinfinity(scip);
6582  }
6583  else
6584  {
6585  *lhs = -SCIPinfinity(scip);
6586  *rhs = consdata->rhs - constant;
6587  }
6588 
6589  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_side%d_linearization_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6590 
6591  return SCIP_OKAY;
6592 }
6593 
6594 /** computes cut coefficients for a nonconvex quadratic function */
6595 static
6597  SCIP* scip, /**< SCIP data structure */
6598  SCIP_CONS* cons, /**< constraint */
6599  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6600  SCIP_Real* ref, /**< reference solution where to generate the cut */
6601  SCIP_Real* coef, /**< array to store cut coefficients w.r.t. quadratic variables */
6602  SCIP_Real* lhs, /**< buffer to store left-hand-side of cut */
6603  SCIP_Real* rhs, /**< buffer to store right-hand-side of cut */
6604  SCIP_Bool* islocal, /**< buffer to set to TRUE if local bounds were used */
6605  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6606  char* name /**< buffer to store name for cut */
6607  )
6608 {
6609  SCIP_CONSDATA* consdata;
6610  SCIP_BILINTERM* bilinterm;
6611  SCIP_Real constant;
6612  SCIP_Real sqrcoef;
6613  SCIP_VAR* var;
6614  int var2pos;
6615  int j;
6616  int k;
6617 
6618  assert(scip != NULL);
6619  assert(cons != NULL);
6620  assert(ref != NULL);
6621  assert(coef != NULL);
6622  assert(lhs != NULL);
6623  assert(rhs != NULL);
6624  assert(islocal != NULL);
6625  assert(success != NULL);
6626 
6627  consdata = SCIPconsGetData(cons);
6628  assert(consdata != NULL);
6629 
6630  *islocal = TRUE;
6631  constant = 0.0;
6632  BMSclearMemoryArray(coef, consdata->nquadvars);
6633  *success = TRUE;
6634 
6635  /* underestimate (secant, McCormick) or linearize each term separately */
6636  for( j = 0; j < consdata->nquadvars && *success; ++j )
6637  {
6638  /* initialize coefficients to linear coefficients of quadratic variables */
6639  coef[j] += consdata->quadvarterms[j].lincoef;
6640 
6641  var = consdata->quadvarterms[j].var;
6642 
6643  sqrcoef = consdata->quadvarterms[j].sqrcoef;
6644  if( sqrcoef != 0.0 )
6645  {
6646  if( (violside == SCIP_SIDETYPE_LEFT && sqrcoef <= 0.0) || (violside == SCIP_SIDETYPE_RIGHT && sqrcoef > 0.0) )
6647  {
6648  /* convex -> linearize */
6649  addSquareLinearization(scip, sqrcoef, ref[j], SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef[j], &constant, success);
6650  }
6651  else
6652  {
6653  /* not convex -> secant approximation */
6654  addSquareSecant(scip, sqrcoef, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j], &coef[j], &constant, success);
6655  }
6656  }
6657 
6658  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6659  {
6660  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6661  if( bilinterm->var1 != var )
6662  continue;
6663  assert(bilinterm->var2 != var);
6664  assert(consdata->sepabilinvar2pos != NULL);
6665 
6666  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6667  assert(var2pos >= 0);
6668  assert(var2pos < consdata->nquadvars);
6669  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6670 
6671  addBilinMcCormick(scip, bilinterm->coef,
6672  SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j],
6673  SCIPvarGetLbLocal(bilinterm->var2), SCIPvarGetUbLocal(bilinterm->var2), ref[var2pos],
6674  violside == SCIP_SIDETYPE_LEFT, &coef[j], &coef[var2pos], &constant, success);
6675  }
6676  }
6677 
6678  if( !*success )
6679  {
6680  SCIPdebugMessage("no success to find estimator for nonconvex <%s>\n", SCIPconsGetName(cons));
6681  return SCIP_OKAY;
6682  }
6683 
6684  if( violside == SCIP_SIDETYPE_LEFT )
6685  {
6686  *lhs = consdata->lhs - constant;
6687  *rhs = SCIPinfinity(scip);
6688  }
6689  else
6690  {
6691  *lhs = -SCIPinfinity(scip);
6692  *rhs = consdata->rhs - constant;
6693  }
6694 
6695  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_side%d_estimation_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6696 
6697  return SCIP_OKAY;
6698 }
6699 
6700 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a given reference point */
6701 static
6703  SCIP* scip, /**< SCIP data structure */
6704  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6705  SCIP_CONS* cons, /**< constraint */
6706  SCIP_Real* ref, /**< reference solution where to generate the cut */
6707  SCIP_SOL* sol, /**< point that we aim to separate, or NULL for LP solution */
6708  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6709  SCIP_ROW** row, /**< storage for cut */
6710  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
6711  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
6712  SCIP_Real minefficacy /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
6713  )
6714 {
6715  SCIP_CONSHDLRDATA* conshdlrdata;
6716  SCIP_CONSDATA* consdata;
6717  SCIP_Bool islocal;
6718  char cutname[SCIP_MAXSTRLEN];
6719  SCIP_Real* lincoefs;
6720  SCIP_Real* coef;
6721  SCIP_Real lhs;
6722  SCIP_Real rhs;
6723  SCIP_Bool success;
6724  SCIP_Real mincoef;
6725  SCIP_Real maxcoef;
6726  SCIP_Real lincoefsmax;
6727  SCIP_Real lincoefsmin;
6728  SCIP_Real viol;
6729  SCIP_Real rowefficacy;
6730  SCIP_VAR* var;
6731  int j;
6732 
6733  assert(scip != NULL);
6734  assert(conshdlr != NULL);
6735  assert(cons != NULL);
6736  assert(ref != NULL);
6737  assert(row != NULL);
6738 
6739  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6740  assert(conshdlrdata != NULL);
6741 
6742  consdata = SCIPconsGetData(cons);
6743  assert(consdata != NULL);
6744  assert(violside != SCIP_SIDETYPE_LEFT || !SCIPisInfinity(scip, -consdata->lhs));
6745  assert(violside != SCIP_SIDETYPE_RIGHT || !SCIPisInfinity(scip, consdata->rhs));
6746 
6747  *row = NULL;
6748  SCIP_CALL( SCIPallocBufferArray(scip, &coef, consdata->nquadvars) );
6749  lincoefs = consdata->lincoefs;
6750  lincoefsmax = consdata->lincoefsmax;
6751  lincoefsmin = consdata->lincoefsmin;
6752  islocal = SCIPconsIsLocal(cons);
6753  success = FALSE;
6754  lhs = -SCIPinfinity(scip);
6755  rhs = SCIPinfinity(scip);
6756  cutname[0] = '\0';
6757 
6758  /* if constraint function is factorable, then try to use factorable form to generate cut */
6759  if( consdata->factorleft != NULL )
6760  {
6761  if( consdata->nlinvars == 0 )
6762  {
6763  SCIP_CALL( generateCutFactorable(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6764  }
6765  else if( sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
6766  {
6767  int i;
6768 
6769  /* generateCutLTI needs reference values also for the linear variables, which we only have if sol is given or LP has been solved */
6770  SCIP_CALL( generateCutLTI(scip, cons, violside, ref, sol, &lincoefs, coef, &lhs, &rhs, &islocal, &success, cutname) );
6771 
6772  /* in case of LTI cuts, we have to recompute the min and max of lincoefs, since they may have been modified */
6773  for( i = 0; i < consdata->nlinvars; ++i )
6774  {
6775  if( REALABS(lincoefs[i]) > lincoefsmax )
6776  lincoefsmax = REALABS(lincoefs[i]);
6777  if( REALABS(lincoefs[i]) < lincoefsmin )
6778  lincoefsmin = REALABS(lincoefs[i]);
6779  }
6780  }
6781  }
6782 
6783  /* if constraint is not factorable or failed to generate cut, try default method */
6784  if( !success )
6785  {
6786  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
6787 
6788  if( (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave) || (violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex) )
6789  {
6790  SCIP_CALL( generateCutConvex(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6791  }
6792  else
6793  {
6794  SCIP_CALL( generateCutNonConvex(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6795  }
6796  }
6797 
6798  /* cut should be one-sided, if any found */
6799  assert(!success || SCIPisInfinity(scip, -lhs) || SCIPisInfinity(scip, rhs));
6800 
6801  /* check if range of cut coefficients is ok
6802  * compute cut activity and violation in sol
6803  */
6804  mincoef = 0.0; /* only for lint */
6805  maxcoef = 0.0; /* only for compiler */
6806  viol = 0.0; /* only for compiler */
6807  if( success )
6808  {
6809  SCIP_Real constant;
6810  SCIP_Real abscoef;
6811  SCIP_Real roundcoef;
6812  int mincoefidx;
6813  SCIP_Real refactivity;
6814  SCIP_Real refactivitylinpart;
6815 
6816  /* compute activity of linear part in sol, if required
6817  * it is required if we need to check or return cut efficacy, for some debug output below, and some assert
6818  * round almost integral coefficients in integers, since this will happen when adding coefs to row (see comments below)
6819  */
6820  refactivitylinpart = 0.0;
6821 #if !defined(SCIP_DEBUG)
6822  if( !SCIPisInfinity(scip, -minefficacy) || efficacy != NULL )
6823 #endif
6824  for( j = 0; j < consdata->nlinvars; ++j )
6825  /* Loose variable have the best bound as LP solution value.
6826  * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
6827  * When this happens, their LP solution value changes to 0.0!
6828  * So when calculating the row activity, we treat loose variable as if they were already column variables.
6829  */
6830  if( SCIPvarGetStatus(consdata->linvars[j]) != SCIP_VARSTATUS_LOOSE )
6831  refactivitylinpart += (SCIPisIntegral(scip, lincoefs[j]) ? SCIPround(scip, lincoefs[j]) : lincoefs[j]) * SCIPgetSolVal(scip, sol, consdata->linvars[j]);
6832 
6833  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
6834 
6835  constant = 0.0;
6836  do
6837  {
6838  refactivity = refactivitylinpart;
6839  mincoefidx = -1;
6840  mincoef = lincoefsmin;
6841  maxcoef = lincoefsmax;
6842 
6843  for( j = 0; j < consdata->nquadvars; ++j )
6844  {
6845  /* coefficients smaller than epsilon are rounded to 0.0 when added to row
6846  * further, coefficients very close to integral values are rounded to integers when added to LP
6847  * both cases can be problematic if variable value is very large (bad numerics)
6848  * thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible)
6849  * i.e., estimate coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x)
6850  * if required bound of x is not finite, then do nothing
6851  */
6852  roundcoef = SCIPround(scip, coef[j]);
6853  if( SCIPisEQ(scip, coef[j], roundcoef) && coef[j] != roundcoef ) /*lint !e777*/
6854  {
6855  SCIP_Real xbnd;
6856 
6857  var = consdata->quadvarterms[j].var;
6858  if( !SCIPisInfinity(scip, rhs) )
6859  if( islocal )
6860  xbnd = coef[j] > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
6861  else
6862  xbnd = coef[j] > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
6863  else
6864  if( islocal )
6865  xbnd = coef[j] > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
6866  else
6867  xbnd = coef[j] > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
6868 
6869  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
6870  {
6871  SCIPdebugMessage("var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g and add constant %g\n",
6872  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef[j], roundcoef, (coef[j]-roundcoef) * xbnd);
6873  constant += (coef[j]-roundcoef) * xbnd;
6874  coef[j] = roundcoef;
6875  }
6876  }
6877 
6878  if( coef[j] == 0.0 )
6879  continue;
6880 
6881  /* As above: When calculating the row activity, we treat loose variable as if they were already column variables. */
6882  if( SCIPvarGetStatus(consdata->quadvarterms[j].var) != SCIP_VARSTATUS_LOOSE )
6883  refactivity += coef[j] * SCIPgetSolVal(scip, sol, consdata->quadvarterms[j].var);
6884 
6885  abscoef = REALABS(coef[j]);
6886  if( abscoef < mincoef )
6887  {
6888  mincoef = abscoef;
6889  mincoefidx = j;
6890  }
6891  if( abscoef > maxcoef )
6892  maxcoef = abscoef;
6893  }
6894 
6895  if( maxcoef < mincoef )
6896  {
6897  /* if all coefficients are zero, then mincoef and maxcoef are still at their initial values
6898  * thus, skip cut generation if its boring
6899  */
6900  assert(maxcoef == 0.0); /*lint !e777 */
6901  assert(mincoef == SCIPinfinity(scip)); /*lint !e777 */
6902 
6903  if( !SCIPisFeasPositive(scip, lhs) && !SCIPisFeasNegative(scip, rhs) )
6904  {
6905  SCIPdebugMessage("skip cut for constraint <%s> since all coefficients are zero and it's always satisfied\n", SCIPconsGetName(cons));
6906  success = FALSE;
6907  }
6908  else
6909  {
6910  /* cut will cutoff node */
6911  }
6912 
6913  break;
6914  }
6915 
6916  if( maxcoef / mincoef > conshdlrdata->cutmaxrange )
6917  {
6918  SCIPdebugMessage("cut coefficients for constraint <%s> have very large range: mincoef = %g maxcoef = %g\n", SCIPconsGetName(cons), mincoef, maxcoef);
6919  if( mincoefidx >= 0 )
6920  {
6921  var = consdata->quadvarterms[mincoefidx].var;
6922  /* try to eliminate coefficient with minimal absolute value by weakening cut and try again
6923  * since we use local bounds, we need to make the row local if they are different from their global counterpart
6924  */
6925  if( ((coef[mincoefidx] > 0.0 && !SCIPisInfinity(scip, rhs)) || (coef[mincoefidx] < 0.0 && !SCIPisInfinity(scip, -lhs))) &&
6926  !SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
6927  {
6928  SCIPdebugMessage("eliminate coefficient %g for <%s> [%g, %g]\n", coef[mincoefidx], SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6929  constant += coef[mincoefidx] * SCIPvarGetLbLocal(var);
6930  coef[mincoefidx] = 0.0;
6931  islocal |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
6932  continue;
6933  }
6934  else if( ((coef[mincoefidx] < 0.0 && !SCIPisInfinity(scip, rhs)) || (coef[mincoefidx] > 0.0 && !SCIPisInfinity(scip, -lhs))) &&
6935  !SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6936  {
6937  SCIPdebugMessage("eliminate coefficient %g for <%s> [%g, %g]\n", coef[mincoefidx], SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6938  constant += coef[mincoefidx] * SCIPvarGetUbLocal(var);
6939  coef[mincoefidx] = 0.0;
6940  islocal |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
6941  continue;
6942  }
6943  }
6944 
6945  SCIPdebugMessage("skip cut\n");
6946  success = FALSE;
6947  }
6948  break;
6949  }
6950  while( TRUE ); /*lint !e506 */
6951 
6952  if( !SCIPisInfinity(scip, -lhs) )
6953  {
6954  lhs -= constant;
6955  viol = lhs - refactivity;
6956  }
6957  if( !SCIPisInfinity(scip, rhs) )
6958  {
6959  rhs -= constant;
6960  viol = refactivity - rhs;
6961  }
6962  }
6963 
6964  if( success && SCIPisInfinity(scip, REALABS(lhs)) && SCIPisInfinity(scip, REALABS(rhs)) )
6965  {
6966  SCIPdebugMessage("skip cut for constraint <%s> because both sides are not finite: lhs = %g, rhs = %g\n", SCIPconsGetName(cons), lhs, rhs);
6967  success = FALSE;
6968  }
6969 
6970  /* check if reference point violates cut sufficiently */
6971  if( success )
6972  {
6973  rowefficacy = viol;
6974  switch( conshdlrdata->scaling )
6975  {
6976  case 'o' :
6977  break;
6978 
6979  case 'g' :
6980  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
6981  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too also we
6982  * use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium scaling) */
6983  rowefficacy /= MAX(1.0, maxcoef);
6984  break;
6985 
6986  case 's' :
6987  {
6988  SCIP_Real abslhs = REALABS(lhs);
6989 
6990  if( !SCIPisInfinity(scip, abslhs) )
6991  rowefficacy /= MAX(1.0, abslhs);
6992  else
6993  {
6994  SCIP_Real absrhs = REALABS(rhs);
6995 
6996  rowefficacy /= MAX(1.0, absrhs);
6997  }
6998 
6999  break;
7000  }
7001 
7002  default:
7003  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
7004  SCIPABORT();
7005  return SCIP_INVALIDDATA; /*lint !e527*/
7006  }
7007  }
7008 
7009  if( success && !SCIPisInfinity(scip, -minefficacy) && rowefficacy < minefficacy ) /*lint !e644*/
7010  {
7011  SCIPdebugMessage("skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), rowefficacy, minefficacy);
7012  success = FALSE;
7013  }
7014 
7015  /* generate row */
7016  if( success )
7017  {
7018  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, lhs, rhs, islocal && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
7019 
7020  /* add coefficients from linear part */
7021  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nlinvars, consdata->linvars, lincoefs) );
7022 
7023  /* add coefficients from quadratic part */
7024  assert(consdata->sepaquadvars != NULL || consdata->nquadvars == 0);
7025  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nquadvars, consdata->sepaquadvars, coef) );
7026 
7027  SCIPdebugMessage("found cut <%s>, lhs=%g, rhs=%g, mincoef=%g, maxcoef=%g, range=%g, nnz=%d, violation=%g, efficacy=%g\n",
7028  SCIProwGetName(*row), lhs, rhs,
7029  mincoef, maxcoef, maxcoef/mincoef,
7030  SCIProwGetNNonz(*row), viol, rowefficacy); /*lint !e414 */
7031 
7032  if( efficacy != NULL )
7033  {
7034  *efficacy = rowefficacy;
7035 
7036  /* check that our computed efficacy is > feastol, iff efficacy computed by row is > feastol
7037  * computing efficacy w.r.t. the LP solution makes only sense if the LP was solved to optimality (see bug 612)
7038  *
7039  * disabled these asserts as they can fail due to numerical reasons (cancelation when substracting big numbers),
7040  * as the order in which we add up the activity for the single terms can be different than the one that lp.c uses
7041  */
7042  /*
7043  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
7044  assert((conshdlrdata->scaling != 'g') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol)/MAX(1.0,SCIPgetRowMaxCoef(scip, *row)))));
7045  assert((conshdlrdata->scaling != 's') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol)/MAX(1.0,MIN(REALABS(lhs),REALABS(rhs))))));
7046  assert((conshdlrdata->scaling != 'o') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol))));
7047  */
7048  }
7049  }
7050 
7051  SCIPfreeBufferArray(scip, &coef);
7052 
7053  /* if coefficients for linear variables are different than those in constraint, then free array */
7054  if( lincoefs != consdata->lincoefs )
7055  {
7056  SCIPfreeBufferArray(scip, &lincoefs);
7057  }
7058 
7059  return SCIP_OKAY;
7060 }
7061 
7062 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a solution
7063  */
7064 static
7066  SCIP* scip, /**< SCIP data structure */
7067  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7068  SCIP_CONS* cons, /**< constraint */
7069  SCIP_SOL* sol, /**< solution where to generate cut, or NULL if LP solution should be used */
7070  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
7071  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7072  SCIP_ROW** row, /**< storage for cut */
7073  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
7074  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7075  SCIP_Real minefficacy /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
7076  )
7077 {
7078  SCIP_CONSDATA* consdata;
7079  SCIP_VAR* var;
7080  SCIP_Real lb;
7081  SCIP_Real ub;
7082  SCIP_Real* ref;
7083  int j;
7084 
7085  assert(scip != NULL);
7086  assert(conshdlr != NULL);
7087  assert(cons != NULL);
7088 
7089  consdata = SCIPconsGetData(cons);
7090  assert(consdata != NULL);
7091 
7092  if( refsol == NULL )
7093  refsol = sol;
7094 
7095  /* get reference point */
7096  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
7097  for( j = 0; j < consdata->nquadvars; ++j )
7098  {
7099  var = consdata->quadvarterms[j].var;
7100  lb = SCIPvarGetLbLocal(var);
7101  ub = SCIPvarGetUbLocal(var);
7102  /* do not like variables at infinity */
7103  assert(!SCIPisInfinity(scip, lb));
7104  assert(!SCIPisInfinity(scip, -ub));
7105 
7106  ref[j] = SCIPgetSolVal(scip, refsol, var);
7107  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
7108  }
7109 
7110  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
7111 
7112  SCIPfreeBufferArray(scip, &ref);
7113 
7114  return SCIP_OKAY;
7115 }
7116 
7117 /** tries to find a cut that intersects with an unbounded ray of the LP
7118  * for convex functions, we do this by linearizing in the feasible solution of the LPI
7119  * for nonconvex functions, we just call generateCutSol with the unbounded solution as reference point */
7120 static
7122  SCIP* scip, /**< SCIP data structure */
7123  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7124  SCIP_CONS* cons, /**< constraint */
7125  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7126  SCIP_ROW** row, /**< storage for cut */
7127  SCIP_Real* rowrayprod, /**< buffer to store product of ray with row coefficients, or NULL if not of interest */
7128  SCIP_Bool checkcurvmultivar /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7129  )
7130 {
7131  SCIP_CONSDATA* consdata;
7132  SCIP_BILINTERM* bilinterm;
7133  SCIP_VAR* var;
7134  SCIP_Real* ref;
7135  SCIP_Real matrixrayprod;
7136  SCIP_Real linrayprod;
7137  SCIP_Real quadrayprod;
7138  SCIP_Real rayval;
7139  int i;
7140  int j;
7141 
7142  assert(scip != NULL);
7143  assert(conshdlr != NULL);
7144  assert(cons != NULL);
7145  assert(row != NULL);
7147 
7148  consdata = SCIPconsGetData(cons);
7149  assert(consdata != NULL);
7150 
7151  *row = NULL;
7152 
7153  if( !SCIPhasPrimalRay(scip) )
7154  {
7155  SCIPdebugMessage("do not have primal ray, thus cannot resolve unboundedness\n");
7156  return SCIP_OKAY;
7157  }
7158 
7159  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
7160  if( (!consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
7161  (!consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
7162  {
7163  /* if not convex, just call generateCut and hope it's getting something useful */
7164  SCIP_CALL( generateCutSol(scip, conshdlr, cons, NULL, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
7165 
7166  /* compute product of cut coefficients with ray, if required */
7167  if( *row != NULL && rowrayprod != NULL )
7168  {
7169  *rowrayprod = 0.0;
7170  for( i = 0; i < SCIProwGetNNonz(*row); ++i )
7171  {
7172  assert(SCIProwGetCols(*row)[i] != NULL);
7173  var = SCIPcolGetVar(SCIProwGetCols(*row)[i]);
7174  assert(var != NULL);
7175 
7176  *rowrayprod += SCIProwGetVals(*row)[i] * SCIPgetPrimalRayVal(scip, var);
7177  }
7178  }
7179 
7180  return SCIP_OKAY;
7181  }
7182 
7183  /* we seek for a linearization of the quadratic function such that it intersects with the unbounded ray
7184  * that is, we need a reference point ref such that for the gradient g of xAx+bx in ref, we have
7185  * <g, ray> > 0.0 if rhs is finite and <g, ray> < 0.0 if lhs is finite
7186  * Since g = 2*A*ref + b, we have <g, ray> = <2*A*ref + b, ray> = <ref, 2*A*ray> + <b,ray>
7187  * 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)
7188  * <ref, 2*A*ray> + <b,ray> is sufficiently larger 0.0, we call generateCut for this point, otherwise, we scale up ref
7189  */
7190 
7191  quadrayprod = 0.0; /* <ref, 2*A*ray> */
7192  linrayprod = 0.0; /* <b, ray> */
7193  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
7194  for( i = 0; i < consdata->nquadvars; ++i )
7195  {
7196  var = consdata->quadvarterms[i].var;
7197  rayval = SCIPgetPrimalRayVal(scip, var);
7198 
7199  /* compute i-th entry of (2*A*ray) */
7200  matrixrayprod = 2.0 * consdata->quadvarterms[i].sqrcoef * rayval;
7201  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
7202  {
7203  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
7204  matrixrayprod += bilinterm->coef * SCIPgetPrimalRayVal(scip, bilinterm->var1 == var ? bilinterm->var2 : bilinterm->var1);
7205  }
7206 
7207  if( SCIPisPositive(scip, matrixrayprod) )
7208  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? 1.0 : -1.0);
7209  else if( SCIPisNegative(scip, matrixrayprod) )
7210  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? -1.0 : 1.0);
7211  else
7212  ref[i] = 0.0;
7213 
7214  quadrayprod += matrixrayprod * ref[i];
7215  linrayprod += consdata->quadvarterms[i].lincoef * rayval;
7216  }
7217  assert((violside == SCIP_SIDETYPE_RIGHT && quadrayprod >= 0.0) || (violside == SCIP_SIDETYPE_LEFT && quadrayprod <= 0.0));
7218 
7219  if( SCIPisZero(scip, quadrayprod) )
7220  {
7221  SCIPdebugMessage("ray is zero along cons <%s>\n", SCIPconsGetName(cons));
7222  SCIPfreeBufferArray(scip, &ref);
7223  return SCIP_OKAY;
7224  }
7225 
7226  /* add linear part to linrayprod */
7227  for( i = 0; i < consdata->nlinvars; ++i )
7228  linrayprod += consdata->lincoefs[i] * SCIPgetPrimalRayVal(scip, consdata->linvars[i]);
7229 
7230  SCIPdebugMessage("initially have <b,ray> = %g and <ref, 2*A*ref> = %g\n", linrayprod, quadrayprod);
7231 
7232  /* 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
7233  * if <b,ray> is zero, then we scale refpoint up if |<ref, 2*A*ray>| < 1.0
7234  */
7235  if( (!SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_RIGHT && quadrayprod < -2*linrayprod) ||
7236  ( !SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_LEFT && quadrayprod > -2*linrayprod) ||
7237  (SCIPisZero(scip, linrayprod) && REALABS(quadrayprod) < 1.0) )
7238  {
7239  SCIP_Real scale;
7240 
7241  if( !SCIPisZero(scip, linrayprod) )
7242  scale = 2*REALABS(linrayprod/quadrayprod); /*lint !e795 */
7243  else
7244  scale = 1.0/REALABS(quadrayprod);
7245 
7246  SCIPdebugMessage("scale refpoint by %g\n", scale);
7247  for( i = 0; i < consdata->nquadvars; ++i )
7248  ref[i] *= scale;
7249  quadrayprod *= scale;
7250  }
7251 
7252  if( rowrayprod != NULL )
7253  *rowrayprod = quadrayprod + linrayprod;
7254 
7255  SCIPdebugMessage("calling generateCut, expecting ray product %g\n", quadrayprod + linrayprod);
7256  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
7257 
7258  SCIPfreeBufferArray(scip, &ref);
7259 
7260  return SCIP_OKAY;
7261 }
7262 
7263 /** tries to separate solution or LP solution by a linear cut
7264  *
7265  * assumes that constraint violations have been computed
7266  */
7267 static
7269  SCIP* scip, /**< SCIP data structure */
7270  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
7271  SCIP_CONS** conss, /**< constraints */
7272  int nconss, /**< number of constraints */
7273  int nusefulconss, /**< number of constraints that seem to be useful */
7274  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7275  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
7276  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
7277  SCIP_RESULT* result, /**< result of separation */
7278  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 */
7279  )
7280 {
7281  SCIP_CONSHDLRDATA* conshdlrdata;
7282  SCIP_CONSDATA* consdata;
7283  SCIP_Real efficacy;
7284  SCIP_Real actminefficacy;
7285  SCIP_SIDETYPE violside;
7286  int c;
7287  SCIP_ROW* row;
7288 
7289  assert(scip != NULL);
7290  assert(conshdlr != NULL);
7291  assert(conss != NULL || nconss == 0);
7292  assert(nusefulconss <= nconss);
7293  assert(result != NULL);
7294 
7295  *result = SCIP_FEASIBLE;
7296 
7297  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7298  assert(conshdlrdata != NULL);
7299 
7300  if( bestefficacy != NULL )
7301  *bestefficacy = 0.0;
7302 
7303  for( c = 0; c < nconss; ++c )
7304  {
7305  assert(conss != NULL);
7306  consdata = SCIPconsGetData(conss[c]);
7307  assert(consdata != NULL);
7308 
7309  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7310  {
7311  /* we are not feasible anymore */
7312  if( *result == SCIP_FEASIBLE )
7313  *result = SCIP_DIDNOTFIND;
7314 
7315  violside = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT;
7316 
7317  /* actual minimal efficacy */
7318  actminefficacy = inenforcement && ((violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex ) || (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave))
7319  ? (SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip))
7320  : minefficacy;
7321 
7322  /* generate cut */
7323  if( sol == NULL && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
7324  {
7325  /* if the LP is unbounded, then we need a cut that cuts into the direction of a hopefully existing primal ray
7326  * 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
7327  * given a cut lhs <= <c,x> <= rhs, we check whether it imposes an upper bound on t and thus bounds the ray
7328  * 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>
7329  * similar, lhs > -infinity and <c,r> < 0 is good
7330  */
7331  SCIP_Real rayprod;
7332  SCIP_Real norm;
7333 
7334  rayprod = 0.0; /* for compiler */
7335  SCIP_CALL( generateCutUnboundedLP(scip, conshdlr, conss[c], violside, &row, &rayprod, conshdlrdata->checkcurvature) );
7336 
7337  if( row != NULL )
7338  {
7339  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) && SCIPisPositive(scip, rayprod) )
7340  efficacy = rayprod;
7341  else if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) && SCIPisNegative(scip, rayprod) )
7342  efficacy = -rayprod;
7343  else
7344  efficacy = 0.0;
7345 
7346  switch( conshdlrdata->scaling )
7347  {
7348  case 'o' :
7349  break;
7350 
7351  case 'g' :
7352  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding
7353  * cuts efficient which are only very slightly violated CPLEX does not seem to scale row
7354  * coefficients up too also we use infinity norm, since that seem to be the usual scaling strategy
7355  * in LP solvers (equilibrium scaling) */
7356  norm = SCIPgetRowMaxCoef(scip, row);
7357  efficacy /= MAX(1.0, norm);
7358  break;
7359 
7360  case 's' :
7361  {
7362  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
7363  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
7364  SCIP_Real minval = MIN(abslhs, absrhs);
7365 
7366  efficacy /= MAX(1.0, minval);
7367  break;
7368  }
7369 
7370  default:
7371  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
7372  SCIPABORT();
7373  return SCIP_INVALIDDATA; /*lint !e527*/
7374  }
7375  }
7376  }
7377  else
7378  {
7379  /* @todo If convex, can we easily move the refpoint closer to the feasible region to get a stronger cut?
7380  * E.g., use bisection on the line between LP solution and best primal (or LP interior)
7381  */
7382  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], sol, NULL, violside, &row, &efficacy, conshdlrdata->checkcurvature, actminefficacy) );
7383  /* @todo If generation failed not because of low efficacy, then probably because of numerical issues;
7384  * if the constraint is convex and we are desperate to get a cut, then we may try again with a better chosen reference point
7385  */
7386  }
7387 
7388  if( row == NULL ) /* failed to generate cut */
7389  continue;
7390 
7391  if( SCIPisGT(scip, efficacy, actminefficacy) && SCIPisCutApplicable(scip, row) ) /*lint !e644 */
7392  {
7393  SCIP_Bool infeasible;
7394 
7395  /* cut cuts off solution */
7396  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE /* forcecut */, &infeasible) );
7397  if( infeasible )
7398  {
7399  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(conss[c]));
7400  *result = SCIP_CUTOFF;
7401  }
7402  else
7403  {
7404  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy,
7405  SCIPconsGetName(conss[c]), consdata->lhsviol+consdata->rhsviol);
7406  *result = SCIP_SEPARATED;
7407  }
7408  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
7409 
7410  /* mark row as not removable from LP for current node, if in enforcement */
7411  if( inenforcement && !conshdlrdata->enfocutsremovable )
7412  SCIPmarkRowNotRemovableLocal(scip, row);
7413  }
7414  if( bestefficacy != NULL && efficacy > *bestefficacy )
7415  *bestefficacy = efficacy;
7416 
7417  SCIP_CALL( SCIPreleaseRow (scip, &row) );
7418  }
7419 
7420  if( *result == SCIP_CUTOFF )
7421  break;
7422 
7423  /* enforce only useful constraints
7424  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
7425  */
7426  if( c >= nusefulconss && *result == SCIP_SEPARATED )
7427  break;
7428  }
7429 
7430  return SCIP_OKAY;
7431 }
7432 
7433 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
7434  * 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
7435  * if separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only
7436  * if separatedlpsol is NULL, then cut is added to cutpool only
7437  */
7438 static
7440  SCIP* scip, /**< SCIP data structure */
7441  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
7442  SCIP_CONS** conss, /**< constraints */
7443  int nconss, /**< number of constraints */
7444  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
7445  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP, or NULL if adding to cutpool only */
7446  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
7447  )
7448 {
7449  SCIP_CONSHDLRDATA* conshdlrdata;
7450  SCIP_CONSDATA* consdata;
7451  SCIP_Bool addedtolp;
7452  SCIP_ROW* row;
7453  int c;
7454 
7455  assert(scip != NULL);
7456  assert(conshdlr != NULL);
7457  assert(conss != NULL || nconss == 0);
7458 
7459  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7460  assert(conshdlrdata != NULL);
7461 
7462  if( separatedlpsol != NULL )
7463  *separatedlpsol = FALSE;
7464 
7465  for( c = 0; c < nconss; ++c )
7466  {
7467  assert(conss[c] != NULL); /*lint !e613 */
7468 
7469  if( SCIPconsIsLocal(conss[c]) ) /*lint !e613 */
7470  continue;
7471 
7472  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
7473 
7474  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
7475  assert(consdata != NULL);
7476 
7477  if( consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
7478  {
7479  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_RIGHT, &row, NULL, conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
7480  }
7481  else if( consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
7482  {
7483  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_LEFT, &row, NULL, conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
7484  }
7485  else
7486  continue;
7487 
7488  if( row == NULL )
7489  continue;
7490 
7491  addedtolp = FALSE;
7492 
7493  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
7494  if( separatedlpsol != NULL )
7495  {
7496  SCIP_Real efficacy;
7497  SCIP_Real norm;
7498 
7499  efficacy = -SCIPgetRowLPFeasibility(scip, row);
7500  switch( conshdlrdata->scaling )
7501  {
7502  case 'o' :
7503  break;
7504 
7505  case 'g' :
7506  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
7507  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too
7508  * also we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
7509  * scaling) */
7510  norm = SCIPgetRowMaxCoef(scip, row);
7511  efficacy /= MAX(1.0, norm);
7512  break;
7513 
7514  case 's' :
7515  {
7516  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
7517  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
7518  SCIP_Real minval = MIN(abslhs, absrhs);
7519 
7520  efficacy /= MAX(1.0, minval);
7521  break;
7522  }
7523 
7524  default:
7525  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
7526  SCIPABORT();
7527  return SCIP_INVALIDDATA; /*lint !e527*/
7528  }
7529 
7530  if( efficacy >= minefficacy )
7531  {
7532  SCIP_Bool infeasible;
7533 
7534  *separatedlpsol = TRUE;
7535  addedtolp = TRUE;
7536  SCIP_CALL( SCIPaddCut(scip, NULL, row, TRUE, &infeasible) );
7537  assert( ! infeasible );
7538  SCIPdebugMessage("added linearization cut <%s> to LP, efficacy = %g\n", SCIProwGetName(row), efficacy);
7539  }
7540  }
7541 
7542  if( !SCIProwIsLocal(row) && !addedtolp )
7543  {
7544  SCIP_CALL( SCIPaddPoolCut(scip, row) );
7545  SCIPdebugMessage("added linearization cut <%s> to cutpool\n", SCIProwGetName(row));
7546  }
7547 
7548  SCIP_CALL( SCIPreleaseRow(scip, &row) );
7549  }
7550 
7551  return SCIP_OKAY;
7552 }
7553 
7554 /** processes the event that a new primal solution has been found */
7555 static
7556 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
7557 {
7558  SCIP_CONSHDLRDATA* conshdlrdata;
7559  SCIP_CONSHDLR* conshdlr;
7560  SCIP_CONS** conss;
7561  int nconss;
7562  SCIP_SOL* sol;
7563 
7564  assert(scip != NULL);
7565  assert(event != NULL);
7566  assert(eventdata != NULL);
7567  assert(eventhdlr != NULL);
7568 
7569  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
7570 
7571  conshdlr = (SCIP_CONSHDLR*)eventdata;
7572 
7573  nconss = SCIPconshdlrGetNConss(conshdlr);
7574 
7575  if( nconss == 0 )
7576  return SCIP_OKAY;
7577 
7578  sol = SCIPeventGetSol(event);
7579  assert(sol != NULL);
7580 
7581  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7582  assert(conshdlrdata != NULL);
7583 
7584  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
7585  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
7586  * or are from the tree, but postprocessed via proposeFeasibleSolution
7587  */
7588  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
7589  return SCIP_OKAY;
7590 
7591  conss = SCIPconshdlrGetConss(conshdlr);
7592  assert(conss != NULL);
7593 
7594  SCIPdebugMessage("caught new sol event %x from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
7595 
7596  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
7597 
7598  return SCIP_OKAY;
7599 }
7600 
7601 /** computes the infeasibilities of variables from the convexification gaps in the constraints and notifies the branching rule about them
7602  */
7603 static
7605  SCIP* scip, /**< SCIP data structure */
7606  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7607  SCIP_CONS** conss, /**< constraints to check */
7608  int nconss, /**< number of constraints to check */
7609  int* nnotify /**< counter for number of notifications performed */
7610  )
7611 {
7612  SCIP_CONSDATA* consdata;
7613  int c;
7614  int j;
7615  SCIP_Bool xbinary;
7616  SCIP_Bool ybinary;
7617  SCIP_Bool xunbounded;
7618  SCIP_Bool yunbounded;
7619  SCIP_VAR* x;
7620  SCIP_VAR* y;
7621  SCIP_Real xlb;
7622  SCIP_Real xub;
7623  SCIP_Real xval;
7624  SCIP_Real ylb;
7625  SCIP_Real yub;
7626  SCIP_Real yval;
7627  SCIP_Real gap;
7628  SCIP_Real coef_;
7629 
7630  assert(scip != NULL);
7631  assert(conshdlr != NULL);
7632  assert(conss != NULL || nconss == 0);
7633 
7634  *nnotify = 0;
7635  yval = SCIP_INVALID;
7636  xval = SCIP_INVALID;
7637 
7638  for( c = 0; c < nconss; ++c )
7639  {
7640  assert(conss != NULL);
7641  consdata = SCIPconsGetData(conss[c]);
7642  assert(consdata != NULL);
7643 
7644  if( !consdata->nquadvars )
7645  continue;
7646 
7647  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
7648  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
7649  continue;
7650  SCIPdebugMessage("cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
7651 
7652  /* square terms */
7653  for( j = 0; j < consdata->nquadvars; ++j )
7654  {
7655  x = consdata->quadvarterms[j].var;
7656  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef < 0) ||
7657  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef > 0) )
7658  {
7659  xlb = SCIPvarGetLbLocal(x);
7660  xub = SCIPvarGetUbLocal(x);
7661  if( SCIPisRelEQ(scip, xlb, xub) )
7662  {
7663  SCIPdebugMessage("ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
7664  continue;
7665  }
7666 
7667  xval = SCIPgetSolVal(scip, NULL, x);
7668 
7669  /* if variable is at bounds, then no need to branch, since secant is exact there */
7670  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
7671  continue;
7672 
7673  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
7674  gap = SCIPinfinity(scip);
7675  else
7676  gap = (xval-xlb)*(xub-xval)/(1+2*ABS(xval));
7677  assert(!SCIPisFeasNegative(scip, gap));
7678  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(gap, 0.0), SCIP_INVALID) );
7679  ++*nnotify;
7680  }
7681  }
7682 
7683  /* bilinear terms */
7684  for( j = 0; j < consdata->nbilinterms; ++j )
7685  {
7686  /* if any of the variables if fixed, then it actually behaves like a linear term, so we don't need to branch on it */
7687  x = consdata->bilinterms[j].var1;
7688  xlb = SCIPvarGetLbLocal(x);
7689  xub = SCIPvarGetUbLocal(x);
7690  if( SCIPisRelEQ(scip, xlb, xub) )
7691  continue;
7692 
7693  y = consdata->bilinterms[j].var2;
7694  ylb = SCIPvarGetLbLocal(y);
7695  yub = SCIPvarGetUbLocal(y);
7696  if( SCIPisRelEQ(scip, ylb, yub) )
7697  continue;
7698 
7699  xunbounded = SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub);
7700  yunbounded = SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub);
7701 
7702  /* compute gap, if both variable are bounded */
7703  gap = SCIPinfinity(scip);
7704  if( !xunbounded && !yunbounded )
7705  {
7706  xval = SCIPgetSolVal(scip, NULL, x);
7707  yval = SCIPgetSolVal(scip, NULL, y);
7708 
7709  /* if both variables are at one of its bounds, then no need to branch, since McCormick is exact there */
7710  if( (SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub)) &&
7711  ( SCIPisLE(scip, yval, ylb) || SCIPisGE(scip, yval, yub)) )
7712  continue;
7713 
7714  xval = MAX(xlb, MIN(xval, xub));
7715  yval = MAX(ylb, MIN(yval, yub));
7716 
7717  coef_ = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? -consdata->bilinterms[j].coef : consdata->bilinterms[j].coef;
7718  if( coef_ > 0.0 )
7719  {
7720  if( (xub-xlb)*yval + (yub-ylb)*xval <= xub*yub - xlb*ylb )
7721  gap = (xval*yval - xlb*yval - ylb*xval + xlb*ylb) / (1+sqrt(xval*xval + yval*yval));
7722  else
7723  gap = (xval*yval - xval*yub - yval*xub + xub*yub) / (1+sqrt(xval*xval + yval*yval));
7724  }
7725  else
7726  { /* coef_ < 0 */
7727  if( (xub-xlb)*yval - (yub-ylb)*xval <= xub*ylb - xlb*yub )
7728  gap = -(xval*yval - xval*ylb - yval*xub + xub*ylb) / (1+sqrt(xval*xval + yval*yval));
7729  else
7730  gap = -(xval*yval - xval*yub - yval*xlb + xlb*yub) / (1+sqrt(xval*xval + yval*yval));
7731  }
7732 
7733  assert(!SCIPisNegative(scip, gap / MAX3(REALABS(xval), REALABS(yval), 1.0))); /*lint !e666*/
7734  if( gap < 0.0 )
7735  gap = 0.0;
7736  }
7737 
7738  /* if one of the variables is binary or integral with domain width 1, then branching on this makes the term linear, so prefer this */
7739  xbinary = SCIPvarIsBinary(x) || (SCIPvarIsIntegral(x) && xub - xlb < 1.5);
7740  ybinary = SCIPvarIsBinary(y) || (SCIPvarIsIntegral(y) && yub - ylb < 1.5);
7741  if( xbinary )
7742  {
7744  ++*nnotify;
7745  }
7746  if( ybinary )
7747  {
7749  ++*nnotify;
7750  }
7751  if( xbinary || ybinary )
7752  continue;
7753 
7754  /* if one of the variables is unbounded, then branch on it first */
7755  if( xunbounded )
7756  {
7758  ++*nnotify;
7759  }
7760  if( yunbounded )
7761  {
7763  ++*nnotify;
7764  }
7765  if( xunbounded || yunbounded )
7766  continue;
7767 
7768  /* if both variables are integral, prefer the one with the smaller domain, so variable gets fixed soon
7769  * does not seem to work well on tln instances, so disable for now and may look at it later again
7770  */
7771 #ifdef BRANCHTOLINEARITY
7772  if( SCIPvarIsIntegral(x) && SCIPvarIsIntegral(y) )
7773  {
7774  if( SCIPisLT(scip, xub-xlb, yub-ylb) )
7775  {
7777  ++*nnotify;
7778  continue;
7779  }
7780  if( SCIPisGT(scip, xub-xlb, yub-ylb) )
7781  {
7783  ++*nnotify;
7784  continue;
7785  }
7786  }
7787 #endif
7788 
7789  /* in the regular case, suggest those variables which are not at its bounds for branching
7790  * this is, because after branching both variables will be one the bounds, and McCormick will be exact then */
7791  if( !SCIPisLE(scip, xval, xlb) && !SCIPisGE(scip, xval, xub) )
7792  {
7794  ++*nnotify;
7795  }
7796  if( !SCIPisLE(scip, yval, ylb) && !SCIPisGE(scip, yval, yub) )
7797  {
7799  ++*nnotify;
7800  }
7801  }
7802  }
7803 
7804  SCIPdebugMessage("registered %d branching candidates\n", *nnotify);
7805 
7806  return SCIP_OKAY;
7807 }
7808 
7809 /** registers a quadratic variable from a violated constraint as branching candidate that has a large absolute value in the LP relaxation */
7810 static
7812  SCIP* scip, /**< SCIP data structure */
7813  SCIP_CONS** conss, /**< constraints */
7814  int nconss, /**< number of constraints */
7815  SCIP_VAR** brvar /**< buffer to store branching variable */
7816  )
7817 {
7818  SCIP_CONSDATA* consdata;
7819  SCIP_Real val;
7820  SCIP_Real brvarval;
7821  int i;
7822  int c;
7823 
7824  assert(scip != NULL);
7825  assert(conss != NULL || nconss == 0);
7826 
7827  *brvar = NULL;
7828  brvarval = -1.0;
7829 
7830  for( c = 0; c < nconss; ++c )
7831  {
7832  assert(conss != NULL);
7833  consdata = SCIPconsGetData(conss[c]);
7834  assert(consdata != NULL);
7835 
7836  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7837  continue;
7838 
7839  for( i = 0; i < consdata->nquadvars; ++i )
7840  {
7841  /* do not propose fixed variables */
7842  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7843  continue;
7844  val = SCIPgetSolVal(scip, NULL, consdata->quadvarterms[i].var);
7845  if( ABS(val) > brvarval )
7846  {
7847  brvarval = ABS(val);
7848  *brvar = consdata->quadvarterms[i].var;
7849  }
7850  }
7851  }
7852 
7853  if( *brvar != NULL )
7854  {
7855  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
7856  }
7857 
7858  return SCIP_OKAY;
7859 }
7860 
7861 /** replaces violated quadratic constraints where all quadratic variables are fixed by linear constraints */
7862 static
7864  SCIP* scip, /**< SCIP data structure */
7865  SCIP_CONS** conss, /**< constraints */
7866  int nconss, /**< number of constraints */
7867  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
7868  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
7869  SCIP_Bool* infeasible /**< whether we detected infeasibility */
7870  )
7871 {
7872  SCIP_CONS* cons;
7873  SCIP_CONSDATA* consdata;
7874  SCIP_RESULT checkresult;
7875  SCIP_Real constant;
7876  SCIP_Real val1;
7877  SCIP_Real val2;
7878  int i;
7879  int c;
7880 
7881  assert(scip != NULL);
7882  assert(conss != NULL || nconss == 0);
7883  assert(addedcons != NULL);
7884  assert(reduceddom != NULL);
7885  assert(infeasible != NULL);
7886 
7887  *addedcons = FALSE;
7888  *reduceddom = FALSE;
7889  *infeasible = FALSE;
7890 
7891  for( c = 0; c < nconss; ++c )
7892  {
7893  assert(conss != NULL);
7894  consdata = SCIPconsGetData(conss[c]);
7895  assert(consdata != NULL);
7896 
7897  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7898  continue;
7899 
7900  constant = 0.0;
7901 
7902  for( i = 0; i < consdata->nquadvars; ++i )
7903  {
7904  /* variables should be fixed if constraint is violated */
7905  assert(SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
7906 
7907  val1 = (SCIPvarGetUbLocal(consdata->quadvarterms[i].var) + SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) / 2.0;
7908  constant += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val1) * val1;
7909  }
7910 
7911  for( i = 0; i < consdata->nbilinterms; ++i )
7912  {
7913  val1 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var1) + SCIPvarGetLbLocal(consdata->bilinterms[i].var1)) / 2.0;
7914  val2 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var2) + SCIPvarGetLbLocal(consdata->bilinterms[i].var2)) / 2.0;
7915  constant += consdata->bilinterms[i].coef * val1 * val2;
7916  }
7917 
7918  /* check if we have a bound change */
7919  if ( consdata->nlinvars == 1 )
7920  {
7921  SCIP_Bool tightened;
7922  SCIP_Real coef;
7923  SCIP_Real lhs;
7924  SCIP_Real rhs;
7925 
7926  coef = *consdata->lincoefs;
7927 
7928  /* compute lhs/rhs */
7929  if ( SCIPisInfinity(scip, -consdata->lhs) )
7930  lhs = -SCIPinfinity(scip);
7931  else
7932  lhs = consdata->lhs - constant;
7933 
7934  if ( SCIPisInfinity(scip, consdata->rhs) )
7935  rhs = SCIPinfinity(scip);
7936  else
7937  rhs = consdata->rhs - constant;
7938 
7939  SCIPdebugMessage("Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(*consdata->linvars), rhs);
7940 
7941  /* possibly correct lhs/rhs */
7942  assert( ! SCIPisZero(scip, coef) );
7943  if ( coef >= 0.0 )
7944  {
7945  if ( ! SCIPisInfinity(scip, -lhs) )
7946  lhs /= coef;
7947  if ( ! SCIPisInfinity(scip, rhs) )
7948  rhs /= coef;
7949  }
7950  else
7951  {
7952  SCIP_Real h;
7953  h = rhs;
7954  if ( ! SCIPisInfinity(scip, -lhs) )
7955  rhs = lhs/coef;
7956  else
7957  rhs = SCIPinfinity(scip);
7958 
7959  if ( ! SCIPisInfinity(scip, h) )
7960  lhs = h/coef;
7961  else
7962  lhs = -SCIPinfinity(scip);
7963  }
7964  SCIPdebugMessage("Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(*consdata->linvars), rhs);
7965 
7966  if ( ! SCIPisInfinity(scip, -lhs) )
7967  {
7968  SCIP_CALL( SCIPtightenVarLb(scip, *consdata->linvars, lhs, TRUE, infeasible, &tightened) );
7969  if ( *infeasible )
7970  {
7971  SCIPdebugMessage("Lower bound leads to infeasibility.\n");
7972  return SCIP_OKAY;
7973  }
7974  if ( tightened )
7975  {
7976  SCIPdebugMessage("Lower boundx changed.\n");
7977  *reduceddom = TRUE;
7978  return SCIP_OKAY;
7979  }
7980  }
7981 
7982  if ( ! SCIPisInfinity(scip, rhs) )
7983  {
7984  SCIP_CALL( SCIPtightenVarUb(scip, *consdata->linvars, rhs, TRUE, infeasible, &tightened) );
7985  if ( *infeasible )
7986  {
7987  SCIPdebugMessage("Upper bound leads to infeasibility.\n");
7988  return SCIP_OKAY;
7989  }
7990  if ( tightened )
7991  {
7992  SCIPdebugMessage("Upper bound changed.\n");
7993  *reduceddom = TRUE;
7994  return SCIP_OKAY;
7995  }
7996  }
7997  }
7998  else
7999  {
8000  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
8001  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
8002  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : (consdata->lhs - constant)),
8003  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : (consdata->rhs - constant)),
8004  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
8005  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
8006  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
8007  SCIPconsIsStickingAtNode(conss[c])) );
8008 
8009  SCIPdebugMessage("replace quadratic constraint <%s> by linear constraint after all quadratic vars have been fixed\n", SCIPconsGetName(conss[c]) );
8010  SCIPdebugPrintCons(scip, cons, NULL);
8011 
8012  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
8013 
8014  if( checkresult != SCIP_INFEASIBLE )
8015  {
8016  SCIPdebugMessage("linear constraint is feasible, thus do not add\n");
8017  }
8018  else
8019  {
8020  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
8021  *addedcons = TRUE;
8022  }
8023  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
8024  }
8025  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
8026  }
8027 
8028  return SCIP_OKAY;
8029 }
8030 
8031 /* tightens a lower bound on a variable and checks the result */
8032 static
8034  SCIP* scip, /**< SCIP data structure */
8035  SCIP_CONS* cons, /**< constraint where we currently propagate */
8036  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8037  SCIP_VAR* var, /**< variable which domain we might reduce */
8038  SCIP_Real bnd, /**< new lower bound for variable */
8039  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
8040  int* nchgbds /**< counter to increase if a bound was tightened */
8041  )
8042 {
8043  SCIP_Bool infeas;
8044  SCIP_Bool tightened;
8045 
8046  assert(scip != NULL);
8047  assert(cons != NULL);
8048  assert(intervalinfty > 0.0);
8049  assert(bnd > -intervalinfty);
8050  assert(var != NULL);
8051  assert(result != NULL);
8052  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
8053  assert(nchgbds != NULL);
8054 
8055  /* new bound is no improvement */
8056  if( SCIPisHugeValue(scip, -bnd) || SCIPisLE(scip, bnd, SCIPvarGetLbLocal(var)) )
8057  return SCIP_OKAY;
8058 
8059  if( SCIPisInfinity(scip, bnd) )
8060  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
8061  *result = SCIP_CUTOFF;
8062  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8063  return SCIP_OKAY;
8064  }
8065 
8066  /* new lower bound is very low (between -intervalinfty and -SCIPinfinity()) */
8067  if( SCIPisInfinity(scip, -bnd) )
8068  return SCIP_OKAY;
8069 
8070  bnd = SCIPadjustedVarLb(scip, var, bnd);
8071  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
8072  if( infeas )
8073  {
8074  SCIPdebugMessage("%s found constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n", SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
8075  *result = SCIP_CUTOFF;
8076  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8077  return SCIP_OKAY;
8078  }
8079  if( tightened )
8080  {
8081  SCIPdebugMessage("%s tightened lower bound of variable <%s> in constraint <%s> to %g\n", SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
8082  ++*nchgbds;
8083  *result = SCIP_REDUCEDDOM;
8084  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8085  }
8086 
8087  return SCIP_OKAY;
8088 }
8089 
8090 /* tightens an upper bound on a variable and checks the result */
8091 static
8093  SCIP* scip, /**< SCIP data structure */
8094  SCIP_CONS* cons, /**< constraint where we currently propagate */
8095  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8096  SCIP_VAR* var, /**< variable which domain we might reduce */
8097  SCIP_Real bnd, /**< new upper bound for variable */
8098  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
8099  int* nchgbds /**< counter to increase if a bound was tightened */
8100  )
8101 {
8102  SCIP_Bool infeas;
8103  SCIP_Bool tightened;
8104 
8105  assert(scip != NULL);
8106  assert(cons != NULL);
8107  assert(intervalinfty > 0.0);
8108  assert(bnd < intervalinfty);
8109  assert(var != NULL);
8110  assert(result != NULL);
8111  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
8112  assert(nchgbds != NULL);
8113 
8114  /* new bound is no improvement */
8115  if( SCIPisHugeValue(scip, bnd) || SCIPisGE(scip, bnd, SCIPvarGetUbLocal(var)) )
8116  return SCIP_OKAY;
8117 
8118  if( SCIPisInfinity(scip, -bnd) )
8119  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
8120  *result = SCIP_CUTOFF;
8121  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8122  return SCIP_OKAY;
8123  }
8124 
8125  /* new upper bound is very high (between SCIPinfinity() and intervalinfty) */
8126  if( SCIPisInfinity(scip, bnd) )
8127  return SCIP_OKAY;
8128 
8129  bnd = SCIPadjustedVarUb(scip, var, bnd);
8130  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
8131  if( infeas )
8132  {
8133  SCIPdebugMessage("%s found constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n", SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
8134  *result = SCIP_CUTOFF;
8135  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8136  return SCIP_OKAY;
8137  }
8138  if( tightened )
8139  {
8140  SCIPdebugMessage("%s tightened upper bound of variable <%s> in constraint <%s> to %g\n", SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
8141  ++*nchgbds;
8142  *result = SCIP_REDUCEDDOM;
8143  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8144  }
8145 
8146  return SCIP_OKAY;
8147 }
8148 
8149 /** 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
8150  */
8151 static
8153  SCIP* scip, /**< SCIP data structure */
8154  SCIP_CONS* cons, /**< constraint where we currently propagate */
8155  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8156  SCIP_VAR* var, /**< variable which bounds with might tighten */
8157  SCIP_Real a, /**< coefficient in square term */
8158  SCIP_INTERVAL b, /**< coefficient in linear term */
8159  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
8160  SCIP_RESULT* result, /**< result of propagation */
8161  int* nchgbds /**< buffer where to add number of tightened bounds */
8162  )
8163 {
8164  SCIP_INTERVAL newrange;
8165 
8166  assert(scip != NULL);
8167  assert(cons != NULL);
8168  assert(var != NULL);
8169  assert(result != NULL);
8170  assert(nchgbds != NULL);
8171 
8172  /* compute solution of a*x^2 + b*x \in rhs */
8173  if( a == 0.0 && SCIPintervalGetInf(b) == 0.0 && SCIPintervalGetSup(b) == 0.0 )
8174  { /* relatively easy case: 0.0 \in rhs, thus check if infeasible or just redundant */
8175  if( SCIPintervalGetInf(rhs) > 0.0 || SCIPintervalGetSup(rhs) < 0.0 )
8176  {
8177  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
8178  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8179  *result = SCIP_CUTOFF;
8180  }
8181  return SCIP_OKAY;
8182  }
8183  else if( SCIPvarGetLbLocal(var) >= 0.0 )
8184  {
8185  SCIP_INTERVAL a_;
8186 
8187  /* need only positive solutions */
8188  SCIPintervalSet(&a_, a);
8189  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &newrange, a_, b, rhs);
8190  }
8191  else if( SCIPvarGetUbLocal(var) <= 0.0 )
8192  {
8193  /* need only negative solutions */
8194  SCIP_INTERVAL a_;
8195  SCIP_INTERVAL tmp;
8196  SCIPintervalSet(&a_, a);
8198  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &tmp, a_, tmp, rhs);
8199  if( SCIPintervalIsEmpty(tmp) )
8200  {
8201  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
8202  *result = SCIP_CUTOFF;
8203  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8204  return SCIP_OKAY;
8205  }
8207  }
8208  else
8209  {
8210  /* need both positive and negative solution */
8211  SCIP_INTERVAL a_;
8212  SCIPintervalSet(&a_, a);
8213  SCIPintervalSolveUnivariateQuadExpression(intervalinfty, &newrange, a_, b, rhs);
8214  }
8215 
8216  /* 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); */
8217 
8218  if( SCIPisInfinity(scip, SCIPintervalGetInf(newrange)) || SCIPisInfinity(scip, -SCIPintervalGetSup(newrange)) )
8219  { /* domain outside [-infty, +infty] -> declare node infeasible */
8220  SCIPdebugMessage("found <%s> infeasible because propagated domain of quadratic variable <%s> is outside of (-infty, +infty)\n", SCIPconsGetName(cons), SCIPvarGetName(var));
8221  *result = SCIP_CUTOFF;
8222  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8223  return SCIP_OKAY;
8224  }
8225 
8226  if( SCIPintervalIsEmpty(newrange) )
8227  {
8228  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
8229  *result = SCIP_CUTOFF;
8230  return SCIP_OKAY;
8231  }
8232 
8233  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(newrange)) )
8234  {
8235  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, SCIPintervalGetInf(newrange), result, nchgbds) );
8236  if( *result == SCIP_CUTOFF )
8237  return SCIP_OKAY;
8238  }
8239 
8240  if( !SCIPisInfinity(scip, SCIPintervalGetSup(newrange)) )
8241  {
8242  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, SCIPintervalGetSup(newrange), result, nchgbds) );
8243  if( *result == SCIP_CUTOFF )
8244  return SCIP_OKAY;
8245  }
8246 
8247  return SCIP_OKAY;
8248 }
8249 
8250 /* the new version below computes potentially tighter bounds, but also always adds a small safety area since it is not implemented roundingsafe,
8251  * this may be a reason why it gives worse results on one of two instances
8252  * further, I have only very few instances where one can expect a difference
8253  */
8254 #ifndef PROPBILINNEW
8255 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
8256  * NOTE that domain reductions for y are not deduced
8257  */
8258 static
8260  SCIP* scip, /**< SCIP data structure */
8261  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
8262  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8263  SCIP_VAR* x, /**< first variable */
8264  SCIP_Real xsqrcoef, /**< square coefficient of x */
8265  SCIP_Real xlincoef, /**< linear coefficient of x */
8266  SCIP_VAR* y, /**< second variable */
8267  SCIP_Real ysqrcoef, /**< square coefficient of y */
8268  SCIP_Real ylincoef, /**< linear coefficient of y */
8269  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
8270  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
8271  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
8272  int* nchgbds /**< counter to increment if domain reductions are found */
8273  )
8274 {
8275  SCIP_INTERVAL myrhs;
8276  SCIP_INTERVAL varbnds;
8277  SCIP_INTERVAL lincoef;
8278 
8279  assert(scip != NULL);
8280  assert(cons != NULL);
8281  assert(x != NULL);
8282  assert(y != NULL);
8283  assert(x != y);
8284  assert(result != NULL);
8285  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
8286  assert(nchgbds != NULL);
8287  assert(bilincoef != 0.0);
8288 
8289  if( SCIPintervalIsEntire(intervalinfty, rhs) )
8290  return SCIP_OKAY;
8291 
8292  /* try to find domain reductions for x */
8294 
8295  /* put ysqrcoef*y^2 + ylincoef * y into rhs */
8296  if( SCIPintervalGetSup(rhs) >= intervalinfty )
8297  {
8298  /* if rhs is unbounded by above, it is sufficient to get an upper bound on ysqrcoef*y^2 + ylincoef * y */
8299  SCIP_ROUNDMODE roundmode;
8300  SCIP_Real tmp;
8301 
8302  SCIPintervalSet(&lincoef, ylincoef);
8303  tmp = SCIPintervalQuadUpperBound(intervalinfty, ysqrcoef, lincoef, varbnds);
8304  roundmode = SCIPintervalGetRoundingMode();
8306  SCIPintervalSetBounds(&myrhs, SCIPintervalGetInf(rhs) - tmp, intervalinfty);
8307  SCIPintervalSetRoundingMode(roundmode);
8308  }
8309  else if( SCIPintervalGetInf(rhs) <= -intervalinfty )
8310  {
8311  /* if rhs is unbounded by below, it is sufficient to get a lower bound on ysqrcoef*y^2 + ylincoef * y */
8312  SCIP_ROUNDMODE roundmode;
8313  SCIP_Real tmp;
8314 
8315  SCIPintervalSet(&lincoef, -ylincoef);
8316  tmp = -SCIPintervalQuadUpperBound(intervalinfty, -ysqrcoef, lincoef, varbnds);
8317  roundmode = SCIPintervalGetRoundingMode();
8319  SCIPintervalSetBounds(&myrhs, -intervalinfty, SCIPintervalGetSup(rhs) - tmp);
8320  SCIPintervalSetRoundingMode(roundmode);
8321  }
8322  else
8323  {
8324  /* if rhs is bounded, we need both bounds on ysqrcoef*y^2 + ylincoef * y */
8325  SCIP_INTERVAL tmp;
8326 
8327  SCIPintervalSet(&lincoef, ylincoef);
8328  SCIPintervalQuad(intervalinfty, &tmp, ysqrcoef, lincoef, varbnds);
8329  SCIPintervalSub(intervalinfty, &myrhs, rhs, tmp);
8330  }
8331 
8332  /* create equation xsqrcoef * x^2 + (xlincoef + bilincoef * [ylb, yub]) * x \in myrhs */
8333  SCIPintervalMulScalar(intervalinfty, &lincoef, varbnds, bilincoef);
8334  SCIPintervalAddScalar(intervalinfty, &lincoef, lincoef, xlincoef);
8335 
8336  /* propagate bounds on x */
8337  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, x, xsqrcoef, lincoef, myrhs, result, nchgbds) );
8338 
8339  return SCIP_OKAY;
8340 }
8341 #else
8342 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
8343  * NOTE that domain reductions for y are not deduced
8344  */
8345 static
8347  SCIP* scip, /**< SCIP data structure */
8348  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
8349  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8350  SCIP_VAR* x, /**< first variable */
8351  SCIP_Real xsqrcoef, /**< square coefficient of x */
8352  SCIP_Real xlincoef, /**< linear coefficient of x */
8353  SCIP_VAR* y, /**< second variable */
8354  SCIP_Real ysqrcoef, /**< square coefficient of y */
8355  SCIP_Real ylincoef, /**< linear coefficient of y */
8356  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
8357  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
8358  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
8359  int* nchgbds /**< counter to increment if domain reductions are found */
8360  )
8361 {
8362  SCIP_INTERVAL xbnds;
8363  SCIP_INTERVAL ybnds;
8364 
8365  assert(scip != NULL);
8366  assert(cons != NULL);
8367  assert(x != NULL);
8368  assert(y != NULL);
8369  assert(x != y);
8370  assert(result != NULL);
8371  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
8372  assert(nchgbds != NULL);
8373  assert(bilincoef != 0.0);
8374 
8375  if( SCIPintervalIsEntire(intervalinfty, rhs) )
8376  return SCIP_OKAY;
8377 
8378  SCIPintervalSetBounds(&xbnds,
8379  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x))), /*lint !e666*/
8380  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)))); /*lint !e666*/
8381  SCIPintervalSetBounds(&ybnds,
8382  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))), /*lint !e666*/
8383  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))); /*lint !e666*/
8384 
8385  /* try to find domain reductions for x */
8386  SCIPintervalSolveBivariateQuadExpressionAllScalar(intervalinfty, &xbnds, xsqrcoef, ysqrcoef, bilincoef, xlincoef, ylincoef, rhs, xbnds, ybnds);
8387 
8388  if( SCIPintervalIsEmpty(xbnds) )
8389  {
8390  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(x));
8391  *result = SCIP_CUTOFF;
8392  return SCIP_OKAY;
8393  }
8394 
8395  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(xbnds)) )
8396  {
8397  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, x, SCIPintervalGetInf(xbnds), result, nchgbds) );
8398  if( *result == SCIP_CUTOFF )
8399  return SCIP_OKAY;
8400  }
8401 
8402  if( !SCIPisInfinity(scip, SCIPintervalGetSup(xbnds)) )
8403  {
8404  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, x, SCIPintervalGetSup(xbnds), result, nchgbds) );
8405  if( *result == SCIP_CUTOFF )
8406  return SCIP_OKAY;
8407  }
8408 
8409  return SCIP_OKAY;
8410 }
8411 #endif
8412 
8413 /** computes the minimal and maximal activity for the quadratic part in a constraint data
8414  * only sums up terms that contribute finite values
8415  * gives the number of terms that contribute infinite values
8416  * only computes those activities where the corresponding side of the constraint is finite
8417  */
8418 static
8420  SCIP* scip, /**< SCIP data structure */
8421  SCIP_CONSDATA* consdata, /**< constraint data */
8422  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8423  SCIP_Real* minquadactivity, /**< minimal activity of quadratic variable terms where only terms with finite minimal activity contribute */
8424  SCIP_Real* maxquadactivity, /**< maximal activity of quadratic variable terms where only terms with finite maximal activity contribute */
8425  int* minactivityinf, /**< number of quadratic variables that contribute -infinity to minimal activity */
8426  int* maxactivityinf, /**< number of quadratic variables that contribute +infinity to maximal activity */
8427  SCIP_INTERVAL* quadactcontr /**< contribution of each quadratic variables to quadactivity */
8428  )
8429 { /*lint --e{666}*/
8430  SCIP_ROUNDMODE prevroundmode;
8431  int i;
8432  int j;
8433  int k;
8434  SCIP_INTERVAL tmp;
8435  SCIP_Real bnd;
8436  SCIP_INTERVAL xrng;
8437  SCIP_INTERVAL lincoef;
8438 
8439  assert(scip != NULL);
8440  assert(consdata != NULL);
8441  assert(minquadactivity != NULL);
8442  assert(maxquadactivity != NULL);
8443  assert(minactivityinf != NULL);
8444  assert(maxactivityinf != NULL);
8445  assert(quadactcontr != NULL);
8446 
8447  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
8448  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
8449  */
8450  *minquadactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
8451  *maxquadactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
8452 
8453  *minactivityinf = 0;
8454  *maxactivityinf = 0;
8455 
8456  if( consdata->nquadvars == 0 )
8457  {
8458  SCIPintervalSet(&consdata->quadactivitybounds, 0.0);
8459  return;
8460  }
8461 
8462  for( i = 0; i < consdata->nquadvars; ++i )
8463  {
8464  /* there should be no quadratic variables fixed at -/+ infinity due to our locks */
8465  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var)));
8466  assert(!SCIPisInfinity(scip, -SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
8467 
8468  SCIPintervalSetBounds(&quadactcontr[i], -intervalinfty, intervalinfty);
8469 
8470  SCIPintervalSetBounds(&xrng,
8471  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))),
8472  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))));
8473 
8474  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
8475  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
8476  {
8477  k = consdata->quadvarterms[i].adjbilin[j];
8478  if( consdata->bilinterms[k].var1 != consdata->quadvarterms[i].var )
8479  continue; /* handle this term later */
8480 
8481  SCIPintervalSetBounds(&tmp,
8482  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
8483  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
8484  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
8485  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
8486  }
8487 
8488  if( !SCIPisInfinity(scip, -consdata->lhs) )
8489  {
8490  /* compute maximal activity only if there is a finite left hand side */
8491  bnd = SCIPintervalQuadUpperBound(intervalinfty, consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
8492  if( SCIPisInfinity(scip, bnd) )
8493  {
8494  ++*maxactivityinf;
8495  }
8496  else if( SCIPisInfinity(scip, -bnd) )
8497  {
8498  /* if maximal activity is below value for -infinity, let's take -1e10 as upper bound on maximal activity
8499  * @todo Something better?
8500  */
8501  bnd = -sqrt(SCIPinfinity(scip));
8502  *maxquadactivity += bnd;
8503  quadactcontr[i].sup = bnd;
8504  }
8505  else
8506  {
8507  prevroundmode = SCIPintervalGetRoundingMode();
8509  *maxquadactivity += bnd;
8510  SCIPintervalSetRoundingMode(prevroundmode);
8511  quadactcontr[i].sup = bnd;
8512  }
8513  }
8514 
8515  if( !SCIPisInfinity(scip, consdata->rhs) )
8516  {
8517  /* compute minimal activity only if there is a finite right hand side */
8518  SCIPintervalSetBounds(&lincoef, -SCIPintervalGetSup(lincoef), -SCIPintervalGetInf(lincoef));
8519  bnd = -SCIPintervalQuadUpperBound(intervalinfty, -consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
8520 
8521  if( SCIPisInfinity(scip, -bnd) )
8522  {
8523  ++*minactivityinf;
8524  }
8525  else if( SCIPisInfinity(scip, bnd) )
8526  {
8527  /* if minimal activity is above value for infinity, let's take 1e10 as lower bound on minimal activity
8528  * @todo Something better?
8529  */
8530  bnd = sqrt(SCIPinfinity(scip));
8531  *minquadactivity += bnd;
8532  quadactcontr[i].inf = bnd;
8533  }
8534  else
8535  {
8536  prevroundmode = SCIPintervalGetRoundingMode();
8538  *minquadactivity += bnd;
8539  SCIPintervalSetRoundingMode(prevroundmode);
8540  quadactcontr[i].inf = bnd;
8541  }
8542  }
8543 
8544  }
8545 
8546  SCIPintervalSetBounds(&consdata->quadactivitybounds,
8547  (*minactivityinf > 0 ? -intervalinfty : *minquadactivity),
8548  (*maxactivityinf > 0 ? intervalinfty : *maxquadactivity));
8549  assert(!SCIPintervalIsEmpty(consdata->quadactivitybounds));
8550 }
8551 
8552 /** propagates bounds on a quadratic constraint */
8553 static
8555  SCIP* scip, /**< SCIP data structure */
8556  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8557  SCIP_CONS* cons, /**< constraint to process */
8558  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
8559  int* nchgbds, /**< buffer where to add the the number of changed bounds */
8560  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
8561  )
8562 { /*lint --e{666}*/
8563  SCIP_CONSDATA* consdata;
8564  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
8565  SCIP_INTERVAL consactivity; /* activity of linear plus quadratic part */
8566  SCIP_Real intervalinfty; /* infinity used for interval computation */
8567  SCIP_Real minquadactivity; /* lower bound on finite activities of quadratic part */
8568  SCIP_Real maxquadactivity; /* upper bound on finite activities of quadratic part */
8569  int quadminactinf; /* number of quadratic variables that contribute -infinity to minimal activity of quadratic term */
8570  int quadmaxactinf; /* number of quadratic variables that contribute +infinity to maximal activity of quadratic term */
8571  SCIP_INTERVAL* quadactcontr; /* contribution of each quadratic variable term to quadactivity */
8572 
8573  SCIP_VAR* var;
8574  SCIP_INTERVAL rhs; /* right hand side of quadratic equation */
8575  SCIP_INTERVAL tmp;
8576  SCIP_ROUNDMODE roundmode;
8577  SCIP_Real bnd;
8578  int i;
8579 
8580  assert(scip != NULL);
8581  assert(conshdlr != NULL);
8582  assert(cons != NULL);
8583  assert(result != NULL);
8584  assert(nchgbds != NULL);
8585  assert(redundant != NULL);
8586 
8587  consdata = SCIPconsGetData(cons);
8588  assert(consdata != NULL);
8589 
8590  *result = SCIP_DIDNOTRUN;
8591  *redundant = FALSE;
8592 
8593  if( consdata->ispropagated )
8594  return SCIP_OKAY;
8595 
8596  *result = SCIP_DIDNOTFIND;
8597 
8598  intervalinfty = 1000 * SCIPinfinity(scip) * SCIPinfinity(scip);
8599 
8600  quadactcontr = NULL;
8601  quadminactinf = -1;
8602  quadmaxactinf = -1;
8603 
8604  SCIPdebugMessage("start domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
8605 
8606  consdata->ispropagated = TRUE;
8607 
8608  /* make sure we have activity of linear term and that they are consistent */
8609  consdataUpdateLinearActivity(scip, consdata, intervalinfty);
8610  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
8611  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
8612  assert(consdata->minlinactivityinf >= 0);
8613  assert(consdata->maxlinactivityinf >= 0);
8614 
8615  /* sort quadratic variable terms, in case we need to search for terms occuring in bilinear terms later
8616  * we sort here already, since we rely on a constant variable order during this method
8617  */
8618  if( consdata->nbilinterms > 0 )
8619  {
8620  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
8621  }
8622 
8623  /* compute activity of quad term part, if not up to date
8624  * in that case, we also collect the contribution of each quad var term for later */
8625  if( SCIPintervalIsEmpty(consdata->quadactivitybounds) )
8626  {
8627  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
8628  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
8629  assert(!SCIPintervalIsEmpty(consdata->quadactivitybounds));
8630  }
8631 
8632  SCIPdebugMessage("linear activity: [%g, %g] quadratic activity: [%g, %g]\n",
8633  (consdata->minlinactivityinf > 0 ? -SCIPinfinity(scip) : consdata->minlinactivity),
8634  (consdata->maxlinactivityinf > 0 ? SCIPinfinity(scip) : consdata->maxlinactivity),
8635  consdata->quadactivitybounds.inf, consdata->quadactivitybounds.sup);
8636 
8637  /* extend constraint bounds by epsilon to avoid some numerical difficulties */
8638  SCIPintervalSetBounds(&consbounds,
8639  -infty2infty(SCIPinfinity(scip), intervalinfty, -consdata->lhs+SCIPepsilon(scip)),
8640  +infty2infty(SCIPinfinity(scip), intervalinfty, consdata->rhs+SCIPepsilon(scip)));
8641 
8642  /* check redundancy and infeasibility */
8643  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity, consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity);
8644  SCIPintervalAdd(intervalinfty, &consactivity, consactivity, consdata->quadactivitybounds);
8645  if( SCIPintervalIsSubsetEQ(intervalinfty, consactivity, consbounds) )
8646  {
8647  SCIPdebugMessage("found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
8648  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
8649  *redundant = TRUE;
8650  goto CLEANUP;
8651  }
8652 
8653  /* was SCIPintervalAreDisjoint(consbounds, consactivity), but that would allow violations up to eps only
8654  * we need to decide feasibility w.r.t. feastol (but still want to propagate w.r.t. eps)
8655  */
8656  if( SCIPisFeasGT(scip, consbounds.inf, consactivity.sup) || SCIPisFeasLT(scip, consbounds.sup, consactivity.inf) )
8657  {
8658  SCIPdebugMessage("found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
8659  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
8660  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
8661  *result = SCIP_CUTOFF;
8662  goto CLEANUP;
8663  }
8664 
8665  /* propagate linear part \in rhs = consbounds - quadactivity (use the one from consdata, since that includes infinities) */
8666  SCIPintervalSub(intervalinfty, &rhs, consbounds, consdata->quadactivitybounds);
8667  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
8668  {
8669  SCIP_Real coef;
8670 
8671  for( i = 0; i < consdata->nlinvars; ++i )
8672  {
8673  coef = consdata->lincoefs[i];
8674  var = consdata->linvars[i];
8675 
8676  /* skip fixed variables
8677  * @todo is that a good or a bad idea?
8678  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
8679  */
8680  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
8681  continue;
8682 
8683  if( coef > 0.0 )
8684  {
8685  if( SCIPintervalGetSup(rhs) < intervalinfty )
8686  {
8687  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
8688  /* try to tighten the upper bound on var x */
8689  if( consdata->minlinactivityinf == 0 )
8690  {
8691  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
8692  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
8693  roundmode = SCIPintervalGetRoundingMode();
8695  bnd = SCIPintervalGetSup(rhs);
8696  bnd -= consdata->minlinactivity;
8697  bnd += coef * SCIPvarGetLbLocal(var);
8698  bnd /= coef;
8699  SCIPintervalSetRoundingMode(roundmode);
8700  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8701  if( *result == SCIP_CUTOFF )
8702  break;
8703  }
8704  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
8705  {
8706  /* x was the variable that made the minimal linear activity equal -infinity, so
8707  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
8708  roundmode = SCIPintervalGetRoundingMode();
8710  bnd = SCIPintervalGetSup(rhs);
8711  bnd -= consdata->minlinactivity;
8712  bnd /= coef;
8713  SCIPintervalSetRoundingMode(roundmode);
8714  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8715  if( *result == SCIP_CUTOFF )
8716  break;
8717  }
8718  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
8719  }
8720 
8721  if( SCIPintervalGetInf(rhs) > -intervalinfty )
8722  {
8723  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
8724  /* try to tighten the lower bound on var x */
8725  if( consdata->maxlinactivityinf == 0 )
8726  {
8727  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
8728  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
8729  roundmode = SCIPintervalGetRoundingMode();
8731  bnd = SCIPintervalGetInf(rhs);
8732  bnd -= consdata->maxlinactivity;
8733  bnd += coef * SCIPvarGetUbLocal(var);
8734  bnd /= coef;
8735  SCIPintervalSetRoundingMode(roundmode);
8736  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8737  if( *result == SCIP_CUTOFF )
8738  break;
8739  }
8740  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
8741  {
8742  /* x was the variable that made the maximal linear activity equal infinity, so
8743  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
8744  roundmode = SCIPintervalGetRoundingMode();
8746  bnd = SCIPintervalGetInf(rhs);
8747  bnd -= consdata->maxlinactivity;
8748  bnd /= coef;
8749  SCIPintervalSetRoundingMode(roundmode);
8750  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8751  if( *result == SCIP_CUTOFF )
8752  break;
8753  }
8754  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
8755  }
8756  }
8757  else
8758  {
8759  assert(coef < 0.0 );
8760  if( SCIPintervalGetInf(rhs) > -intervalinfty )
8761  {
8762  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
8763  /* try to tighten the upper bound on var x */
8764  if( consdata->maxlinactivityinf == 0 )
8765  {
8766  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
8767  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
8768  roundmode = SCIPintervalGetRoundingMode();
8770  bnd = consdata->maxlinactivity;
8771  bnd += (-coef) * SCIPvarGetLbLocal(var);
8772  bnd -= SCIPintervalGetInf(rhs);
8773  bnd /= (-coef);
8774  SCIPintervalSetRoundingMode(roundmode);
8775  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8776  if( *result == SCIP_CUTOFF )
8777  break;
8778  }
8779  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
8780  {
8781  /* x was the variable that made the maximal linear activity equal infinity, so
8782  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
8783  roundmode = SCIPintervalGetRoundingMode();
8785  bnd = consdata->maxlinactivity;
8786  bnd -= SCIPintervalGetInf(rhs);
8787  bnd /= (-coef);
8788  SCIPintervalSetRoundingMode(roundmode);
8789  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8790  if( *result == SCIP_CUTOFF )
8791  break;
8792  }
8793  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
8794  }
8795 
8796  if( SCIPintervalGetSup(rhs) < intervalinfty )
8797  {
8798  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
8799  /* try to tighten the lower bound on var x */
8800  if( consdata->minlinactivityinf == 0 )
8801  {
8802  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
8803  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
8804  roundmode = SCIPintervalGetRoundingMode();
8806  bnd = consdata->minlinactivity;
8807  bnd += (-coef) * SCIPvarGetUbLocal(var);
8808  bnd -= SCIPintervalGetSup(rhs);
8809  bnd /= (-coef);
8810  SCIPintervalSetRoundingMode(roundmode);
8811  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8812  if( *result == SCIP_CUTOFF )
8813  break;
8814  }
8815  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
8816  {
8817  /* x was the variable that made the maximal linear activity equal -infinity, so
8818  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
8819  roundmode = SCIPintervalGetRoundingMode();
8821  bnd = consdata->minlinactivity;
8822  bnd -= SCIPintervalGetSup(rhs);
8823  bnd /= (-coef);
8824  SCIPintervalSetRoundingMode(roundmode);
8825  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8826  if( *result == SCIP_CUTOFF )
8827  break;
8828  }
8829  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
8830  }
8831  }
8832  }
8833  if( *result == SCIP_CUTOFF )
8834  goto CLEANUP;
8835  }
8836 
8837  /* propagate quadratic part \in rhs = consbounds - linactivity */
8838  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
8839  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
8840  consdataUpdateLinearActivity(scip, consdata, intervalinfty); /* make sure, activities of linear part did not become invalid by above bound changes, if any */
8841  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
8842  SCIPintervalSetBounds(&tmp,
8843  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
8844  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity));
8845  SCIPintervalSub(intervalinfty, &rhs, consbounds, tmp);
8846  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
8847  {
8848  if( consdata->nquadvars == 1 )
8849  {
8850  /* quadratic part is just a*x^2+b*x -> a common case that we treat directly */
8851  SCIP_INTERVAL lincoef; /* linear coefficient of quadratic equation */
8852 
8853  assert(consdata->nbilinterms == 0);
8854 
8855  var = consdata->quadvarterms[0].var;
8856  SCIPintervalSet(&lincoef, consdata->quadvarterms[0].lincoef);
8857 
8858  /* propagate a*x^2 + b*x \in rhs */
8859  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[0].sqrcoef, lincoef, rhs, result, nchgbds) );
8860  }
8861  else if( consdata->nbilinterms == 1 && consdata->nquadvars == 2 )
8862  {
8863  /* quadratic part is just ax*x^2+bx*x + ay*y^2+by*y + c*xy -> a common case that we treat directly */
8864  assert(consdata->bilinterms[0].var1 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var1 == consdata->quadvarterms[1].var);
8865  assert(consdata->bilinterms[0].var2 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var2 == consdata->quadvarterms[1].var);
8866 
8867  /* 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 */
8868  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
8869  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
8870  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
8871  consdata->bilinterms[0].coef,
8872  rhs, result, nchgbds) );
8873  if( *result != SCIP_CUTOFF )
8874  {
8875  /* 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 */
8876  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
8877  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
8878  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
8879  consdata->bilinterms[0].coef,
8880  rhs, result, nchgbds) );
8881  }
8882  }
8883  else
8884  {
8885  /* general case */
8886 
8887  /* compute "advanced" information on quad var term activities, if not up-to-date */
8888  if( quadminactinf == -1 )
8889  {
8890  assert(quadactcontr == NULL);
8891  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
8892  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
8893  }
8894  assert(quadactcontr != NULL);
8895  assert(quadminactinf >= 0);
8896  assert(quadmaxactinf >= 0);
8897 
8898  /* if the quad activities are not hopelessly unbounded on useful sides, try to deduce domain reductions on quad vars */
8899  if( (SCIPintervalGetSup(rhs) < intervalinfty && quadminactinf <= 1) ||
8900  ( SCIPintervalGetInf(rhs) > -intervalinfty && quadmaxactinf <= 1) )
8901  {
8902  SCIP_INTERVAL lincoef;
8903  SCIP_INTERVAL rhs2;
8904  int j;
8905  int k;
8906 
8907  for( i = 0; i < consdata->nquadvars; ++i )
8908  {
8909  var = consdata->quadvarterms[i].var;
8910 
8911  /* skip fixed variables
8912  * @todo is that a good or a bad idea?
8913  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
8914  */
8915  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
8916  continue;
8917 
8918  /* compute rhs2 such that we can propagate quadvarterm(x_i) \in rhs2 */
8919 
8920  /* setup rhs2.sup = rhs.sup - (quadactivity.inf - quadactcontr[i].inf), if everything were finite
8921  * if only quadactcontr[i].inf is infinite (i.e., the other i are all finite), we just get rhs2.sup = rhs.sup
8922  * otherwise we get rhs2.sup = infinity */
8923  if( SCIPintervalGetSup(rhs) < intervalinfty )
8924  {
8925  if( quadminactinf == 0 || (quadminactinf == 1 && SCIPintervalGetInf(quadactcontr[i]) <= -intervalinfty) )
8926  {
8927  /* the residual quad min activity w.r.t. quad var term i is finite */
8928  assert(!SCIPisInfinity(scip, -minquadactivity)); /*lint !e644*/
8929  roundmode = SCIPintervalGetRoundingMode();
8931  rhs2.sup = rhs.sup - minquadactivity;
8932  if( quadminactinf == 0 && SCIPintervalGetInf(quadactcontr[i]) != 0.0 )
8933  {
8934  /* the residual quad min activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
8935  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(quadactcontr[i])));
8936  rhs2.sup += SCIPintervalGetInf(quadactcontr[i]);
8937  }
8938  SCIPintervalSetRoundingMode(roundmode);
8939  }
8940  else
8941  {
8942  /* there are either >= 2 quad var terms contributing -infinity, or there is one which is not i */
8943  rhs2.sup = intervalinfty;
8944  }
8945  }
8946  else
8947  {
8948  rhs2.sup = intervalinfty;
8949  }
8950 
8951  /* setup rhs.inf = rhs.inf - (quadactivity.sup - quadactcontr[i].sup), see also above */
8952  if( SCIPintervalGetInf(rhs) > -intervalinfty )
8953  {
8954  if( quadmaxactinf == 0 || (quadmaxactinf == 1 && SCIPintervalGetSup(quadactcontr[i]) >= intervalinfty) )
8955  {
8956  /* the residual quad max activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
8957  assert(!SCIPisInfinity(scip, maxquadactivity)); /*lint !e644*/
8958  roundmode = SCIPintervalGetRoundingMode();
8960  rhs2.inf = rhs.inf - maxquadactivity;
8961  /* the residual quad max activity w.r.t. quad var term i is finite */
8962  if( quadmaxactinf == 0 && SCIPintervalGetSup(quadactcontr[i]) != 0.0 )
8963  {
8964  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(quadactcontr[i])));
8965  rhs2.inf += SCIPintervalGetSup(quadactcontr[i]);
8966  }
8967  SCIPintervalSetRoundingMode(roundmode);
8968  }
8969  else
8970  {
8971  /* there are either >= 2 quad var terms contributing infinity, or there is one which is not i */
8972  rhs2.inf = -intervalinfty;
8973  }
8974  }
8975  else
8976  {
8977  rhs2.inf = -intervalinfty;
8978  }
8979  assert(!SCIPintervalIsEmpty(rhs2));
8980 
8981  /* if rhs2 is entire, then there is nothing we could propagate */
8982  if( SCIPintervalIsEntire(intervalinfty, rhs2) )
8983  continue;
8984 
8985  /* assemble linear coefficient for quad equation a*x^2 + b*x \in rhs2 */
8986  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
8987  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
8988  {
8989  k = consdata->quadvarterms[i].adjbilin[j];
8990 #if 1
8991  if( consdata->bilinterms[k].var1 == var )
8992  {
8993  /* bilinear term k contributes to the activity of quad var term i, so just add bounds to linear coef */
8994  SCIPintervalSetBounds(&tmp,
8995  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
8996  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
8997  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
8998  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
8999 
9000  }
9001  else
9002  {
9003  /* bilinear term k does not contribute to the activity of quad var term i
9004  * so bounds on term k are contained in rhs2
9005  * if they are finite, we try to remove them from rhs2 and update lincoef instead
9006  * 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
9007  * HOWEVER: when computing rhs2, we may not just have added the bounds for the bilinear term, but for the associated quadratic term
9008  * for this complete term, we used SCIPintervalQuad to compute the bounds
9009  * since we do not want to repeat a call to SCIPintervalQuad for that quadratic term with bilinear term k removed,
9010  * we only remove the bounds for the bilinear term k from rhs2 if the associated quadratic term consists only of this bilinear term,
9011  * i.e., the quadratic term corresponding to var1 should be only var1*var2, but have no square or linear coefs or other bilinear terms
9012  * (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)
9013  */
9014  SCIP_INTERVAL me;
9015  SCIP_INTERVAL bilinbounds;
9016  int otherpos;
9017 
9018  assert(consdata->bilinterms[k].var2 == var);
9019 
9020  assert(consdata->quadvarssorted);
9021  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[k].var1, &otherpos) );
9022  assert(otherpos >= 0);
9023  assert(consdata->quadvarterms[otherpos].var == consdata->bilinterms[k].var1);
9024 
9025  if( (consdata->quadvarterms[otherpos].sqrcoef != 0.0) || consdata->quadvarterms[otherpos].lincoef != 0.0 || consdata->quadvarterms[otherpos].nadjbilin > 1 )
9026  continue;
9027 
9028  /* set tmp to bounds of other variable and multiply with bilin coef */
9029  SCIPintervalSetBounds(&tmp,
9030  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))),
9031  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))));
9032  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9033 
9034  /* set me to bounds of i'th variable */
9036  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9037  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9038 
9039  /* remove me*tmp from rhs2 */
9040 
9041  roundmode = SCIPintervalGetRoundingMode();
9042 
9043  if( rhs2.inf > -intervalinfty )
9044  {
9045  /* need upward rounding for SCIPintervalMulSup */
9047  SCIPintervalMulSup(intervalinfty, &bilinbounds, me, tmp);
9048  /* rhs2.inf += bilinbounds.sup, but we are in upward rounding */
9049  if( bilinbounds.sup < intervalinfty )
9050  rhs2.inf = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.inf) - bilinbounds.sup);
9051  }
9052 
9053  if( rhs2.sup < intervalinfty )
9054  {
9055  /* need downward rounding for SCIPintervalMulInf */
9057  SCIPintervalMulInf(intervalinfty, &bilinbounds, me, tmp);
9058  /* rhs2.sup += bilinbounds.inf, but we are in downward rounding */
9059  if( bilinbounds.inf > -intervalinfty )
9060  rhs2.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.sup) - bilinbounds.inf);
9061  }
9062 
9063  SCIPintervalSetRoundingMode(roundmode);
9064 
9065  /* add tmp to lincoef */
9066  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9067  }
9068 #else
9069  if( consdata->bilinterms[k].var1 != var )
9070  continue; /* this term does not contribute to the activity of quad var term i */
9071 
9072  SCIPintervalSetBounds(&tmp,
9073  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9074  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9075  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9076  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9077 #endif
9078  }
9079 
9080  /* deduce domain reductions for x_i */
9081  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[i].sqrcoef, lincoef, rhs2, result, nchgbds) );
9082  if( *result == SCIP_CUTOFF )
9083  goto CLEANUP;
9084  }
9085  }
9086  }
9087  }
9088 
9089  CLEANUP:
9090  SCIPfreeBufferArrayNull(scip, &quadactcontr);
9091 
9092  return SCIP_OKAY;
9093 }
9094 
9095 /** calls domain propagation for a set of constraints */
9096 static
9098  SCIP* scip, /**< SCIP data structure */
9099  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9100  SCIP_CONS** conss, /**< constraints to process */
9101  int nconss, /**< number of constraints */
9102  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
9103  int* nchgbds /**< buffer where to add the the number of changed bounds */
9104  )
9105 {
9106  SCIP_CONSHDLRDATA* conshdlrdata;
9107  SCIP_RESULT propresult;
9108  SCIP_Bool redundant;
9109  int c;
9110  int roundnr;
9111  SCIP_Bool success;
9112  int maxproprounds;
9113 
9114  assert(scip != NULL);
9115  assert(conshdlr != NULL);
9116  assert(conss != NULL || nconss == 0);
9117  assert(result != NULL);
9118  assert(nchgbds != NULL);
9119 
9121 
9122  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9123  assert(conshdlrdata != NULL);
9124 
9125  *result = SCIP_DIDNOTFIND;
9126  roundnr = 0;
9127  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
9128  maxproprounds = conshdlrdata->maxproproundspresolve;
9129  else
9130  maxproprounds = conshdlrdata->maxproprounds;
9131 
9132  do
9133  {
9134  success = FALSE;
9135  ++roundnr;
9136 
9137  SCIPdebugMessage("starting domain propagation round %d of %d for %d constraints\n", roundnr, maxproprounds, nconss);
9138 
9139  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
9140  {
9141  assert(conss != NULL);
9142  if( !SCIPconsIsEnabled(conss[c]) )
9143  continue;
9144 
9145  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
9146  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
9147  {
9148  *result = propresult;
9149  success = TRUE;
9150  }
9151  if( redundant )
9152  {
9153  SCIPdebugMessage("deleting constraint <%s> locally\n", SCIPconsGetName(conss[c]));
9154  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
9155  }
9156  }
9157 
9158  }
9159  while( success && *result != SCIP_CUTOFF && roundnr < maxproprounds );
9160 
9161  return SCIP_OKAY;
9162 }
9163 
9164 /* checks for a linear variable that can be increase or decreased without harming feasibility */
9165 static
9167  SCIP* scip, /**< SCIP data structure */
9168  SCIP_CONSDATA* consdata /**< constraint data */
9169  )
9170 {
9171  int i;
9172  int poslock;
9173  int neglock;
9174 
9175  consdata->linvar_maydecrease = -1;
9176  consdata->linvar_mayincrease = -1;
9177 
9178  /* check for a linear variable that can be increase or decreased without harming feasibility */
9179  for( i = 0; i < consdata->nlinvars; ++i )
9180  {
9181  /* compute locks of i'th linear variable */
9182  assert(consdata->lincoefs[i] != 0.0);
9183  if( consdata->lincoefs[i] > 0.0 )
9184  {
9185  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
9186  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
9187  }
9188  else
9189  {
9190  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
9191  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
9192  }
9193 
9194  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - neglock == 0 )
9195  {
9196  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
9197  /* if we have already one candidate, then take the one where the loss in the objective function is less */
9198  if( (consdata->linvar_maydecrease < 0) ||
9199  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
9200  consdata->linvar_maydecrease = i;
9201  }
9202 
9203  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - poslock == 0 )
9204  {
9205  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
9206  /* if we have already one candidate, then take the one where the loss in the objective function is less */
9207  if( (consdata->linvar_mayincrease < 0) ||
9208  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
9209  consdata->linvar_mayincrease = i;
9210  }
9211  }
9212 
9213 #ifdef SCIP_DEBUG
9214  if( consdata->linvar_mayincrease >= 0 )
9215  {
9216  SCIPdebugMessage("may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
9217  }
9218  if( consdata->linvar_maydecrease >= 0 )
9219  {
9220  SCIPdebugMessage("may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
9221  }
9222 #endif
9223 }
9224 
9225 /** Given a solution where every quadratic constraint is either feasible or can be made feasible by
9226  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
9227  * The method assumes that this is always possible and that not all constraints are feasible already.
9228  */
9229 static
9231  SCIP* scip, /**< SCIP data structure */
9232  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9233  SCIP_CONS** conss, /**< constraints to process */
9234  int nconss, /**< number of constraints */
9235  SCIP_SOL* sol, /**< solution to process */
9236  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
9237  )
9238 {
9239  SCIP_CONSHDLRDATA* conshdlrdata;
9240  SCIP_CONSDATA* consdata;
9241  char origscaling;
9242  SCIP_SOL* newsol;
9243  SCIP_VAR* var;
9244  int c;
9245  SCIP_Real viol;
9246  SCIP_Real delta;
9247  SCIP_Real gap;
9248 
9249  assert(scip != NULL);
9250  assert(conshdlr != NULL);
9251  assert(conss != NULL || nconss == 0);
9252  assert(success != NULL);
9253 
9254  *success = FALSE;
9255 
9256  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9257  assert(conshdlrdata != NULL);
9258 
9259  if( sol != NULL )
9260  {
9261  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
9262  }
9263  else
9264  {
9265  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
9266  }
9267  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
9268  SCIPdebugMessage("attempt to make solution from <%s> feasible by shifting linear variable\n",
9269  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
9270 
9271  origscaling = conshdlrdata->scaling;
9272  for( c = 0; c < nconss; ++c )
9273  {
9274  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
9275  assert(consdata != NULL);
9276 
9277  /* recompute violation of solution in case solution has changed
9278  * get absolution violation and sign
9279  * @todo avoid doing it this way
9280  */
9281  conshdlrdata->scaling = 'o';
9282  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
9283  {
9284  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
9285  viol = consdata->lhs - consdata->activity;
9286  }
9287  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
9288  {
9289  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
9290  viol = consdata->rhs - consdata->activity;
9291  }
9292  else
9293  continue; /* constraint is satisfied */
9294 
9295  assert(viol != 0.0);
9296  if( consdata->linvar_mayincrease >= 0 &&
9297  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
9298  {
9299  /* have variable where increasing makes the constraint less violated */
9300  var = consdata->linvars[consdata->linvar_mayincrease];
9301  /* compute how much we would like to increase var */
9302  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
9303  assert(delta > 0.0);
9304  /* if var has an upper bound, may need to reduce delta */
9305  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
9306  {
9307  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
9308  delta = MIN(MAX(0.0, gap), delta);
9309  }
9310  if( SCIPisPositive(scip, delta) )
9311  {
9312  /* if variable is integral, round delta up so that it will still have an integer value */
9313  if( SCIPvarIsIntegral(var) )
9314  delta = SCIPceil(scip, delta);
9315 
9316  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
9317  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
9318 
9319  /* adjust constraint violation, if satisfied go on to next constraint */
9320  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
9321  if( SCIPisZero(scip, viol) )
9322  continue;
9323  }
9324  }
9325 
9326  assert(viol != 0.0);
9327  if( consdata->linvar_maydecrease >= 0 &&
9328  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
9329  {
9330  /* have variable where decreasing makes constraint less violated */
9331  var = consdata->linvars[consdata->linvar_maydecrease];
9332  /* compute how much we would like to decrease var */
9333  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
9334  assert(delta < 0.0);
9335  /* if var has a lower bound, may need to reduce delta */
9336  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
9337  {
9338  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
9339  delta = MAX(MIN(0.0, gap), delta);
9340  }
9341  if( SCIPisNegative(scip, delta) )
9342  {
9343  /* if variable is integral, round delta down so that it will still have an integer value */
9344  if( SCIPvarIsIntegral(var) )
9345  delta = SCIPfloor(scip, delta);
9346  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
9347  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
9348 
9349  /* adjust constraint violation, if satisfied go on to next constraint */
9350  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
9351  if( SCIPisZero(scip, viol) )
9352  continue;
9353  }
9354  }
9355 
9356  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
9357  break;
9358  }
9359  conshdlrdata->scaling = origscaling;
9360 
9361  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
9362  * then pass it to the trysol heuristic
9363  */
9364  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
9365  {
9366  SCIPdebugMessage("pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
9367 
9368  assert(conshdlrdata->trysolheur != NULL);
9369  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
9370 
9371  *success = TRUE;
9372  }
9373 
9374  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
9375 
9376  return SCIP_OKAY;
9377 }
9378 
9379 /** tries to upgrade a nonlinear constraint into a quadratic constraint */
9380 static
9381 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
9382 {
9383  SCIP_EXPRGRAPH* exprgraph;
9384  SCIP_EXPRGRAPHNODE* node;
9385  int i;
9386 
9387  assert(nupgdconss != NULL);
9388  assert(upgdconss != NULL);
9389 
9390  *nupgdconss = 0;
9391 
9392  node = SCIPgetExprgraphNodeNonlinear(scip, cons);
9393 
9394  /* no interest in linear constraints */
9395  if( node == NULL )
9396  return SCIP_OKAY;
9397 
9398  /* if a quadratic expression has been simplified, then all children of the node should be variables */
9400  return SCIP_OKAY;
9401 
9402  switch( SCIPexprgraphGetNodeOperator(node) )
9403  {
9404  case SCIP_EXPR_VARIDX:
9405  case SCIP_EXPR_CONST:
9406  case SCIP_EXPR_PLUS:
9407  case SCIP_EXPR_MINUS:
9408  case SCIP_EXPR_SUM:
9409  case SCIP_EXPR_LINEAR:
9410  /* these should not appear as exprgraphnodes after constraint presolving */
9411  return SCIP_OKAY;
9412 
9413  case SCIP_EXPR_DIV:
9414  case SCIP_EXPR_SQRT:
9415  case SCIP_EXPR_REALPOWER:
9416  case SCIP_EXPR_INTPOWER:
9417  case SCIP_EXPR_SIGNPOWER:
9418  case SCIP_EXPR_EXP:
9419  case SCIP_EXPR_LOG:
9420  case SCIP_EXPR_SIN:
9421  case SCIP_EXPR_COS:
9422  case SCIP_EXPR_TAN:
9423  /* case SCIP_EXPR_ERF: */
9424  /* case SCIP_EXPR_ERFI: */
9425  case SCIP_EXPR_MIN:
9426  case SCIP_EXPR_MAX:
9427  case SCIP_EXPR_ABS:
9428  case SCIP_EXPR_SIGN:
9429  case SCIP_EXPR_PRODUCT:
9430  case SCIP_EXPR_POLYNOMIAL:
9431  /* these do not look like an quadratic expression (assuming the expression graph simplifier did run) */
9432  return SCIP_OKAY;
9433 
9434  case SCIP_EXPR_MUL:
9435  case SCIP_EXPR_SQUARE:
9436  case SCIP_EXPR_QUADRATIC:
9437  /* these mean that we have something quadratic */
9438  break;
9439 
9440  case SCIP_EXPR_PARAM:
9441  case SCIP_EXPR_LAST:
9442  default:
9443  SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
9444  return SCIP_OKAY;
9445  }
9446 
9447  /* setup a quadratic constraint */
9448 
9449  if( upgdconsssize < 1 )
9450  {
9451  /* request larger upgdconss array */
9452  *nupgdconss = -1;
9453  return SCIP_OKAY;
9454  }
9455 
9456  *nupgdconss = 1;
9457  SCIP_CALL( SCIPcreateConsQuadratic(scip, &upgdconss[0], SCIPconsGetName(cons),
9459  0, NULL, 0, NULL,
9460  SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
9464  assert(!SCIPconsIsStickingAtNode(cons));
9465 
9466  exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
9467 
9468  /* add variables from expression tree as "quadratic" variables to quadratic constraint */
9469  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
9470  {
9471  assert(SCIPexprgraphGetNodeChildren(node)[i] != NULL);
9472  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, upgdconss[0], (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[i]), 0.0, 0.0) );
9473  }
9474 
9475  switch( SCIPexprgraphGetNodeOperator(node) )
9476  {
9477  case SCIP_EXPR_MUL:
9478  /* expression is product of two variables, so add bilinear term to constraint */
9479  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
9480 
9481  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
9484  1.0) );
9485 
9486  break;
9487 
9488  case SCIP_EXPR_SQUARE:
9489  /* expression is square of a variable, so change square coefficient of quadratic variable */
9490  assert(SCIPexprgraphGetNodeNChildren(node) == 1);
9491 
9492  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
9494  1.0) );
9495 
9496  break;
9497 
9498  case SCIP_EXPR_QUADRATIC:
9499  {
9500  /* expression is quadratic */
9501  SCIP_QUADELEM* quadelems;
9502  int nquadelems;
9503  SCIP_Real* lincoefs;
9504 
9506  nquadelems = SCIPexprgraphGetNodeQuadraticNQuadElements(node);
9508 
9510 
9511  if( lincoefs != NULL )
9512  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
9513  if( lincoefs[i] != 0.0 )
9514  {
9515  /* linear term */
9516  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, upgdconss[0],
9518  lincoefs[i]) );
9519  }
9520 
9521  for( i = 0; i < nquadelems; ++i )
9522  {
9523  assert(quadelems[i].idx1 < SCIPexprgraphGetNodeNChildren(node));
9524  assert(quadelems[i].idx2 < SCIPexprgraphGetNodeNChildren(node));
9525 
9526  if( quadelems[i].idx1 == quadelems[i].idx2 )
9527  {
9528  /* square term */
9529  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
9530  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
9531  quadelems[i].coef) );
9532  }
9533  else
9534  {
9535  /* bilinear term */
9536  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
9537  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
9538  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx2]),
9539  quadelems[i].coef) );
9540  }
9541  }
9542 
9543  break;
9544  }
9545 
9546  default:
9547  SCIPerrorMessage("you should not be here\n");
9548  return SCIP_ERROR;
9549  } /*lint !e788 */
9550 
9551  return SCIP_OKAY;
9552 }
9553 
9554 /*
9555  * Callback methods of constraint handler
9556  */
9557 
9558 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
9559 static
9560 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
9561 { /*lint --e{715}*/
9562  assert(scip != NULL);
9563  assert(conshdlr != NULL);
9564  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
9565 
9566  /* call inclusion method of constraint handler */
9568 
9569  *valid = TRUE;
9570 
9571  return SCIP_OKAY;
9572 }
9573 
9574 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
9575 static
9576 SCIP_DECL_CONSFREE(consFreeQuadratic)
9577 {
9578  SCIP_CONSHDLRDATA* conshdlrdata;
9579  int i;
9580 
9581  assert(scip != NULL);
9582  assert(conshdlr != NULL);
9583 
9584  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9585  assert(conshdlrdata != NULL);
9586 
9587  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
9588  {
9589  assert(conshdlrdata->quadconsupgrades[i] != NULL);
9590  SCIPfreeMemory(scip, &conshdlrdata->quadconsupgrades[i]);
9591  }
9592  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->quadconsupgrades);
9593 
9594  SCIPfreeMemory(scip, &conshdlrdata);
9595 
9596  return SCIP_OKAY;
9597 }
9598 
9599 /** initialization method of constraint handler (called after problem was transformed) */
9600 static
9601 SCIP_DECL_CONSINIT(consInitQuadratic)
9602 { /*lint --e{715} */
9603  SCIP_CONSHDLRDATA* conshdlrdata;
9604  int c;
9605 
9606  assert(scip != NULL);
9607  assert(conshdlr != NULL);
9608 
9609  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9610  assert(conshdlrdata != NULL);
9611 
9612  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
9613  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
9614 
9615  /* catch variable events */
9616  for( c = 0; c < nconss; ++c )
9617  {
9618  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[c]) );
9619  }
9620 
9621  return SCIP_OKAY;
9622 }
9623 
9624 
9625 /** deinitialization method of constraint handler (called before transformed problem is freed) */
9626 static
9627 SCIP_DECL_CONSEXIT(consExitQuadratic)
9628 { /*lint --e{715} */
9629  SCIP_CONSHDLRDATA* conshdlrdata;
9630  int c;
9631 
9632  assert(scip != NULL);
9633  assert(conshdlr != NULL);
9634 
9635  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9636  assert(conshdlrdata != NULL);
9637 
9638  /* drop variable events */
9639  for( c = 0; c < nconss; ++c )
9640  {
9641  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, conss[c]) );
9642  }
9643 
9644  conshdlrdata->subnlpheur = NULL;
9645  conshdlrdata->trysolheur = NULL;
9646 
9647  return SCIP_OKAY;
9648 }
9649 
9650 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
9651 #if 0
9652 static
9653 SCIP_DECL_CONSINITPRE(consInitpreQuadratic)
9654 { /*lint --e{715}*/
9655  SCIP_CONSHDLRDATA* conshdlrdata;
9656  SCIP_CONSDATA* consdata;
9657  int c;
9658 
9659  assert(scip != NULL);
9660  assert(conshdlr != NULL);
9661  assert(conss != NULL || nconss == 0);
9662 
9663  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9664  assert(conshdlrdata != NULL);
9665 
9666  return SCIP_OKAY;
9667 }
9668 #endif
9669 
9670 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
9671 static
9672 SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
9673 { /*lint --e{715}*/
9674  SCIP_CONSDATA* consdata;
9675  int c;
9676 #ifndef NDEBUG
9677  int i;
9678 #endif
9679 
9680  assert(scip != NULL);
9681  assert(conshdlr != NULL);
9682  assert(conss != NULL || nconss == 0);
9683 
9684  for( c = 0; c < nconss; ++c )
9685  {
9686  assert(conss != NULL);
9687  consdata = SCIPconsGetData(conss[c]);
9688  assert(consdata != NULL);
9689 
9690  if( !consdata->isremovedfixings )
9691  {
9692  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
9693  }
9694 
9695  /* make sure we do not have duplicate bilinear terms, quad var terms, or linear vars */
9696  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
9697  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
9698  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
9699 
9700  assert(consdata->isremovedfixings);
9701  assert(consdata->linvarsmerged);
9702  assert(consdata->quadvarsmerged);
9703  assert(consdata->bilinmerged);
9704 
9705 #ifndef NDEBUG
9706  for( i = 0; i < consdata->nlinvars; ++i )
9707  assert(SCIPvarIsActive(consdata->linvars[i]));
9708 
9709  for( i = 0; i < consdata->nquadvars; ++i )
9710  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
9711 #endif
9712 
9713  /* tell SCIP that we have something nonlinear */
9714  if( SCIPconsIsAdded(conss[c]) && consdata->nquadvars > 0 )
9715  SCIPenableNLP(scip);
9716  }
9717 
9718  return SCIP_OKAY;
9719 }
9720 
9721 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
9722 static
9723 SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
9724 {
9725  SCIP_CONSHDLRDATA* conshdlrdata;
9726  SCIP_CONSDATA* consdata;
9727  int c;
9728  int i;
9729 
9730  assert(scip != NULL);
9731  assert(conshdlr != NULL);
9732  assert(conss != NULL || nconss == 0);
9733 
9734  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9735  assert(conshdlrdata != NULL);
9736 
9737  for( c = 0; c < nconss; ++c )
9738  {
9739  assert(conss != NULL);
9740  consdata = SCIPconsGetData(conss[c]);
9741  assert(consdata != NULL);
9742 
9743  /* check for a linear variable that can be increase or decreased without harming feasibility */
9744  consdataFindUnlockedLinearVar(scip, consdata);
9745 
9746  /* setup lincoefsmin, lincoefsmax */
9747  consdata->lincoefsmin = SCIPinfinity(scip);
9748  consdata->lincoefsmax = 0.0;
9749  for( i = 0; i < consdata->nlinvars; ++i )
9750  {
9751  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666 */
9752  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666 */
9753  }
9754 
9755  /* add nlrow representation to NLP, if NLP had been constructed */
9756  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
9757  {
9758  if( consdata->nlrow == NULL )
9759  {
9760  SCIP_CALL( createNlRow(scip, conss[c]) );
9761  assert(consdata->nlrow != NULL);
9762  }
9763  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
9764  }
9765 
9766  /* setup sepaquadvars and sepabilinvar2pos */
9767  assert(consdata->sepaquadvars == NULL);
9768  assert(consdata->sepabilinvar2pos == NULL);
9769  if( consdata->nquadvars > 0 )
9770  {
9771  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepaquadvars, consdata->nquadvars) );
9772  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms) );
9773 
9774  /* make sure, quadratic variable terms are sorted */
9775  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
9776 
9777  for( i = 0; i < consdata->nquadvars; ++i )
9778  consdata->sepaquadvars[i] = consdata->quadvarterms[i].var;
9779 
9780  for( i = 0; i < consdata->nbilinterms; ++i )
9781  {
9782  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &consdata->sepabilinvar2pos[i]) );
9783  }
9784  }
9785 
9786  if( conshdlrdata->checkfactorable )
9787  {
9788  /* check if constraint function is factorable, i.e., can be written as product of two linear functions */
9789  SCIP_CALL( checkFactorable(scip, conss[c]) );
9790  }
9791  }
9792 
9793  conshdlrdata->newsoleventfilterpos = -1;
9794  if( nconss != 0 && conshdlrdata->linearizeheursol )
9795  {
9796  SCIP_EVENTHDLR* eventhdlr;
9797 
9798  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
9799  assert(eventhdlr != NULL);
9800 
9801  /* @todo Should we catch every new solution or only new *best* solutions */
9802  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
9803  }
9804 
9805  if( nconss != 0 && !SCIPisIpoptAvailableIpopt() && !SCIPisInRestart(scip) )
9806  {
9807  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");
9808  }
9809 
9810  /* reset flags and counters */
9811  conshdlrdata->sepanlp = FALSE;
9812  conshdlrdata->lastenfolpnode = NULL;
9813  conshdlrdata->nenfolprounds = 0;
9814 
9815  return SCIP_OKAY;
9816 }
9817 
9818 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9819 static
9820 SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
9821 { /*lint --e{715}*/
9822  SCIP_CONSHDLRDATA* conshdlrdata;
9823  SCIP_CONSDATA* consdata;
9824  int c;
9825 
9826  assert(scip != NULL);
9827  assert(conshdlr != NULL);
9828  assert(conss != NULL || nconss == 0);
9829 
9830  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9831  assert(conshdlrdata != NULL);
9832 
9833  if( conshdlrdata->newsoleventfilterpos >= 0 )
9834  {
9835  SCIP_EVENTHDLR* eventhdlr;
9836 
9837  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
9838  assert(eventhdlr != NULL);
9839 
9840  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
9841  conshdlrdata->newsoleventfilterpos = -1;
9842  }
9843 
9844  for( c = 0; c < nconss; ++c )
9845  {
9846  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
9847  assert(consdata != NULL);
9848 
9849  /* free nonlinear row representation */
9850  if( consdata->nlrow != NULL )
9851  {
9852  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
9853  }
9854 
9855  assert(consdata->sepaquadvars != NULL || consdata->nquadvars == 0);
9856  assert(consdata->sepabilinvar2pos != NULL || consdata->nquadvars == 0);
9857  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepaquadvars, consdata->nquadvars);
9858  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms);
9859 
9860  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorleft, consdata->nquadvars + 1);
9861  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorright, consdata->nquadvars + 1);
9862  }
9863 
9864  return SCIP_OKAY;
9865 }
9866 
9867 /** frees specific constraint data */
9868 static
9869 SCIP_DECL_CONSDELETE(consDeleteQuadratic)
9870 {
9871  SCIP_CONSHDLRDATA* conshdlrdata;
9872 
9873  assert(scip != NULL);
9874  assert(conshdlr != NULL);
9875  assert(cons != NULL);
9876  assert(consdata != NULL);
9877  assert(SCIPconsGetData(cons) == *consdata);
9878 
9879  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9880  assert(conshdlrdata != NULL);
9881 
9882  if( SCIPconsIsTransformed(cons) )
9883  {
9884  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
9885  }
9886 
9887  SCIP_CALL( consdataFree(scip, consdata) );
9888 
9889  assert(*consdata == NULL);
9890 
9891  return SCIP_OKAY;
9892 }
9893 
9894 /** transforms constraint data into data belonging to the transformed problem */
9895 static
9896 SCIP_DECL_CONSTRANS(consTransQuadratic)
9897 {
9898  SCIP_CONSDATA* sourcedata;
9899  SCIP_CONSDATA* targetdata;
9900  int i;
9901 
9902  sourcedata = SCIPconsGetData(sourcecons);
9903  assert(sourcedata != NULL);
9904 
9905  SCIP_CALL( consdataCreate(scip, &targetdata,
9906  sourcedata->lhs, sourcedata->rhs,
9907  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
9908  sourcedata->nquadvars, sourcedata->quadvarterms,
9909  sourcedata->nbilinterms, sourcedata->bilinterms,
9910  FALSE) );
9911 
9912  for( i = 0; i < targetdata->nlinvars; ++i )
9913  {
9914  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
9915  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
9916  }
9917 
9918  for( i = 0; i < targetdata->nquadvars; ++i )
9919  {
9920  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->quadvarterms[i].var, &targetdata->quadvarterms[i].var) );
9921  SCIP_CALL( SCIPcaptureVar(scip, targetdata->quadvarterms[i].var) );
9922  }
9923 
9924  for( i = 0; i < targetdata->nbilinterms; ++i )
9925  {
9926  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var1, &targetdata->bilinterms[i].var1) );
9927  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var2, &targetdata->bilinterms[i].var2) );
9928 
9929  if( SCIPvarCompare(targetdata->bilinterms[i].var1, targetdata->bilinterms[i].var2) > 0 )
9930  {
9931  SCIP_VAR* tmp;
9932  tmp = targetdata->bilinterms[i].var2;
9933  targetdata->bilinterms[i].var2 = targetdata->bilinterms[i].var1;
9934  targetdata->bilinterms[i].var1 = tmp;
9935  }
9936  }
9937 
9938  /* create target constraint */
9939  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
9940  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
9941  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
9942  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
9943  SCIPconsIsStickingAtNode(sourcecons)) );
9944 
9945  SCIPdebugMessage("created transformed quadratic constraint ");
9946  SCIPdebugPrintCons(scip, *targetcons, NULL);
9947 
9948  return SCIP_OKAY;
9949 }
9950 
9951 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9952 static
9953 SCIP_DECL_CONSINITLP(consInitlpQuadratic)
9954 {
9955  SCIP_CONSHDLRDATA* conshdlrdata;
9956  SCIP_CONSDATA* consdata;
9957  SCIP_VAR* var;
9958  SCIP_ROW* row;
9959  SCIP_Real* x;
9960  int c;
9961  int i;
9962 
9963  assert(scip != NULL);
9964  assert(conshdlr != NULL);
9965  assert(conss != NULL || nconss == 0);
9966 
9967  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9968  assert(conshdlrdata != NULL);
9969 
9970  for( c = 0; c < nconss; ++c )
9971  {
9972  assert(conss[c] != NULL); /*lint !e613 */
9973 
9974  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
9975 
9976  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
9977  assert(consdata != NULL);
9978 
9979  row = NULL;
9980 
9981  if( consdata->nquadvars == 0 )
9982  {
9983  SCIP_Bool infeasible;
9984 
9985  /* if we are actually linear, add the constraint as row to the LP */
9986  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
9987  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613 */
9988  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
9989  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
9990  assert( ! infeasible );
9991  SCIP_CALL( SCIPreleaseRow (scip, &row) );
9992  continue;
9993  }
9994 
9995  /* alloc memory for reference point */
9996  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nquadvars) );
9997 
9998  /* for convex parts, add linearizations in 5 points */
9999  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
10000  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
10001  {
10002  SCIP_Real lb;
10003  SCIP_Real ub;
10004  SCIP_Real lambda;
10005  int k;
10006 
10007  for( k = 0; k < 5; ++k )
10008  {
10009  lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
10010  for( i = 0; i < consdata->nquadvars; ++i )
10011  {
10012  var = consdata->quadvarterms[i].var;
10013  lb = SCIPvarGetLbGlobal(var);
10014  ub = SCIPvarGetUbGlobal(var);
10015 
10016  if( ub > -INITLPMAXVARVAL )
10017  lb = MAX(lb, -INITLPMAXVARVAL);
10018  if( lb < INITLPMAXVARVAL )
10019  ub = MIN(ub, INITLPMAXVARVAL);
10020 
10021  /* make bounds finite */
10022  if( SCIPisInfinity(scip, -lb) )
10023  lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
10024  if( SCIPisInfinity(scip, ub) )
10025  ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
10026 
10028  x[i] = lambda * ub + (1.0 - lambda) * lb;
10029  else
10030  x[i] = lambda * lb + (1.0 - lambda) * ub;
10031  }
10032 
10033  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, consdata->isconvex ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT, &row, NULL, FALSE, -SCIPinfinity(scip)) ); /*lint !e613 */
10034  if( row != NULL )
10035  {
10036  SCIP_Bool infeasible;
10037 
10038  SCIPdebugMessage("initlp adds row <%s> for lambda = %g of conss <%s>\n", SCIProwGetName(row), lambda, SCIPconsGetName(conss[c])); /*lint !e613 */
10039  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
10040 
10041  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
10042  assert( ! infeasible );
10043 
10044  SCIP_CALL( SCIPreleaseRow (scip, &row) );
10045  }
10046  }
10047  }
10048 
10049  /* for concave parts, add underestimator w.r.t. at most 2 reference points */
10050  if( (!consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
10051  (!consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
10052  {
10053  SCIP_Bool unbounded;
10054  SCIP_Bool possquare;
10055  SCIP_Bool negsquare;
10056  SCIP_Real lb;
10057  SCIP_Real ub;
10058  SCIP_Real lambda;
10059  int k;
10060 
10061  unbounded = FALSE; /* whether there are unbounded variables */
10062  possquare = FALSE; /* whether there is a positive square term */
10063  negsquare = FALSE; /* whether there is a negative square term */
10064  lambda = 0.6; /* weight of preferred bound */
10065  for( k = 0; k < 2; ++k )
10066  {
10067  /* set reference point to 0 projected on bounds for unbounded variables or in between lower and upper bound for bounded variables
10068  * in the first round, we set it closer to the best bound, in the second closer to the worst bound
10069  * the reason is, that for a bilinear term with bounded variables, there are always two linear underestimators
10070  * if the reference point is set to the middle, then rounding and luck decides which underestimator is chosen
10071  * we thus choose the reference point not to be the middle, so both McCormick terms are definitely chosen one time
10072  * of course, the possible number of cuts is something in the order of 2^nquadvars, and we choose two of them here
10073  */
10074  for( i = 0; i < consdata->nquadvars; ++i )
10075  {
10076  var = consdata->quadvarterms[i].var;
10077  lb = SCIPvarGetLbGlobal(var);
10078  ub = SCIPvarGetUbGlobal(var);
10079 
10080  if( SCIPisInfinity(scip, -lb) )
10081  {
10082  if( SCIPisInfinity(scip, ub) )
10083  x[i] = 0.0;
10084  else
10085  x[i] = MIN(0.0, ub);
10086  unbounded = TRUE;
10087  }
10088  else
10089  {
10090  if( SCIPisInfinity(scip, ub) )
10091  {
10092  x[i] = MAX(0.0, lb);
10093  unbounded = TRUE;
10094  }
10095  else
10096  x[i] = lambda * SCIPvarGetBestBoundLocal(var) + (1.0-lambda) * SCIPvarGetWorstBoundLocal(var);
10097  }
10098 
10099  possquare |= consdata->quadvarterms[i].sqrcoef > 0.0; /*lint !e514 */
10100  negsquare |= consdata->quadvarterms[i].sqrcoef < 0.0; /*lint !e514 */
10101  }
10102 
10103  if( !consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
10104  {
10105  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_RIGHT, &row, NULL, conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
10106  if( row != NULL )
10107  {
10108  SCIP_Bool infeasible;
10109 
10110  SCIPdebugMessage("initlp adds row <%s> for rhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
10111  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
10112 
10113  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
10114  assert( ! infeasible );
10115 
10116  SCIP_CALL( SCIPreleaseRow (scip, &row) );
10117  }
10118  }
10119  if( !consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
10120  {
10121  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_LEFT, &row, NULL, conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
10122  if( row != NULL )
10123  {
10124  SCIP_Bool infeasible;
10125 
10126  SCIPdebugMessage("initlp adds row <%s> for lhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
10127  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
10128 
10129  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
10130  assert( ! infeasible );
10131 
10132  SCIP_CALL( SCIPreleaseRow (scip, &row) );
10133  }
10134  }
10135 
10136  /* if there are unbounded variables, then there is typically only at most one possible underestimator, so don't try another round
10137  * 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 */
10138  if( unbounded ||
10139  (consdata->nbilinterms == 0 && (!possquare || SCIPisInfinity(scip, consdata->rhs))) ||
10140  (consdata->nbilinterms == 0 && (!negsquare || SCIPisInfinity(scip, -consdata->lhs))) )
10141  break;
10142 
10143  /* invert lambda for second round */
10144  lambda = 1.0 - lambda;
10145  }
10146  }
10147 
10148  SCIPfreeBufferArray(scip, &x);
10149  }
10150 
10151  return SCIP_OKAY;
10152 }
10153 
10154 /** separation method of constraint handler for LP solutions */
10155 static
10156 SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
10157 {
10158  SCIP_CONSHDLRDATA* conshdlrdata;
10159  SCIP_CONS* maxviolcon;
10160 
10161  assert(scip != NULL);
10162  assert(conshdlr != NULL);
10163  assert(conss != NULL || nconss == 0);
10164  assert(result != NULL);
10165 
10166  *result = SCIP_DIDNOTFIND;
10167 
10168  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10169  assert(conshdlrdata != NULL);
10170 
10171  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
10172  if( maxviolcon == NULL )
10173  return SCIP_OKAY;
10174 
10175  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
10176  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
10177  */
10178  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
10179  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) || (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
10180  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
10181  {
10182  SCIP_CONSDATA* consdata;
10183  SCIP_NLPSOLSTAT solstat;
10184  SCIP_Bool solvednlp;
10185  int c;
10186 
10187  solstat = SCIPgetNLPSolstat(scip);
10188  solvednlp = FALSE;
10189  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
10190  {
10191  /* NLP is not solved yet, so we might want to do this
10192  * but first check whether there is a violated constraint side which corresponds to a convex function
10193  */
10194  for( c = 0; c < nconss; ++c )
10195  {
10196  assert(conss[c] != NULL); /*lint !e613 */
10197 
10198  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
10199  assert(consdata != NULL);
10200 
10201  /* skip feasible constraints */
10202  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10203  continue;
10204 
10205  /* make sure curvature has been checked */
10206  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
10207 
10208  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->isconvex) ||
10209  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->isconcave) )
10210  break;
10211  }
10212 
10213  if( c < nconss )
10214  {
10215  /* try to solve NLP and update solstat */
10216 
10217  /* ensure linear conss are in NLP */
10218  if( conshdlrdata->subnlpheur != NULL )
10219  {
10220  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
10221  }
10222 
10223  /* set LP solution as starting values, if available */
10225  {
10227  }
10228 
10229  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
10230  SCIP_CALL( SCIPsolveNLP(scip) );
10231 
10232  solstat = SCIPgetNLPSolstat(scip);
10233  SCIPdebugMessage("solved NLP relax, solution status: %d\n", solstat);
10234 
10235  solvednlp = TRUE;
10236  }
10237  }
10238 
10239  conshdlrdata->sepanlp = TRUE;
10240 
10241  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
10242  {
10243  SCIPdebugMessage("NLP relaxation is globally infeasible, thus can cutoff node\n");
10244  *result = SCIP_CUTOFF;
10245  return SCIP_OKAY;
10246  }
10247 
10248  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
10249  {
10250  /* if we have feasible NLP solution, generate linearization cuts there */
10251  SCIP_Bool lpsolseparated;
10252  SCIP_SOL* nlpsol;
10253 
10254  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
10255  assert(nlpsol != NULL);
10256 
10257  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
10258  if( solvednlp && conshdlrdata->trysolheur != NULL )
10259  {
10260  int nfracvars;
10261 
10262  nfracvars = 0;
10263  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
10264  {
10265  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
10266  }
10267 
10268  if( nfracvars == 0 )
10269  {
10270  SCIPdebugMessage("pass solution with obj. value %g to trysol\n", SCIPgetSolOrigObj(scip, nlpsol));
10271  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
10272  }
10273  }
10274 
10275  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, conshdlrdata->mincutefficacysepa) );
10276 
10277  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
10278 
10279  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
10280  if( lpsolseparated )
10281  {
10282  SCIPdebugMessage("linearization cuts separate LP solution\n");
10283  *result = SCIP_SEPARATED;
10284 
10285  return SCIP_OKAY;
10286  }
10287  }
10288  }
10289  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
10290  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
10291  */
10292 
10293  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
10294 
10295  return SCIP_OKAY;
10296 }
10297 
10298 /** separation method of constraint handler for arbitrary primal solutions */
10299 static
10300 SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
10301 {
10302  SCIP_CONSHDLRDATA* conshdlrdata;
10303  SCIP_CONS* maxviolcon;
10304 
10305  assert(scip != NULL);
10306  assert(conshdlr != NULL);
10307  assert(conss != NULL || nconss == 0);
10308  assert(sol != NULL);
10309  assert(result != NULL);
10310 
10311  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10312  assert(conshdlrdata != NULL);
10313 
10314  *result = SCIP_DIDNOTFIND;
10315 
10316  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &maxviolcon) );
10317  if( maxviolcon == NULL )
10318  return SCIP_OKAY;
10319 
10320  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
10321 
10322  return SCIP_OKAY;
10323 }
10324 
10325 /** constraint enforcing method of constraint handler for LP solutions */
10326 static
10327 SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
10328 { /*lint --e{715}*/
10329  SCIP_CONSHDLRDATA* conshdlrdata;
10330  SCIP_CONSDATA* consdata;
10331  SCIP_CONS* maxviolcon;
10332  SCIP_Real maxviol;
10333  SCIP_RESULT propresult;
10334  SCIP_RESULT separateresult;
10335  int nchgbds;
10336  int nnotify;
10337  SCIP_Real sepaefficacy;
10338  SCIP_Real minefficacy;
10339  SCIP_Real leastpossibleefficacy;
10340 
10341  assert(scip != NULL);
10342  assert(conshdlr != NULL);
10343  assert(conss != NULL || nconss == 0);
10344 
10345  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10346  assert(conshdlrdata != NULL);
10347 
10348  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
10349  if( maxviolcon == NULL )
10350  {
10351  *result = SCIP_FEASIBLE;
10352  return SCIP_OKAY;
10353  }
10354 
10355  *result = SCIP_INFEASIBLE;
10356 
10357  consdata = SCIPconsGetData(maxviolcon);
10358  assert(consdata != NULL);
10359  maxviol = consdata->lhsviol + consdata->rhsviol;
10360  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
10361 
10362  SCIPdebugMessage("enfolp with max violation %g in cons <%s>\n", maxviol, SCIPconsGetName(maxviolcon));
10363 
10364  /* if we are above the 100'th enforcement round for this node, something is strange
10365  * (maybe the LP does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
10366  * 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
10367  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
10368  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
10369  * we only increment nenfolprounds until 101 to avoid an overflow
10370  */
10371  if( conshdlrdata->lastenfolpnode == SCIPgetCurrentNode(scip) )
10372  {
10373  if( conshdlrdata->nenfolprounds > 100 )
10374  {
10375  if( SCIPisStopped(scip) )
10376  {
10377  SCIP_NODE* child;
10378 
10379  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
10380  *result = SCIP_BRANCHED;
10381 
10382  return SCIP_OKAY;
10383  }
10384  }
10385 
10386  ++conshdlrdata->nenfolprounds;
10387 
10388  /* cut off the current subtree, if a limit on the enforcement rounds should be applied. At this point, feasible
10389  * solutions might get cut off; the enfolplimit parameter should therefore only be set if SCIP is used as a
10390  * heuristic solver and when the returned result (infeasible, optimal, the gap) can be ignored
10391  */
10392  if( conshdlrdata->enfolplimit != -1 && conshdlrdata->nenfolprounds > conshdlrdata->enfolplimit )
10393  {
10395  "cut off subtree because enforcement limit was reached; this might lead to incorrect results\n");
10396  *result = SCIP_CUTOFF;
10397  return SCIP_OKAY;
10398  }
10399  }
10400  else
10401  {
10402  conshdlrdata->lastenfolpnode = SCIPgetCurrentNode(scip);
10403  conshdlrdata->nenfolprounds = 0;
10404  }
10405 
10406  /* run domain propagation */
10407  nchgbds = 0;
10408  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
10409  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
10410  {
10411  SCIPdebugMessage("propagation succeeded (%s)\n", propresult == SCIP_CUTOFF ? "cutoff" : "reduceddom");
10412  *result = propresult;
10413  return SCIP_OKAY;
10414  }
10415 
10416  /* we would like a cut that is efficient enough that it is not redundant in the LP (>feastol)
10417  * however, if the maximal violation is very small, also the best cut efficacy cannot be large
10418  * thus, in the latter case, we are also happy if the efficacy is at least, say, 75% of the maximal violation
10419  * but in any case we need an efficacy that is at least feastol
10420  */
10421  minefficacy = MIN(0.75*maxviol, conshdlrdata->mincutefficacyenfofac * SCIPfeastol(scip)); /*lint !e666 */
10422  minefficacy = MAX(minefficacy, SCIPfeastol(scip)); /*lint !e666 */
10423  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, minefficacy, TRUE, &separateresult, &sepaefficacy) );
10424  if( separateresult == SCIP_CUTOFF )
10425  {
10426  SCIPdebugMessage("separation found cutoff\n");
10427  *result = SCIP_CUTOFF;
10428  return SCIP_OKAY;
10429  }
10430  if( separateresult == SCIP_SEPARATED )
10431  {
10432  SCIPdebugMessage("separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, minefficacy);
10433  *result = SCIP_SEPARATED;
10434  return SCIP_OKAY;
10435  }
10436 
10437  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
10438  * -> collect variables for branching
10439  */
10440 
10441  SCIPdebugMessage("separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, minefficacy, maxviol);
10442 
10443  /* find branching candidates */
10444  SCIP_CALL( registerVariableInfeasibilities(scip, conshdlr, conss, nconss, &nnotify) );
10445 
10446  /* if sepastore can decrease LP feasibility tolerance, we can add cuts with efficacy in [eps, feastol] */
10447  leastpossibleefficacy = SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip);
10448  if( nnotify == 0 && !solinfeasible && minefficacy > leastpossibleefficacy )
10449  {
10450  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
10451  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, leastpossibleefficacy, TRUE, &separateresult, &sepaefficacy) );
10452  if( separateresult == SCIP_CUTOFF )
10453  {
10454  SCIPdebugMessage("separation found cutoff\n");
10455  *result = SCIP_CUTOFF;
10456  return SCIP_OKAY;
10457  }
10458  if( separateresult == SCIP_SEPARATED )
10459  {
10460  SCIPdebugMessage("separation fallback succeeded, efficacy = %g\n", sepaefficacy);
10461  *result = SCIP_SEPARATED;
10462  return SCIP_OKAY;
10463  }
10464  }
10465 
10466  if( nnotify == 0 && !solinfeasible )
10467  {
10468  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
10469  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
10470  */
10471  SCIP_VAR* brvar = NULL;
10472  SCIP_CALL( registerLargeLPValueVariableForBranching(scip, conss, nconss, &brvar) );
10473  if( brvar == NULL )
10474  {
10475  /* fallback 3: all quadratic variables seem to be fixed -> replace by linear constraint */
10476  SCIP_Bool addedcons;
10477  SCIP_Bool reduceddom;
10478  SCIP_Bool infeasible;
10479 
10480  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
10481  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
10482  * when it enforces the new constraints again and nothing resolves the infeasiblity that we declare here thus,
10483  * we only add them if considered violated, and otherwise claim the solution is feasible (but print a
10484  * warning) */
10485  if ( infeasible )
10486  *result = SCIP_CUTOFF;
10487  else if ( addedcons )
10488  *result = SCIP_CONSADDED;
10489  else if ( reduceddom )
10490  *result = SCIP_REDUCEDDOM;
10491  else
10492  {
10493  *result = SCIP_FEASIBLE;
10494  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
10495  assert(!SCIPisInfinity(scip, maxviol));
10496  }
10497  return SCIP_OKAY;
10498  }
10499  else
10500  {
10501  SCIPdebugMessage("Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
10502  SCIPvarGetName(brvar), SCIPgetSolVal(scip, NULL, brvar));
10503  nnotify = 1;
10504  }
10505  }
10506 
10507  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
10508  return SCIP_OKAY;
10509 }
10510 
10511 
10512 /** constraint enforcing method of constraint handler for pseudo solutions */
10513 static
10514 SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
10515 { /*lint --e{715}*/
10516  SCIP_CONS* maxviolcon;
10517  SCIP_CONSDATA* consdata;
10518  SCIP_RESULT propresult;
10519  SCIP_VAR* var;
10520  int c;
10521  int i;
10522  int nchgbds;
10523  int nnotify;
10524 
10525  assert(scip != NULL);
10526  assert(conss != NULL || nconss == 0);
10527 
10528  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
10529  if( maxviolcon == NULL )
10530  {
10531  *result = SCIP_FEASIBLE;
10532  return SCIP_OKAY;
10533  }
10534 
10535  *result = SCIP_INFEASIBLE;
10536 
10537  SCIPdebugMessage("enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcon));
10538 
10539  /* run domain propagation */
10540  nchgbds = 0;
10541  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
10542  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
10543  {
10544  *result = propresult;
10545  return SCIP_OKAY;
10546  }
10547 
10548  /* we are not feasible and we cannot proof that the whole node is infeasible
10549  * -> collect all variables in violated constraints for branching
10550  */
10551  nnotify = 0;
10552  for( c = 0; c < nconss; ++c )
10553  {
10554  assert(conss != NULL);
10555  consdata = SCIPconsGetData(conss[c]);
10556  assert(consdata != NULL);
10557 
10558  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10559  continue;
10560 
10561  for( i = 0; i < consdata->nlinvars; ++i )
10562  {
10563  var = consdata->linvars[i];
10564  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10565  {
10566  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
10567  ++nnotify;
10568  }
10569  }
10570 
10571  for( i = 0; i < consdata->nquadvars; ++i )
10572  {
10573  var = consdata->quadvarterms[i].var;
10574  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10575  {
10576  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
10577  ++nnotify;
10578  }
10579  }
10580  }
10581 
10582  if( nnotify == 0 )
10583  {
10584  SCIPdebugMessage("All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
10585  *result = SCIP_SOLVELP;
10586  }
10587 
10588  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
10589  return SCIP_OKAY;
10590 }
10591 
10592 /** domain propagation method of constraint handler */
10593 static
10594 SCIP_DECL_CONSPROP(consPropQuadratic)
10595 {
10596  int nchgbds;
10597 
10598  assert(scip != NULL);
10599  assert(conshdlr != NULL);
10600  assert(conss != NULL || nconss == 0);
10601  assert(result != NULL);
10602 
10603  nchgbds = 0;
10604  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, result, &nchgbds) );
10605 
10606  return SCIP_OKAY;
10607 } /*lint !e715 */
10608 
10609 /** presolving method of constraint handler */
10610 static
10611 SCIP_DECL_CONSPRESOL(consPresolQuadratic)
10612 { /*lint --e{715,788}*/
10613  SCIP_CONSHDLRDATA* conshdlrdata;
10614  SCIP_CONSDATA* consdata;
10615  SCIP_RESULT solveresult;
10616  SCIP_Bool redundant;
10617  SCIP_Bool havechange;
10618  SCIP_Bool doreformulations;
10619  int c;
10620  int i;
10621 
10622  assert(scip != NULL);
10623  assert(conshdlr != NULL);
10624  assert(conss != NULL || nconss == 0);
10625  assert(result != NULL);
10626 
10627  *result = SCIP_DIDNOTFIND;
10628 
10629  /* if other presolvers did not find enough changes for another presolving round,
10630  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
10631  * otherwise, we wait with these
10632  * @todo first do all usual presolving steps, then check SCIPisPresolveFinished(scip), and if true then do reformulations (and usual steps again)
10633  */
10634  doreformulations = (nrounds > 0 || SCIPconshdlrWasPresolvingDelayed(conshdlr)) && SCIPisPresolveFinished(scip);
10635  SCIPdebugMessage("presolving will %swait with reformulation\n", doreformulations ? "not " : "");
10636 
10637  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10638  assert(conshdlrdata != NULL);
10639 
10640  for( c = 0; c < nconss; ++c )
10641  {
10642  assert(conss != NULL);
10643  consdata = SCIPconsGetData(conss[c]);
10644  assert(consdata != NULL);
10645 
10646  SCIPdebugMessage("process constraint <%s>\n", SCIPconsGetName(conss[c]));
10647  SCIPdebugPrintCons(scip, conss[c], NULL);
10648 
10649  if( !consdata->initialmerge )
10650  {
10651  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
10652  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
10653  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
10654  consdata->initialmerge = TRUE;
10655  }
10656 
10657  havechange = FALSE;
10658 #ifdef CHECKIMPLINBILINEAR
10659  if( consdata->isimpladded )
10660  {
10661  int nbilinremoved;
10662  SCIP_CALL( presolveApplyImplications(scip, conss[c], &nbilinremoved) );
10663  if( nbilinremoved > 0 )
10664  {
10665  *nchgcoefs += nbilinremoved;
10666  havechange = TRUE;
10667  *result = SCIP_SUCCESS;
10668  }
10669  assert(!consdata->isimpladded);
10670  }
10671 #endif
10672  /* 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
10673  * we want to do this before (multi)aggregated variables are replaced, since that may change structure, e.g., introduce bilinear terms
10674  */
10675  if( !consdata->ispresolved || !consdata->ispropagated || nnewchgvartypes > 0 )
10676  {
10677  SCIP_Bool upgraded;
10678 
10679  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10680  if( upgraded )
10681  {
10682  *result = SCIP_SUCCESS;
10683  continue;
10684  }
10685  }
10686 
10687  if( !consdata->isremovedfixings )
10688  {
10689  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
10690  assert(consdata->isremovedfixings);
10691  havechange = TRUE;
10692  }
10693 
10694  /* try to "solve" the constraint, e.g., reduce to a variable aggregation */
10695  SCIP_CALL( presolveSolve(scip, conss[c], &solveresult, &redundant, naggrvars) );
10696  if( solveresult == SCIP_CUTOFF )
10697  {
10698  SCIPdebugMessage("solving constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
10699  *result = SCIP_CUTOFF;
10700  return SCIP_OKAY;
10701  }
10702  if( redundant )
10703  {
10704  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, conss[c]) );
10705  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
10706  ++*ndelconss;
10707  *result = SCIP_SUCCESS;
10708  break;
10709  }
10710  if( solveresult == SCIP_SUCCESS )
10711  {
10712  *result = SCIP_SUCCESS;
10713  havechange = TRUE;
10714  }
10715 
10716  /* @todo divide constraint by gcd of coefficients if all are integral */
10717 
10718  if( doreformulations )
10719  {
10720  int naddconss_old;
10721 
10722  naddconss_old = *naddconss;
10723 
10724  SCIP_CALL( presolveTryAddAND(scip, conshdlr, conss[c], naddconss) );
10725  assert(*naddconss >= naddconss_old);
10726 
10727  if( *naddconss == naddconss_old )
10728  {
10729  /* user not so empathic about AND, or we don't have products of two binaries, so try this more general reformulation */
10730  SCIP_CALL( presolveTryAddLinearReform(scip, conshdlr, conss[c], naddconss) );
10731  assert(*naddconss >= naddconss_old);
10732  }
10733 
10734  if( conshdlrdata->disaggregate )
10735  {
10736  /* try disaggregation, if enabled */
10737  SCIP_CALL( presolveDisaggregate(scip, conshdlr, conss[c], naddconss) );
10738  }
10739 
10740  if( *naddconss > naddconss_old )
10741  {
10742  /* if something happened, report success and cleanup constraint */
10743  *result = SCIP_SUCCESS;
10744  havechange = TRUE;
10745  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
10746  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
10747  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
10748  }
10749  }
10750 
10751  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
10752  {
10753  /* all variables fixed or removed, constraint function is 0.0 now */
10754  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, conss[c]) ); /* well, there shouldn't be any variables left anyway */
10755  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
10756  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
10757  { /* left hand side positive or right hand side negative */
10758  SCIPdebugMessage("constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
10759  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
10760  ++*ndelconss;
10761  *result = SCIP_CUTOFF;
10762  return SCIP_OKAY;
10763  }
10764 
10765  /* left and right hand side are consistent */
10766  SCIPdebugMessage("constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
10767  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
10768  ++*ndelconss;
10769  *result = SCIP_SUCCESS;
10770  continue;
10771  }
10772 
10773  if( !consdata->ispropagated )
10774  {
10775  /* try domain propagation if there were bound changes or constraint has changed (in which case, processVarEvents may have set ispropagated to false) */
10776  SCIP_RESULT propresult;
10777  int roundnr;
10778 
10779  roundnr = 0;
10780  do
10781  {
10782  ++roundnr;
10783 
10784  SCIPdebugMessage("starting domain propagation round %d of %d\n", roundnr, conshdlrdata->maxproproundspresolve);
10785 
10786  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
10787 
10788  if( propresult == SCIP_CUTOFF )
10789  {
10790  SCIPdebugMessage("propagation on constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
10791  *result = SCIP_CUTOFF;
10792  return SCIP_OKAY;
10793  }
10794 
10795  /* delete constraint if found redundant by bound tightening */
10796  if( redundant )
10797  {
10798  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, conss[c]) );
10799  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
10800  ++*ndelconss;
10801  *result = SCIP_SUCCESS;
10802  break;
10803  }
10804 
10805  if( propresult == SCIP_REDUCEDDOM )
10806  {
10807  *result = SCIP_SUCCESS;
10808  havechange = TRUE;
10809  }
10810 
10811  }
10812  while( !consdata->ispropagated && roundnr < conshdlrdata->maxproproundspresolve );
10813 
10814  if( redundant )
10815  continue;
10816  }
10817 
10818  /* check if we have a single linear continuous variable that we can make implicit integer */
10819  if( (nnewchgvartypes != 0 || havechange || !consdata->ispresolved)
10820  && (SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->lhs)) )
10821  {
10822  int ncontvar;
10823  SCIP_VAR* candidate;
10824  SCIP_Bool fail;
10825 
10826  fail = FALSE;
10827  candidate = NULL;
10828  ncontvar = 0;
10829 
10830  for( i = 0; !fail && i < consdata->nlinvars; ++i )
10831  {
10832  if( !SCIPisIntegral(scip, consdata->lincoefs[i]) )
10833  {
10834  fail = TRUE;
10835  }
10836  else if( SCIPvarGetType(consdata->linvars[i]) == SCIP_VARTYPE_CONTINUOUS )
10837  {
10838  if( ncontvar > 0 ) /* now at 2nd continuous variable */
10839  fail = TRUE;
10840  else if( SCIPisEQ(scip, ABS(consdata->lincoefs[i]), 1.0) )
10841  candidate = consdata->linvars[i];
10842  ++ncontvar;
10843  }
10844  }
10845  for( i = 0; !fail && i < consdata->nquadvars; ++i )
10846  fail = SCIPvarGetType(consdata->quadvarterms[i].var) == SCIP_VARTYPE_CONTINUOUS ||
10847  !SCIPisIntegral(scip, consdata->quadvarterms[i].lincoef) ||
10848  !SCIPisIntegral(scip, consdata->quadvarterms[i].sqrcoef);
10849  for( i = 0; !fail && i < consdata->nbilinterms; ++i )
10850  fail = !SCIPisIntegral(scip, consdata->bilinterms[i].coef);
10851 
10852  if( !fail && candidate != NULL )
10853  {
10854  SCIP_Bool infeasible;
10855 
10856  SCIPdebugMessage("make variable <%s> implicit integer due to constraint <%s>\n", SCIPvarGetName(candidate), SCIPconsGetName(conss[c]));
10857 
10858  SCIP_CALL( SCIPchgVarType(scip, candidate, SCIP_VARTYPE_IMPLINT, &infeasible) );
10859  if( infeasible )
10860  {
10861  SCIPdebugMessage("infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(candidate));
10862  *result = SCIP_CUTOFF;
10863 
10864  return SCIP_OKAY;
10865  }
10866 
10867  ++(*nchgvartypes);
10868  *result = SCIP_SUCCESS;
10869  havechange = TRUE;
10870  }
10871  }
10872 
10873  /* call upgrade methods again if constraint has been changed */
10874  if( havechange )
10875  {
10876  SCIP_Bool upgraded;
10877 
10878  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10879  if( upgraded )
10880  {
10881  *result = SCIP_SUCCESS;
10882  continue;
10883  }
10884  }
10885 
10886  consdata->ispresolved = TRUE;
10887  }
10888 
10889  /* if we did not try reformulations, ensure that presolving is called again even if there were only a few changes (< abortfac) */
10890  if( !doreformulations )
10891  *result = SCIP_DELAYED;
10892 
10893  return SCIP_OKAY;
10894 }
10895 
10896 /** variable rounding lock method of constraint handler */
10897 static
10898 SCIP_DECL_CONSLOCK(consLockQuadratic)
10899 { /*lint --e{715}*/
10900  SCIP_CONSDATA* consdata;
10901  SCIP_Bool haslb;
10902  SCIP_Bool hasub;
10903  int i;
10904 
10905  assert(scip != NULL);
10906  assert(cons != NULL);
10907 
10908  consdata = SCIPconsGetData(cons);
10909  assert(consdata != NULL);
10910 
10911  haslb = !SCIPisInfinity(scip, -consdata->lhs);
10912  hasub = !SCIPisInfinity(scip, consdata->rhs);
10913 
10914  for( i = 0; i < consdata->nlinvars; ++i )
10915  {
10916  if( consdata->lincoefs[i] > 0 )
10917  {
10918  if( haslb )
10919  {
10920  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
10921  }
10922  if( hasub )
10923  {
10924  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
10925  }
10926  }
10927  else
10928  {
10929  if( haslb )
10930  {
10931  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
10932  }
10933  if( hasub )
10934  {
10935  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
10936  }
10937  }
10938  }
10939 
10940  for( i = 0; i < consdata->nquadvars; ++i )
10941  {
10942  /* @todo try to be more clever, but variable locks that depend on the bounds of other variables are not trival to maintain */
10943  SCIP_CALL( SCIPaddVarLocks(scip, consdata->quadvarterms[i].var, nlockspos+nlocksneg, nlockspos+nlocksneg) );
10944  }
10945 
10946  return SCIP_OKAY;
10947 }
10948 
10949 /** constraint display method of constraint handler */
10950 static
10951 SCIP_DECL_CONSPRINT(consPrintQuadratic)
10952 { /*lint --e{715}*/
10953  SCIP_CONSDATA* consdata;
10954 
10955  assert(scip != NULL);
10956  assert(cons != NULL);
10957 
10958  consdata = SCIPconsGetData(cons);
10959  assert(consdata != NULL);
10960 
10961  /* print left hand side for ranged rows */
10962  if( !SCIPisInfinity(scip, -consdata->lhs)
10963  && !SCIPisInfinity(scip, consdata->rhs)
10964  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10965  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
10966 
10967  /* print coefficients and variables */
10968  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
10969  {
10970  SCIPinfoMessage(scip, file, "0 ");
10971  }
10972  else
10973  {
10974  SCIP_VAR*** monomialvars;
10975  SCIP_Real** monomialexps;
10976  SCIP_Real* monomialcoefs;
10977  int* monomialnvars;
10978  int nmonomials;
10979  int monomialssize;
10980  int j;
10981 
10982  monomialssize = consdata->nlinvars + 2 * consdata->nquadvars + consdata->nbilinterms;
10983  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, monomialssize) );
10984  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps, monomialssize) );
10985  SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, monomialssize) );
10986  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, monomialssize) );
10987 
10988  nmonomials = 0;
10989  for( j = 0; j < consdata->nlinvars; ++j )
10990  {
10991  assert(nmonomials < monomialssize);
10992 
10993  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
10994 
10995  monomialvars[nmonomials][0] = consdata->linvars[j];
10996  monomialexps[nmonomials] = NULL;
10997  monomialcoefs[nmonomials] = consdata->lincoefs[j];
10998  monomialnvars[nmonomials] = 1;
10999  ++nmonomials;
11000  }
11001 
11002  for( j = 0; j < consdata->nquadvars; ++j )
11003  {
11004  if( consdata->quadvarterms[j].lincoef != 0.0 )
11005  {
11006  assert(nmonomials < monomialssize);
11007 
11008  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
11009 
11010  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
11011  monomialexps[nmonomials] = NULL;
11012  monomialcoefs[nmonomials] = consdata->quadvarterms[j].lincoef;
11013  monomialnvars[nmonomials] = 1;
11014  ++nmonomials;
11015  }
11016 
11017  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
11018  {
11019  assert(nmonomials < monomialssize);
11020 
11021  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
11022  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps[nmonomials], 1) ); /*lint !e866 */
11023 
11024  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
11025  monomialexps[nmonomials][0] = 2.0;
11026  monomialcoefs[nmonomials] = consdata->quadvarterms[j].sqrcoef;
11027  monomialnvars[nmonomials] = 1;
11028  ++nmonomials;
11029  }
11030  }
11031 
11032  for( j = 0; j < consdata->nbilinterms; ++j )
11033  {
11034  assert(nmonomials < monomialssize);
11035 
11036  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 2) ); /*lint !e866 */
11037 
11038  monomialvars[nmonomials][0] = consdata->bilinterms[j].var1;
11039  monomialvars[nmonomials][1] = consdata->bilinterms[j].var2;
11040  monomialexps[nmonomials] = NULL;
11041  monomialcoefs[nmonomials] = consdata->bilinterms[j].coef;
11042  monomialnvars[nmonomials] = 2;
11043  ++nmonomials;
11044  }
11045 
11046  SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, monomialexps, monomialcoefs, monomialnvars, nmonomials, TRUE) );
11047 
11048  for( j = 0; j < nmonomials; ++j )
11049  {
11050  SCIPfreeBufferArray(scip, &monomialvars[j]);
11051  SCIPfreeBufferArrayNull(scip, &monomialexps[j]);
11052  }
11053 
11054  SCIPfreeBufferArray(scip, &monomialvars);
11055  SCIPfreeBufferArray(scip, &monomialexps);
11056  SCIPfreeBufferArray(scip, &monomialcoefs);
11057  SCIPfreeBufferArray(scip, &monomialnvars);
11058  }
11059 
11060  /* print right hand side */
11061  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11062  {
11063  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
11064  }
11065  else if( !SCIPisInfinity(scip, consdata->rhs) )
11066  {
11067  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
11068  }
11069  else if( !SCIPisInfinity(scip, -consdata->lhs) )
11070  {
11071  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
11072  }
11073  else
11074  {
11075  /* should be ignored by parser */
11076  SCIPinfoMessage(scip, file, " [free]");
11077  }
11078 
11079  return SCIP_OKAY;
11080 }
11081 
11082 /** feasibility check method of constraint handler for integral solutions */
11083 static
11084 SCIP_DECL_CONSCHECK(consCheckQuadratic)
11085 { /*lint --e{715}*/
11086  SCIP_CONSHDLRDATA* conshdlrdata;
11087  SCIP_CONSDATA* consdata;
11088  SCIP_Real maxviol;
11089  int c;
11090  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
11091 
11092  assert(scip != NULL);
11093  assert(conss != NULL || nconss == 0);
11094  assert(result != NULL);
11095 
11096  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11097  assert(conshdlrdata != NULL);
11098 
11099  *result = SCIP_FEASIBLE;
11100 
11101  maxviol = 0.0;
11102  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
11104  for( c = 0; c < nconss; ++c )
11105  {
11106  assert(conss != NULL);
11107  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
11108 
11109  consdata = SCIPconsGetData(conss[c]);
11110  assert(consdata != NULL);
11111 
11112  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11113  {
11114  *result = SCIP_INFEASIBLE;
11115  if( printreason )
11116  {
11117  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11118  SCIPinfoMessage(scip, NULL, ";\n");
11119  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
11120  {
11121  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
11122  }
11123  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11124  {
11125  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
11126  }
11127  }
11128  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible )
11129  return SCIP_OKAY;
11130  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
11131  maxviol = consdata->lhsviol + consdata->rhsviol;
11132 
11133  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11134  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
11135  maypropfeasible = FALSE;
11136 
11137  if( maypropfeasible )
11138  {
11139  /* update information on linear variables that may be in- or decreased */
11140  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
11141  consdataFindUnlockedLinearVar(scip, consdata);
11142 
11143  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
11144  {
11145  /* check if there is a variable which may help to get the left hand side satisfied
11146  * if there is no such var, then we cannot get feasible */
11147  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
11148  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
11149  maypropfeasible = FALSE;
11150  }
11151  else
11152  {
11153  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
11154  /* check if there is a variable which may help to get the right hand side satisfied
11155  * if there is no such var, then we cannot get feasible */
11156  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
11157  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
11158  maypropfeasible = FALSE;
11159  }
11160  }
11161  }
11162  }
11163 
11164  if( *result == SCIP_INFEASIBLE && maypropfeasible )
11165  {
11166  SCIP_Bool success;
11167 
11168  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11169 
11170  /* do not pass solution to NLP heuristic if we made it feasible this way */
11171  if( success )
11172  return SCIP_OKAY;
11173  }
11174 
11175  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL )
11176  {
11177  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11178  }
11179 
11180  return SCIP_OKAY;
11181 }
11182 
11183 /** constraint copying method of constraint handler */
11184 static
11185 SCIP_DECL_CONSCOPY(consCopyQuadratic)
11186 {
11187  SCIP_CONSDATA* consdata;
11188  SCIP_CONSDATA* targetconsdata;
11189  SCIP_VAR** linvars;
11190  SCIP_QUADVARTERM* quadvarterms;
11191  SCIP_BILINTERM* bilinterms;
11192  int i;
11193  int j;
11194  int k;
11195 
11196  assert(scip != NULL);
11197  assert(cons != NULL);
11198  assert(sourcescip != NULL);
11199  assert(sourceconshdlr != NULL);
11200  assert(sourcecons != NULL);
11201  assert(varmap != NULL);
11202  assert(valid != NULL);
11203 
11204  consdata = SCIPconsGetData(sourcecons);
11205  assert(consdata != NULL);
11206 
11207  linvars = NULL;
11208  quadvarterms = NULL;
11209  bilinterms = NULL;
11210 
11211  *valid = TRUE;
11212 
11213  if( consdata->nlinvars != 0 )
11214  {
11215  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
11216  for( i = 0; i < consdata->nlinvars; ++i )
11217  {
11218  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
11219  assert(!(*valid) || linvars[i] != NULL);
11220 
11221  /* we do not copy, if a variable is missing */
11222  if( !(*valid) )
11223  goto TERMINATE;
11224  }
11225  }
11226 
11227  if( consdata->nbilinterms != 0 )
11228  {
11229  SCIP_CALL( SCIPallocBufferArray(sourcescip, &bilinterms, consdata->nbilinterms) );
11230  }
11231 
11232  if( consdata->nquadvars != 0 )
11233  {
11234  SCIP_CALL( SCIPallocBufferArray(sourcescip, &quadvarterms, consdata->nquadvars) );
11235  for( i = 0; i < consdata->nquadvars; ++i )
11236  {
11237  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->quadvarterms[i].var, &quadvarterms[i].var, varmap, consmap, global, valid) );
11238  assert(!(*valid) || quadvarterms[i].var != NULL);
11239 
11240  /* we do not copy, if a variable is missing */
11241  if( !(*valid) )
11242  goto TERMINATE;
11243 
11244  quadvarterms[i].lincoef = consdata->quadvarterms[i].lincoef;
11245  quadvarterms[i].sqrcoef = consdata->quadvarterms[i].sqrcoef;
11246  quadvarterms[i].eventdata = NULL;
11247  quadvarterms[i].nadjbilin = consdata->quadvarterms[i].nadjbilin;
11248  quadvarterms[i].adjbilin = consdata->quadvarterms[i].adjbilin;
11249 
11250  assert(consdata->nbilinterms != 0 || consdata->quadvarterms[i].nadjbilin == 0);
11251 
11252  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
11253  {
11254  assert(bilinterms != NULL);
11255 
11256  k = consdata->quadvarterms[i].adjbilin[j];
11257  assert(consdata->bilinterms[k].var1 != NULL);
11258  assert(consdata->bilinterms[k].var2 != NULL);
11259  if( consdata->bilinterms[k].var1 == consdata->quadvarterms[i].var )
11260  {
11261  assert(consdata->bilinterms[k].var2 != consdata->quadvarterms[i].var);
11262  bilinterms[k].var1 = quadvarterms[i].var;
11263  }
11264  else
11265  {
11266  assert(consdata->bilinterms[k].var2 == consdata->quadvarterms[i].var);
11267  bilinterms[k].var2 = quadvarterms[i].var;
11268  }
11269  bilinterms[k].coef = consdata->bilinterms[k].coef;
11270  }
11271  }
11272  }
11273 
11274  assert(stickingatnode == FALSE);
11275  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name ? name : SCIPconsGetName(sourcecons),
11276  consdata->nlinvars, linvars, consdata->lincoefs,
11277  consdata->nquadvars, quadvarterms,
11278  consdata->nbilinterms, bilinterms,
11279  consdata->lhs, consdata->rhs,
11280  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11281 
11282  /* copy information on curvature */
11283  targetconsdata = SCIPconsGetData(*cons);
11284  targetconsdata->isconvex = consdata->isconvex;
11285  targetconsdata->isconcave = consdata->isconcave;
11286  targetconsdata->iscurvchecked = consdata->iscurvchecked;
11287 
11288  TERMINATE:
11289  SCIPfreeBufferArrayNull(sourcescip, &quadvarterms);
11290  SCIPfreeBufferArrayNull(sourcescip, &bilinterms);
11291  SCIPfreeBufferArrayNull(sourcescip, &linvars);
11292 
11293  return SCIP_OKAY;
11294 }
11295 
11296 /** constraint parsing method of constraint handler */
11297 static
11298 SCIP_DECL_CONSPARSE(consParseQuadratic)
11299 { /*lint --e{715}*/
11300  SCIP_VAR*** monomialvars;
11301  SCIP_Real** monomialexps;
11302  SCIP_Real* monomialcoefs;
11303  char* endptr;
11304  int* monomialnvars;
11305  int nmonomials;
11306 
11307  SCIP_Real lhs;
11308  SCIP_Real rhs;
11309 
11310  assert(scip != NULL);
11311  assert(success != NULL);
11312  assert(str != NULL);
11313  assert(name != NULL);
11314  assert(cons != NULL);
11315 
11316  /* set left and right hand side to their default values */
11317  lhs = -SCIPinfinity(scip);
11318  rhs = SCIPinfinity(scip);
11319 
11320  (*success) = FALSE;
11321 
11322  /* return of string empty */
11323  if( !*str )
11324  return SCIP_OKAY;
11325 
11326  /* ignore whitespace */
11327  while( isspace((unsigned char)*str) )
11328  ++str;
11329 
11330  /* check for left hand side */
11331  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
11332  {
11333  /* there is a number coming, maybe it is a left-hand-side */
11334  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
11335  {
11336  SCIPerrorMessage("error parsing number from <%s>\n", str);
11337  return SCIP_OKAY;
11338  }
11339 
11340  /* ignore whitespace */
11341  while( isspace((unsigned char)*endptr) )
11342  ++endptr;
11343 
11344  if( endptr[0] != '<' || endptr[1] != '=' )
11345  {
11346  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
11347  lhs = -SCIPinfinity(scip);
11348  }
11349  else
11350  {
11351  /* it was indeed a left-hand-side, so continue parsing after it */
11352  str = endptr + 2;
11353 
11354  /* ignore whitespace */
11355  while( isspace((unsigned char)*str) )
11356  ++str;
11357  }
11358  }
11359 
11360  SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, &endptr, success) );
11361 
11362  if( *success )
11363  {
11364  /* check for right hand side */
11365  str = endptr;
11366 
11367  /* ignore whitespace */
11368  while( isspace((unsigned char)*str) )
11369  ++str;
11370 
11371  if( *str && str[0] == '<' && str[1] == '=' )
11372  {
11373  /* we seem to get a right-hand-side */
11374  str += 2;
11375 
11376  if( !SCIPstrToRealValue(str, &rhs, &endptr) )
11377  {
11378  SCIPerrorMessage("error parsing right-hand-side from %s\n", str);
11379  *success = FALSE;
11380  }
11381  }
11382  else if( *str && str[0] == '>' && str[1] == '=' )
11383  {
11384  /* we seem to get a left-hand-side */
11385  str += 2;
11386 
11387  /* we should not have a left-hand-side already */
11388  assert(SCIPisInfinity(scip, -lhs));
11389 
11390  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
11391  {
11392  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
11393  *success = FALSE;
11394  }
11395  }
11396  else if( *str && str[0] == '=' && str[1] == '=' )
11397  {
11398  /* we seem to get a left- and right-hand-side */
11399  str += 2;
11400 
11401  /* we should not have a left-hand-side already */
11402  assert(SCIPisInfinity(scip, -lhs));
11403 
11404  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
11405  {
11406  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
11407  *success = FALSE;
11408  }
11409  else
11410  {
11411  rhs = lhs;
11412  }
11413  }
11414  }
11415 
11416  if( *success )
11417  {
11418  int i;
11419 
11420  /* setup constraint */
11421  assert(stickingatnode == FALSE);
11422  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL,
11423  0, NULL, NULL, NULL, lhs, rhs,
11424  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11425 
11426  for( i = 0; i < nmonomials; ++i )
11427  {
11428  if( monomialnvars[i] == 0 )
11429  {
11430  /* constant monomial */
11431  SCIPaddConstantQuadratic(scip, *cons, monomialcoefs[i]);
11432  }
11433  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 1.0 )
11434  {
11435  /* linear monomial */
11436  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, *cons, monomialvars[i][0], monomialcoefs[i]) );
11437  }
11438  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 2.0 )
11439  {
11440  /* square monomial */
11441  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, monomialvars[i][0], 0.0, monomialcoefs[i]) );
11442  }
11443  else if( monomialnvars[i] == 2 && monomialexps[i][0] == 1.0 && monomialexps[i][1] == 1.0 )
11444  {
11445  /* bilinear term */
11446  SCIP_VAR* var1;
11447  SCIP_VAR* var2;
11448  int pos;
11449 
11450  var1 = monomialvars[i][0];
11451  var2 = monomialvars[i][1];
11452  if( var1 == var2 )
11453  {
11454  /* actually a square term */
11455  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, monomialcoefs[i]) );
11456  }
11457  else
11458  {
11459  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var1, &pos) );
11460  if( pos == -1 )
11461  {
11462  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, 0.0) );
11463  }
11464 
11465  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var2, &pos) );
11466  if( pos == -1 )
11467  {
11468  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var2, 0.0, 0.0) );
11469  }
11470  }
11471 
11472  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, *cons, var1, var2, monomialcoefs[i]) );
11473  }
11474  else
11475  {
11476  SCIPerrorMessage("polynomial in quadratic constraint does not have degree at most 2\n");
11477  *success = FALSE;
11478  SCIP_CALL( SCIPreleaseCons(scip, cons) );
11479  break;
11480  }
11481  }
11482  }
11483 
11484  SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
11485 
11486  return SCIP_OKAY;
11487 }
11488 
11489 /** constraint method of constraint handler which returns the variables (if possible) */
11490 static
11491 SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
11492 { /*lint --e{715}*/
11493  SCIP_CONSDATA* consdata;
11494 
11495  assert(cons != NULL);
11496  assert(success != NULL);
11497 
11498  consdata = SCIPconsGetData(cons);
11499  assert(consdata != NULL);
11500 
11501  if( varssize < consdata->nlinvars + consdata->nquadvars )
11502  (*success) = FALSE;
11503  else
11504  {
11505  int i;
11506 
11507  assert(vars != NULL);
11508 
11509  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
11510 
11511  for( i = 0; i < consdata->nquadvars; ++i )
11512  vars[consdata->nlinvars+i] = consdata->quadvarterms[i].var;
11513 
11514  (*success) = TRUE;
11515  }
11516 
11517  return SCIP_OKAY;
11518 }
11519 
11520 /** constraint method of constraint handler which returns the number of variables (if possible) */
11521 static
11522 SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
11523 { /*lint --e{715}*/
11524  SCIP_CONSDATA* consdata;
11525 
11526  assert(cons != NULL);
11527  assert(success != NULL);
11528 
11529  consdata = SCIPconsGetData(cons);
11530  assert(consdata != NULL);
11531 
11532  (*nvars) = consdata->nlinvars + consdata->nquadvars;
11533  (*success) = TRUE;
11534 
11535  return SCIP_OKAY;
11536 }
11537 
11538 
11539 /*
11540  * constraint specific interface methods
11541  */
11542 
11543 /** creates the handler for quadratic constraints and includes it in SCIP */
11545  SCIP* scip /**< SCIP data structure */
11546  )
11547 {
11548  SCIP_CONSHDLRDATA* conshdlrdata;
11549  SCIP_CONSHDLR* conshdlr;
11550 
11551  /* create quadratic constraint handler data */
11552  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
11553  BMSclearMemory(conshdlrdata);
11554 
11555  /* include constraint handler */
11558  consEnfolpQuadratic, consEnfopsQuadratic, consCheckQuadratic, consLockQuadratic,
11559  conshdlrdata) );
11560  assert(conshdlr != NULL);
11561 
11562 
11563  /* set non-fundamental callbacks via specific setter functions */
11564  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyQuadratic, consCopyQuadratic) );
11565  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteQuadratic) );
11566  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitQuadratic) );
11567  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreQuadratic) );
11568  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolQuadratic) );
11569  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeQuadratic) );
11570  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsQuadratic) );
11571  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsQuadratic) );
11572  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitQuadratic) );
11573  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolQuadratic) );
11574  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpQuadratic) );
11575  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseQuadratic) );
11576  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolQuadratic, CONSHDLR_MAXPREROUNDS, CONSHDLR_DELAYPRESOL) );
11577  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintQuadratic) );
11578  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropQuadratic, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
11580  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpQuadratic, consSepasolQuadratic, CONSHDLR_SEPAFREQ,
11582  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransQuadratic) );
11583 
11584  /* add quadratic constraint handler parameters */
11585  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/replacebinaryprod",
11586  "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)",
11587  &conshdlrdata->replacebinaryprodlength, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
11588 
11589  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/empathy4and",
11590  "empathy level for using the AND constraint handler: 0 always avoid using AND; 1 use AND sometimes; 2 use AND as often as possible",
11591  &conshdlrdata->empathy4and, FALSE, 0, 0, 2, NULL, NULL) );
11592 
11593  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/binreforminitial",
11594  "whether to make non-varbound linear constraints added due to replacing products with binary variables initial",
11595  &conshdlrdata->binreforminitial, TRUE, FALSE, NULL, NULL) );
11596 
11597  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/binreformmaxcoef",
11598  "limit (as factor on 1/feastol) on coefficients and coef. range in linear constraints created when replacing products with binary variables",
11599  &conshdlrdata->binreformmaxcoef, TRUE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
11600 
11601  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/minefficacysepa",
11602  "minimal efficacy for a cut to be added to the LP during separation; overwrites separating/efficacy",
11603  &conshdlrdata->mincutefficacysepa, TRUE, 0.0001, 0.0, SCIPinfinity(scip), NULL, NULL) );
11604 
11605  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/minefficacyenfofac",
11606  "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)",
11607  &conshdlrdata->mincutefficacyenfofac, TRUE, 2.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
11608 
11609  SCIP_CALL( SCIPaddCharParam(scip, "constraints/"CONSHDLR_NAME"/scaling",
11610  "whether scaling of infeasibility is 'o'ff, by sup-norm of function 'g'radient, or by left/right hand 's'ide",
11611  &conshdlrdata->scaling, TRUE, 'o', "ogs", NULL, NULL) );
11612 
11613  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/cutmaxrange",
11614  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
11615  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
11616 
11617  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/linearizeheursol",
11618  "whether linearizations of convex quadratic constraints should be added to cutpool in a solution found by some heuristic",
11619  &conshdlrdata->linearizeheursol, TRUE, TRUE, NULL, NULL) );
11620 
11621  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/checkcurvature",
11622  "whether multivariate quadratic functions should be checked for convexity/concavity",
11623  &conshdlrdata->checkcurvature, FALSE, TRUE, NULL, NULL) );
11624 
11625  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/checkfactorable",
11626  "whether constraint functions should be checked to be factorable",
11627  &conshdlrdata->checkfactorable, TRUE, TRUE, NULL, NULL) );
11628 
11629  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/linfeasshift",
11630  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
11631  &conshdlrdata->linfeasshift, TRUE, TRUE, NULL, NULL) );
11632 
11633  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/disaggregate",
11634  "whether to disaggregate quadratic parts that decompose into a sum of non-overlapping quadratic terms",
11635  &conshdlrdata->disaggregate, TRUE, FALSE, NULL, NULL) );
11636 
11637  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/maxproprounds",
11638  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve",
11639  &conshdlrdata->maxproprounds, TRUE, 1, 0, INT_MAX, NULL, NULL) );
11640 
11641  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/maxproproundspresolve",
11642  "limit on number of propagation rounds for a single constraint within one round of SCIP presolve",
11643  &conshdlrdata->maxproproundspresolve, TRUE, 10, 0, INT_MAX, NULL, NULL) );
11644 
11645  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/enfolplimit",
11646  "maximum number of enforcement rounds before declaring the LP relaxation infeasible (-1: no limit); WARNING: changing this parameter might lead to incorrect results!",
11647  &conshdlrdata->enfolplimit, TRUE, -1, -1, INT_MAX, NULL, NULL) );
11648 
11649  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/sepanlpmincont",
11650  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
11651  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
11652 
11653  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/enfocutsremovable",
11654  "are cuts added during enforcement removable from the LP in the same node?",
11655  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
11656 
11657  conshdlrdata->eventhdlr = NULL;
11658  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr),CONSHDLR_NAME"_boundchange", "signals a bound change to a quadratic constraint",
11659  processVarEvent, NULL) );
11660  assert(conshdlrdata->eventhdlr != NULL);
11661 
11662  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
11663  processNewSolutionEvent, NULL) );
11664 
11665  /* include the quadratic constraint upgrade in the nonlinear constraint handler */
11667 
11668  return SCIP_OKAY;
11669 }
11670 
11671 /** includes a quadratic constraint update method into the quadratic constraint handler */
11673  SCIP* scip, /**< SCIP data structure */
11674  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
11675  int priority, /**< priority of upgrading method */
11676  SCIP_Bool active, /**< should the upgrading method be active by default? */
11677  const char* conshdlrname /**< name of the constraint handler */
11678  )
11679 {
11680  SCIP_CONSHDLR* conshdlr;
11681  SCIP_CONSHDLRDATA* conshdlrdata;
11682  SCIP_QUADCONSUPGRADE* quadconsupgrade;
11683  char paramname[SCIP_MAXSTRLEN];
11684  char paramdesc[SCIP_MAXSTRLEN];
11685  int i;
11686 
11687  assert(quadconsupgd != NULL);
11688  assert(conshdlrname != NULL );
11689 
11690  /* find the quadratic constraint handler */
11691  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11692  if( conshdlr == NULL )
11693  {
11694  SCIPerrorMessage("quadratic constraint handler not found\n");
11695  return SCIP_PLUGINNOTFOUND;
11696  }
11697 
11698  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11699  assert(conshdlrdata != NULL);
11700 
11701  if( !conshdlrdataHasUpgrade(scip, conshdlrdata, quadconsupgd, conshdlrname) )
11702  {
11703  /* create a quadratic constraint upgrade data object */
11704  SCIP_CALL( SCIPallocMemory(scip, &quadconsupgrade) );
11705  quadconsupgrade->quadconsupgd = quadconsupgd;
11706  quadconsupgrade->priority = priority;
11707  quadconsupgrade->active = active;
11708 
11709  /* insert quadratic constraint upgrade method into constraint handler data */
11710  assert(conshdlrdata->nquadconsupgrades <= conshdlrdata->quadconsupgradessize);
11711  if( conshdlrdata->nquadconsupgrades+1 > conshdlrdata->quadconsupgradessize )
11712  {
11713  int newsize;
11714 
11715  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nquadconsupgrades+1);
11716  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->quadconsupgrades, newsize) );
11717  conshdlrdata->quadconsupgradessize = newsize;
11718  }
11719  assert(conshdlrdata->nquadconsupgrades+1 <= conshdlrdata->quadconsupgradessize);
11720 
11721  for( i = conshdlrdata->nquadconsupgrades; i > 0 && conshdlrdata->quadconsupgrades[i-1]->priority < quadconsupgrade->priority; --i )
11722  conshdlrdata->quadconsupgrades[i] = conshdlrdata->quadconsupgrades[i-1];
11723  assert(0 <= i && i <= conshdlrdata->nquadconsupgrades);
11724  conshdlrdata->quadconsupgrades[i] = quadconsupgrade;
11725  conshdlrdata->nquadconsupgrades++;
11726 
11727  /* adds parameter to turn on and off the upgrading step */
11728  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/"CONSHDLR_NAME"/upgrade/%s", conshdlrname);
11729  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable quadratic upgrading for constraint handler <%s>", conshdlrname);
11731  paramname, paramdesc,
11732  &quadconsupgrade->active, FALSE, active, NULL, NULL) );
11733  }
11734 
11735  return SCIP_OKAY;
11736 }
11737 
11738 /** Creates and captures a quadratic constraint.
11739  *
11740  * The constraint should be given in the form
11741  * \f[
11742  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_jz_j \leq u,
11743  * \f]
11744  * where \f$x_i = y_j = z_k\f$ is possible.
11745  *
11746  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11747  */
11749  SCIP* scip, /**< SCIP data structure */
11750  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11751  const char* name, /**< name of constraint */
11752  int nlinvars, /**< number of linear terms (n) */
11753  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
11754  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
11755  int nquadterms, /**< number of quadratic terms (m) */
11756  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
11757  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
11758  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
11759  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
11760  SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
11761  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11762  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11763  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11764  * Usually set to TRUE. */
11765  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11766  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11767  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11768  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11769  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11770  * Usually set to TRUE. */
11771  SCIP_Bool local, /**< is constraint only valid locally?
11772  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11773  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11774  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11775  * adds coefficients to this constraint. */
11776  SCIP_Bool dynamic, /**< is constraint subject to aging?
11777  * Usually set to FALSE. Set to TRUE for own cuts which
11778  * are separated as constraints. */
11779  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11780  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11781  )
11782 {
11783  SCIP_CONSHDLR* conshdlr;
11784  SCIP_CONSDATA* consdata;
11785  SCIP_HASHMAP* quadvaridxs;
11786  SCIP_Real sqrcoef;
11787  int i;
11788  int var1pos;
11789  int var2pos;
11790 
11791  int nbilinterms;
11792 
11793  assert(modifiable == FALSE); /* we do not support column generation */
11794 
11795  /* find the quadratic constraint handler */
11796  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11797  if( conshdlr == NULL )
11798  {
11799  SCIPerrorMessage("quadratic constraint handler not found\n");
11800  return SCIP_PLUGINNOTFOUND;
11801  }
11802 
11803  /* create constraint data and constraint */
11804  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
11805 
11806  consdata->lhs = lhs;
11807  consdata->rhs = rhs;
11808 
11809  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
11810  local, modifiable, dynamic, removable, FALSE) );
11811 
11812  /* add quadratic variables and remember their indices */
11813  SCIP_CALL( SCIPhashmapCreate(&quadvaridxs, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * nquadterms)) );
11814  nbilinterms = 0;
11815  for( i = 0; i < nquadterms; ++i )
11816  {
11817  if( SCIPisZero(scip, quadcoefs[i]) )
11818  continue;
11819 
11820  /* if it is actually a square term, remember it's coefficient */
11821  if( quadvars1[i] == quadvars2[i] )
11822  sqrcoef = quadcoefs[i];
11823  else
11824  sqrcoef = 0.0;
11825 
11826  /* add quadvars1[i], if not in there already */
11827  if( !SCIPhashmapExists(quadvaridxs, quadvars1[i]) )
11828  {
11829  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars1[i], 0.0, sqrcoef, FALSE) );
11830  assert(consdata->nquadvars >= 0);
11831  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars1[i]);
11832 
11833  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars1[i], (void*)(size_t)(consdata->nquadvars-1)) );
11834  }
11835  else if( !SCIPisZero(scip, sqrcoef) )
11836  {
11837  /* if it's there already, but we got a square coefficient, add it to the previous one */
11838  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]);
11839  assert(consdata->quadvarterms[var1pos].var == quadvars1[i]);
11840  consdata->quadvarterms[var1pos].sqrcoef += sqrcoef;
11841  }
11842 
11843  if( quadvars1[i] == quadvars2[i] )
11844  continue;
11845 
11846  /* add quadvars2[i], if not in there already */
11847  if( !SCIPhashmapExists(quadvaridxs, quadvars2[i]) )
11848  {
11849  assert(sqrcoef == 0.0);
11850  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars2[i], 0.0, 0.0, FALSE) );
11851  assert(consdata->nquadvars >= 0);
11852  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars2[i]);
11853 
11854  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars2[i], (void*)(size_t)(consdata->nquadvars-1)) );
11855  }
11856 
11857  ++nbilinterms;
11858  }
11859 
11860  /* add bilinear terms, if we saw any */
11861  if( nbilinterms > 0 )
11862  {
11863  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, nbilinterms) );
11864  for( i = 0; i < nquadterms; ++i )
11865  {
11866  if( SCIPisZero(scip, quadcoefs[i]) )
11867  continue;
11868 
11869  /* square terms have been taken care of already */
11870  if( quadvars1[i] == quadvars2[i] )
11871  continue;
11872 
11873  assert(SCIPhashmapExists(quadvaridxs, quadvars1[i]));
11874  assert(SCIPhashmapExists(quadvaridxs, quadvars2[i]));
11875 
11876  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]);
11877  var2pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars2[i]);
11878 
11879  SCIP_CALL( addBilinearTerm(scip, *cons, var1pos, var2pos, quadcoefs[i]) );
11880  }
11881  }
11882 
11883  /* add linear variables */
11884  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
11885  for( i = 0; i < nlinvars; ++i )
11886  {
11887  if( SCIPisZero(scip, lincoefs[i]) )
11888  continue;
11889 
11890  /* if it's a linear coefficient for a quadratic variable, add it there, otherwise add as linear variable */
11891  if( SCIPhashmapExists(quadvaridxs, linvars[i]) )
11892  {
11893  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, linvars[i]);
11894  assert(consdata->quadvarterms[var1pos].var == linvars[i]);
11895  consdata->quadvarterms[var1pos].lincoef += lincoefs[i];
11896  }
11897  else
11898  {
11899  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) );
11900  }
11901  }
11902 
11903  if( SCIPisTransformed(scip) )
11904  {
11905  SCIP_CONSHDLRDATA* conshdlrdata = SCIPconshdlrGetData(conshdlr);
11906  assert(conshdlrdata != NULL);
11907  assert(conshdlrdata->eventhdlr != NULL);
11908 
11909  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, *cons) );
11910  }
11911 
11912  SCIPhashmapFree(&quadvaridxs);
11913 
11914  /* merge duplicate bilinear terms, move quad terms that are linear to linear vars */
11915  SCIP_CALL( mergeAndCleanBilinearTerms(scip, *cons) );
11916  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, *cons) );
11917  SCIP_CALL( mergeAndCleanLinearVars(scip, *cons) );
11918 
11919  SCIPdebugMessage("created quadratic constraint ");
11920  SCIPdebugPrintCons(scip, *cons, NULL);
11921 
11922  return SCIP_OKAY;
11923 }
11924 
11925 /** creates and captures a quadratic constraint with all its
11926  * flags set to their default values.
11927  *
11928  * The constraint should be given in the form
11929  * \f[
11930  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_jz_j \leq u,
11931  * \f]
11932  * where \f$x_i = y_j = z_k\f$ is possible.
11933  *
11934  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11935  */
11937  SCIP* scip, /**< SCIP data structure */
11938  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11939  const char* name, /**< name of constraint */
11940  int nlinvars, /**< number of linear terms (n) */
11941  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
11942  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
11943  int nquadterms, /**< number of quadratic terms (m) */
11944  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
11945  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
11946  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
11947  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
11948  SCIP_Real rhs /**< right hand side of quadratic equation (u) */
11949  )
11950 {
11951  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, nlinvars, linvars, lincoefs,
11952  nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
11953  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11954 
11955  return SCIP_OKAY;
11956 }
11957 
11958 /** Creates and captures a quadratic constraint.
11959  *
11960  * The constraint should be given in the form
11961  * \f[
11962  * \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_kv_kw_k \leq u.
11963  * \f]
11964  *
11965  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11966  */
11968  SCIP* scip, /**< SCIP data structure */
11969  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11970  const char* name, /**< name of constraint */
11971  int nlinvars, /**< number of linear terms (n) */
11972  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
11973  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
11974  int nquadvarterms, /**< number of quadratic terms (m) */
11975  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
11976  int nbilinterms, /**< number of bilinear terms (p) */
11977  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
11978  SCIP_Real lhs, /**< constraint left hand side (ell) */
11979  SCIP_Real rhs, /**< constraint right hand side (u) */
11980  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
11981  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
11982  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
11983  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
11984  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
11985  SCIP_Bool local, /**< is constraint only valid locally? */
11986  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
11987  SCIP_Bool dynamic, /**< is constraint dynamic? */
11988  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
11989  )
11990 {
11991  SCIP_CONSHDLR* conshdlr;
11992  SCIP_CONSDATA* consdata;
11993 
11994  assert(modifiable == FALSE); /* we do not support column generation */
11995  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
11996  assert(nquadvarterms == 0 || quadvarterms != NULL);
11997  assert(nbilinterms == 0 || bilinterms != NULL);
11998 
11999  /* find the quadratic constraint handler */
12000  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12001  if( conshdlr == NULL )
12002  {
12003  SCIPerrorMessage("quadratic constraint handler not found\n");
12004  return SCIP_PLUGINNOTFOUND;
12005  }
12006 
12007  /* create constraint data */
12008  SCIP_CALL( consdataCreate(scip, &consdata, lhs, rhs,
12009  nlinvars, linvars, lincoefs, nquadvarterms, quadvarterms, nbilinterms, bilinterms,
12010  TRUE) );
12011 
12012  /* create constraint */
12013  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
12014  local, modifiable, dynamic, removable, FALSE) );
12015 
12016  if( SCIPisTransformed(scip) )
12017  {
12018  SCIP_CONSHDLRDATA* conshdlrdata = SCIPconshdlrGetData(conshdlr);
12019  assert(conshdlrdata != NULL);
12020  assert(conshdlrdata->eventhdlr != NULL);
12021 
12022  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, *cons) );
12023  }
12024 
12025  return SCIP_OKAY;
12026 }
12027 
12028 /** creates and captures a quadratic constraint in its most basic version, i.e.,
12029  * all constraint flags are set to their default values.
12030  *
12031  * The constraint should be given in the form
12032  * \f[
12033  * \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_kv_kw_k \leq u.
12034  * \f]
12035  *
12036  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12037  */
12039  SCIP* scip, /**< SCIP data structure */
12040  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12041  const char* name, /**< name of constraint */
12042  int nlinvars, /**< number of linear terms (n) */
12043  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
12044  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
12045  int nquadvarterms, /**< number of quadratic terms (m) */
12046  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
12047  int nbilinterms, /**< number of bilinear terms (p) */
12048  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
12049  SCIP_Real lhs, /**< constraint left hand side (ell) */
12050  SCIP_Real rhs /**< constraint right hand side (u) */
12051  )
12052 {
12053  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name, nlinvars, linvars, lincoefs,
12054  nquadvarterms, quadvarterms, nbilinterms, bilinterms, lhs, rhs,
12055  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
12056 
12057  return SCIP_OKAY;
12058 }
12059 
12060 
12061 /** Adds a constant to the constraint function, that is, subtracts a constant from both sides */
12063  SCIP* scip, /**< SCIP data structure */
12064  SCIP_CONS* cons, /**< constraint */
12065  SCIP_Real constant /**< constant to subtract from both sides */
12066  )
12067 {
12068  SCIP_CONSDATA* consdata;
12069 
12070  assert(scip != NULL);
12071  assert(cons != NULL);
12072  assert(!SCIPisInfinity(scip, REALABS(constant)));
12073 
12074  consdata = SCIPconsGetData(cons);
12075  assert(consdata != NULL);
12076  assert(consdata->lhs <= consdata->rhs);
12077 
12078  if( !SCIPisInfinity(scip, -consdata->lhs) )
12079  consdata->lhs -= constant;
12080  if( !SCIPisInfinity(scip, consdata->rhs) )
12081  consdata->rhs -= constant;
12082 
12083  if( consdata->lhs > consdata->rhs )
12084  {
12085  assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
12086  consdata->lhs = consdata->rhs;
12087  }
12088 }
12089 
12090 /** Adds a linear variable with coefficient to a quadratic constraint.
12091  */
12093  SCIP* scip, /**< SCIP data structure */
12094  SCIP_CONS* cons, /**< constraint */
12095  SCIP_VAR* var, /**< variable */
12096  SCIP_Real coef /**< coefficient of variable */
12097  )
12098 {
12099  assert(scip != NULL);
12100  assert(cons != NULL);
12101  assert(var != NULL);
12102  assert(!SCIPisInfinity(scip, REALABS(coef)));
12103 
12104  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
12105 
12106  return SCIP_OKAY;
12107 }
12108 
12109 /** Adds a quadratic variable with linear and square coefficient to a quadratic constraint.
12110  */
12112  SCIP* scip, /**< SCIP data structure */
12113  SCIP_CONS* cons, /**< constraint */
12114  SCIP_VAR* var, /**< variable */
12115  SCIP_Real lincoef, /**< linear coefficient of variable */
12116  SCIP_Real sqrcoef /**< square coefficient of variable */
12117  )
12118 {
12119  assert(scip != NULL);
12120  assert(cons != NULL);
12121  assert(var != NULL);
12122  assert(!SCIPisInfinity(scip, REALABS(lincoef)));
12123  assert(!SCIPisInfinity(scip, REALABS(sqrcoef)));
12124 
12125  SCIP_CALL( addQuadVarTerm(scip, cons, var, lincoef, sqrcoef, SCIPconsIsTransformed(cons)) );
12126 
12127  return SCIP_OKAY;
12128 }
12129 
12130 /** Adds a linear coefficient for a quadratic variable.
12131  *
12132  * Variable will be added with square coefficient 0.0 if not existing yet.
12133  */
12135  SCIP* scip, /**< SCIP data structure */
12136  SCIP_CONS* cons, /**< constraint */
12137  SCIP_VAR* var, /**< variable */
12138  SCIP_Real coef /**< value to add to linear coefficient of variable */
12139  )
12140 {
12141  SCIP_CONSDATA* consdata;
12142  int pos;
12143 
12144  assert(scip != NULL);
12145  assert(cons != NULL);
12146  assert(var != NULL);
12147  assert(!SCIPisInfinity(scip, REALABS(coef)));
12148 
12149  if( SCIPisZero(scip, coef) )
12150  return SCIP_OKAY;
12151 
12152  consdata = SCIPconsGetData(cons);
12153  assert(consdata != NULL);
12154 
12155  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
12156  if( pos < 0 )
12157  {
12158  SCIP_CALL( addQuadVarTerm(scip, cons, var, coef, 0.0, SCIPconsIsTransformed(cons)) );
12159  return SCIP_OKAY;
12160  }
12161  assert(pos < consdata->nquadvars);
12162  assert(consdata->quadvarterms[pos].var == var);
12163 
12164  consdata->quadvarterms[pos].lincoef += coef;
12165 
12166  /* update flags and invalid activities */
12167  consdata->ispropagated = FALSE;
12168  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].lincoef);
12169 
12170  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
12171  consdata->activity = SCIP_INVALID;
12172 
12173  return SCIP_OKAY;
12174 }
12175 
12176 /** Adds a square coefficient for a quadratic variable.
12177  *
12178  * Variable will be added with linear coefficient 0.0 if not existing yet.
12179  */
12181  SCIP* scip, /**< SCIP data structure */
12182  SCIP_CONS* cons, /**< constraint */
12183  SCIP_VAR* var, /**< variable */
12184  SCIP_Real coef /**< value to add to square coefficient of variable */
12185  )
12186 {
12187  SCIP_CONSDATA* consdata;
12188  int pos;
12189 
12190  assert(scip != NULL);
12191  assert(cons != NULL);
12192  assert(var != NULL);
12193  assert(!SCIPisInfinity(scip, REALABS(coef)));
12194 
12195  if( SCIPisZero(scip, coef) )
12196  return SCIP_OKAY;
12197 
12198  consdata = SCIPconsGetData(cons);
12199  assert(consdata != NULL);
12200 
12201  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
12202  if( pos < 0 )
12203  {
12204  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef, SCIPconsIsTransformed(cons)) );
12205  return SCIP_OKAY;
12206  }
12207  assert(pos < consdata->nquadvars);
12208  assert(consdata->quadvarterms[pos].var == var);
12209 
12210  consdata->quadvarterms[pos].sqrcoef += coef;
12211 
12212  /* update flags and invalid activities */
12213  consdata->isconvex = FALSE;
12214  consdata->isconcave = FALSE;
12215  consdata->iscurvchecked = FALSE;
12216  consdata->ispropagated = FALSE;
12217  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].sqrcoef);
12218 
12219  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
12220  consdata->activity = SCIP_INVALID;
12221 
12222  return SCIP_OKAY;
12223 }
12224 
12225 /** Adds a bilinear term to a quadratic constraint.
12226  *
12227  * Variables will be added with linear and square coefficient 0.0 if not existing yet.
12228  * If variables are equal, only the square coefficient of the variable is updated.
12229  */
12231  SCIP* scip, /**< SCIP data structure */
12232  SCIP_CONS* cons, /**< constraint */
12233  SCIP_VAR* var1, /**< first variable */
12234  SCIP_VAR* var2, /**< second variable */
12235  SCIP_Real coef /**< coefficient of bilinear term */
12236  )
12237 {
12238  SCIP_CONSDATA* consdata;
12239  int var1pos;
12240  int var2pos;
12241 
12242  assert(scip != NULL);
12243  assert(cons != NULL);
12244  assert(var1 != NULL);
12245  assert(var2 != NULL);
12246  assert(!SCIPisInfinity(scip, REALABS(coef)));
12247 
12248  if( var1 == var2 )
12249  {
12250  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, cons, var1, coef) );
12251  return SCIP_OKAY;
12252  }
12253 
12254  consdata = SCIPconsGetData(cons);
12255  assert(consdata != NULL);
12256 
12257  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
12258  if( var1pos < 0 )
12259  {
12260  SCIP_CALL( addQuadVarTerm(scip, cons, var1, 0.0, 0.0, SCIPconsIsTransformed(cons)) );
12261  var1pos = consdata->nquadvars-1;
12262  }
12263 
12264  if( !consdata->quadvarssorted )
12265  {
12266  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
12267  /* sorting may change the position of var1 */
12268  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
12269  assert(var1pos >= 0);
12270  }
12271 
12272  assert(consdata->quadvarssorted);
12273  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var2, &var2pos) );
12274  if( var2pos < 0 )
12275  {
12276  SCIP_CALL( addQuadVarTerm(scip, cons, var2, 0.0, 0.0, SCIPconsIsTransformed(cons)) );
12277  var2pos = consdata->nquadvars-1;
12278  }
12279 
12280  assert(consdata->quadvarterms[var1pos].var == var1);
12281  assert(consdata->quadvarterms[var2pos].var == var2);
12282 
12283  SCIP_CALL( addBilinearTerm(scip, cons, var1pos, var2pos, coef) );
12284 
12285  return SCIP_OKAY;
12286 }
12287 
12288 /** Gets the quadratic constraint as a nonlinear row representation.
12289  */
12291  SCIP* scip, /**< SCIP data structure */
12292  SCIP_CONS* cons, /**< constraint */
12293  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
12294  )
12295 {
12296  SCIP_CONSDATA* consdata;
12297 
12298  assert(cons != NULL);
12299  assert(nlrow != NULL);
12300 
12301  consdata = SCIPconsGetData(cons);
12302  assert(consdata != NULL);
12303 
12304  if( consdata->nlrow == NULL )
12305  {
12306  SCIP_CALL( createNlRow(scip, cons) );
12307  }
12308  assert(consdata->nlrow != NULL);
12309  *nlrow = consdata->nlrow;
12310 
12311  return SCIP_OKAY;
12312 }
12313 
12314 /** Gets the number of variables in the linear term of a quadratic constraint.
12315  */
12317  SCIP* scip, /**< SCIP data structure */
12318  SCIP_CONS* cons /**< constraint */
12319  )
12320 {
12321  assert(cons != NULL);
12322  assert(SCIPconsGetData(cons) != NULL);
12323 
12324  return SCIPconsGetData(cons)->nlinvars;
12325 }
12326 
12327 /** Gets the variables in the linear part of a quadratic constraint.
12328  * Length is given by SCIPgetNLinearVarsQuadratic.
12329  */
12331  SCIP* scip, /**< SCIP data structure */
12332  SCIP_CONS* cons /**< constraint */
12333  )
12334 {
12335  assert(cons != NULL);
12336  assert(SCIPconsGetData(cons) != NULL);
12337 
12338  return SCIPconsGetData(cons)->linvars;
12339 }
12340 
12341 /** Gets the coefficients in the linear part of a quadratic constraint.
12342  * Length is given by SCIPgetNLinearVarsQuadratic.
12343  */
12345  SCIP* scip, /**< SCIP data structure */
12346  SCIP_CONS* cons /**< constraint */
12347  )
12348 {
12349  assert(cons != NULL);
12350  assert(SCIPconsGetData(cons) != NULL);
12351 
12352  return SCIPconsGetData(cons)->lincoefs;
12353 }
12354 
12355 /** Gets the number of quadratic variable terms of a quadratic constraint.
12356  */
12358  SCIP* scip, /**< SCIP data structure */
12359  SCIP_CONS* cons /**< constraint */
12360  )
12361 {
12362  assert(cons != NULL);
12363  assert(SCIPconsGetData(cons) != NULL);
12364 
12365  return SCIPconsGetData(cons)->nquadvars;
12366 }
12367 
12368 /** Gets the quadratic variable terms of a quadratic constraint.
12369  * Length is given by SCIPgetNQuadVarTermsQuadratic.
12370  */
12372  SCIP* scip, /**< SCIP data structure */
12373  SCIP_CONS* cons /**< constraint */
12374  )
12375 {
12376  assert(cons != NULL);
12377  assert(SCIPconsGetData(cons) != NULL);
12378 
12379  return SCIPconsGetData(cons)->quadvarterms;
12380 }
12381 
12382 /** Ensures that quadratic variable terms are sorted. */
12384  SCIP* scip, /**< SCIP data structure */
12385  SCIP_CONS* cons /**< constraint */
12386  )
12387 {
12388  assert(cons != NULL);
12389  assert(SCIPconsGetData(cons) != NULL);
12390 
12392 
12393  return SCIP_OKAY;
12394 }
12395 
12396 /** Finds the position of a quadratic variable term for a given variable.
12397  *
12398  * @note If the quadratic variable terms have not been sorted before, then a search may reorder the current order of the terms.
12399  */
12401  SCIP* scip, /**< SCIP data structure */
12402  SCIP_CONS* cons, /**< constraint */
12403  SCIP_VAR* var, /**< variable to search for */
12404  int* pos /**< buffer to store position of quadvarterm for var, or -1 if not found */
12405  )
12406 {
12407  assert(cons != NULL);
12408  assert(SCIPconsGetData(cons) != NULL);
12409  assert(var != NULL);
12410  assert(pos != NULL);
12411 
12412  SCIP_CALL( consdataFindQuadVarTerm(scip, SCIPconsGetData(cons), var, pos) );
12413 
12414  return SCIP_OKAY;
12415 }
12416 
12417 /** Gets the number of bilinear terms of a quadratic constraint.
12418  */
12420  SCIP* scip, /**< SCIP data structure */
12421  SCIP_CONS* cons /**< constraint */
12422  )
12423 {
12424  assert(cons != NULL);
12425  assert(SCIPconsGetData(cons) != NULL);
12426 
12427  return SCIPconsGetData(cons)->nbilinterms;
12428 }
12429 
12430 /** Gets the bilinear terms of a quadratic constraint.
12431  * Length is given by SCIPgetNBilinTermQuadratic.
12432  */
12434  SCIP* scip, /**< SCIP data structure */
12435  SCIP_CONS* cons /**< constraint */
12436  )
12437 {
12438  assert(cons != NULL);
12439  assert(SCIPconsGetData(cons) != NULL);
12440 
12441  return SCIPconsGetData(cons)->bilinterms;
12442 }
12443 
12444 /** Gets the left hand side of a quadratic constraint.
12445  */
12447  SCIP* scip, /**< SCIP data structure */
12448  SCIP_CONS* cons /**< constraint */
12449  )
12450 {
12451  assert(cons != NULL);
12452  assert(SCIPconsGetData(cons) != NULL);
12453 
12454  return SCIPconsGetData(cons)->lhs;
12455 }
12456 
12457 /** Gets the right hand side of a quadratic constraint.
12458  */
12460  SCIP* scip, /**< SCIP data structure */
12461  SCIP_CONS* cons /**< constraint */
12462  )
12463 {
12464  assert(cons != NULL);
12465  assert(SCIPconsGetData(cons) != NULL);
12466 
12467  return SCIPconsGetData(cons)->rhs;
12468 }
12469 
12470 /** Check the quadratic function of a quadratic constraint for its semi-definiteness, if not done yet.
12471  */
12473  SCIP* scip, /**< SCIP data structure */
12474  SCIP_CONS* cons /**< constraint */
12475  )
12476 {
12477  assert(cons != NULL);
12478 
12479  SCIP_CALL( checkCurvature(scip, cons, TRUE) );
12480 
12481  return SCIP_OKAY;
12482 }
12483 
12484 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) convex.
12485  */
12487  SCIP* scip, /**< SCIP data structure */
12488  SCIP_CONS* cons /**< constraint */
12489  )
12490 {
12491  SCIP_Bool determined;
12492 
12493  assert(cons != NULL);
12494  assert(SCIPconsGetData(cons) != NULL);
12495 
12496  checkCurvatureEasy(scip, cons, &determined, FALSE);
12497  assert(determined);
12498 
12499  return (SCIPconsGetData(cons)->isconvex);
12500 }
12501 
12502 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) concave.
12503  */
12505  SCIP* scip, /**< SCIP data structure */
12506  SCIP_CONS* cons /**< constraint */
12507  )
12508 {
12509  SCIP_Bool determined;
12510 
12511  assert(cons != NULL);
12512  assert(SCIPconsGetData(cons) != NULL);
12513 
12514  checkCurvatureEasy(scip, cons, &determined, FALSE);
12515  assert(determined);
12516 
12517  return (SCIPconsGetData(cons)->isconcave);
12518 }
12519 
12520 /** Computes the violation of a constraint by a solution */
12522  SCIP* scip, /**< SCIP data structure */
12523  SCIP_CONS* cons, /**< constraint */
12524  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
12525  SCIP_Real* violation /**< pointer to store violation of constraint */
12526  )
12527 {
12528  SCIP_CONSHDLR* conshdlr;
12529  SCIP_CONSDATA* consdata;
12530 
12531  assert(scip != NULL);
12532  assert(cons != NULL);
12533  assert(violation != NULL);
12534 
12535  conshdlr = SCIPconsGetHdlr(cons);
12536  assert(conshdlr != NULL);
12537 
12538  SCIP_CALL( computeViolation(scip, conshdlr, cons, sol) );
12539 
12540  consdata = SCIPconsGetData(cons);
12541  assert(consdata != NULL);
12542 
12543  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
12544 
12545  return SCIP_OKAY;
12546 }
12547 
12548 /** Indicates whether the quadratic constraint is local w.r.t. the current local bounds.
12549  *
12550  * That is, checks whether each variable with a square term is fixed and for each bilinear term at least one variable is fixed.
12551  */
12553  SCIP* scip, /**< SCIP data structure */
12554  SCIP_CONS* cons /**< constraint */
12555 )
12556 {
12557  SCIP_CONSDATA* consdata;
12558  SCIP_VAR* var1;
12559  SCIP_VAR* var2;
12560  int i;
12561 
12562  assert(scip != NULL);
12563  assert(cons != NULL);
12564 
12565  consdata = SCIPconsGetData(cons);
12566  assert(consdata != NULL);
12567 
12568  /* check all square terms */
12569  for( i = 0; i < consdata->nquadvars; ++i )
12570  {
12571  if( consdata->quadvarterms[i].sqrcoef == 0.0 )
12572  continue;
12573 
12574  var1 = consdata->quadvarterms[i].var;
12575  assert(var1 != NULL);
12576 
12577  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) )
12578  return FALSE;
12579  }
12580 
12581  for( i = 0; i < consdata->nbilinterms; ++i )
12582  {
12583  var1 = consdata->bilinterms[i].var1;
12584  var2 = consdata->bilinterms[i].var2;
12585 
12586  assert(var1 != NULL);
12587  assert(var2 != NULL);
12588 
12589  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) &&
12590  ! SCIPisRelEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
12591  return FALSE;
12592  }
12593 
12594  return TRUE;
12595 }
12596 
12597 /** Adds the constraint to an NLPI problem. */
12599  SCIP* scip, /**< SCIP data structure */
12600  SCIP_CONS* cons, /**< constraint */
12601  SCIP_NLPI* nlpi, /**< interface to NLP solver */
12602  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
12603  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
12604  SCIP_Bool names /**< whether to pass constraint names to NLPI */
12605  )
12606 {
12607  SCIP_CONSDATA* consdata;
12608  int nlininds;
12609  int* lininds;
12610  SCIP_Real* linvals;
12611  int nquadelems;
12612  SCIP_QUADELEM* quadelems;
12613  SCIP_VAR* othervar;
12614  const char* name;
12615  int j;
12616  int l;
12617  int lincnt;
12618  int quadcnt;
12619  int idx1;
12620  int idx2;
12621 
12622  assert(scip != NULL);
12623  assert(cons != NULL);
12624  assert(nlpi != NULL);
12625  assert(nlpiprob != NULL);
12626  assert(scipvar2nlpivar != NULL);
12627 
12628  consdata = SCIPconsGetData(cons);
12629  assert(consdata != NULL);
12630 
12631  /* count nonzeros in quadratic part */
12632  nlininds = consdata->nlinvars;
12633  nquadelems = consdata->nbilinterms;
12634  for( j = 0; j < consdata->nquadvars; ++j )
12635  {
12636  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
12637  ++nquadelems;
12638  if( consdata->quadvarterms[j].lincoef != 0.0 )
12639  ++nlininds;
12640  }
12641 
12642  /* setup linear part */
12643  lininds = NULL;
12644  linvals = NULL;
12645  lincnt = 0;
12646  if( nlininds > 0 )
12647  {
12648  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
12649  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
12650 
12651  for( j = 0; j < consdata->nlinvars; ++j )
12652  {
12653  linvals[j] = consdata->lincoefs[j];
12654  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->linvars[j]));
12655  lininds[j] = (int) (size_t) SCIPhashmapGetImage(scipvar2nlpivar, consdata->linvars[j]);
12656  }
12657 
12658  lincnt = consdata->nlinvars;
12659  }
12660 
12661  /* setup quadratic part */
12662  quadelems = NULL;
12663  if( nquadelems > 0 )
12664  {
12665  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
12666  }
12667  quadcnt = 0;
12668 
12669  for( j = 0; j < consdata->nquadvars; ++j )
12670  {
12671  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->quadvarterms[j].var));
12672  idx1 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, consdata->quadvarterms[j].var);
12673  if( consdata->quadvarterms[j].lincoef != 0.0 )
12674  {
12675  assert(lininds != NULL);
12676  assert(linvals != NULL);
12677  lininds[lincnt] = idx1;
12678  linvals[lincnt] = consdata->quadvarterms[j].lincoef;
12679  ++lincnt;
12680  }
12681 
12682  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
12683  {
12684  assert(quadcnt < nquadelems);
12685  assert(quadelems != NULL);
12686  quadelems[quadcnt].idx1 = idx1;
12687  quadelems[quadcnt].idx2 = idx1;
12688  quadelems[quadcnt].coef = consdata->quadvarterms[j].sqrcoef;
12689  ++quadcnt;
12690  }
12691 
12692  for( l = 0; l < consdata->quadvarterms[j].nadjbilin; ++l )
12693  {
12694  othervar = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].var2;
12695  /* if othervar is on position 2, then we process this bilinear term later (or it was processed already) */
12696  if( othervar == consdata->quadvarterms[j].var )
12697  continue;
12698 
12699  assert(quadcnt < nquadelems);
12700  assert(quadelems != NULL);
12701  assert(SCIPhashmapExists(scipvar2nlpivar, othervar));
12702  idx2 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, othervar);
12703  quadelems[quadcnt].idx1 = MIN(idx1, idx2);
12704  quadelems[quadcnt].idx2 = MAX(idx1, idx2);
12705  quadelems[quadcnt].coef = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].coef;
12706  ++quadcnt;
12707  }
12708  }
12709 
12710  assert(quadcnt == nquadelems);
12711  assert(lincnt == nlininds);
12712 
12713  name = names ? SCIPconsGetName(cons) : NULL;
12714 
12715  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
12716  &consdata->lhs, &consdata->rhs,
12717  &nlininds, &lininds, &linvals ,
12718  &nquadelems, &quadelems,
12719  NULL, NULL, &name) );
12720 
12721  SCIPfreeBufferArrayNull(scip, &quadelems);
12722  SCIPfreeBufferArrayNull(scip, &lininds);
12723  SCIPfreeBufferArrayNull(scip, &linvals);
12724 
12725  return SCIP_OKAY;
12726 }
12727