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 */
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))
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  /* invalidate activity information
300  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
301  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
302  */
303  consdata->minlinactivity = SCIP_INVALID;
304  consdata->maxlinactivity = SCIP_INVALID;
305  consdata->minlinactivityinf = -1;
306  consdata->maxlinactivityinf = -1;
307 
308  return SCIP_OKAY;
309 }
310 
311 /* drops variable bound change events on a linear variable in a quadratic constraint */
312 static
314  SCIP* scip, /**< SCIP data structure */
315  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
316  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
317  int linvarpos /**< position of variable in linear variables array */
318  )
319 {
320  SCIP_CONSDATA* consdata;
321  SCIP_EVENTTYPE eventtype;
322 
323  assert(scip != NULL);
324  assert(eventhdlr != NULL);
325  assert(cons != NULL);
326 
327  consdata = SCIPconsGetData(cons);
328  assert(consdata != NULL);
329 
330  assert(linvarpos >= 0);
331  assert(linvarpos < consdata->nlinvars);
332  assert(consdata->lineventdata != NULL);
333  assert(consdata->lineventdata[linvarpos] != NULL);
334  assert(consdata->lineventdata[linvarpos]->consdata == consdata);
335  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
336  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
337 
338  eventtype = SCIP_EVENTTYPE_VARFIXED;
339  if( !SCIPisInfinity(scip, consdata->rhs) )
340  {
341  /* if right hand side is finite, then a tightening in the lower 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_LBCHANGED;
345  else
346  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
347  }
348  if( !SCIPisInfinity(scip, -consdata->lhs) )
349  {
350  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
351  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
352  if( consdata->lincoefs[linvarpos] > 0.0 )
353  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
354  else
355  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
356  }
357 
358  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
359 
360  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866 */
361 
362  return SCIP_OKAY;
363 }
364 
365 /* catches variable bound change events on a quadratic variable in a quadratic constraint */
366 static
368  SCIP* scip, /**< SCIP data structure */
369  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
370  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
371  int quadvarpos /**< position of variable in quadratic variables array */
372  )
373 {
374  SCIP_CONSDATA* consdata;
375  SCIP_QUADVAREVENTDATA* eventdata;
376  SCIP_EVENTTYPE eventtype;
377 
378  assert(scip != NULL);
379  assert(eventhdlr != NULL);
380  assert(cons != NULL);
381 
382  consdata = SCIPconsGetData(cons);
383  assert(consdata != NULL);
384 
385  assert(quadvarpos >= 0);
386  assert(quadvarpos < consdata->nquadvars);
387  assert(consdata->quadvarterms[quadvarpos].eventdata == NULL);
388 
389  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
390 
392 #ifdef CHECKIMPLINBILINEAR
393  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
394 #endif
395  eventdata->consdata = consdata;
396  eventdata->varidx = -quadvarpos-1;
397  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
398 
399  consdata->quadvarterms[quadvarpos].eventdata = eventdata;
400 
401  /* invalidate activity information
402  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
403  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
404  */
405  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
406 
407  return SCIP_OKAY;
408 }
409 
410 /* catches variable bound change events on a quadratic variable in a quadratic constraint */
411 static
413  SCIP* scip, /**< SCIP data structure */
414  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
415  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
416  int quadvarpos /**< position of variable in quadratic variables array */
417  )
418 {
419  SCIP_CONSDATA* consdata;
420  SCIP_EVENTTYPE eventtype;
421 
422  assert(scip != NULL);
423  assert(eventhdlr != NULL);
424  assert(cons != NULL);
425 
426  consdata = SCIPconsGetData(cons);
427  assert(consdata != NULL);
428 
429  assert(quadvarpos >= 0);
430  assert(quadvarpos < consdata->nquadvars);
431  assert(consdata->quadvarterms[quadvarpos].eventdata != NULL);
432  assert(consdata->quadvarterms[quadvarpos].eventdata->consdata == consdata);
433  assert(consdata->quadvarterms[quadvarpos].eventdata->varidx == -quadvarpos-1);
434  assert(consdata->quadvarterms[quadvarpos].eventdata->filterpos >= 0);
435 
437 #ifdef CHECKIMPLINBILINEAR
438  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
439 #endif
440 
441  SCIP_CALL( SCIPdropVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->quadvarterms[quadvarpos].eventdata, consdata->quadvarterms[quadvarpos].eventdata->filterpos) );
442 
443  SCIPfreeBlockMemory(scip, &consdata->quadvarterms[quadvarpos].eventdata);
444 
445  return SCIP_OKAY;
446 }
447 
448 /** catch variable events */
449 static
451  SCIP* scip, /**< SCIP data structure */
452  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
453  SCIP_CONS* cons /**< constraint for which to catch bound change events */
454  )
455 {
456  SCIP_CONSDATA* consdata;
457  int i;
458 
459  assert(scip != NULL);
460  assert(cons != NULL);
461  assert(eventhdlr != NULL);
462 
463  consdata = SCIPconsGetData(cons);
464  assert(consdata != NULL);
465  assert(consdata->lineventdata == NULL);
466 
467  /* we will update isremovedfixings, so reset it to TRUE first */
468  consdata->isremovedfixings = TRUE;
469 
470  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
471  for( i = 0; i < consdata->nlinvars; ++i )
472  {
473  SCIP_CALL( catchLinearVarEvents(scip, eventhdlr, cons, i) );
474 
475  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(consdata->linvars[i]);
476  }
477 
478  for( i = 0; i < consdata->nquadvars; ++i )
479  {
480  assert(consdata->quadvarterms[i].eventdata == NULL);
481 
482  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, i) );
483 
484  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(consdata->quadvarterms[i].var);
485  }
486 
487  consdata->ispropagated = FALSE;
488 
489  return SCIP_OKAY;
490 }
491 
492 /** drop variable events */
493 static
495  SCIP* scip, /**< SCIP data structure */
496  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
497  SCIP_CONS* cons /**< constraint for which to drop bound change events */
498  )
499 {
500  SCIP_CONSDATA* consdata;
501  int i;
502 
503  assert(scip != NULL);
504  assert(eventhdlr != NULL);
505  assert(cons != NULL);
506 
507  consdata = SCIPconsGetData(cons);
508  assert(consdata != NULL);
509 
510  if( consdata->lineventdata != NULL )
511  {
512  for( i = 0; i < consdata->nlinvars; ++i )
513  {
514  if( consdata->lineventdata[i] != NULL )
515  {
516  SCIP_CALL( dropLinearVarEvents(scip, eventhdlr, cons, i) );
517  }
518  }
519  SCIPfreeBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize);
520  }
521 
522  for( i = 0; i < consdata->nquadvars; ++i )
523  {
524  if( consdata->quadvarterms[i].eventdata != NULL )
525  {
526  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, i) );
527  }
528  }
529 
530  return SCIP_OKAY;
531 }
532 
533 /** locks a linear variable in a constraint */
534 static
536  SCIP* scip, /**< SCIP data structure */
537  SCIP_CONS* cons, /**< constraint where to lock a variable */
538  SCIP_VAR* var, /**< variable to lock */
539  SCIP_Real coef /**< coefficient of variable in constraint */
540  )
541 {
542  SCIP_CONSDATA* consdata;
543 
544  assert(scip != NULL);
545  assert(cons != NULL);
546  assert(var != NULL);
547  assert(coef != 0.0);
548 
549  consdata = SCIPconsGetData(cons);
550  assert(consdata != NULL);
551 
552  if( coef > 0.0 )
553  {
554  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
555  }
556  else
557  {
558  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
559  }
560 
561  return SCIP_OKAY;
562 }
563 
564 /** unlocks a linear variable in a constraint */
565 static
567  SCIP* scip, /**< SCIP data structure */
568  SCIP_CONS* cons, /**< constraint where to unlock a variable */
569  SCIP_VAR* var, /**< variable to unlock */
570  SCIP_Real coef /**< coefficient of variable in constraint */
571  )
572 {
573  SCIP_CONSDATA* consdata;
574 
575  assert(scip != NULL);
576  assert(cons != NULL);
577  assert(var != NULL);
578  assert(coef != 0.0);
579 
580  consdata = SCIPconsGetData(cons);
581  assert(consdata != NULL);
582 
583  if( coef > 0.0 )
584  {
585  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
586  }
587  else
588  {
589  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
590  }
591 
592  return SCIP_OKAY;
593 }
594 
595 /** locks a quadratic variable in a constraint */
596 static
598  SCIP* scip, /**< SCIP data structure */
599  SCIP_CONS* cons, /**< constraint where to lock a variable */
600  SCIP_VAR* var /**< variable to lock */
601  )
602 {
603  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
604 
605  return SCIP_OKAY;
606 }
607 
608 /** unlocks a quadratic variable in a constraint */
609 static
611  SCIP* scip, /**< SCIP data structure */
612  SCIP_CONS* cons, /**< constraint where to unlock a variable */
613  SCIP_VAR* var /**< variable to unlock */
614  )
615 {
616  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
617 
618  return SCIP_OKAY;
619 }
620 
621 /** computes the minimal and maximal activity for the linear part in a constraint data
622  * only sums up terms that contribute finite values
623  * gives the number of terms that contribute infinite values
624  * only computes those activities where the corresponding side of the constraint is finite
625  */
626 static
628  SCIP* scip, /**< SCIP data structure */
629  SCIP_CONSDATA* consdata, /**< constraint data */
630  SCIP_Real intervalinfty /**< infinity value used in interval operations */
631  )
632 { /*lint --e{666}*/
633  SCIP_ROUNDMODE prevroundmode;
634  int i;
635  SCIP_Real bnd;
636 
637  assert(scip != NULL);
638  assert(consdata != NULL);
639 
640  /* if variable bounds are not strictly consistent, then the activity update methods may yield inconsistent activities
641  * in this case, we also recompute the activities
642  */
643  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID && /*lint !e777 */
644  (consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity) )
645  {
646  /* activities should be up-to-date */
647  assert(consdata->minlinactivityinf >= 0);
648  assert(consdata->maxlinactivityinf >= 0);
649  return;
650  }
651 
652  consdata->minlinactivityinf = 0;
653  consdata->maxlinactivityinf = 0;
654 
655  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
656  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
657  */
658  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
659  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
660 
661  if( consdata->nlinvars == 0 )
662  return;
663 
664  /* if the activities computed here should be still up-to-date after bound changes,
665  * variable events need to be caught */
666  assert(consdata->lineventdata != NULL);
667 
668  prevroundmode = SCIPintervalGetRoundingMode();
669 
670  if( !SCIPisInfinity(scip, consdata->rhs) )
671  {
672  /* compute minimal activity only if there is a finite right hand side */
674 
675  for( i = 0; i < consdata->nlinvars; ++i )
676  {
677  assert(consdata->lineventdata[i] != NULL);
678  if( consdata->lincoefs[i] >= 0.0 )
679  {
680  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
681  if( SCIPisInfinity(scip, -bnd) )
682  {
683  ++consdata->minlinactivityinf;
684  continue;
685  }
686  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
687  }
688  else
689  {
690  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
691  if( SCIPisInfinity(scip, bnd) )
692  {
693  ++consdata->minlinactivityinf;
694  continue;
695  }
696  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
697  }
698  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
699  }
700  }
701 
702  if( !SCIPisInfinity(scip, -consdata->lhs) )
703  {
704  /* compute maximal activity only if there is a finite left hand side */
706 
707  for( i = 0; i < consdata->nlinvars; ++i )
708  {
709  assert(consdata->lineventdata[i] != NULL);
710  if( consdata->lincoefs[i] >= 0.0 )
711  {
712  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
713  if( SCIPisInfinity(scip, bnd) )
714  {
715  ++consdata->maxlinactivityinf;
716  continue;
717  }
718  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
719  }
720  else
721  {
722  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
723  if( SCIPisInfinity(scip, -bnd) )
724  {
725  ++consdata->maxlinactivityinf;
726  continue;
727  }
728  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
729  }
730  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
731  }
732  }
733 
734  SCIPintervalSetRoundingMode(prevroundmode);
735 
736  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
737 }
738 
739 /** update the linear activities after a change in the lower bound of a variable */
740 static
742  SCIP* scip, /**< SCIP data structure */
743  SCIP_CONSDATA* consdata, /**< constraint data */
744  SCIP_Real coef, /**< coefficient of variable in constraint */
745  SCIP_Real oldbnd, /**< previous lower bound of variable */
746  SCIP_Real newbnd /**< new lower bound of variable */
747  )
748 {
749  SCIP_ROUNDMODE prevroundmode;
750 
751  assert(scip != NULL);
752  assert(consdata != NULL);
753  /* we can't deal with lower bounds at infinity */
754  assert(!SCIPisInfinity(scip, oldbnd));
755  assert(!SCIPisInfinity(scip, newbnd));
756 
757  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
758 
759  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
760  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
761  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
762  */
763 
764  if( coef > 0.0 )
765  {
766  /* we should only be called if rhs is finite */
767  assert(!SCIPisInfinity(scip, consdata->rhs));
768 
769  /* we have no min activities computed so far, so cannot update */
770  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
771  return;
772 
773  assert(!SCIPisInfinity(scip, -consdata->minlinactivity));
774 
775  prevroundmode = SCIPintervalGetRoundingMode();
777 
778  /* update min activity */
779  if( SCIPisInfinity(scip, -oldbnd) )
780  {
781  --consdata->minlinactivityinf;
782  assert(consdata->minlinactivityinf >= 0);
783  }
784  else
785  {
786  SCIP_Real minuscoef;
787  minuscoef = -coef;
788  consdata->minlinactivity += minuscoef * oldbnd;
789  }
790 
791  if( SCIPisInfinity(scip, -newbnd) )
792  {
793  ++consdata->minlinactivityinf;
794  }
795  else
796  {
797  consdata->minlinactivity += coef * newbnd;
798  }
799 
800  SCIPintervalSetRoundingMode(prevroundmode);
801  }
802  else
803  {
804  /* we should only be called if lhs is finite */
805  assert(!SCIPisInfinity(scip, -consdata->lhs));
806 
807  /* we have no max activities computed so far, so cannot update */
808  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
809  return;
810 
811  assert(!SCIPisInfinity(scip, consdata->maxlinactivity));
812 
813  prevroundmode = SCIPintervalGetRoundingMode();
815 
816  /* update max activity */
817  if( SCIPisInfinity(scip, -oldbnd) )
818  {
819  --consdata->maxlinactivityinf;
820  assert(consdata->maxlinactivityinf >= 0);
821  }
822  else
823  {
824  SCIP_Real minuscoef;
825  minuscoef = -coef;
826  consdata->maxlinactivity += minuscoef * oldbnd;
827  }
828 
829  if( SCIPisInfinity(scip, -newbnd) )
830  {
831  ++consdata->maxlinactivityinf;
832  }
833  else
834  {
835  consdata->maxlinactivity += coef * newbnd;
836  }
837 
838  SCIPintervalSetRoundingMode(prevroundmode);
839  }
840 }
841 
842 /** update the linear activities after a change in the upper bound of a variable */
843 static
845  SCIP* scip, /**< SCIP data structure */
846  SCIP_CONSDATA* consdata, /**< constraint data */
847  SCIP_Real coef, /**< coefficient of variable in constraint */
848  SCIP_Real oldbnd, /**< previous lower bound of variable */
849  SCIP_Real newbnd /**< new lower bound of variable */
850  )
851 {
852  SCIP_ROUNDMODE prevroundmode;
853 
854  assert(scip != NULL);
855  assert(consdata != NULL);
856  /* we can't deal with upper bounds at -infinity */
857  assert(!SCIPisInfinity(scip, -oldbnd));
858  assert(!SCIPisInfinity(scip, -newbnd));
859 
860  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
861 
862  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
863  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
864  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
865  */
866 
867  if( coef > 0.0 )
868  {
869  /* we should only be called if lhs is finite */
870  assert(!SCIPisInfinity(scip, -consdata->lhs));
871 
872  /* we have no max activities computed so far, so cannot update */
873  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
874  return;
875 
876  assert(!SCIPisInfinity(scip, consdata->maxlinactivity));
877 
878  prevroundmode = SCIPintervalGetRoundingMode();
880 
881  /* update max activity */
882  if( SCIPisInfinity(scip, oldbnd) )
883  {
884  --consdata->maxlinactivityinf;
885  assert(consdata->maxlinactivityinf >= 0);
886  }
887  else
888  {
889  SCIP_Real minuscoef;
890  minuscoef = -coef;
891  consdata->maxlinactivity += minuscoef * oldbnd;
892  }
893 
894  if( SCIPisInfinity(scip, newbnd) )
895  {
896  ++consdata->maxlinactivityinf;
897  }
898  else
899  {
900  consdata->maxlinactivity += coef * newbnd;
901  }
902 
903  SCIPintervalSetRoundingMode(prevroundmode);
904  }
905  else
906  {
907  /* we should only be called if rhs is finite */
908  assert(!SCIPisInfinity(scip, consdata->rhs));
909 
910  /* we have no min activities computed so far, so cannot update */
911  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
912  return;
913 
914  assert(!SCIPisInfinity(scip, -consdata->minlinactivity));
915 
916  prevroundmode = SCIPintervalGetRoundingMode();
918 
919  /* update min activity */
920  if( SCIPisInfinity(scip, oldbnd) )
921  {
922  --consdata->minlinactivityinf;
923  assert(consdata->minlinactivityinf >= 0);
924  }
925  else
926  {
927  SCIP_Real minuscoef;
928  minuscoef = -coef;
929  consdata->minlinactivity += minuscoef * oldbnd;
930  }
931 
932  if( SCIPisInfinity(scip, newbnd) )
933  {
934  ++consdata->minlinactivityinf;
935  }
936  else
937  {
938  consdata->minlinactivity += coef * newbnd;
939  }
940 
941  SCIPintervalSetRoundingMode(prevroundmode);
942  }
943 }
944 
945 /** processes variable fixing or bound change event */
946 static
947 SCIP_DECL_EVENTEXEC(processVarEvent)
948 {
949  SCIP_CONSDATA* consdata;
950  SCIP_EVENTTYPE eventtype;
951  int varidx;
952 
953  assert(scip != NULL);
954  assert(event != NULL);
955  assert(eventdata != NULL);
956  assert(eventhdlr != NULL);
957 
958  consdata = ((SCIP_QUADVAREVENTDATA*)eventdata)->consdata;
959  assert(consdata != NULL);
960 
961  varidx = ((SCIP_QUADVAREVENTDATA*)eventdata)->varidx;
962  assert(varidx < 0 || varidx < consdata->nlinvars);
963  assert(varidx >= 0 || -varidx-1 < consdata->nquadvars);
964 
965  eventtype = SCIPeventGetType(event);
966 
967  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
968  {
969  if( varidx < 0 )
970  {
971  /* mark activity bounds for quad term as not up to date anymore */
972  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
973  }
974  else
975  {
976  /* update activity bounds for linear terms */
977  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
978  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
979  else
980  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
981  }
982 
983  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
984  consdata->ispropagated = FALSE;
985  }
986 
987  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
988  {
989  consdata->isremovedfixings = FALSE;
990  }
991 
992 #ifdef CHECKIMPLINBILINEAR
993  if( eventtype & SCIP_EVENTTYPE_IMPLADDED )
994  {
995  assert(varidx < 0); /* we catch impladded events only for quadratic variables */
996  /* 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 */
997  if( SCIPvarIsBinary(SCIPeventGetVar(event)) && consdata->quadvarterms[-varidx-1].nadjbilin > 0 )
998  consdata->isimpladded = TRUE;
999  }
1000 #endif
1001 
1002  return SCIP_OKAY;
1003 }
1004 
1005 /** ensures, that linear vars and coefs arrays can store at least num entries */
1006 static
1008  SCIP* scip, /**< SCIP data structure */
1009  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1010  int num /**< minimum number of entries to store */
1011  )
1012 {
1013  assert(scip != NULL);
1014  assert(consdata != NULL);
1015  assert(consdata->nlinvars <= consdata->linvarssize);
1016 
1017  if( num > consdata->linvarssize )
1018  {
1019  int newsize;
1020 
1021  newsize = SCIPcalcMemGrowSize(scip, num);
1022  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1023  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1024  if( consdata->lineventdata != NULL )
1025  {
1026  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1027  }
1028  consdata->linvarssize = newsize;
1029  }
1030  assert(num <= consdata->linvarssize);
1031 
1032  return SCIP_OKAY;
1033 }
1034 
1035 /** ensures, that quadratic variable terms array can store at least num entries */
1036 static
1038  SCIP* scip, /**< SCIP data structure */
1039  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1040  int num /**< minimum number of entries to store */
1041  )
1042 {
1043  assert(scip != NULL);
1044  assert(consdata != NULL);
1045  assert(consdata->nquadvars <= consdata->quadvarssize);
1046 
1047  if( num > consdata->quadvarssize )
1048  {
1049  int newsize;
1050 
1051  newsize = SCIPcalcMemGrowSize(scip, num);
1052  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->quadvarterms, consdata->quadvarssize, newsize) );
1053  consdata->quadvarssize = newsize;
1054  }
1055  assert(num <= consdata->quadvarssize);
1056 
1057  return SCIP_OKAY;
1058 }
1059 
1060 /** ensures, that adjacency array can store at least num entries */
1061 static
1063  SCIP* scip, /**< SCIP data structure */
1064  SCIP_QUADVARTERM* quadvarterm, /**< quadratic variable term */
1065  int num /**< minimum number of entries to store */
1066  )
1067 {
1068  assert(scip != NULL);
1069  assert(quadvarterm != NULL);
1070  assert(quadvarterm->nadjbilin <= quadvarterm->adjbilinsize);
1071 
1072  if( num > quadvarterm->adjbilinsize )
1073  {
1074  int newsize;
1075 
1076  newsize = SCIPcalcMemGrowSize(scip, num);
1077  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvarterm->adjbilin, quadvarterm->adjbilinsize, newsize) );
1078  quadvarterm->adjbilinsize = newsize;
1079  }
1080  assert(num <= quadvarterm->adjbilinsize);
1081 
1082  return SCIP_OKAY;
1083 }
1084 
1085 /** ensures, that bilinear term arrays can store at least num entries */
1086 static
1088  SCIP* scip, /**< SCIP data structure */
1089  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1090  int num /**< minimum number of entries to store */
1091  )
1092 {
1093  assert(scip != NULL);
1094  assert(consdata != NULL);
1095  assert(consdata->nbilinterms <= consdata->bilintermssize);
1096 
1097  if( num > consdata->bilintermssize )
1098  {
1099  int newsize;
1100 
1101  newsize = SCIPcalcMemGrowSize(scip, num);
1102  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize, newsize) );
1103  consdata->bilintermssize = newsize;
1104  }
1105  assert(num <= consdata->bilintermssize);
1106 
1107  return SCIP_OKAY;
1108 }
1109 
1110 /** creates empty constraint data structure */
1111 static
1113  SCIP* scip, /**< SCIP data structure */
1114  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1115  )
1116 {
1117  assert(scip != NULL);
1118  assert(consdata != NULL);
1119 
1120  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1121  BMSclearMemory(*consdata);
1122 
1123  (*consdata)->lhs = -SCIPinfinity(scip);
1124  (*consdata)->rhs = SCIPinfinity(scip);
1125 
1126  (*consdata)->linvarssorted = TRUE;
1127  (*consdata)->linvarsmerged = TRUE;
1128  (*consdata)->quadvarssorted = TRUE;
1129  (*consdata)->quadvarsmerged = TRUE;
1130  (*consdata)->bilinsorted = TRUE;
1131  (*consdata)->bilinmerged = TRUE;
1132 
1133  (*consdata)->isremovedfixings = TRUE;
1134  (*consdata)->ispropagated = TRUE;
1135  (*consdata)->initialmerge = FALSE;
1136 
1137  (*consdata)->linvar_maydecrease = -1;
1138  (*consdata)->linvar_mayincrease = -1;
1139 
1140  (*consdata)->minlinactivity = SCIP_INVALID;
1141  (*consdata)->maxlinactivity = SCIP_INVALID;
1142  (*consdata)->minlinactivityinf = -1;
1143  (*consdata)->maxlinactivityinf = -1;
1144 
1145  return SCIP_OKAY;
1146 }
1147 
1148 /** creates constraint data structure */
1149 static
1151  SCIP* scip, /**< SCIP data structure */
1152  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1153  SCIP_Real lhs, /**< left hand side of constraint */
1154  SCIP_Real rhs, /**< right hand side of constraint */
1155  int nlinvars, /**< number of linear variables */
1156  SCIP_VAR** linvars, /**< array of linear variables */
1157  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1158  int nquadvars, /**< number of quadratic variables */
1159  SCIP_QUADVARTERM* quadvarterms, /**< array of quadratic variable terms */
1160  int nbilinterms, /**< number of bilinear terms */
1161  SCIP_BILINTERM* bilinterms, /**< array of bilinear terms */
1162  SCIP_Bool capturevars /**< whether we should capture variables */
1163  )
1164 {
1165  int i;
1166 
1167  assert(scip != NULL);
1168  assert(consdata != NULL);
1169 
1170  assert(nlinvars == 0 || linvars != NULL);
1171  assert(nlinvars == 0 || lincoefs != NULL);
1172  assert(nquadvars == 0 || quadvarterms != NULL);
1173  assert(nbilinterms == 0 || bilinterms != NULL);
1174 
1175  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1176  BMSclearMemory(*consdata);
1177 
1178  (*consdata)->minlinactivity = SCIP_INVALID;
1179  (*consdata)->maxlinactivity = SCIP_INVALID;
1180  (*consdata)->minlinactivityinf = -1;
1181  (*consdata)->maxlinactivityinf = -1;
1182 
1183  (*consdata)->lhs = lhs;
1184  (*consdata)->rhs = rhs;
1185 
1186  if( nlinvars > 0 )
1187  {
1188  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1189  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1190  (*consdata)->nlinvars = nlinvars;
1191  (*consdata)->linvarssize = nlinvars;
1192 
1193  if( capturevars )
1194  for( i = 0; i < nlinvars; ++i )
1195  {
1196  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1197  }
1198  }
1199  else
1200  {
1201  (*consdata)->linvarssorted = TRUE;
1202  (*consdata)->linvarsmerged = TRUE;
1203  (*consdata)->minlinactivity = 0.0;
1204  (*consdata)->maxlinactivity = 0.0;
1205  (*consdata)->minlinactivityinf = 0;
1206  (*consdata)->maxlinactivityinf = 0;
1207  }
1208 
1209  if( nquadvars > 0 )
1210  {
1211  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms, quadvarterms, nquadvars) );
1212 
1213  for( i = 0; i < nquadvars; ++i )
1214  {
1215  (*consdata)->quadvarterms[i].eventdata = NULL;
1216  if( quadvarterms[i].nadjbilin )
1217  {
1218  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms[i].adjbilin, quadvarterms[i].adjbilin, quadvarterms[i].nadjbilin) );
1219  (*consdata)->quadvarterms[i].adjbilinsize = quadvarterms[i].nadjbilin;
1220  }
1221  else
1222  {
1223  assert((*consdata)->quadvarterms[i].nadjbilin == 0);
1224  (*consdata)->quadvarterms[i].adjbilin = NULL;
1225  (*consdata)->quadvarterms[i].adjbilinsize = 0;
1226  }
1227  if( capturevars )
1228  {
1229  SCIP_CALL( SCIPcaptureVar(scip, quadvarterms[i].var) );
1230  }
1231  }
1232 
1233  (*consdata)->nquadvars = nquadvars;
1234  (*consdata)->quadvarssize = nquadvars;
1235  SCIPintervalSetEmpty(&(*consdata)->quadactivitybounds);
1236  }
1237  else
1238  {
1239  (*consdata)->quadvarssorted = TRUE;
1240  (*consdata)->quadvarsmerged = TRUE;
1241  SCIPintervalSet(&(*consdata)->quadactivitybounds, 0.0);
1242  }
1243 
1244  if( nbilinterms > 0 )
1245  {
1246  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->bilinterms, bilinterms, nbilinterms) );
1247  (*consdata)->nbilinterms = nbilinterms;
1248  (*consdata)->bilintermssize = nbilinterms;
1249  }
1250  else
1251  {
1252  (*consdata)->bilinsorted = TRUE;
1253  (*consdata)->bilinmerged = TRUE;
1254  }
1255 
1256  (*consdata)->linvar_maydecrease = -1;
1257  (*consdata)->linvar_mayincrease = -1;
1258 
1259  (*consdata)->activity = SCIP_INVALID;
1260  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1261  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1262 
1263  return SCIP_OKAY;
1264 }
1265 
1266 /** frees constraint data structure */
1267 static
1269  SCIP* scip, /**< SCIP data structure */
1270  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1271  )
1272 {
1273  int i;
1274 
1275  assert(scip != NULL);
1276  assert(consdata != NULL);
1277  assert(*consdata != NULL);
1278 
1279  /* free sepa arrays, may exists if constraint is deleted in solving stage */
1280  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepaquadvars, (*consdata)->nquadvars);
1281  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepabilinvar2pos, (*consdata)->nbilinterms);
1282 
1283  /* release linear variables and free linear part */
1284  if( (*consdata)->linvarssize > 0 )
1285  {
1286  for( i = 0; i < (*consdata)->nlinvars; ++i )
1287  {
1288  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1289  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1290  }
1291  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1292  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1293  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1294  }
1295  assert((*consdata)->linvars == NULL);
1296  assert((*consdata)->lincoefs == NULL);
1297  assert((*consdata)->lineventdata == NULL);
1298 
1299  /* release quadratic variables and free quadratic variable term part */
1300  for( i = 0; i < (*consdata)->nquadvars; ++i )
1301  {
1302  assert((*consdata)->quadvarterms[i].eventdata == NULL); /* variable events should have been dropped earlier */
1303  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms[i].adjbilin, (*consdata)->quadvarterms[i].adjbilinsize);
1304  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->quadvarterms[i].var) );
1305  }
1306  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms, (*consdata)->quadvarssize);
1307 
1308  /* free bilinear terms */
1309  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilinterms, (*consdata)->bilintermssize);
1310 
1311  /* free nonlinear row representation */
1312  if( (*consdata)->nlrow != NULL )
1313  {
1314  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1315  }
1316 
1317  SCIPfreeBlockMemory(scip, consdata);
1318  *consdata = NULL;
1319 
1320  return SCIP_OKAY;
1321 }
1322 
1323 /** sorts linear part of constraint data */
1324 static
1326  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1327  )
1328 {
1329  assert(consdata != NULL);
1330 
1331  if( consdata->linvarssorted )
1332  return;
1333 
1334  if( consdata->nlinvars <= 1 )
1335  {
1336  consdata->linvarssorted = TRUE;
1337  return;
1338  }
1339 
1340  if( consdata->lineventdata == NULL )
1341  {
1342  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1343  }
1344  else
1345  {
1346  int i;
1347 
1348  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1349 
1350  /* update variable indices in event data */
1351  for( i = 0; i < consdata->nlinvars; ++i )
1352  if( consdata->lineventdata[i] != NULL )
1353  consdata->lineventdata[i]->varidx = i;
1354  }
1355 
1356  consdata->linvarssorted = TRUE;
1357 }
1358 
1359 #ifdef SCIP_DISABLED_CODE /* no-one needs this routine currently */
1360 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1361 static
1362 int consdataFindLinearVar(
1363  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1364  SCIP_VAR* var /**< variable to search for */
1365  )
1366 {
1367  int pos;
1368 
1369  assert(consdata != NULL);
1370  assert(var != NULL);
1371 
1372  if( consdata->nlinvars == 0 )
1373  return -1;
1374 
1375  consdataSortLinearVars(consdata);
1376 
1377  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1378  pos = -1;
1379 
1380  return pos;
1381 }
1382 #endif
1383 
1384 /** index comparison method for quadratic variable terms: compares two indices of the quadratic variable set in the quadratic constraint */
1385 static
1386 SCIP_DECL_SORTINDCOMP(quadVarTermComp)
1387 { /*lint --e{715}*/
1388  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1389 
1390  assert(consdata != NULL);
1391  assert(0 <= ind1 && ind1 < consdata->nquadvars);
1392  assert(0 <= ind2 && ind2 < consdata->nquadvars);
1393 
1394  return SCIPvarCompare(consdata->quadvarterms[ind1].var, consdata->quadvarterms[ind2].var);
1395 }
1396 
1397 /** sorting of quadratic variable terms */
1398 static
1400  SCIP* scip, /**< SCIP data structure */
1401  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1402  )
1403 {
1404  int* perm;
1405  int i;
1406  int nexti;
1407  int v;
1408  SCIP_QUADVARTERM quadterm;
1409 
1410  assert(scip != NULL);
1411  assert(consdata != NULL);
1412 
1413  if( consdata->quadvarssorted )
1414  return SCIP_OKAY;
1415 
1416  if( consdata->nquadvars == 0 )
1417  {
1418  consdata->quadvarssorted = TRUE;
1419  return SCIP_OKAY;
1420  }
1421 
1422  /* get temporary memory to store the sorted permutation */
1423  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nquadvars) );
1424 
1425  /* call bubble sort */
1426  SCIPsort(perm, quadVarTermComp, (void*)consdata, consdata->nquadvars);
1427 
1428  /* permute the quadratic variable terms according to the resulting permutation */
1429  for( v = 0; v < consdata->nquadvars; ++v )
1430  {
1431  if( perm[v] != v )
1432  {
1433  quadterm = consdata->quadvarterms[v];
1434 
1435  i = v;
1436  do
1437  {
1438  assert(0 <= perm[i] && perm[i] < consdata->nquadvars);
1439  assert(perm[i] != i);
1440  consdata->quadvarterms[i] = consdata->quadvarterms[perm[i]];
1441  if( consdata->quadvarterms[i].eventdata != NULL )
1442  {
1443  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1444  }
1445  nexti = perm[i];
1446  perm[i] = i;
1447  i = nexti;
1448  }
1449  while( perm[i] != v );
1450  consdata->quadvarterms[i] = quadterm;
1451  if( consdata->quadvarterms[i].eventdata != NULL )
1452  {
1453  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1454  }
1455  perm[i] = i;
1456  }
1457  }
1458  consdata->quadvarssorted = TRUE;
1459 
1460  /* free temporary memory */
1461  SCIPfreeBufferArray(scip, &perm);
1462 
1463  return SCIP_OKAY;
1464 }
1465 
1466 /** returns the position of variable in the quadratic variable terms array of a constraint, or -1 if not found */
1467 static
1469  SCIP* scip, /**< SCIP data structure */
1470  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1471  SCIP_VAR* var, /**< variable to search for */
1472  int* pos /**< buffer where to store position of var in quadvarterms array, or -1 if not found */
1473  )
1474 {
1475  int left;
1476  int right;
1477  int cmpres;
1478 
1479  assert(consdata != NULL);
1480  assert(var != NULL);
1481  assert(pos != NULL);
1482 
1483  if( consdata->nquadvars == 0 )
1484  {
1485  *pos = -1;
1486  return SCIP_OKAY;
1487  }
1488 
1489  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
1490 
1491  left = 0;
1492  right = consdata->nquadvars - 1;
1493  while( left <= right )
1494  {
1495  int middle;
1496 
1497  middle = (left+right)/2;
1498  assert(0 <= middle && middle < consdata->nquadvars);
1499 
1500  cmpres = SCIPvarCompare(var, consdata->quadvarterms[middle].var);
1501 
1502  if( cmpres < 0 )
1503  right = middle - 1;
1504  else if( cmpres > 0 )
1505  left = middle + 1;
1506  else
1507  {
1508  *pos = middle;
1509  return SCIP_OKAY;
1510  }
1511  }
1512  assert(left == right+1);
1513 
1514  *pos = -1;
1515 
1516  return SCIP_OKAY;
1517 }
1518 
1519 /** index comparison method for bilinear terms: compares two index pairs of the bilinear term set in the quadratic constraint */
1520 static
1521 SCIP_DECL_SORTINDCOMP(bilinTermComp)
1522 { /*lint --e{715}*/
1523  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1524  int var1cmp;
1525 
1526  assert(consdata != NULL);
1527  assert(0 <= ind1 && ind1 < consdata->nbilinterms);
1528  assert(0 <= ind2 && ind2 < consdata->nbilinterms);
1529 
1530  var1cmp = SCIPvarCompare(consdata->bilinterms[ind1].var1, consdata->bilinterms[ind2].var1);
1531  if( var1cmp != 0 )
1532  return var1cmp;
1533 
1534  return SCIPvarCompare(consdata->bilinterms[ind1].var2, consdata->bilinterms[ind2].var2);
1535 }
1536 
1537 /** sorting of bilinear terms */
1538 static
1540  SCIP* scip, /**< SCIP data structure */
1541  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1542  )
1543 {
1544  int* perm;
1545  int* invperm;
1546  int i;
1547  int nexti;
1548  int v;
1549  SCIP_BILINTERM bilinterm;
1550 
1551  assert(scip != NULL);
1552  assert(consdata != NULL);
1553 
1554  if( consdata->bilinsorted )
1555  return SCIP_OKAY;
1556 
1557  if( consdata->nbilinterms == 0 )
1558  {
1559  consdata->bilinsorted = TRUE;
1560  return SCIP_OKAY;
1561  }
1562 
1563  /* get temporary memory to store the sorted permutation and the inverse permutation */
1564  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nbilinterms) );
1565  SCIP_CALL( SCIPallocBufferArray(scip, &invperm, consdata->nbilinterms) );
1566 
1567  /* call bubble sort */
1568  SCIPsort(perm, bilinTermComp, (void*)consdata, consdata->nbilinterms);
1569 
1570  /* compute inverted permutation */
1571  for( v = 0; v < consdata->nbilinterms; ++v )
1572  {
1573  assert(0 <= perm[v] && perm[v] < consdata->nbilinterms);
1574  invperm[perm[v]] = v;
1575  }
1576 
1577  /* permute the bilinear terms according to the resulting permutation */
1578  for( v = 0; v < consdata->nbilinterms; ++v )
1579  {
1580  if( perm[v] != v )
1581  {
1582  bilinterm = consdata->bilinterms[v];
1583 
1584  i = v;
1585  do
1586  {
1587  assert(0 <= perm[i] && perm[i] < consdata->nbilinterms);
1588  assert(perm[i] != i);
1589  consdata->bilinterms[i] = consdata->bilinterms[perm[i]];
1590  nexti = perm[i];
1591  perm[i] = i;
1592  i = nexti;
1593  }
1594  while( perm[i] != v );
1595  consdata->bilinterms[i] = bilinterm;
1596  perm[i] = i;
1597  }
1598  }
1599 
1600  /* update the adjacency information in the quadratic variable terms */
1601  for( v = 0; v < consdata->nquadvars; ++v )
1602  for( i = 0; i < consdata->quadvarterms[v].nadjbilin; ++i )
1603  consdata->quadvarterms[v].adjbilin[i] = invperm[consdata->quadvarterms[v].adjbilin[i]];
1604 
1605  consdata->bilinsorted = TRUE;
1606 
1607  /* free temporary memory */
1608  SCIPfreeBufferArray(scip, &perm);
1609  SCIPfreeBufferArray(scip, &invperm);
1610 
1611  return SCIP_OKAY;
1612 }
1613 
1614 /** moves a linear variable from one position to another */
1615 static
1617  SCIP_CONSDATA* consdata, /**< constraint data */
1618  int oldpos, /**< position of variable that shall be moved */
1619  int newpos /**< new position of variable */
1620  )
1621 {
1622  assert(consdata != NULL);
1623  assert(oldpos >= 0);
1624  assert(oldpos < consdata->nlinvars);
1625  assert(newpos >= 0);
1626  assert(newpos < consdata->linvarssize);
1627 
1628  if( newpos == oldpos )
1629  return;
1630 
1631  consdata->linvars [newpos] = consdata->linvars [oldpos];
1632  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1633 
1634  if( consdata->lineventdata != NULL )
1635  {
1636  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1637 
1638  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1639  consdata->lineventdata[newpos]->varidx = newpos;
1640 
1641  consdata->lineventdata[oldpos] = NULL;
1642  }
1643 
1644  consdata->linvarssorted = FALSE;
1645 }
1646 
1647 /** moves a quadratic variable from one position to another */
1648 static
1650  SCIP_CONSDATA* consdata, /**< constraint data */
1651  int oldpos, /**< position of variable that shall be moved */
1652  int newpos /**< new position of variable */
1653  )
1654 {
1655  assert(consdata != NULL);
1656  assert(oldpos >= 0);
1657  assert(oldpos < consdata->nquadvars);
1658  assert(newpos >= 0);
1659  assert(newpos < consdata->quadvarssize);
1660 
1661  if( newpos == oldpos )
1662  return;
1663 
1664  assert(newpos >= consdata->nquadvars || consdata->quadvarterms[newpos].eventdata == NULL);
1665 
1666  consdata->quadvarterms[newpos] = consdata->quadvarterms[oldpos];
1667 
1668  if( consdata->quadvarterms[newpos].eventdata != NULL )
1669  {
1670  consdata->quadvarterms[newpos].eventdata->varidx = -newpos-1;
1671  consdata->quadvarterms[oldpos].eventdata = NULL;
1672  }
1673 
1674  consdata->quadvarssorted = FALSE;
1675 }
1676 
1677 /** adds linear coefficient in quadratic constraint */
1678 static
1680  SCIP* scip, /**< SCIP data structure */
1681  SCIP_CONS* cons, /**< quadratic constraint */
1682  SCIP_VAR* var, /**< variable of constraint entry */
1683  SCIP_Real coef /**< coefficient of constraint entry */
1684  )
1685 {
1686  SCIP_CONSDATA* consdata;
1687  SCIP_Bool transformed;
1688 
1689  assert(scip != NULL);
1690  assert(cons != NULL);
1691  assert(var != NULL);
1692 
1693  /* ignore coefficient if it is nearly zero */
1694  if( SCIPisZero(scip, coef) )
1695  return SCIP_OKAY;
1696 
1697  consdata = SCIPconsGetData(cons);
1698  assert(consdata != NULL);
1699 
1700  /* are we in the transformed problem? */
1701  transformed = SCIPconsIsTransformed(cons);
1702 
1703  /* always use transformed variables in transformed constraints */
1704  if( transformed )
1705  {
1706  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1707  }
1708  assert(var != NULL);
1709  assert(transformed == SCIPvarIsTransformed(var));
1710 
1711  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1712  consdata->linvars [consdata->nlinvars] = var;
1713  consdata->lincoefs[consdata->nlinvars] = coef;
1714 
1715  ++consdata->nlinvars;
1716 
1717  /* catch variable events */
1718  if( consdata->lineventdata != NULL )
1719  {
1720  SCIP_CONSHDLR* conshdlr;
1721  SCIP_CONSHDLRDATA* conshdlrdata;
1722 
1723  /* get event handler */
1724  conshdlr = SCIPconsGetHdlr(cons);
1725  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1726  assert(conshdlrdata != NULL);
1727  assert(conshdlrdata->eventhdlr != NULL);
1728 
1729  consdata->lineventdata[consdata->nlinvars-1] = NULL;
1730 
1731  /* catch bound change events of variable */
1732  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nlinvars-1) );
1733  }
1734 
1735  /* invalidate activity information */
1736  consdata->activity = SCIP_INVALID;
1737  consdata->minlinactivity = SCIP_INVALID;
1738  consdata->maxlinactivity = SCIP_INVALID;
1739  consdata->minlinactivityinf = -1;
1740  consdata->maxlinactivityinf = -1;
1741 
1742  /* invalidate nonlinear row */
1743  if( consdata->nlrow != NULL )
1744  {
1745  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1746  }
1747 
1748  /* install rounding locks for new variable */
1749  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1750 
1751  /* capture new variable */
1752  SCIP_CALL( SCIPcaptureVar(scip, var) );
1753 
1754  consdata->ispropagated = FALSE;
1755  consdata->ispresolved = FALSE;
1756  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
1757  if( consdata->nlinvars == 1 )
1758  consdata->linvarssorted = TRUE;
1759  else
1760  consdata->linvarssorted = consdata->linvarssorted && (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1761  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1762  consdata->linvarsmerged = FALSE;
1763 
1764  return SCIP_OKAY;
1765 }
1766 
1767 /** deletes linear coefficient at given position from quadratic constraint data */
1768 static
1770  SCIP* scip, /**< SCIP data structure */
1771  SCIP_CONS* cons, /**< quadratic constraint */
1772  int pos /**< position of coefficient to delete */
1773  )
1774 {
1775  SCIP_CONSDATA* consdata;
1776  SCIP_VAR* var;
1777  SCIP_Real coef;
1778 
1779  assert(scip != NULL);
1780  assert(cons != NULL);
1781 
1782  consdata = SCIPconsGetData(cons);
1783  assert(consdata != NULL);
1784  assert(0 <= pos && pos < consdata->nlinvars);
1785 
1786  var = consdata->linvars[pos];
1787  coef = consdata->lincoefs[pos];
1788  assert(var != NULL);
1789 
1790  /* remove rounding locks for deleted variable */
1791  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1792 
1793  /* if we catch variable events, drop the events on the variable */
1794  if( consdata->lineventdata != NULL )
1795  {
1796  SCIP_CONSHDLR* conshdlr;
1797  SCIP_CONSHDLRDATA* conshdlrdata;
1798 
1799  /* get event handler */
1800  conshdlr = SCIPconsGetHdlr(cons);
1801  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1802  assert(conshdlrdata != NULL);
1803  assert(conshdlrdata->eventhdlr != NULL);
1804 
1805  /* drop bound change events of variable */
1806  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1807  }
1808 
1809  /* release variable */
1810  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
1811 
1812  /* move the last variable to the free slot */
1813  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
1814 
1815  --consdata->nlinvars;
1816 
1817  /* invalidate activity */
1818  consdata->activity = SCIP_INVALID;
1819  consdata->minlinactivity = SCIP_INVALID;
1820  consdata->maxlinactivity = SCIP_INVALID;
1821  consdata->minlinactivityinf = -1;
1822  consdata->maxlinactivityinf = -1;
1823 
1824  /* invalidate nonlinear row */
1825  if( consdata->nlrow != NULL )
1826  {
1827  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1828  }
1829 
1830  consdata->ispropagated = FALSE;
1831  consdata->ispresolved = FALSE;
1832 
1833  return SCIP_OKAY;
1834 }
1835 
1836 /** changes linear coefficient value at given position of quadratic constraint */
1837 static
1839  SCIP* scip, /**< SCIP data structure */
1840  SCIP_CONS* cons, /**< quadratic constraint */
1841  int pos, /**< position of linear coefficient to change */
1842  SCIP_Real newcoef /**< new value of linear coefficient */
1843  )
1844 {
1845  SCIP_CONSHDLR* conshdlr;
1846  SCIP_CONSHDLRDATA* conshdlrdata;
1847  SCIP_CONSDATA* consdata;
1848  SCIP_VAR* var;
1849  SCIP_Real coef;
1850 
1851  assert(scip != NULL);
1852  assert(cons != NULL);
1853  assert(!SCIPisZero(scip, newcoef));
1854 
1855  conshdlrdata = NULL;
1856 
1857  consdata = SCIPconsGetData(cons);
1858  assert(consdata != NULL);
1859  assert(0 <= pos);
1860  assert(pos < consdata->nlinvars);
1861  assert(!SCIPisZero(scip, newcoef));
1862 
1863  var = consdata->linvars[pos];
1864  coef = consdata->lincoefs[pos];
1865  assert(var != NULL);
1866  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
1867 
1868  /* invalidate activity */
1869  consdata->activity = SCIP_INVALID;
1870  consdata->minlinactivity = SCIP_INVALID;
1871  consdata->maxlinactivity = SCIP_INVALID;
1872  consdata->minlinactivityinf = -1;
1873  consdata->maxlinactivityinf = -1;
1874 
1875  /* invalidate nonlinear row */
1876  if( consdata->nlrow != NULL )
1877  {
1878  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1879  }
1880 
1881  /* if necessary, remove the rounding locks and event catching of the variable */
1882  if( newcoef * coef < 0.0 )
1883  {
1884  if( SCIPconsIsLocked(cons) )
1885  {
1886  assert(SCIPconsIsTransformed(cons));
1887 
1888  /* remove rounding locks for variable with old coefficient */
1889  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1890  }
1891 
1892  if( consdata->lineventdata[pos] != NULL )
1893  {
1894  /* get event handler */
1895  conshdlr = SCIPconsGetHdlr(cons);
1896  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1897  assert(conshdlrdata != NULL);
1898  assert(conshdlrdata->eventhdlr != NULL);
1899 
1900  /* drop bound change events of variable */
1901  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1902  }
1903  }
1904 
1905  /* change the coefficient */
1906  consdata->lincoefs[pos] = newcoef;
1907 
1908  /* if necessary, install the rounding locks and event catching of the variable again */
1909  if( newcoef * coef < 0.0 )
1910  {
1911  if( SCIPconsIsLocked(cons) )
1912  {
1913  /* install rounding locks for variable with new coefficient */
1914  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
1915  }
1916 
1917  if( conshdlrdata != NULL )
1918  {
1919  /* catch bound change events of variable */
1920  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1921  }
1922  }
1923 
1924  consdata->ispropagated = FALSE;
1925  consdata->ispresolved = FALSE;
1926 
1927  return SCIP_OKAY;
1928 }
1929 
1930 /** adds quadratic variable term to quadratic constraint */
1931 static
1933  SCIP* scip, /**< SCIP data structure */
1934  SCIP_CONS* cons, /**< quadratic constraint */
1935  SCIP_VAR* var, /**< variable to add */
1936  SCIP_Real lincoef, /**< linear coefficient of variable */
1937  SCIP_Real sqrcoef, /**< square coefficient of variable */
1938  SCIP_Bool catchevents /**< whether we should catch variable events */
1939  )
1940 {
1941  SCIP_CONSDATA* consdata;
1942  SCIP_Bool transformed;
1943  SCIP_QUADVARTERM* quadvarterm;
1944 
1945  assert(scip != NULL);
1946  assert(cons != NULL);
1947  assert(var != NULL);
1948 
1949  consdata = SCIPconsGetData(cons);
1950  assert(consdata != NULL);
1951 
1952  /* are we in the transformed problem? */
1953  transformed = SCIPconsIsTransformed(cons);
1954 
1955  /* always use transformed variables in transformed constraints */
1956  if( transformed )
1957  {
1958  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1959  }
1960  assert(var != NULL);
1961  assert(transformed == SCIPvarIsTransformed(var));
1962 
1963  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars+1) );
1964 
1965  quadvarterm = &consdata->quadvarterms[consdata->nquadvars];
1966  quadvarterm->var = var;
1967  quadvarterm->lincoef = lincoef;
1968  quadvarterm->sqrcoef = sqrcoef;
1969  quadvarterm->adjbilinsize = 0;
1970  quadvarterm->nadjbilin = 0;
1971  quadvarterm->adjbilin = NULL;
1972  quadvarterm->eventdata = NULL;
1973 
1974  ++consdata->nquadvars;
1975 
1976  /* capture variable */
1977  SCIP_CALL( SCIPcaptureVar(scip, var) );
1978 
1979  /* catch variable events, if we do so */
1980  if( catchevents )
1981  {
1982  SCIP_CONSHDLR* conshdlr;
1983  SCIP_CONSHDLRDATA* conshdlrdata;
1984 
1985  /* get event handler */
1986  conshdlr = SCIPconsGetHdlr(cons);
1987  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1988  assert(conshdlrdata != NULL);
1989  assert(conshdlrdata->eventhdlr != NULL);
1990 
1991  /* catch bound change events of variable */
1992  SCIP_CALL( catchQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nquadvars-1) );
1993  }
1994 
1995  /* invalidate activity information */
1996  consdata->activity = SCIP_INVALID;
1997  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
1998 
1999  /* invalidate nonlinear row */
2000  if( consdata->nlrow != NULL )
2001  {
2002  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2003  }
2004 
2005  /* install rounding locks for new variable */
2006  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2007 
2008  consdata->ispropagated = FALSE;
2009  consdata->ispresolved = FALSE;
2010  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
2011  if( consdata->nquadvars == 1 )
2012  consdata->quadvarssorted = TRUE;
2013  else
2014  consdata->quadvarssorted = consdata->quadvarssorted && (SCIPvarCompare(consdata->quadvarterms[consdata->nquadvars-2].var, consdata->quadvarterms[consdata->nquadvars-1].var) == -1);
2015  /* also set to FALSE if nquadvars == 1, since the new variable should be checked for linearity and other stuff in mergeAndClean ... */
2016  consdata->quadvarsmerged = FALSE;
2017 
2018  consdata->iscurvchecked = FALSE;
2019 
2020  return SCIP_OKAY;
2021 }
2022 
2023 /** deletes quadratic variable term at given position from quadratic constraint data */
2024 static
2026  SCIP* scip, /**< SCIP data structure */
2027  SCIP_CONS* cons, /**< quadratic constraint */
2028  int pos /**< position of term to delete */
2029  )
2030 {
2031  SCIP_CONSDATA* consdata;
2032  SCIP_VAR* var;
2033 
2034  assert(scip != NULL);
2035  assert(cons != NULL);
2036 
2037  consdata = SCIPconsGetData(cons);
2038  assert(consdata != NULL);
2039  assert(0 <= pos && pos < consdata->nquadvars);
2040 
2041  var = consdata->quadvarterms[pos].var;
2042  assert(var != NULL);
2043  assert(consdata->quadvarterms[pos].nadjbilin == 0);
2044 
2045  /* remove rounding locks for deleted variable */
2046  SCIP_CALL( unlockQuadraticVariable(scip, cons, var) );
2047 
2048  /* if we catch variable events, drop the events on the variable */
2049  if( consdata->quadvarterms[pos].eventdata != NULL )
2050  {
2051  SCIP_CONSHDLR* conshdlr;
2052  SCIP_CONSHDLRDATA* conshdlrdata;
2053 
2054  /* get event handler */
2055  conshdlr = SCIPconsGetHdlr(cons);
2056  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2057  assert(conshdlrdata != NULL);
2058  assert(conshdlrdata->eventhdlr != NULL);
2059 
2060  /* drop bound change events of variable */
2061  SCIP_CALL( dropQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2062  }
2063 
2064  /* release variable */
2065  SCIP_CALL( SCIPreleaseVar(scip, &consdata->quadvarterms[pos].var) );
2066 
2067  /* free adjacency array */
2068  SCIPfreeBlockMemoryArrayNull(scip, &consdata->quadvarterms[pos].adjbilin, consdata->quadvarterms[pos].adjbilinsize);
2069 
2070  /* move the last variable term to the free slot */
2071  consdataMoveQuadVarTerm(consdata, consdata->nquadvars-1, pos);
2072 
2073  --consdata->nquadvars;
2074 
2075  /* invalidate activity */
2076  consdata->activity = SCIP_INVALID;
2077  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2078 
2079  /* invalidate nonlinear row */
2080  if( consdata->nlrow != NULL )
2081  {
2082  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2083  }
2084 
2085  consdata->ispropagated = FALSE;
2086  consdata->ispresolved = FALSE;
2087  consdata->iscurvchecked = FALSE;
2088 
2089  return SCIP_OKAY;
2090 }
2091 
2092 /** replace variable in quadratic variable term at given position of quadratic constraint data
2093  * allows to replace x by coef*y+offset, thereby maintaining linear and square coefficients and bilinear terms */
2094 static
2096  SCIP* scip, /**< SCIP data structure */
2097  SCIP_CONS* cons, /**< quadratic constraint */
2098  int pos, /**< position of term to replace */
2099  SCIP_VAR* var, /**< new variable */
2100  SCIP_Real coef, /**< linear coefficient of new variable */
2101  SCIP_Real offset /**< offset of new variable */
2102  )
2103 {
2104  SCIP_CONSDATA* consdata;
2105  SCIP_QUADVARTERM* quadvarterm;
2106  SCIP_EVENTHDLR* eventhdlr;
2107  SCIP_BILINTERM* bilinterm;
2108  SCIP_Real constant;
2109 
2110  int i;
2111  SCIP_VAR* var2;
2112 
2113  consdata = SCIPconsGetData(cons);
2114  assert(consdata != NULL);
2115  assert(pos >= 0);
2116  assert(pos < consdata->nquadvars);
2117 
2118  quadvarterm = &consdata->quadvarterms[pos];
2119 
2120  /* remove rounding locks for old variable */
2121  SCIP_CALL( unlockQuadraticVariable(scip, cons, quadvarterm->var) );
2122 
2123  /* if we catch variable events, drop the events on the old variable */
2124  if( quadvarterm->eventdata != NULL )
2125  {
2126  SCIP_CONSHDLR* conshdlr;
2127  SCIP_CONSHDLRDATA* conshdlrdata;
2128 
2129  /* get event handler */
2130  conshdlr = SCIPconsGetHdlr(cons);
2131  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2132  assert(conshdlrdata != NULL);
2133  assert(conshdlrdata->eventhdlr != NULL);
2134 
2135  eventhdlr = conshdlrdata->eventhdlr;
2136 
2137  /* drop bound change events of variable */
2138  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, pos) );
2139  }
2140  else
2141  {
2142  eventhdlr = NULL;
2143  }
2144 
2145  /* compute constant and put into lhs/rhs */
2146  constant = quadvarterm->lincoef * offset + quadvarterm->sqrcoef * offset * offset;
2147  if( constant != 0.0 )
2148  {
2149  /* maintain constant part */
2150  if( !SCIPisInfinity(scip, -consdata->lhs) )
2151  consdata->lhs -= constant;
2152  if( !SCIPisInfinity(scip, consdata->rhs) )
2153  consdata->rhs -= constant;
2154  }
2155 
2156  /* update linear and square coefficient */
2157  quadvarterm->lincoef *= coef;
2158  quadvarterm->lincoef += 2.0 * quadvarterm->sqrcoef * coef * offset;
2159  quadvarterm->sqrcoef *= coef * coef;
2160 
2161  /* update bilinear terms */
2162  for( i = 0; i < quadvarterm->nadjbilin; ++i )
2163  {
2164  bilinterm = &consdata->bilinterms[quadvarterm->adjbilin[i]];
2165 
2166  if( bilinterm->var1 == quadvarterm->var )
2167  {
2168  bilinterm->var1 = var;
2169  var2 = bilinterm->var2;
2170  }
2171  else
2172  {
2173  assert(bilinterm->var2 == quadvarterm->var);
2174  bilinterm->var2 = var;
2175  var2 = bilinterm->var1;
2176  }
2177 
2178  if( var == var2 )
2179  {
2180  /* looks like we actually have a square term here */
2181  quadvarterm->lincoef += bilinterm->coef * offset;
2182  quadvarterm->sqrcoef += bilinterm->coef * coef;
2183  /* deleting bilinear terms is expensive, since it requires updating adjacency information
2184  * thus, for now we just set the coefficient to 0.0 and clear in later when the bilinear terms are merged */
2185  bilinterm->coef = 0.0;
2186  continue;
2187  }
2188 
2189  /* swap var1 and var2 if they are in wrong order */
2190  if( SCIPvarCompare(bilinterm->var1, bilinterm->var2) > 0 )
2191  {
2192  SCIP_VAR* tmp;
2193  tmp = bilinterm->var1;
2194  bilinterm->var1 = bilinterm->var2;
2195  bilinterm->var2 = tmp;
2196  }
2197  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2198 
2199  if( offset != 0.0 )
2200  {
2201  /* need to find var2 and add offset*bilinterm->coef to linear coefficient */
2202  int var2pos;
2203 
2204  var2pos = 0;
2205  while( consdata->quadvarterms[var2pos].var != var2 )
2206  {
2207  ++var2pos;
2208  assert(var2pos < consdata->nquadvars);
2209  }
2210 
2211  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2212  }
2213 
2214  bilinterm->coef *= coef;
2215  }
2216 
2217  /* release old variable */
2218  SCIP_CALL( SCIPreleaseVar(scip, &quadvarterm->var) );
2219 
2220  /* set new variable */
2221  quadvarterm->var = var;
2222 
2223  /* capture new variable */
2224  SCIP_CALL( SCIPcaptureVar(scip, quadvarterm->var) );
2225 
2226  /* catch variable events, if we do so */
2227  if( eventhdlr != NULL )
2228  {
2229  /* catch bound change events of variable */
2230  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, pos) );
2231  }
2232 
2233  /* invalidate activity information */
2234  consdata->activity = SCIP_INVALID;
2235  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2236 
2237  /* invalidate nonlinear row */
2238  if( consdata->nlrow != NULL )
2239  {
2240  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2241  }
2242 
2243  /* install rounding locks for new variable */
2244  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2245 
2246  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var);
2247  consdata->quadvarssorted = (consdata->nquadvars == 1);
2248  consdata->quadvarsmerged = FALSE;
2249  consdata->bilinsorted &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2250  consdata->bilinmerged &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2251 
2252  consdata->ispropagated = FALSE;
2253  consdata->ispresolved = FALSE;
2254  consdata->iscurvchecked = FALSE;
2255 
2256  return SCIP_OKAY;
2257 }
2258 
2259 /** adds a bilinear term to quadratic constraint */
2260 static
2262  SCIP* scip, /**< SCIP data structure */
2263  SCIP_CONS* cons, /**< quadratic constraint */
2264  int var1pos, /**< position of first variable in quadratic variables array */
2265  int var2pos, /**< position of second variable in quadratic variables array */
2266  SCIP_Real coef /**< coefficient of bilinear term */
2267  )
2268 {
2269  SCIP_CONSDATA* consdata;
2270  SCIP_BILINTERM* bilinterm;
2271 
2272  assert(scip != NULL);
2273  assert(cons != NULL);
2274 
2275  if( var1pos == var2pos )
2276  {
2277  SCIPerrorMessage("tried to add bilinear term where both variables are the same\n");
2278  return SCIP_INVALIDDATA;
2279  }
2280 
2281  consdata = SCIPconsGetData(cons);
2282  assert(consdata != NULL);
2283 
2284  assert(var1pos >= 0);
2285  assert(var1pos < consdata->nquadvars);
2286  assert(var2pos >= 0);
2287  assert(var2pos < consdata->nquadvars);
2288 
2289  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nbilinterms + 1) );
2290 
2291  bilinterm = &consdata->bilinterms[consdata->nbilinterms];
2292  if( SCIPvarCompare(consdata->quadvarterms[var1pos].var, consdata->quadvarterms[var2pos].var) < 0 )
2293  {
2294  bilinterm->var1 = consdata->quadvarterms[var1pos].var;
2295  bilinterm->var2 = consdata->quadvarterms[var2pos].var;
2296  }
2297  else
2298  {
2299  bilinterm->var1 = consdata->quadvarterms[var2pos].var;
2300  bilinterm->var2 = consdata->quadvarterms[var1pos].var;
2301  }
2302  bilinterm->coef = coef;
2303 
2304  if( bilinterm->var1 == bilinterm->var2 )
2305  {
2306  SCIPerrorMessage("tried to add bilinear term where both variables are the same, but appear at different positions in quadvarterms array\n");
2307  return SCIP_INVALIDDATA;
2308  }
2309  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2310 
2311  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var1pos], consdata->quadvarterms[var1pos].nadjbilin + 1) );
2312  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var2pos], consdata->quadvarterms[var2pos].nadjbilin + 1) );
2313 
2314  consdata->quadvarterms[var1pos].adjbilin[consdata->quadvarterms[var1pos].nadjbilin] = consdata->nbilinterms;
2315  consdata->quadvarterms[var2pos].adjbilin[consdata->quadvarterms[var2pos].nadjbilin] = consdata->nbilinterms;
2316  ++consdata->quadvarterms[var1pos].nadjbilin;
2317  ++consdata->quadvarterms[var2pos].nadjbilin;
2318 
2319  ++consdata->nbilinterms;
2320 
2321  /* invalidate activity information */
2322  consdata->activity = SCIP_INVALID;
2323  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2324 
2325  /* invalidate nonlinear row */
2326  if( consdata->nlrow != NULL )
2327  {
2328  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2329  }
2330 
2331  consdata->ispropagated = FALSE;
2332  consdata->ispresolved = FALSE;
2333  if( consdata->nbilinterms == 1 )
2334  {
2335  consdata->bilinsorted = TRUE;
2336  consdata->bilinmerged = TRUE;
2337  }
2338  else
2339  {
2340  consdata->bilinsorted = consdata->bilinsorted
2341  && (bilinTermComp(consdata, consdata->nbilinterms-2, consdata->nbilinterms-1) >= 0);
2342  consdata->bilinmerged = FALSE;
2343  }
2344 
2345  consdata->iscurvchecked = FALSE;
2346 
2347  return SCIP_OKAY;
2348 }
2349 
2350 /** removes a set of bilinear terms and updates adjacency information in quad var terms
2351  * Note: this function sorts the given array termposs */
2352 static
2354  SCIP* scip, /**< SCIP data structure */
2355  SCIP_CONS* cons, /**< quadratic constraint */
2356  int nterms, /**< number of terms to delete */
2357  int* termposs /**< indices of terms to delete */
2358  )
2359 {
2360  SCIP_CONSDATA* consdata;
2361  int* newpos;
2362  int i;
2363  int j;
2364  int offset;
2365 
2366  assert(scip != NULL);
2367  assert(cons != NULL);
2368  assert(nterms == 0 || termposs != NULL);
2369 
2370  if( nterms == 0 )
2371  return SCIP_OKAY;
2372 
2373  consdata = SCIPconsGetData(cons);
2374  assert(consdata != NULL);
2375 
2376  SCIPsortInt(termposs, nterms);
2377 
2378  SCIP_CALL( SCIPallocBufferArray(scip, &newpos, consdata->nbilinterms) );
2379 
2380  i = 0;
2381  offset = 0;
2382  for( j = 0; j < consdata->nbilinterms; ++j )
2383  {
2384  /* if j'th term is deleted, increase offset and continue */
2385  if( i < nterms && j == termposs[i] )
2386  {
2387  ++offset;
2388  ++i;
2389  newpos[j] = -1;
2390  continue;
2391  }
2392 
2393  /* otherwise, move it forward and remember new position */
2394  if( offset > 0 )
2395  consdata->bilinterms[j-offset] = consdata->bilinterms[j];
2396  newpos[j] = j - offset;
2397  }
2398  assert(offset == nterms);
2399 
2400  /* update adjacency and activity information in quad var terms */
2401  for( i = 0; i < consdata->nquadvars; ++i )
2402  {
2403  offset = 0;
2404  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2405  {
2406  assert(consdata->quadvarterms[i].adjbilin[j] < consdata->nbilinterms);
2407  if( newpos[consdata->quadvarterms[i].adjbilin[j]] == -1 )
2408  {
2409  /* corresponding bilinear term was deleted, thus increase offset */
2410  ++offset;
2411  }
2412  else
2413  {
2414  /* update index of j'th bilinear term and store at position j-offset */
2415  consdata->quadvarterms[i].adjbilin[j-offset] = newpos[consdata->quadvarterms[i].adjbilin[j]];
2416  }
2417  }
2418  consdata->quadvarterms[i].nadjbilin -= offset;
2419  /* some bilinear term was removed, so invalidate activity bounds */
2420  }
2421 
2422  consdata->nbilinterms -= nterms;
2423 
2424  SCIPfreeBufferArray(scip, &newpos);
2425 
2426  /* some quad vars may be linear now */
2427  consdata->quadvarsmerged = FALSE;
2428 
2429  consdata->ispropagated = FALSE;
2430  consdata->ispresolved = FALSE;
2431  consdata->iscurvchecked = FALSE;
2432 
2433  /* invalidate activity */
2434  consdata->activity = SCIP_INVALID;
2435  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2436 
2437  /* invalidate nonlinear row */
2438  if( consdata->nlrow != NULL )
2439  {
2440  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2441  }
2442 
2443  return SCIP_OKAY;
2444 }
2445 
2446 /* merges quad var terms that correspond to the same variable and does additional cleanup
2447  * if a quadratic variable terms is actually linear, makes a linear term out of it
2448  * also replaces squares of binary variables by the binary variables, i.e., adds sqrcoef to lincoef
2449  */
2450 static
2452  SCIP* scip, /**< SCIP data structure */
2453  SCIP_CONS* cons /**< quadratic constraint */
2454  )
2455 {
2456  SCIP_QUADVARTERM* quadvarterm;
2457  SCIP_CONSDATA* consdata;
2458  int i;
2459  int j;
2460 
2461  assert(scip != NULL);
2462  assert(cons != NULL);
2463 
2464  consdata = SCIPconsGetData(cons);
2465 
2466  if( consdata->quadvarsmerged )
2467  return SCIP_OKAY;
2468 
2469  if( consdata->nquadvars == 0 )
2470  {
2471  consdata->quadvarsmerged = TRUE;
2472  return SCIP_OKAY;
2473  }
2474 
2475  i = 0;
2476  while( i < consdata->nquadvars )
2477  {
2478  /* make sure quad var terms are sorted (do this in every round, since we may move variables around) */
2479  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
2480 
2481  quadvarterm = &consdata->quadvarterms[i];
2482 
2483  for( j = i+1; j < consdata->nquadvars && consdata->quadvarterms[j].var == quadvarterm->var; ++j )
2484  {
2485  /* add quad var term j to current term i */
2486  quadvarterm->lincoef += consdata->quadvarterms[j].lincoef;
2487  quadvarterm->sqrcoef += consdata->quadvarterms[j].sqrcoef;
2488  if( consdata->quadvarterms[j].nadjbilin > 0 )
2489  {
2490  /* move adjacency information from j to i */
2491  SCIP_CALL( consdataEnsureAdjBilinSize(scip, quadvarterm, quadvarterm->nadjbilin + consdata->quadvarterms[j].nadjbilin) );
2492  BMScopyMemoryArray(&quadvarterm->adjbilin[quadvarterm->nadjbilin], consdata->quadvarterms[j].adjbilin, consdata->quadvarterms[j].nadjbilin); /*lint !e866*/
2493  quadvarterm->nadjbilin += consdata->quadvarterms[j].nadjbilin;
2494  consdata->quadvarterms[j].nadjbilin = 0;
2495  }
2496  consdata->quadvarterms[j].lincoef = 0.0;
2497  consdata->quadvarterms[j].sqrcoef = 0.0;
2498  /* mark that activity information in quadvarterm is not up to date anymore */
2499  }
2500 
2501  /* remove quad var terms i+1..j-1 backwards */
2502  for( j = j-1; j > i; --j )
2503  {
2504  SCIP_CALL( delQuadVarTermPos(scip, cons, j) );
2505  }
2506 
2507  /* for binary variables, x^2 = x
2508  * however, we may destroy convexity of a quadratic term that involves also bilinear terms
2509  * thus, we do this step only if the variable does not appear in any bilinear term */
2510  if( quadvarterm->sqrcoef != 0.0 && SCIPvarIsBinary(quadvarterm->var) && quadvarterm->nadjbilin == 0 )
2511  {
2512  SCIPdebugMessage("replace square of binary variable by itself: <%s>^2 --> <%s>\n", SCIPvarGetName(quadvarterm->var), SCIPvarGetName(quadvarterm->var));
2513  quadvarterm->lincoef += quadvarterm->sqrcoef;
2514  quadvarterm->sqrcoef = 0.0;
2515 
2516  /* invalidate nonlinear row */
2517  if( consdata->nlrow != NULL )
2518  {
2519  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2520  }
2521  }
2522 
2523  /* if its 0.0 or linear, get rid of it */
2524  if( SCIPisZero(scip, quadvarterm->sqrcoef) && quadvarterm->nadjbilin == 0 )
2525  {
2526  if( !SCIPisZero(scip, quadvarterm->lincoef) )
2527  {
2528  /* seem to be a linear term now, thus add as linear term */
2529  SCIP_CALL( addLinearCoef(scip, cons, quadvarterm->var, quadvarterm->lincoef) );
2530  }
2531  /* remove term at pos i */
2532  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2533  }
2534  else
2535  {
2536  ++i;
2537  }
2538  }
2539 
2540  consdata->quadvarsmerged = TRUE;
2541  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2542 
2543  return SCIP_OKAY;
2544 }
2545 
2546 /* merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
2547 static
2549  SCIP* scip, /**< SCIP data structure */
2550  SCIP_CONS* cons /**< quadratic constraint */
2551  )
2552 {
2553  SCIP_CONSDATA* consdata;
2554  SCIP_Real newcoef;
2555  int i;
2556  int j;
2557  int qvarpos;
2558 
2559  assert(scip != NULL);
2560  assert(cons != NULL);
2561 
2562  consdata = SCIPconsGetData(cons);
2563 
2564  if( consdata->linvarsmerged )
2565  return SCIP_OKAY;
2566 
2567  if( consdata->nlinvars == 0 )
2568  {
2569  consdata->linvarsmerged = TRUE;
2570  return SCIP_OKAY;
2571  }
2572 
2573  i = 0;
2574  while( i < consdata->nlinvars )
2575  {
2576  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
2577  consdataSortLinearVars(consdata);
2578 
2579  /* sum up coefficients that correspond to variable i */
2580  newcoef = consdata->lincoefs[i];
2581  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
2582  newcoef += consdata->lincoefs[j];
2583  /* delete the additional variables in backward order */
2584  for( j = j-1; j > i; --j )
2585  {
2586  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
2587  }
2588 
2589  /* check if there is already a quadratic variable term with this variable */
2590  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->linvars[i], &qvarpos) );
2591  if( qvarpos >= 0)
2592  {
2593  /* add newcoef to linear coefficient of quadratic variable and mark linear variable as to delete */
2594  assert(qvarpos < consdata->nquadvars);
2595  assert(consdata->quadvarterms[qvarpos].var == consdata->linvars[i]);
2596  consdata->quadvarterms[qvarpos].lincoef += newcoef;
2597  newcoef = 0.0;
2598  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2599  }
2600 
2601  /* delete also entry at position i, if it became zero (or was zero before) */
2602  if( SCIPisZero(scip, newcoef) )
2603  {
2604  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2605  }
2606  else
2607  {
2608  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
2609  ++i;
2610  }
2611  }
2612 
2613  consdata->linvarsmerged = TRUE;
2614 
2615  return SCIP_OKAY;
2616 }
2617 
2618 /* merges bilinear terms with same variables into a single term, removes bilinear terms with coefficient 0.0 */
2619 static
2621  SCIP* scip, /**< SCIP data structure */
2622  SCIP_CONS* cons /**< quadratic constraint */
2623  )
2624 {
2625  SCIP_CONSDATA* consdata;
2626  SCIP_BILINTERM* bilinterm;
2627  int i;
2628  int j;
2629  int* todelete;
2630  int ntodelete;
2631 
2632  assert(scip != NULL);
2633  assert(cons != NULL);
2634 
2635  consdata = SCIPconsGetData(cons);
2636 
2637  if( consdata->bilinmerged )
2638  return SCIP_OKAY;
2639 
2640  if( consdata->nbilinterms == 0 )
2641  {
2642  consdata->bilinmerged = TRUE;
2643  return SCIP_OKAY;
2644  }
2645 
2646  /* alloc memory for array of terms that need to be deleted finally */
2647  ntodelete = 0;
2648  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
2649 
2650  /* make sure bilinear terms are sorted */
2651  SCIP_CALL( consdataSortBilinTerms(scip, consdata) );
2652 
2653  i = 0;
2654  while( i < consdata->nbilinterms )
2655  {
2656  bilinterm = &consdata->bilinterms[i];
2657 
2658  /* sum up coefficients that correspond to same variables as term i */
2659  for( j = i+1; j < consdata->nbilinterms && bilinterm->var1 == consdata->bilinterms[j].var1 && bilinterm->var2 == consdata->bilinterms[j].var2; ++j )
2660  {
2661  bilinterm->coef += consdata->bilinterms[j].coef;
2662  todelete[ntodelete++] = j;
2663  }
2664 
2665  /* delete also entry at position i, if it became zero (or was zero before) */
2666  if( SCIPisZero(scip, bilinterm->coef) )
2667  {
2668  todelete[ntodelete++] = i;
2669  }
2670 
2671  /* continue with term after the current series */
2672  i = j;
2673  }
2674 
2675  /* delete bilinear terms */
2676  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
2677 
2678  SCIPfreeBufferArray(scip, &todelete);
2679 
2680  consdata->bilinmerged = TRUE;
2681 
2682  return SCIP_OKAY;
2683 }
2684 
2685 /** removes fixes (or aggregated) variables from a quadratic constraint */
2686 static
2688  SCIP* scip, /**< SCIP data structure */
2689  SCIP_CONS* cons /**< quadratic constraint */
2690  )
2691 {
2692  SCIP_CONSDATA* consdata;
2693  SCIP_BILINTERM* bilinterm;
2694  SCIP_Real coef;
2695  SCIP_Real offset;
2696  SCIP_VAR* var;
2697  SCIP_VAR* var2;
2698  int var2pos;
2699  int i;
2700  int j;
2701  int k;
2702 
2703  SCIP_Bool have_change;
2704 
2705  assert(scip != NULL);
2706  assert(cons != NULL);
2707 
2708  consdata = SCIPconsGetData(cons);
2709 
2710  have_change = FALSE;
2711  i = 0;
2712  while( i < consdata->nlinvars )
2713  {
2714  var = consdata->linvars[i];
2715 
2716  if( SCIPvarIsActive(var) )
2717  {
2718  ++i;
2719  continue;
2720  }
2721 
2722  have_change = TRUE;
2723 
2724  coef = consdata->lincoefs[i];
2725  offset = 0.0;
2726 
2727  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2728 
2729  SCIPdebugMessage(" linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]), coef, SCIPvarGetName(var), offset);
2730 
2731  /* delete previous variable (this will move another variable to position i) */
2732  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2733 
2734  /* put constant part into bounds */
2735  if( offset != 0.0 )
2736  {
2737  if( !SCIPisInfinity(scip, -consdata->lhs) )
2738  consdata->lhs -= offset;
2739  if( !SCIPisInfinity(scip, consdata->rhs) )
2740  consdata->rhs -= offset;
2741  }
2742 
2743  /* nothing left to do if variable had been fixed */
2744  if( coef == 0.0 )
2745  continue;
2746 
2747  /* if GetProbvar gave a linear variable, just add it
2748  * if it's a multilinear variable, add it's disaggregated variables */
2749  if( SCIPvarIsActive(var) )
2750  {
2751  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
2752  }
2753  else
2754  {
2755  int naggrs;
2756  SCIP_VAR** aggrvars;
2757  SCIP_Real* aggrscalars;
2758  SCIP_Real aggrconstant;
2759 
2760  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2761 
2762  naggrs = SCIPvarGetMultaggrNVars(var);
2763  aggrvars = SCIPvarGetMultaggrVars(var);
2764  aggrscalars = SCIPvarGetMultaggrScalars(var);
2765  aggrconstant = SCIPvarGetMultaggrConstant(var);
2766 
2767  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
2768 
2769  for( j = 0; j < naggrs; ++j )
2770  {
2771  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
2772  }
2773 
2774  if( aggrconstant != 0.0 )
2775  {
2776  if( !SCIPisInfinity(scip, -consdata->lhs) )
2777  consdata->lhs -= coef * aggrconstant;
2778  if( !SCIPisInfinity(scip, consdata->rhs) )
2779  consdata->rhs -= coef * aggrconstant;
2780  }
2781  }
2782  }
2783 
2784  i = 0;
2785  while( i < consdata->nquadvars )
2786  {
2787  var = consdata->quadvarterms[i].var;
2788 
2789  if( SCIPvarIsActive(var) )
2790  {
2791  ++i;
2792  continue;
2793  }
2794 
2795  have_change = TRUE;
2796 
2797  coef = 1.0;
2798  offset = 0.0;
2799  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2800 
2801  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);
2802 
2803  /* handle fixed variable */
2804  if( coef == 0.0 )
2805  {
2806  /* if not fixed to 0.0, add to linear coefs of vars in bilinear terms, and deal with linear and square term as constant */
2807  if( offset != 0.0 )
2808  {
2809  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2810  {
2811  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
2812 
2813  var2 = bilinterm->var1 == consdata->quadvarterms[i].var ? bilinterm->var2 : bilinterm->var1;
2814  assert(var2 != consdata->quadvarterms[i].var);
2815 
2816  var2pos = 0;
2817  while( consdata->quadvarterms[var2pos].var != var2 )
2818  {
2819  ++var2pos;
2820  assert(var2pos < consdata->nquadvars);
2821  }
2822  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2823  }
2824 
2825  offset = consdata->quadvarterms[i].lincoef * offset + consdata->quadvarterms[i].sqrcoef * offset * offset;
2826  if( !SCIPisInfinity(scip, -consdata->lhs) )
2827  consdata->lhs -= offset;
2828  if( !SCIPisInfinity(scip, consdata->rhs) )
2829  consdata->rhs -= offset;
2830  }
2831 
2832  /* remove bilinear terms */
2833  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
2834 
2835  /* delete quad. var term i */
2836  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2837 
2838  continue;
2839  }
2840 
2841  assert(var != NULL);
2842 
2843  /* if GetProbvar gave an active variable, replace the quad var term so that it uses the new variable */
2844  if( SCIPvarIsActive(var) )
2845  {
2846  /* replace x by coef*y+offset */
2847  SCIP_CALL( replaceQuadVarTermPos(scip, cons, i, var, coef, offset) );
2848 
2849  continue;
2850  }
2851  else
2852  {
2853  /* if GetProbVar gave a multi-aggregated variable, add new quad var terms and new bilinear terms
2854  * x is replaced by coef * (sum_i a_ix_i + b) + offset
2855  * lcoef * x + scoef * x^2 + bcoef * x * y ->
2856  * (b*coef + offset) * (lcoef + (b*coef + offset) * scoef)
2857  * + sum_i a_i*coef * (lcoef + 2 (b*coef + offset) * scoef) x_i
2858  * + sum_i (a_i*coef)^2 * scoef * x_i^2
2859  * + 2 sum_{i,j, i<j} (a_i a_j coef^2 scoef) x_i x_j
2860  * + bcoef * (b*coef + offset + coef * sum_i a_ix_i) y
2861  */
2862  int naggrs;
2863  SCIP_VAR** aggrvars; /* x_i */
2864  SCIP_Real* aggrscalars; /* a_i */
2865  SCIP_Real aggrconstant; /* b */
2866  int nquadtermsold;
2867 
2868  SCIP_Real lcoef;
2869  SCIP_Real scoef;
2870 
2871  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2872 
2873  naggrs = SCIPvarGetMultaggrNVars(var);
2874  aggrvars = SCIPvarGetMultaggrVars(var);
2875  aggrscalars = SCIPvarGetMultaggrScalars(var);
2876  aggrconstant = SCIPvarGetMultaggrConstant(var);
2877 
2878  lcoef = consdata->quadvarterms[i].lincoef;
2879  scoef = consdata->quadvarterms[i].sqrcoef;
2880 
2881  nquadtermsold = consdata->nquadvars;
2882 
2883  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars + naggrs) );
2884 
2885  /* take care of constant part */
2886  if( aggrconstant != 0.0 || offset != 0.0 )
2887  {
2888  SCIP_Real constant;
2889  constant = (aggrconstant * coef + offset) * (lcoef + (aggrconstant * coef + offset) * scoef);
2890  if( !SCIPisInfinity(scip, -consdata->lhs) )
2891  consdata->lhs -= constant;
2892  if( !SCIPisInfinity(scip, consdata->rhs) )
2893  consdata->rhs -= constant;
2894  }
2895 
2896  /* add x_i's with linear and square coefficients */
2897  for( j = 0; j < naggrs; ++j )
2898  {
2899  SCIP_CALL( addQuadVarTerm(scip, cons, aggrvars[j],
2900  coef * aggrscalars[j] * (lcoef + 2.0 * scoef * (coef * aggrconstant + offset)),
2901  coef * coef * aggrscalars[j] * aggrscalars[j] * scoef,
2902  TRUE) );
2903  }
2904 
2905  /* ensure space for bilinear terms */
2906  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nquadvars + (scoef != 0.0 ? (naggrs * (naggrs-1))/2 : 0) + consdata->quadvarterms[j].nadjbilin * naggrs) );
2907 
2908  /* add x_j*x_k's */
2909  if( scoef != 0.0 )
2910  {
2911  for( j = 0; j < naggrs; ++j )
2912  for( k = 0; k < j; ++k )
2913  {
2914  assert(aggrvars[j] != aggrvars[k]);
2915  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, nquadtermsold + k,
2916  2.0 * aggrscalars[j] * aggrscalars[k] * coef * coef * scoef) );
2917  }
2918  }
2919 
2920  /* add x_i*y's */
2921  for( k = 0; k < consdata->quadvarterms[i].nadjbilin; ++k )
2922  {
2923  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[k]];
2924  var2 = (bilinterm->var1 == consdata->quadvarterms[i].var) ? bilinterm->var2 : bilinterm->var1;
2925  assert(var2 != consdata->quadvarterms[i].var);
2926 
2927  /* this is not efficient, but we cannot sort the quadratic terms here, since we currently iterate over them */
2928  var2pos = 0;
2929  while( consdata->quadvarterms[var2pos].var != var2 )
2930  {
2931  ++var2pos;
2932  assert(var2pos < consdata->nquadvars);
2933  }
2934 
2935  for( j = 0; j < naggrs; ++j )
2936  {
2937  if( aggrvars[j] == var2 )
2938  { /* x_i == y, so we have a square term here */
2939  consdata->quadvarterms[var2pos].sqrcoef += bilinterm->coef * coef * aggrscalars[j];
2940  }
2941  else
2942  { /* x_i != y, so we need to add a bilinear term here */
2943  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, var2pos,
2944  bilinterm->coef * coef * aggrscalars[j]) );
2945  }
2946  }
2947 
2948  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * (aggrconstant * coef + offset);
2949  }
2950 
2951  /* remove bilinear terms */
2952  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
2953 
2954  /* delete quad. var term i */
2955  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2956  }
2957  }
2958 
2959  consdata->isremovedfixings = TRUE;
2960 
2961  SCIPdebugMessage("removed fixations from <%s>\n -> ", SCIPconsGetName(cons));
2962  SCIPdebugPrintCons(scip, cons, NULL);
2963 
2964 #ifndef NDEBUG
2965  for( i = 0; i < consdata->nlinvars; ++i )
2966  assert(SCIPvarIsActive(consdata->linvars[i]));
2967 
2968  for( i = 0; i < consdata->nquadvars; ++i )
2969  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
2970 #endif
2971 
2972  if( !have_change )
2973  return SCIP_OKAY;
2974 
2975  /* some quadratic variable may have been replaced by an already existing linear variable
2976  * in this case, we want the linear variable to be removed, which happens in mergeAndCleanLinearVars
2977  */
2978  consdata->linvarsmerged = FALSE;
2979 
2980  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
2981  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
2982  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
2983 
2984 #ifndef NDEBUG
2985  for( i = 0; i < consdata->nbilinterms; ++i )
2986  {
2987  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
2988  assert(consdata->bilinterms[i].coef != 0.0);
2989  assert(SCIPvarCompare(consdata->bilinterms[i].var1, consdata->bilinterms[i].var2) < 0);
2990  }
2991 #endif
2992 
2993  return SCIP_OKAY;
2994 }
2995 
2996 /** create a nonlinear row representation of the constraint and stores them in consdata */
2997 static
2999  SCIP* scip, /**< SCIP data structure */
3000  SCIP_CONS* cons /**< quadratic constraint */
3001  )
3002 {
3003  SCIP_CONSDATA* consdata;
3004  int nquadvars; /* number of variables in quadratic terms */
3005  SCIP_VAR** quadvars; /* variables in quadratic terms */
3006  int nquadelems; /* number of quadratic elements (square and bilinear terms) */
3007  SCIP_QUADELEM* quadelems; /* quadratic elements (square and bilinear terms) */
3008  int nquadlinterms; /* number of linear terms using variables that are in quadratic terms */
3009  SCIP_VAR** quadlinvars; /* variables of linear terms using variables that are in quadratic terms */
3010  SCIP_Real* quadlincoefs; /* coefficients of linear terms using variables that are in quadratic terms */
3011  int i;
3012  int idx1;
3013  int idx2;
3014  int lincnt;
3015  int elcnt;
3016  SCIP_VAR* lastvar;
3017  int lastvaridx;
3018 
3019  assert(scip != NULL);
3020  assert(cons != NULL);
3021 
3022  consdata = SCIPconsGetData(cons);
3023  assert(consdata != NULL);
3024 
3025  if( consdata->nlrow != NULL )
3026  {
3027  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3028  }
3029 
3030  nquadvars = consdata->nquadvars;
3031  nquadelems = consdata->nbilinterms;
3032  nquadlinterms = 0;
3033  for( i = 0; i < nquadvars; ++i )
3034  {
3035  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3036  ++nquadelems;
3037  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3038  ++nquadlinterms;
3039  }
3040 
3041  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, nquadvars) );
3042  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
3043  SCIP_CALL( SCIPallocBufferArray(scip, &quadlinvars, nquadlinterms) );
3044  SCIP_CALL( SCIPallocBufferArray(scip, &quadlincoefs, nquadlinterms) );
3045 
3046  lincnt = 0;
3047  elcnt = 0;
3048  for( i = 0; i < nquadvars; ++i )
3049  {
3050  quadvars[i] = consdata->quadvarterms[i].var;
3051 
3052  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3053  {
3054  assert(elcnt < nquadelems);
3055  quadelems[elcnt].idx1 = i;
3056  quadelems[elcnt].idx2 = i;
3057  quadelems[elcnt].coef = consdata->quadvarterms[i].sqrcoef;
3058  ++elcnt;
3059  }
3060 
3061  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3062  {
3063  assert(lincnt < nquadlinterms);
3064  quadlinvars [lincnt] = consdata->quadvarterms[i].var;
3065  quadlincoefs[lincnt] = consdata->quadvarterms[i].lincoef;
3066  ++lincnt;
3067  }
3068  }
3069  assert(lincnt == nquadlinterms);
3070 
3071  /* bilinear terms are sorted first by first variable, then by second variable
3072  * 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 */
3073  lastvar = NULL;
3074  lastvaridx = -1;
3075  for( i = 0; i < consdata->nbilinterms; ++i )
3076  {
3077  if( lastvar == consdata->bilinterms[i].var1 )
3078  {
3079  assert(lastvaridx >= 0);
3080  assert(consdata->quadvarterms[lastvaridx].var == consdata->bilinterms[i].var1);
3081  }
3082  else
3083  {
3084  lastvar = consdata->bilinterms[i].var1;
3085  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, lastvar, &lastvaridx) );
3086  }
3087  idx1 = lastvaridx;
3088 
3089  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &idx2) );
3090 
3091  assert(elcnt < nquadelems);
3092  quadelems[elcnt].idx1 = MIN(idx1, idx2);
3093  quadelems[elcnt].idx2 = MAX(idx1, idx2);
3094  quadelems[elcnt].coef = consdata->bilinterms[i].coef;
3095  ++elcnt;
3096  }
3097  assert(elcnt == nquadelems);
3098 
3099  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3100  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
3101  nquadvars, quadvars, nquadelems, quadelems,
3102  NULL, consdata->lhs, consdata->rhs) );
3103 
3104  SCIP_CALL( SCIPaddLinearCoefsToNlRow(scip, consdata->nlrow, nquadlinterms, quadlinvars, quadlincoefs) );
3105 
3106  SCIPfreeBufferArray(scip, &quadvars);
3107  SCIPfreeBufferArray(scip, &quadelems);
3108  SCIPfreeBufferArray(scip, &quadlinvars);
3109  SCIPfreeBufferArray(scip, &quadlincoefs);
3110 
3111  return SCIP_OKAY;
3112 }
3113 
3114 static
3116  SCIP* scip, /**< SCIP data structure */
3117  SCIP_CONS* cons, /**< constraint */
3118  SCIP_RESULT* result, /**< to store result of solve: cutoff, success, or do-not-find */
3119  SCIP_Bool* redundant, /**< to store whether constraint is redundant now (should be deleted) */
3120  int* naggrvars /**< counter on number of variable aggregations */
3121  )
3122 {
3123  SCIP_CONSDATA* consdata;
3124 
3125  assert(scip != NULL);
3126  assert(cons != NULL);
3127  assert(result != NULL);
3128  assert(redundant != NULL);
3129 
3130  *result = SCIP_DIDNOTFIND;
3131  *redundant = FALSE;
3132 
3133  consdata = SCIPconsGetData(cons);
3134  assert(consdata != NULL);
3135 
3136  /* if constraint is an equality with two variables, at least one of them binary,
3137  * and linear after fixing the binary, then we can aggregate the variables */
3138  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && consdata->nlinvars == 0 && consdata->nquadvars == 2 &&
3139  ((SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ||
3140  (SCIPvarIsBinary(consdata->quadvarterms[1].var) && consdata->quadvarterms[0].sqrcoef == 0.0)) )
3141  {
3142  SCIP_Bool infeasible;
3143  SCIP_Bool aggregated;
3144  SCIP_Real a;
3145  SCIP_Real b;
3146  SCIP_Real c;
3147  SCIP_VAR* x;
3148  SCIP_VAR* y;
3149  int binvaridx;
3150 
3151  /* constraint is a*(x+x^2) + b*y + c*x*y = rhs, with x binary variable
3152  * x = 0 -> b*y == rhs
3153  * x = 1 -> (b+c)*y == rhs - a
3154  *
3155  * 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
3156  */
3157 
3158  binvaridx = (SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ? 0 : 1;
3159 
3160  x = consdata->quadvarterms[binvaridx].var;
3161  a = consdata->quadvarterms[binvaridx].sqrcoef + consdata->quadvarterms[binvaridx].lincoef;
3162 
3163  y = consdata->quadvarterms[1-binvaridx].var;
3164  b = consdata->quadvarterms[1-binvaridx].lincoef;
3165 
3166  assert(consdata->nbilinterms <= 1); /* should actually be 1, since constraint is otherwise linear */
3167  c = (consdata->nbilinterms == 1) ? consdata->bilinterms[0].coef : 0.0;
3168 
3169  if( !SCIPisZero(scip, b) && !SCIPisZero(scip, b+c) )
3170  {
3171  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);
3172  SCIPdebugMessage("=> attempt aggregation <%s> = %g*<%s> + %g\n", SCIPvarGetName(y), (consdata->rhs-a)/(b+c) - consdata->rhs/b, SCIPvarGetName(x), consdata->rhs/b);
3173 
3174  SCIP_CALL( SCIPaggregateVars(scip, x, y, (consdata->rhs-a)/(b+c) - consdata->rhs/b, -1.0, -consdata->rhs/b, &infeasible, redundant, &aggregated) );
3175  if( infeasible )
3176  *result = SCIP_CUTOFF;
3177  else if( *redundant || aggregated )
3178  {
3179  /* aggregated (or were already aggregated), so constraint is now redundant */
3180  *result = SCIP_SUCCESS;
3181  *redundant = TRUE;
3182 
3183  if( aggregated )
3184  ++*naggrvars;
3185  }
3186  }
3187 
3188  /* @todo if b is 0 or b+c is 0, or lhs != rhs, then could replace by varbound constraint */
3189  }
3190 
3191  return SCIP_OKAY;
3192 }
3193 
3194 
3195 /** reformulates products of binary variables as AND constraint
3196  * 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.
3197  */
3198 static
3200  SCIP* scip, /**< SCIP data structure */
3201  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3202  SCIP_CONS* cons, /**< constraint */
3203  int* naddconss /**< buffer where to add the number of AND constraints added */
3204  )
3205 {
3206  SCIP_CONSHDLRDATA* conshdlrdata;
3207  SCIP_CONSDATA* consdata;
3208  char name[SCIP_MAXSTRLEN];
3209  SCIP_VAR* vars[2];
3210  SCIP_VAR* auxvar;
3211  SCIP_CONS* andcons;
3212  int i;
3213  int ntodelete;
3214  int* todelete;
3215 
3216  assert(scip != NULL);
3217  assert(conshdlr != NULL);
3218  assert(cons != NULL);
3219  assert(naddconss != NULL);
3220 
3221  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3222  assert(conshdlrdata != NULL);
3223 
3224  /* if user does not like AND very much, then return */
3225  if( conshdlrdata->empathy4and < 2 )
3226  return SCIP_OKAY;
3227 
3228  consdata = SCIPconsGetData(cons);
3229  assert(consdata != NULL);
3230 
3231  if( consdata->nbilinterms == 0 )
3232  return SCIP_OKAY;
3233 
3234  /* get array to store indices of bilinear terms that shall be deleted */
3235  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
3236  ntodelete = 0;
3237 
3238  for( i = 0; i < consdata->nbilinterms; ++i )
3239  {
3240  vars[0] = consdata->bilinterms[i].var1;
3241  if( !SCIPvarIsBinary(vars[0]) )
3242  continue;
3243 
3244  vars[1] = consdata->bilinterms[i].var2;
3245  if( !SCIPvarIsBinary(vars[1]) )
3246  continue;
3247 
3248  /* create auxiliary variable */
3249  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]), SCIPconsGetName(cons));
3250  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
3251  SCIPvarIsInitial(vars[0]) || SCIPvarIsInitial(vars[1]), SCIPvarIsRemovable(vars[0]) && SCIPvarIsRemovable(vars[1]), NULL, NULL, NULL, NULL, NULL) );
3252  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3253 #ifdef SCIP_DEBUG_SOLUTION
3254  if( SCIPdebugIsMainscip(scip) )
3255  {
3256  SCIP_Real var0val;
3257  SCIP_Real var1val;
3258  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[0], &var0val) );
3259  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[1], &var1val) );
3260  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3261  }
3262 #endif
3263 
3264  /* create and constraint auxvar = x and y */
3265  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3266  SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, auxvar, 2, vars,
3267  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3271  SCIP_CALL( SCIPaddCons(scip, andcons) );
3272  SCIPdebugMessage("added AND constraint: ");
3273  SCIPdebugPrintCons(scip, andcons, NULL);
3274  SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
3275  ++*naddconss;
3276 
3277  /* add bilincoef * auxvar to linear terms */
3278  SCIP_CALL( addLinearCoef(scip, cons, auxvar, consdata->bilinterms[i].coef) );
3279  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3280 
3281  /* remember that we have to delete this bilinear term */
3282  assert(ntodelete < consdata->nbilinterms);
3283  todelete[ntodelete++] = i;
3284  }
3285 
3286  /* remove bilinear terms that have been replaced */
3287  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3288  SCIPfreeBufferArray(scip, &todelete);
3289 
3290  return SCIP_OKAY;
3291 }
3292 
3293 /** gets bounds of variable y if x takes a certain value
3294  * checks whether x = xval has implications on y
3295  */
3296 static
3297 void getImpliedBounds(
3298  SCIP_VAR* x, /**< variable which implications to check */
3299  SCIP_Bool xval, /**< value of x to check for (TRUE for 1, FALSE for 0) */
3300  SCIP_VAR* y, /**< variable to check if bounds can be reduced */
3301  SCIP_INTERVAL* resultant /**< buffer to store bounds on y */
3302  )
3303 {
3304  int nimpls;
3305  int nbinimpls;
3306  SCIP_VAR** implvars;
3307  SCIP_BOUNDTYPE* impltypes;
3308  SCIP_Real* implbounds;
3309  int pos;
3310 
3311  assert(x != NULL);
3312  assert(y != NULL);
3313  assert(resultant != NULL);
3314 
3316 
3317  if( !SCIPvarIsBinary(x) || !SCIPvarIsActive(x) )
3318  return;
3319 
3320  /* analyze implications for x = xval */
3321  nimpls = SCIPvarGetNImpls(x, xval);
3322  if( nimpls == 0 )
3323  return;
3324 
3325  nbinimpls = SCIPvarGetNBinImpls (x, xval);
3326  implvars = SCIPvarGetImplVars (x, xval);
3327  impltypes = SCIPvarGetImplTypes (x, xval);
3328  implbounds = SCIPvarGetImplBounds(x, xval);
3329 
3330  assert(implvars != NULL);
3331  assert(impltypes != NULL);
3332  assert(implbounds != NULL);
3333 
3335  {
3336  if( !SCIPsortedvecFindPtr((void**)implvars, SCIPvarComp, (void*)y, nbinimpls, &pos) )
3337  return;
3338  }
3339  else if( nbinimpls < nimpls )
3340  {
3341  if( !SCIPsortedvecFindPtr((void**)&implvars[nbinimpls], SCIPvarComp, (void*)y, nimpls - nbinimpls, &pos) )
3342  return;
3343  }
3344  else
3345  return;
3346 
3347  /* if there are several implications on y, go to the first one */
3348  while( pos > 0 && implvars[pos-1] == y )
3349  --pos;
3350 
3351  /* update implied lower and upper bounds on y
3352  * but make sure that resultant will not be empty, due to tolerances
3353  */
3354  while( pos < nimpls && implvars[pos] == y )
3355  {
3356  if( impltypes[pos] == SCIP_BOUNDTYPE_LOWER )
3357  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, implbounds[pos]));
3358  else
3359  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, implbounds[pos]));
3360  ++pos;
3361  }
3362 
3363  assert(!SCIPintervalIsEmpty(*resultant));
3364 }
3365 
3366 /** Reformulates products of binary times bounded continuous variables as system of linear inequalities (plus auxiliary variable).
3367  *
3368  * For a product x*y, with y a binary variable and x a continous variable with finite bounds,
3369  * 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.
3370  *
3371  * 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.
3372  * For each product of linear term of length at most maxnrvar with y, an auxiliary z and linear inequalities are added.
3373  *
3374  * If y is a binary variable, the AND constraint \f$ z = x \wedge y \f$ may be added instead of linear constraints.
3375  */
3376 static
3378  SCIP* scip, /**< SCIP data structure */
3379  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3380  SCIP_CONS* cons, /**< constraint */
3381  int* naddconss /**< buffer where to add the number of auxiliary constraints added */
3382  )
3383 { /*lint --e{666} */
3384  SCIP_CONSHDLRDATA* conshdlrdata;
3385  SCIP_CONSDATA* consdata;
3386  SCIP_VAR** xvars;
3387  SCIP_Real* xcoef;
3388  SCIP_INTERVAL xbndszero;
3389  SCIP_INTERVAL xbndsone;
3390  SCIP_INTERVAL act0;
3391  SCIP_INTERVAL act1;
3392  int nxvars;
3393  SCIP_VAR* y;
3394  SCIP_VAR* bvar;
3395  char name[SCIP_MAXSTRLEN];
3396  int nbilinterms;
3397  SCIP_VAR* auxvar;
3398  SCIP_CONS* auxcons;
3399  int i;
3400  int j;
3401  int k;
3402  int bilinidx;
3403  SCIP_Real bilincoef;
3404  SCIP_Real mincoef;
3405  SCIP_Real maxcoef;
3406  int* todelete;
3407  int ntodelete;
3408  int maxnrvar;
3409  SCIP_Bool integral;
3410  SCIP_Longint gcd;
3411  SCIP_Bool auxvarinitial;
3412  SCIP_Bool auxvarremovable;
3413 
3414  assert(scip != NULL);
3415  assert(conshdlr != NULL);
3416  assert(cons != NULL);
3417  assert(naddconss != NULL);
3418 
3419  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3420  assert(conshdlrdata != NULL);
3421 
3422  maxnrvar = conshdlrdata->replacebinaryprodlength;
3423  if( maxnrvar == 0 )
3424  return SCIP_OKAY;
3425 
3426  consdata = SCIPconsGetData(cons);
3427  assert(consdata != NULL);
3428 
3429  xvars = NULL;
3430  xcoef = NULL;
3431  todelete = NULL;
3432  gcd = 0;
3433 
3434  for( i = 0; i < consdata->nquadvars; ++i )
3435  {
3436  y = consdata->quadvarterms[i].var;
3437  if( !SCIPvarIsBinary(y) )
3438  continue;
3439 
3440  nbilinterms = consdata->quadvarterms[i].nadjbilin;
3441  if( nbilinterms == 0 )
3442  continue;
3443 
3444  SCIP_CALL( SCIPreallocBufferArray(scip, &xvars, MIN(maxnrvar, nbilinterms)+2) ); /* add 2 for later use when creating linear constraints */
3445  SCIP_CALL( SCIPreallocBufferArray(scip, &xcoef, MIN(maxnrvar, nbilinterms)+2) );
3446 
3447  /* alloc array to store indices of bilinear terms that shall be deleted */
3448  SCIP_CALL( SCIPreallocBufferArray(scip, &todelete, nbilinterms) );
3449  ntodelete = 0;
3450 
3451  auxvarinitial = SCIPvarIsInitial(y);
3452  auxvarremovable = SCIPvarIsRemovable(y);
3453 
3454  /* 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)
3455  * and compute range of sum_i a_i*x_i for the cases y = 0 and y = 1
3456  * we may need several rounds of maxnrvar < nbilinterms
3457  */
3458  j = 0;
3459  do
3460  {
3461  nxvars = 0;
3462  SCIPintervalSet(&xbndszero, 0.0);
3463  SCIPintervalSet(&xbndsone, 0.0);
3464 
3465  mincoef = SCIPinfinity(scip);
3466  maxcoef = 0.0;
3467  integral = TRUE;
3468 
3469  /* collect at most maxnrvar variables for x term */
3470  for( ; j < nbilinterms && nxvars < maxnrvar; ++j )
3471  {
3472  bilinidx = consdata->quadvarterms[i].adjbilin[j];
3473  assert(bilinidx >= 0);
3474  assert(bilinidx < consdata->nbilinterms);
3475 
3476  bvar = consdata->bilinterms[bilinidx].var1;
3477  if( bvar == y )
3478  bvar = consdata->bilinterms[bilinidx].var2;
3479  assert(bvar != y);
3480 
3481  /* skip products with unbounded variables */
3482  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(bvar)) || SCIPisInfinity(scip, SCIPvarGetUbGlobal(bvar)) )
3483  {
3484  SCIPdebugMessage("skip reform of <%s><%s> due to unbounded second variable [%g,%g]\n",
3486  continue;
3487  }
3488 
3489  bilincoef = consdata->bilinterms[bilinidx].coef;
3490  assert(bilincoef != 0.0);
3491 
3492  /* get activity of bilincoef * x if y = 0 */
3493  getImpliedBounds(y, FALSE, bvar, &act0);
3494  SCIPintervalMulScalar(SCIPinfinity(scip), &act0, act0, bilincoef);
3495 
3496  /* get activity of bilincoef * x if y = 1 */
3497  getImpliedBounds(y, TRUE, bvar, &act1);
3498  SCIPintervalMulScalar(SCIPinfinity(scip), &act1, act1, bilincoef);
3499 
3500  /* skip products that give rise to very large coefficients (big big-M's) */
3501  if( SCIPfeastol(scip) * REALABS(act0.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act0.sup) >= conshdlrdata->binreformmaxcoef )
3502  {
3503  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 0.0\n",
3504  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act0), SCIPintervalGetSup(act0), SCIPvarGetName(y));
3505  continue;
3506  }
3507  if( SCIPfeastol(scip) * REALABS(act1.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act1.sup) >= conshdlrdata->binreformmaxcoef )
3508  {
3509  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 1.0\n",
3510  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act1), SCIPintervalGetSup(act1), SCIPvarGetName(y));
3511  continue;
3512  }
3513  if( !SCIPisZero(scip, MIN(REALABS(act0.inf), REALABS(act0.sup))) &&
3514  SCIPfeastol(scip) * MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)) >= conshdlrdata->binreformmaxcoef )
3515  {
3516  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n",
3517  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)), SCIPvarGetName(y));
3518  continue;
3519  }
3520  if( !SCIPisZero(scip, MIN(REALABS(act1.inf), REALABS(act1.sup))) &&
3521  SCIPfeastol(scip) * MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)) >= conshdlrdata->binreformmaxcoef )
3522  {
3523  SCIPdebugMessage("skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n",
3524  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)), SCIPvarGetName(y));
3525  continue;
3526  }
3527 
3528  /* add bvar to x term */
3529  xvars[nxvars] = bvar;
3530  xcoef[nxvars] = bilincoef;
3531  ++nxvars;
3532 
3533  /* update bounds on x term */
3534  SCIPintervalAdd(SCIPinfinity(scip), &xbndszero, xbndszero, act0);
3535  SCIPintervalAdd(SCIPinfinity(scip), &xbndsone, xbndsone, act1);
3536 
3537  if( REALABS(bilincoef) < mincoef )
3538  mincoef = ABS(bilincoef);
3539  if( REALABS(bilincoef) > maxcoef )
3540  maxcoef = ABS(bilincoef);
3541 
3542  /* update whether all coefficients will be integral and if so, compute their gcd */
3543  integral &= (SCIPvarGetType(bvar) < SCIP_VARTYPE_CONTINUOUS) && SCIPisIntegral(scip, bilincoef); /*lint !e514 */
3544  if( integral )
3545  {
3546  if( nxvars == 1 )
3547  gcd = (SCIP_Longint)SCIPround(scip, REALABS(bilincoef));
3548  else
3549  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)SCIPround(scip, REALABS(bilincoef)));
3550  }
3551 
3552  /* if bvar is initial, then also the auxiliary variable should be initial
3553  * if bvar is not removable, then also the auxiliary variable should not be removable
3554  */
3555  auxvarinitial |= SCIPvarIsInitial(bvar);
3556  auxvarremovable &= SCIPvarIsRemovable(bvar);
3557 
3558  /* remember that we have to remove this bilinear term later */
3559  assert(ntodelete < nbilinterms);
3560  todelete[ntodelete++] = bilinidx;
3561  }
3562 
3563  if( nxvars == 0 ) /* all (remaining) x_j seem to be unbounded */
3564  break;
3565 
3566  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndszero)));
3567  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndszero)));
3568  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndsone)));
3569  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndsone)));
3570 
3571 #ifdef SCIP_DEBUG
3572  if( SCIPintervalGetInf(xbndszero) != SCIPintervalGetInf(xbndsone) || /*lint !e777*/
3573  +SCIPintervalGetSup(xbndszero) != SCIPintervalGetSup(xbndsone) ) /*lint !e777*/
3574  {
3575  SCIPdebugMessage("got different bounds for y = 0: [%g, %g] and y = 1: [%g, %g]\n", xbndszero.inf, xbndszero.sup, xbndsone.inf, xbndsone.sup);
3576  }
3577 #endif
3578 
3579  if( nxvars == 1 && conshdlrdata->empathy4and >= 1 && SCIPvarIsBinary(xvars[0]) )
3580  {
3581  /* product of two binary variables, replace by auxvar and AND constraint */
3582  /* add auxiliary variable z */
3583  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3584  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT,
3585  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3586  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3587 
3588 #ifdef SCIP_DEBUG_SOLUTION
3589  if( SCIPdebugIsMainscip(scip) )
3590  {
3591  SCIP_Real var0val;
3592  SCIP_Real var1val;
3593  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[0], &var0val) );
3594  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &var1val) );
3595  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3596  }
3597 #endif
3598 
3599  /* add constraint z = x and y */
3600  xvars[1] = y;
3601  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3602  SCIP_CALL( SCIPcreateConsAnd(scip, &auxcons, name, auxvar, 2, xvars,
3603  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3607  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3608  SCIPdebugMessage("added AND constraint: ");
3609  SCIPdebugPrintCons(scip, auxcons, NULL);
3610  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3611  ++*naddconss;
3612 
3613  /* add linear term coef*auxvar */
3614  SCIP_CALL( addLinearCoef(scip, cons, auxvar, xcoef[0]) );
3615 
3616  /* forget about auxvar */
3617  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3618  }
3619  else
3620  {
3621  /* 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 */
3622  SCIP_Real scale;
3623 
3624  /* scale auxiliary constraint by some nice value,
3625  * if all coefficients are integral, take a value that preserves integrality (-> gcd), so we can make the auxiliary variable impl. integer
3626  */
3627  if( integral )
3628  {
3629  scale = (SCIP_Real)gcd;
3630  assert(scale >= 1.0);
3631  }
3632  else if( nxvars == 1 )
3633  {
3634  /* scaling by the only coefficient gives auxiliary variable = x * y, which thus will be implicit integral provided y is not continuous */
3635  assert(mincoef == maxcoef); /*lint !e777 */
3636  scale = mincoef;
3637  integral = SCIPvarGetType(xvars[0]) < SCIP_VARTYPE_CONTINUOUS;
3638  }
3639  else
3640  {
3641  scale = 1.0;
3642  if( maxcoef < 0.5 )
3643  scale = maxcoef;
3644  if( mincoef > 2.0 )
3645  scale = mincoef;
3646  if( scale != 1.0 )
3647  scale = SCIPselectSimpleValue(scale / 2.0, 1.5 * scale, MAXDNOM);
3648  }
3649  assert(scale > 0.0);
3650  assert(!SCIPisInfinity(scip, scale));
3651 
3652  /* if x-term is always negative for y = 1, negate scale so we get a positive auxiliary variable; maybe this is better sometimes? */
3653  if( !SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3654  scale = -scale;
3655 
3656  SCIPdebugMessage("binary reformulation using scale %g, nxvars = %d, integral = %u\n", scale, nxvars, integral);
3657  if( scale != 1.0 )
3658  {
3659  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndszero, xbndszero, scale);
3660  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndsone, xbndsone, scale);
3661  for( k = 0; k < nxvars; ++k )
3662  xcoef[k] /= scale;
3663  }
3664 
3665  /* add auxiliary variable z */
3666  if( nxvars == 1 )
3667  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3668  else
3669  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_more_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3670  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, MIN(0., SCIPintervalGetInf(xbndsone)), MAX(0., SCIPintervalGetSup(xbndsone)),
3672  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3673  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3674 
3675  /* compute value of auxvar in debug solution */
3676 #ifdef SCIP_DEBUG_SOLUTION
3677  if( SCIPdebugIsMainscip(scip) )
3678  {
3679  SCIP_Real debugval;
3680  SCIP_Real varval;
3681 
3682  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &varval) );
3683  if( SCIPisZero(scip, varval) )
3684  {
3685  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, 0.0) );
3686  }
3687  else
3688  {
3689  assert(SCIPisEQ(scip, varval, 1.0));
3690 
3691  debugval = 0.0;
3692  for( k = 0; k < nxvars; ++k )
3693  {
3694  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[k], &varval) );
3695  debugval += xcoef[k] * varval;
3696  }
3697  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
3698  }
3699  }
3700 #endif
3701 
3702  /* add auxiliary constraints
3703  * it seems to be advantageous to make the varbound constraints initial and the linear constraints not initial
3704  * maybe because it is more likely that a binary variable takes value 0 instead of 1, and thus the varbound constraints
3705  * are more often active, compared to the linear constraints added below
3706  * also, the varbound constraints are more sparse than the linear cons
3707  */
3708  if( SCIPisNegative(scip, SCIPintervalGetInf(xbndsone)) )
3709  {
3710  /* add 0 <= z - xbndsone.inf * y constraint (as varbound constraint) */
3711  if( nxvars == 1 )
3712  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3713  else
3714  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3715  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetInf(xbndsone), 0.0, SCIPinfinity(scip),
3716  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3720  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3721  SCIPdebugMessage("added varbound constraint: ");
3722  SCIPdebugPrintCons(scip, auxcons, NULL);
3723  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3724  ++*naddconss;
3725  }
3726  if( SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3727  {
3728  /* add z - xbndsone.sup * y <= 0 constraint (as varbound constraint) */
3729  if( nxvars == 1 )
3730  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3731  else
3732  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3733  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetSup(xbndsone), -SCIPinfinity(scip), 0.0,
3734  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3738  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3739  SCIPdebugMessage("added varbound constraint: ");
3740  SCIPdebugPrintCons(scip, auxcons, NULL);
3741  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3742  ++*naddconss;
3743  }
3744 
3745  /* add xbndszero.inf <= sum_i a_i*x_i + xbndszero.inf * y - z constraint */
3746  xvars[nxvars] = y;
3747  xvars[nxvars+1] = auxvar;
3748  xcoef[nxvars] = SCIPintervalGetInf(xbndszero);
3749  xcoef[nxvars+1] = -1;
3750 
3751  if( nxvars == 1 )
3752  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3753  else
3754  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3755  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, SCIPintervalGetInf(xbndszero), SCIPinfinity(scip),
3756  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3760  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3761  SCIPdebugMessage("added linear constraint: ");
3762  SCIPdebugPrintCons(scip, auxcons, NULL);
3763  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3764  ++*naddconss;
3765 
3766  /* add sum_i a_i*x_i + xbndszero.sup * y - z <= xbndszero.sup constraint */
3767  xcoef[nxvars] = SCIPintervalGetSup(xbndszero);
3768 
3769  if( nxvars == 1 )
3770  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3771  else
3772  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3773  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, -SCIPinfinity(scip), SCIPintervalGetSup(xbndszero),
3774  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3778  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3779  SCIPdebugMessage("added linear constraint: ");
3780  SCIPdebugPrintCons(scip, auxcons, NULL);
3781  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3782  ++*naddconss;
3783 
3784  /* add linear term scale*auxvar to this constraint */
3785  SCIP_CALL( addLinearCoef(scip, cons, auxvar, scale) );
3786 
3787  /* forget about auxvar */
3788  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3789  }
3790  }
3791  while( j < nbilinterms );
3792 
3793  /* remove bilinear terms that have been replaced */
3794  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3795  }
3796  SCIPdebugMessage("resulting quadratic constraint: ");
3797  SCIPdebugPrintCons(scip, cons, NULL);
3798 
3799  SCIPfreeBufferArrayNull(scip, &xvars);
3800  SCIPfreeBufferArrayNull(scip, &xcoef);
3801  SCIPfreeBufferArrayNull(scip, &todelete);
3802 
3803  return SCIP_OKAY;
3804 }
3805 
3806 /** tries to automatically convert a quadratic constraint (or a part of it) into a more specific and more specialized constraint */
3807 static
3809  SCIP* scip, /**< SCIP data structure */
3810  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
3811  SCIP_CONS* cons, /**< source constraint to try to convert */
3812  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
3813  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
3814  int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
3815  )
3816 {
3817  SCIP_CONSHDLRDATA* conshdlrdata;
3818  SCIP_CONSDATA* consdata;
3819  SCIP_VAR* var;
3820  SCIP_Real lincoef;
3821  SCIP_Real quadcoef;
3822  SCIP_Real lb;
3823  SCIP_Real ub;
3824  int nbinlin;
3825  int nbinquad;
3826  int nintlin;
3827  int nintquad;
3828  int nimpllin;
3829  int nimplquad;
3830  int ncontlin;
3831  int ncontquad;
3832  SCIP_Bool integral;
3833  int i;
3834  int j;
3835  SCIP_CONS** upgdconss;
3836  int upgdconsssize;
3837  int nupgdconss_;
3838 
3839  assert(scip != NULL);
3840  assert(conshdlr != NULL);
3841  assert(cons != NULL);
3842  assert(!SCIPconsIsModifiable(cons));
3843  assert(upgraded != NULL);
3844  assert(nupgdconss != NULL);
3845  assert(naddconss != NULL);
3846 
3847  *upgraded = FALSE;
3848 
3849  nupgdconss_ = 0;
3850 
3851  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3852  assert(conshdlrdata != NULL);
3853 
3854  /* if there are no upgrade methods, we can also stop */
3855  if( conshdlrdata->nquadconsupgrades == 0 )
3856  return SCIP_OKAY;
3857 
3858  upgdconsssize = 2;
3859  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
3860 
3861  consdata = SCIPconsGetData(cons);
3862  assert(consdata != NULL);
3863 
3864  /* calculate some statistics on quadratic constraint */
3865  nbinlin = 0;
3866  nbinquad = 0;
3867  nintlin = 0;
3868  nintquad = 0;
3869  nimpllin = 0;
3870  nimplquad = 0;
3871  ncontlin = 0;
3872  ncontquad = 0;
3873  integral = TRUE;
3874  for( i = 0; i < consdata->nlinvars; ++i )
3875  {
3876  var = consdata->linvars[i];
3877  lincoef = consdata->lincoefs[i];
3878  lb = SCIPvarGetLbLocal(var);
3879  ub = SCIPvarGetUbLocal(var);
3880  assert(!SCIPisZero(scip, lincoef));
3881 
3882  switch( SCIPvarGetType(var) )
3883  {
3884  case SCIP_VARTYPE_BINARY:
3885  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3886  integral = integral && SCIPisIntegral(scip, lincoef);
3887  nbinlin++;
3888  break;
3889  case SCIP_VARTYPE_INTEGER:
3890  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3891  integral = integral && SCIPisIntegral(scip, lincoef);
3892  nintlin++;
3893  break;
3894  case SCIP_VARTYPE_IMPLINT:
3895  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3896  integral = integral && SCIPisIntegral(scip, lincoef);
3897  nimpllin++;
3898  break;
3900  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb);
3901  ncontlin++;
3902  break;
3903  default:
3904  SCIPerrorMessage("unknown variable type\n");
3905  return SCIP_INVALIDDATA;
3906  }
3907  }
3908 
3909  for( i = 0; i < consdata->nquadvars; ++i )
3910  {
3911  var = consdata->quadvarterms[i].var;
3912  lincoef = consdata->quadvarterms[i].lincoef;
3913  quadcoef = consdata->quadvarterms[i].sqrcoef;
3914  lb = SCIPvarGetLbLocal(var);
3915  ub = SCIPvarGetUbLocal(var);
3916 
3917  switch( SCIPvarGetType(var) )
3918  {
3919  case SCIP_VARTYPE_BINARY:
3920  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3921  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
3922  nbinquad++;
3923  break;
3924  case SCIP_VARTYPE_INTEGER:
3925  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3926  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
3927  nintquad++;
3928  break;
3929  case SCIP_VARTYPE_IMPLINT:
3930  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
3931  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
3932  nimplquad++;
3933  break;
3935  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb + quadcoef * lb * lb);
3936  ncontquad++;
3937  break;
3938  default:
3939  SCIPerrorMessage("unknown variable type\n");
3940  return SCIP_INVALIDDATA;
3941  }
3942  }
3943 
3944  if( integral )
3945  {
3946  for( i = 0; i < consdata->nbilinterms && integral; ++i )
3947  {
3948  if( SCIPvarGetType(consdata->bilinterms[i].var1) < SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->bilinterms[i].var2) < SCIP_VARTYPE_CONTINUOUS )
3949  integral = integral && SCIPisIntegral(scip, consdata->bilinterms[i].coef);
3950  else
3951  integral = FALSE;
3952  }
3953  }
3954 
3955  /* call the upgrading methods */
3956 
3957  SCIPdebugMessage("upgrading quadratic constraint <%s> (%d upgrade methods):\n",
3958  SCIPconsGetName(cons), conshdlrdata->nquadconsupgrades);
3959  SCIPdebugMessage(" binlin=%d binquad=%d intlin=%d intquad=%d impllin=%d implquad=%d contlin=%d contquad=%d integral=%u\n",
3960  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral);
3961  SCIPdebugPrintCons(scip, cons, NULL);
3962 
3963  /* try all upgrading methods in priority order in case the upgrading step is enable */
3964  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
3965  {
3966  if( !conshdlrdata->quadconsupgrades[i]->active )
3967  continue;
3968 
3969  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
3970  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
3971  &nupgdconss_, upgdconss, upgdconsssize) );
3972 
3973  while( nupgdconss_ < 0 )
3974  {
3975  /* upgrade function requires more memory: resize upgdconss and call again */
3976  assert(-nupgdconss_ > upgdconsssize);
3977  upgdconsssize = -nupgdconss_;
3978  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
3979 
3980  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
3981  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
3982  &nupgdconss_, upgdconss, upgdconsssize) );
3983 
3984  assert(nupgdconss_ != 0);
3985  }
3986 
3987  if( nupgdconss_ > 0 )
3988  {
3989  /* got upgrade */
3990  SCIPdebugPrintCons(scip, cons, NULL);
3991  SCIPdebugMessage(" -> upgraded to %d constraints:\n", nupgdconss_);
3992 
3993  /* add the upgraded constraints to the problem and forget them */
3994  for( j = 0; j < nupgdconss_; ++j )
3995  {
3996  SCIPdebugPrintf("\t");
3997  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
3998 
3999  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
4000  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
4001  }
4002 
4003  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
4004  *nupgdconss += 1;
4005  *naddconss += nupgdconss_ - 1;
4006  *upgraded = TRUE;
4007 
4008  /* delete upgraded constraint */
4009  SCIPdebugMessage("delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
4010  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
4011  SCIP_CALL( SCIPdelCons(scip, cons) );
4012 
4013  break;
4014  }
4015  }
4016 
4017  SCIPfreeBufferArray(scip, &upgdconss);
4018 
4019  return SCIP_OKAY;
4020 }
4021 
4022 /** helper function for presolveDisaggregate */
4023 static
4025  SCIP* scip, /**< SCIP data structure */
4026  SCIP_CONSDATA* consdata, /**< constraint data */
4027  int quadvaridx, /**< index of quadratic variable to mark */
4028  SCIP_HASHMAP* var2component, /**< variables to components mapping */
4029  int componentnr /**< the component number to mark to */
4030  )
4031 {
4032  SCIP_QUADVARTERM* quadvarterm;
4033  SCIP_VAR* othervar;
4034  int othervaridx;
4035  int i;
4036 
4037  assert(consdata != NULL);
4038  assert(quadvaridx >= 0);
4039  assert(quadvaridx < consdata->nquadvars);
4040  assert(var2component != NULL);
4041  assert(componentnr >= 0);
4042 
4043  quadvarterm = &consdata->quadvarterms[quadvaridx];
4044 
4045  if( SCIPhashmapExists(var2component, quadvarterm->var) )
4046  {
4047  /* if we saw the variable before, then it should have the same component number */
4048  assert((int)(size_t)SCIPhashmapGetImage(var2component, quadvarterm->var) == componentnr);
4049  return SCIP_OKAY;
4050  }
4051 
4052  /* assign component number to variable */
4053  SCIP_CALL( SCIPhashmapInsert(var2component, quadvarterm->var, (void*)(size_t)componentnr) );
4054 
4055  /* assign same component number to all variables this variable is multiplied with */
4056  for( i = 0; i < quadvarterm->nadjbilin; ++i )
4057  {
4058  othervar = consdata->bilinterms[quadvarterm->adjbilin[i]].var1 == quadvarterm->var ?
4059  consdata->bilinterms[quadvarterm->adjbilin[i]].var2 : consdata->bilinterms[quadvarterm->adjbilin[i]].var1;
4060  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, othervar, &othervaridx) );
4061  assert(othervaridx >= 0);
4062  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, othervaridx, var2component, componentnr) );
4063  }
4064 
4065  return SCIP_OKAY;
4066 }
4067 
4068 /** for quadratic constraints that consists of a sum of quadratic terms, disaggregates the sum into a set of constraints by introducing auxiliary variables */
4069 static
4071  SCIP* scip, /**< SCIP data structure */
4072  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4073  SCIP_CONS* cons, /**< source constraint to try to convert */
4074  int* naddconss /**< pointer to counter of added constraints */
4075  )
4076 {
4077  SCIP_CONSDATA* consdata;
4078  SCIP_HASHMAP* var2component;
4079  int ncomponents;
4080  int i;
4081  int comp;
4082  SCIP_CONS** auxconss;
4083  SCIP_VAR** auxvars;
4084  SCIP_Real* auxcoefs;
4085  char name[SCIP_MAXSTRLEN];
4086 
4087  assert(scip != NULL);
4088  assert(conshdlr != NULL);
4089  assert(cons != NULL);
4090  assert(naddconss != NULL);
4091 
4092  consdata = SCIPconsGetData(cons);
4093  assert(consdata != NULL);
4094 
4095  /* make sure there are no quadratic variables without coefficients */
4096  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4097  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
4098 
4099  if( consdata->nquadvars <= 1 )
4100  return SCIP_OKAY;
4101 
4102  /* sort quadratic variable terms here, so we can later search in it without reordering the array */
4103  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4104 
4105  /* check how many quadratic terms with non-overlapping variables we have
4106  * in other words, the number of components in the sparsity graph of the quadratic term matrix */
4107  ncomponents = 0;
4108  SCIP_CALL( SCIPhashmapCreate(&var2component, SCIPblkmem(scip), SCIPcalcHashtableSize(consdata->nquadvars)) );
4109  for( i = 0; i < consdata->nquadvars; ++i )
4110  {
4111  /* if variable was marked already, skip it */
4112  if( SCIPhashmapExists(var2component, (void*)consdata->quadvarterms[i].var) )
4113  continue;
4114 
4115  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, i, var2component, ncomponents) );
4116  ++ncomponents;
4117  }
4118  assert(ncomponents >= 1);
4119 
4120  /* if there is only one component, we cannot disaggregate
4121  * @todo we could still split the constraint into several while keeping the number of variables sharing several constraints as small as possible
4122  */
4123  if( ncomponents == 1 )
4124  {
4125  SCIPhashmapFree(&var2component);
4126  return SCIP_OKAY;
4127  }
4128 
4129  SCIP_CALL( SCIPallocBufferArray(scip, &auxconss, ncomponents) );
4130  SCIP_CALL( SCIPallocBufferArray(scip, &auxvars, ncomponents) );
4131  SCIP_CALL( SCIPallocBufferArray(scip, &auxcoefs, ncomponents) );
4132 
4133  /* create auxiliary variables and empty constraints for each component */
4134  for( comp = 0; comp < ncomponents; ++comp )
4135  {
4136  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp%d", SCIPconsGetName(cons), comp);
4137 
4138  SCIP_CALL( SCIPcreateVar(scip, &auxvars[comp], name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
4140 
4141  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &auxconss[comp], name, 0, NULL, NULL, 0, NULL, 0, NULL,
4142  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : 0.0),
4143  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : 0.0),
4146  SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons)) );
4147 
4148  auxcoefs[comp] = SCIPinfinity(scip);
4149  }
4150 
4151  /* add quadratic variables to each component constraint
4152  * delete adjacency information */
4153  for( i = 0; i < consdata->nquadvars; ++i )
4154  {
4155  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->quadvarterms[i].var);
4156  assert(comp >= 0);
4157  assert(comp < ncomponents);
4158 
4159  /* add variable term to corresponding constraint */
4160  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, auxconss[comp], consdata->quadvarterms[i].var, consdata->quadvarterms[i].lincoef, consdata->quadvarterms[i].sqrcoef) );
4161 
4162  /* reduce coefficient of aux variable */
4163  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) && ABS(consdata->quadvarterms[i].lincoef) < auxcoefs[comp] )
4164  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].lincoef);
4165  if( !SCIPisZero(scip, consdata->quadvarterms[i].sqrcoef) && ABS(consdata->quadvarterms[i].sqrcoef) < auxcoefs[comp] )
4166  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].sqrcoef);
4167 
4168  SCIPfreeBlockMemoryArray(scip, &consdata->quadvarterms[i].adjbilin, consdata->quadvarterms[i].adjbilinsize);
4169  consdata->quadvarterms[i].nadjbilin = 0;
4170  consdata->quadvarterms[i].adjbilinsize = 0;
4171  }
4172 
4173  /* add bilinear terms to each component constraint */
4174  for( i = 0; i < consdata->nbilinterms; ++i )
4175  {
4176  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var1);
4177  assert(comp == (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var2));
4178  assert(!SCIPisZero(scip, consdata->bilinterms[i].coef));
4179 
4180  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, auxconss[comp],
4181  consdata->bilinterms[i].var1, consdata->bilinterms[i].var2, consdata->bilinterms[i].coef) );
4182 
4183  if( ABS(consdata->bilinterms[i].coef) < auxcoefs[comp] )
4184  auxcoefs[comp] = ABS(consdata->bilinterms[i].coef);
4185  }
4186 
4187  /* forget about bilinear terms in cons */
4188  SCIPfreeBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize);
4189  consdata->nbilinterms = 0;
4190  consdata->bilintermssize = 0;
4191 
4192  /* remove quadratic variable terms from cons */
4193  for( i = consdata->nquadvars - 1; i >= 0; --i )
4194  {
4195  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
4196  }
4197  assert(consdata->nquadvars == 0);
4198 
4199  /* add auxiliary variables to auxiliary constraints
4200  * add aux vars and constraints to SCIP
4201  * add aux vars to this constraint
4202  * @todo compute debug solution values and set for auxvars
4203  */
4204  SCIPdebugMessage("add %d constraints for disaggregation of quadratic constraint <%s>\n", ncomponents, SCIPconsGetName(cons));
4205  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + ncomponents) );
4206  for( comp = 0; comp < ncomponents; ++comp )
4207  {
4208  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, auxconss[comp], auxvars[comp], -auxcoefs[comp]) );
4209 
4210  SCIP_CALL( SCIPaddVar(scip, auxvars[comp]) );
4211 
4212  SCIP_CALL( SCIPaddCons(scip, auxconss[comp]) );
4213  SCIPdebugPrintCons(scip, auxconss[comp], NULL);
4214 
4215  SCIP_CALL( addLinearCoef(scip, cons, auxvars[comp], auxcoefs[comp]) );
4216 
4217  SCIP_CALL( SCIPreleaseCons(scip, &auxconss[comp]) );
4218  SCIP_CALL( SCIPreleaseVar(scip, &auxvars[comp]) );
4219  }
4220  *naddconss += ncomponents;
4221 
4222  SCIPdebugPrintCons(scip, cons, NULL);
4223 
4224  SCIPfreeBufferArray(scip, &auxconss);
4225  SCIPfreeBufferArray(scip, &auxvars);
4226  SCIPfreeBufferArray(scip, &auxcoefs);
4227  SCIPhashmapFree(&var2component);
4228 
4229  return SCIP_OKAY;
4230 }
4231 
4232 #ifdef CHECKIMPLINBILINEAR
4233 /** checks if there are bilinear terms x*y with a binary variable x and an implication x = {0,1} -> y = 0
4234  * in this case, the bilinear term can be removed (x=0 case) or replaced by y (x=1 case)
4235  */
4236 static
4237 SCIP_RETCODE presolveApplyImplications(
4238  SCIP* scip, /**< SCIP data structure */
4239  SCIP_CONS* cons, /**< quadratic constraint */
4240  int* nbilinremoved /**< buffer to store number of removed bilinear terms */
4241  )
4242 {
4243  SCIP_CONSDATA* consdata;
4244  SCIP_VAR* x;
4245  SCIP_VAR* y;
4246  SCIP_INTERVAL implbnds;
4247  int i;
4248  int j;
4249  int k;
4250 
4251  assert(scip != NULL);
4252  assert(cons != NULL);
4253  assert(nbilinremoved != NULL);
4254 
4255  *nbilinremoved = 0;
4256 
4257  consdata = SCIPconsGetData(cons);
4258  assert(consdata != NULL);
4259 
4260  SCIPdebugMessage("apply implications in <%s>\n", SCIPconsGetName(cons));
4261 
4262  /* sort quadvarterms in case we need to search */
4263  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4264 
4265  for( i = 0; i < consdata->nquadvars; ++i )
4266  {
4267  x = consdata->quadvarterms[i].var;
4268  assert(x != NULL);
4269 
4270  if( consdata->quadvarterms[i].nadjbilin == 0 )
4271  continue;
4272 
4273  if( !SCIPvarIsBinary(x) )
4274  continue;
4275 
4276  if( !SCIPvarIsActive(x) )
4277  continue;
4278 
4279  if( SCIPvarGetNImpls(x, TRUE) == 0 && SCIPvarGetNImpls(x, FALSE) == 0 )
4280  continue;
4281 
4282  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4283  {
4284  k = consdata->quadvarterms[i].adjbilin[j];
4285  assert(k >= 0);
4286  assert(k < consdata->nbilinterms);
4287 
4288  if( consdata->bilinterms[k].coef == 0.0 )
4289  continue;
4290 
4291  y = consdata->bilinterms[k].var1 == x ? consdata->bilinterms[k].var2 : consdata->bilinterms[k].var1;
4292  assert(x != y);
4293 
4294  getImpliedBounds(x, TRUE, y, &implbnds);
4295  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4296  {
4297  /* if x = 1 implies y = 0, then we can remove the bilinear term x*y, since it is always 0
4298  * we only set the coefficient to 0.0 here and mark the bilinterms as not merged */
4299  SCIPdebugMessage("remove bilinear term %g<%s><%s> from <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), SCIPconsGetName(cons));
4300  consdata->bilinterms[k].coef = 0.0;
4301  consdata->bilinmerged = FALSE;
4302  ++*nbilinremoved;
4303  continue;
4304  }
4305 
4306  getImpliedBounds(x, FALSE, y, &implbnds);
4307  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4308  {
4309  /* if x = 0 implies y = 0, then we can replace the bilinear term x*y by y
4310  * we only move the coefficient to the linear coef of y here and mark the bilinterms as not merged */
4311  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));
4312  assert(consdata->quadvarssorted);
4313  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, cons, y, consdata->bilinterms[k].coef) );
4314  consdata->bilinterms[k].coef = 0.0;
4315  consdata->bilinmerged = FALSE;
4316  ++*nbilinremoved;
4317  }
4318  }
4319  }
4320 
4321  if( *nbilinremoved > 0 )
4322  {
4323  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4324 
4325  /* invalidate nonlinear row */
4326  if( consdata->nlrow != NULL )
4327  {
4328  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4329  }
4330 
4331  consdata->ispropagated = FALSE;
4332  consdata->ispresolved = FALSE;
4333  consdata->iscurvchecked = FALSE;
4334  }
4335 
4336  consdata->isimpladded = FALSE;
4337 
4338  return SCIP_OKAY;
4339 }
4340 #endif
4341 
4342 /** checks a quadratic constraint for convexity and/or concavity without checking multivariate functions */
4343 static
4344 void checkCurvatureEasy(
4345  SCIP* scip, /**< SCIP data structure */
4346  SCIP_CONS* cons, /**< quadratic constraint */
4347  SCIP_Bool* determined, /**< pointer to store whether the curvature could be determined */
4348  SCIP_Bool checkmultivariate /**< whether curvature will be checked later on for multivariate functions */
4349  )
4350 {
4351  SCIP_CONSDATA* consdata;
4352  int nquadvars;
4353 
4354  assert(scip != NULL);
4355  assert(cons != NULL);
4356  assert(determined != NULL);
4357 
4358  consdata = SCIPconsGetData(cons);
4359  assert(consdata != NULL);
4360 
4361  nquadvars = consdata->nquadvars;
4362  *determined = TRUE;
4363 
4364  if( consdata->iscurvchecked )
4365  return;
4366 
4367  SCIPdebugMessage("Checking curvature of constraint <%s> without multivariate functions\n", SCIPconsGetName(cons));
4368 
4369  if( nquadvars == 1 )
4370  {
4371  assert(consdata->nbilinterms == 0);
4372  consdata->isconvex = !SCIPisNegative(scip, consdata->quadvarterms[0].sqrcoef);
4373  consdata->isconcave = !SCIPisPositive(scip, consdata->quadvarterms[0].sqrcoef);
4374  consdata->iscurvchecked = TRUE;
4375  }
4376  else if( nquadvars == 0 )
4377  {
4378  consdata->isconvex = TRUE;
4379  consdata->isconcave = TRUE;
4380  consdata->iscurvchecked = TRUE;
4381  }
4382  else if( consdata->nbilinterms == 0 )
4383  {
4384  int v;
4385 
4386  consdata->isconvex = TRUE;
4387  consdata->isconcave = TRUE;
4388 
4389  for( v = nquadvars - 1; v >= 0; --v )
4390  {
4391  consdata->isconvex = consdata->isconvex && !SCIPisNegative(scip, consdata->quadvarterms[v].sqrcoef);
4392  consdata->isconcave = consdata->isconcave && !SCIPisPositive(scip, consdata->quadvarterms[v].sqrcoef);
4393  }
4394 
4395  consdata->iscurvchecked = TRUE;
4396  }
4397  else if( !checkmultivariate )
4398  {
4399  consdata->isconvex = FALSE;
4400  consdata->isconcave = FALSE;
4401  consdata->iscurvchecked = TRUE;
4402  }
4403  else
4404  *determined = FALSE;
4405 }
4406 
4407 /** checks a quadratic constraint for convexity and/or concavity */
4408 static
4410  SCIP* scip, /**< SCIP data structure */
4411  SCIP_CONS* cons, /**< quadratic constraint */
4412  SCIP_Bool checkmultivariate /**< whether curvature should also be checked for multivariate functions */
4413  )
4414 {
4415  SCIP_CONSDATA* consdata;
4416  double* matrix;
4417  SCIP_HASHMAP* var2index;
4418  int i;
4419  int n;
4420  int nn;
4421  int row;
4422  int col;
4423  double* alleigval;
4424  SCIP_Bool determined;
4425 
4426  assert(scip != NULL);
4427  assert(cons != NULL);
4428 
4429  consdata = SCIPconsGetData(cons);
4430  assert(consdata != NULL);
4431 
4432  n = consdata->nquadvars;
4433 
4434  if( consdata->iscurvchecked )
4435  return SCIP_OKAY;
4436 
4437  /* easy checks for curvature detection */
4438  checkCurvatureEasy(scip, cons, &determined, checkmultivariate);
4439 
4440  /* if curvature was already detected stop */
4441  if( determined )
4442  return SCIP_OKAY;
4443 
4444  SCIPdebugMessage("Checking curvature of constraint <%s> with multivariate functions\n", SCIPconsGetName(cons));
4445 
4446  if( n == 2 )
4447  {
4448  /* compute eigenvalues by hand */
4449  assert(consdata->nbilinterms == 1);
4450  consdata->isconvex =
4451  consdata->quadvarterms[0].sqrcoef >= 0 &&
4452  consdata->quadvarterms[1].sqrcoef >= 0 &&
4453  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4454  consdata->isconcave =
4455  consdata->quadvarterms[0].sqrcoef <= 0 &&
4456  consdata->quadvarterms[1].sqrcoef <= 0 &&
4457  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4458  consdata->iscurvchecked = TRUE;
4459  return SCIP_OKAY;
4460  }
4461 
4462  /* lower triangular of quadratic term matrix */
4463  nn = n * n;
4464  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, nn) );
4465  BMSclearMemoryArray(matrix, nn);
4466 
4467  consdata->isconvex = TRUE;
4468  consdata->isconcave = TRUE;
4469 
4470  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * n)) );
4471  for( i = 0; i < n; ++i )
4472  {
4473  if( consdata->quadvarterms[i].nadjbilin > 0 )
4474  {
4475  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
4476  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4477  }
4478  /* nonzero elements on diagonal tell a lot about convexity/concavity */
4479  if( SCIPisNegative(scip, consdata->quadvarterms[i].sqrcoef) )
4480  consdata->isconvex = FALSE;
4481  if( SCIPisPositive(scip, consdata->quadvarterms[i].sqrcoef) )
4482  consdata->isconcave = FALSE;
4483  }
4484 
4485  if( !consdata->isconvex && !consdata->isconcave )
4486  {
4487  SCIPfreeBufferArray(scip, &matrix);
4488  SCIPhashmapFree(&var2index);
4489  consdata->iscurvchecked = TRUE;
4490  return SCIP_OKAY;
4491  }
4492 
4494  {
4495  for( i = 0; i < consdata->nbilinterms; ++i )
4496  {
4497  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
4498  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
4499  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
4500  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
4501  if( row < col )
4502  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
4503  else
4504  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
4505  }
4506 
4507  SCIP_CALL( SCIPallocBufferArray(scip, &alleigval, n) );
4508  /* @todo Can we compute only min and max eigen value?
4509  * @todo Can we estimate the numerical error?
4510  * @todo Trying a cholesky factorization may be much faster.
4511  */
4512  if( LapackDsyev(FALSE, n, matrix, alleigval) != SCIP_OKAY )
4513  {
4514  SCIPwarningMessage(scip, "Failed to compute eigenvalues of quadratic coefficient matrix of constraint %s. Assuming matrix is indefinite.\n", SCIPconsGetName(cons));
4515  consdata->isconvex = FALSE;
4516  consdata->isconcave = FALSE;
4517  }
4518  else
4519  {
4520  /* deconvexification reformulates a stricly convex quadratic function in binaries such that it becomes not-strictly convex
4521  * by adding the -lambda*(x^2-x) terms for lambda the smallest eigenvalue of the matrix
4522  * 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
4523  */
4524 #ifdef DECONVEXIFY
4525  SCIP_Bool allbinary;
4526  printf("cons <%s>[%g,%g] spectrum = [%g,%g]\n", SCIPconsGetName(cons), consdata->lhs, consdata->rhs, alleigval[0], alleigval[n-1]);
4527 #endif
4528  consdata->isconvex &= !SCIPisNegative(scip, alleigval[0]); /*lint !e514*/
4529  consdata->isconcave &= !SCIPisPositive(scip, alleigval[n-1]); /*lint !e514*/
4530  consdata->iscurvchecked = TRUE;
4531 #ifdef DECONVEXIFY
4532  for( i = 0; i < consdata->nquadvars; ++i )
4533  if( !SCIPvarIsBinary(consdata->quadvarterms[i].var) )
4534  break;
4535  allbinary = i == consdata->nquadvars;
4536 
4537  if( !SCIPisInfinity(scip, consdata->rhs) && alleigval[0] > 0.1 && allbinary )
4538  {
4539  printf("deconvexify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[0]);
4540  for( i = 0; i < consdata->nquadvars; ++i )
4541  {
4542  consdata->quadvarterms[i].sqrcoef -= alleigval[0];
4543  consdata->quadvarterms[i].lincoef += alleigval[0];
4544  }
4545  }
4546 
4547  if( !SCIPisInfinity(scip, consdata->lhs) && alleigval[n-1] < -0.1 && allbinary )
4548  {
4549  printf("deconcavify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[n-1]);
4550  for( i = 0; i < consdata->nquadvars; ++i )
4551  {
4552  consdata->quadvarterms[i].sqrcoef -= alleigval[n-1];
4553  consdata->quadvarterms[i].lincoef += alleigval[n-1];
4554  }
4555  }
4556 #endif
4557  }
4558 
4559  SCIPfreeBufferArray(scip, &alleigval);
4560  }
4561  else
4562  {
4563  consdata->isconvex = FALSE;
4564  consdata->isconcave = FALSE;
4565  consdata->iscurvchecked = TRUE; /* set to TRUE since it does not help to repeat this procedure again and again (that will not bring Ipopt in) */
4566  }
4567 
4568  SCIPhashmapFree(&var2index);
4569  SCIPfreeBufferArray(scip, &matrix);
4570 
4571  return SCIP_OKAY;
4572 }
4573 
4574 /** check whether indefinite constraint function is factorable and store corresponding coefficients */
4575 static
4577  SCIP* scip, /**< SCIP data structure */
4578  SCIP_CONS* cons /**< constraint */
4579  )
4580 {
4581  SCIP_BILINTERM* bilinterm;
4582  SCIP_CONSDATA* consdata;
4583  SCIP_Real* a;
4584  SCIP_Real* eigvals;
4585  SCIP_Real sigma1;
4586  SCIP_Real sigma2;
4587  SCIP_Bool success;
4588  int n;
4589  int i;
4590  int idx1;
4591  int idx2;
4592  int posidx;
4593  int negidx;
4594 
4595  assert(scip != NULL);
4596  assert(cons != NULL);
4597 
4598  consdata = SCIPconsGetData(cons);
4599  assert(consdata != NULL);
4600  assert(consdata->factorleft == NULL);
4601  assert(consdata->factorright == NULL);
4602 
4603  /* we don't need this if there are no bilinear terms */
4604  if( consdata->nbilinterms == 0 )
4605  return SCIP_OKAY;
4606 
4607  /* write constraint as lhs <= linear + x'^T A x' <= rhs where x' = (x,1) and
4608  * A = ( Q b/2 )
4609  * ( b^T/2 0 )
4610  * compute an eigenvalue factorization of A and check if there are one positive and one negative eigenvalue
4611  * 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
4612  * thus, x'^T A x' = sigma1^2 (v1^T x')^2 - sigma2^2 (v2^T x')^2
4613  * = (sigma1 (v1^T x') - sigma2 (v2^T x')) * (sigma1 (v1^T x') + sigma2 (v2^T x'))
4614  * we then store sigma1 v1^T - sigma2 v2^T as left factor coef, and sigma1 v1^T + sigma2 v2^T as right factor coef
4615  */
4616 
4617  /* if we already know that there are only positive or only negative eigenvalues, then don't try */
4618  if( consdata->iscurvchecked && (consdata->isconvex || consdata->isconcave) )
4619  return SCIP_OKAY;
4620 
4621  n = consdata->nquadvars + 1;
4622 
4623  /* @todo handle case n=3 explicitly */
4624 
4625  /* skip too large matrices */
4626  if( n > 50 )
4627  return SCIP_OKAY;
4628 
4629  /* need routine to compute eigenvalues/eigenvectors */
4630  if( !SCIPisIpoptAvailableIpopt() )
4631  return SCIP_OKAY;
4632 
4633  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4634 
4635  SCIP_CALL( SCIPallocBufferArray(scip, &a, n*n) );
4636  BMSclearMemoryArray(a, n*n);
4637 
4638  /* set lower triangular entries of A corresponding to bilinear terms */
4639  for( i = 0; i < consdata->nbilinterms; ++i )
4640  {
4641  bilinterm = &consdata->bilinterms[i];
4642 
4643  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4644  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4645  assert(idx1 >= 0);
4646  assert(idx2 >= 0);
4647  assert(idx1 != idx2);
4648 
4649  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
4650  }
4651 
4652  /* set lower triangular entries of A corresponding to square and linear terms */
4653  for( i = 0; i < consdata->nquadvars; ++i )
4654  {
4655  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4656  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
4657  }
4658 
4659  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, n) );
4660  if( LapackDsyev(TRUE, n, a, eigvals) != SCIP_OKAY )
4661  {
4662  SCIPdebugMessage("Failed to compute eigenvalues and eigenvectors of augmented quadratic form matrix for constraint <%s>.\n", SCIPconsGetName(cons));
4663  goto CLEANUP;
4664  }
4665 
4666  /* check if there is exactly one positive and one negative eigenvalue */
4667  posidx = -1;
4668  negidx = -1;
4669  for( i = 0; i < n; ++i )
4670  {
4671  if( SCIPisPositive(scip, eigvals[i]) )
4672  {
4673  if( posidx == -1 )
4674  posidx = i;
4675  else
4676  break;
4677  }
4678  else if( SCIPisNegative(scip, eigvals[i]) )
4679  {
4680  if( negidx == -1 )
4681  negidx = i;
4682  else
4683  break;
4684  }
4685  }
4686  if( i < n || posidx == -1 || negidx == -1 )
4687  {
4688  SCIPdebugMessage("Augmented quadratic form of constraint <%s> is not factorable.\n", SCIPconsGetName(cons));
4689  goto CLEANUP;
4690  }
4691  assert(SCIPisPositive(scip, eigvals[posidx]));
4692  assert(SCIPisNegative(scip, eigvals[negidx]));
4693 
4694  /* compute factorleft and factorright */
4695  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1) );
4696  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1) );
4697 
4698  /* eigenvectors are stored in a, inverse eigenvector matrix is transposed of a
4699  * it seems that v1 and v2 are at &a[posidx*n] and &a[negidx*n]
4700  */
4701  sigma1 = sqrt( eigvals[posidx]);
4702  sigma2 = sqrt(-eigvals[negidx]);
4703  for( i = 0; i < n; ++i )
4704  {
4705  consdata->factorleft[i] = sigma1 * a[posidx * n + i] - sigma2 * a[negidx * n + i];
4706  consdata->factorright[i] = sigma1 * a[posidx * n + i] + sigma2 * a[negidx * n + i];
4707  /* set almost-zero elements to zero */
4708  if( SCIPisZero(scip, consdata->factorleft[i]) )
4709  consdata->factorleft[i] = 0.0;
4710  if( SCIPisZero(scip, consdata->factorright[i]) )
4711  consdata->factorright[i] = 0.0;
4712  }
4713 
4714 #ifdef SCIP_DEBUG
4715  SCIPdebugMessage("constraint <%s> has factorable quadratic form: (%g", SCIPconsGetName(cons), consdata->factorleft[n-1]);
4716  for( i = 0; i < consdata->nquadvars; ++i )
4717  {
4718  if( consdata->factorleft[i] != 0.0 )
4719  SCIPdebugPrintf(" %+g<%s>", consdata->factorleft[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4720  }
4721  SCIPdebugPrintf(") * (%g", consdata->factorright[n-1]);
4722  for( i = 0; i < consdata->nquadvars; ++i )
4723  {
4724  if( consdata->factorright[i] != 0.0 )
4725  SCIPdebugPrintf(" %+g<%s>", consdata->factorright[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4726  }
4727  SCIPdebugPrintf(")\n");
4728 #endif
4729 
4730  /* check whether factorleft * factorright^T is matrix of augmented quadratic form
4731  * we check here only the nonzero entries from the quadratic form
4732  */
4733  success = TRUE;
4734 
4735  /* check bilinear terms */
4736  for( i = 0; i < consdata->nbilinterms; ++i )
4737  {
4738  bilinterm = &consdata->bilinterms[i];
4739 
4740  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4741  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4742 
4743  if( !SCIPisRelEQ(scip, consdata->factorleft[idx1] * consdata->factorright[idx2] + consdata->factorleft[idx2] * consdata->factorright[idx1], bilinterm->coef) )
4744  {
4745  success = FALSE;
4746  break;
4747  }
4748  }
4749 
4750  /* set lower triangular entries of A corresponding to square and linear terms */
4751  for( i = 0; i < consdata->nquadvars; ++i )
4752  {
4753  if( !SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[i], consdata->quadvarterms[i].sqrcoef) )
4754  {
4755  success = FALSE;
4756  break;
4757  }
4758 
4759  if( !SCIPisRelEQ(scip, consdata->factorleft[n-1] * consdata->factorright[i] + consdata->factorleft[i] * consdata->factorright[n-1], consdata->quadvarterms[i].lincoef) )
4760  {
4761  success = FALSE;
4762  break;
4763  }
4764  }
4765 
4766  if( !success )
4767  {
4768  SCIPdebugMessage("Factorization not accurate enough. Dropping it.\n");
4769  SCIPfreeBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1);
4770  SCIPfreeBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1);
4771  }
4772 
4773  CLEANUP:
4774  SCIPfreeBufferArray(scip, &a);
4775  SCIPfreeBufferArray(scip, &eigvals);
4776 
4777  return SCIP_OKAY;
4778 }
4779 
4780 /** gets maximal absolute value in gradient of quadratic function */
4781 static
4783  SCIP* scip, /**< SCIP data structure */
4784  SCIP_CONS* cons, /**< constraint */
4785  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
4786  )
4787 {
4788  SCIP_CONSDATA* consdata;
4789  SCIP_Real maxelem;
4790  SCIP_Real g;
4791  int i, j, k;
4792  SCIP_VAR* var;
4793 
4794  assert(scip != NULL);
4795  assert(cons != NULL);
4796 
4797  consdata = SCIPconsGetData(cons);
4798  assert(consdata != NULL);
4799 
4800  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
4801  {
4802  maxelem = 0.0;
4803  for( i = 0; i < consdata->nlinvars; ++i )
4804  if( REALABS(consdata->lincoefs[i]) > maxelem )
4805  maxelem = REALABS(consdata->lincoefs[i]);
4806  }
4807  else
4808  {
4809  maxelem = consdata->lincoefsmax;
4810  }
4811 
4812  for( i = 0; i < consdata->nquadvars; ++i )
4813  {
4814  var = consdata->quadvarterms[i].var;
4815  assert(!SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)));
4816  assert(!SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)));
4817  g = consdata->quadvarterms[i].lincoef;
4818  g += 2.0 * consdata->quadvarterms[i].sqrcoef * SCIPgetSolVal(scip, sol, var);
4819  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4820  {
4821  k = consdata->quadvarterms[i].adjbilin[j];
4822  if( consdata->bilinterms[k].var1 == var )
4823  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var2);
4824  else
4825  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var1);
4826  }
4827  if( REALABS(g) > maxelem )
4828  maxelem = REALABS(g);
4829  }
4830 
4831  return maxelem;
4832 }
4833 
4834 /** computes activity and violation of a constraint */
4835 static
4837  SCIP* scip, /**< SCIP data structure */
4838  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4839  SCIP_CONS* cons, /**< constraint */
4840  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
4841  )
4842 { /*lint --e{666}*/
4843  SCIP_CONSHDLRDATA* conshdlrdata;
4844  SCIP_CONSDATA* consdata;
4845  SCIP_Real varval;
4846  SCIP_Real varval2;
4847  SCIP_VAR* var;
4848  SCIP_VAR* var2;
4849  int i;
4850  int j;
4851 
4852  assert(scip != NULL);
4853  assert(cons != NULL);
4854 
4855  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4856  assert(conshdlrdata != NULL);
4857 
4858  consdata = SCIPconsGetData(cons);
4859  assert(consdata != NULL);
4860 
4861  consdata->activity = 0.0;
4862  varval = 0.0;
4863 
4864  /* @todo Take better care of variables at +/- infinity: e.g., run instance waste in debug mode with a short timelimit (30s). */
4865  for( i = 0; i < consdata->nlinvars; ++i )
4866  {
4867  var = consdata->linvars[i];
4868  varval = SCIPgetSolVal(scip, sol, var);
4869 
4870  if( SCIPisInfinity(scip, REALABS(varval)) )
4871  {
4872  consdata->activity = SCIPinfinity(scip);
4873  if( !SCIPisInfinity(scip, -consdata->lhs) )
4874  consdata->lhsviol = SCIPinfinity(scip);
4875  if( !SCIPisInfinity(scip, consdata->rhs) )
4876  consdata->rhsviol = SCIPinfinity(scip);
4877  return SCIP_OKAY;
4878  }
4879 
4880  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
4881  if( sol == NULL )
4882  {
4883  /* 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
4884  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
4885  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
4886  */
4887  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
4888  }
4889 
4890  consdata->activity += consdata->lincoefs[i] * varval;
4891  }
4892 
4893  for( j = 0; j < consdata->nquadvars; ++j )
4894  {
4895  var = consdata->quadvarterms[j].var;
4896  varval = SCIPgetSolVal(scip, sol, var);
4897  if( SCIPisInfinity(scip, REALABS(varval)) )
4898  {
4899  consdata->activity = SCIPinfinity(scip);
4900  if( !SCIPisInfinity(scip, -consdata->lhs) )
4901  consdata->lhsviol = SCIPinfinity(scip);
4902  if( !SCIPisInfinity(scip, consdata->rhs) )
4903  consdata->rhsviol = SCIPinfinity(scip);
4904  return SCIP_OKAY;
4905  }
4906 
4907  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
4908  if( sol == NULL )
4909  {
4910  /* 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
4911  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
4912  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
4913  */
4914  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
4915  }
4916 
4917  consdata->activity += (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
4918  }
4919 
4920  for( j = 0; j < consdata->nbilinterms; ++j )
4921  {
4922  var = consdata->bilinterms[j].var1;
4923  var2 = consdata->bilinterms[j].var2;
4924  varval = SCIPgetSolVal(scip, sol, var);
4925  varval2 = SCIPgetSolVal(scip, sol, var2);
4926 
4927  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
4928  if( sol == NULL )
4929  {
4930 #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 */
4931  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
4932  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
4933 #endif
4934  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
4935 
4936 #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 */
4937  assert(SCIPisFeasGE(scip, varval2, SCIPvarGetLbLocal(var2)));
4938  assert(SCIPisFeasLE(scip, varval2, SCIPvarGetUbLocal(var2)));
4939 #endif
4940  varval2 = MAX(SCIPvarGetLbLocal(var2), MIN(SCIPvarGetUbLocal(var2), varval2));
4941  }
4942 
4943  consdata->activity += consdata->bilinterms[j].coef * varval * varval2;
4944  }
4945 
4946  /* compute absolute violation left hand side */
4947  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
4948  consdata->lhsviol = consdata->lhs - consdata->activity;
4949  else
4950  consdata->lhsviol = 0.0;
4951 
4952  /* compute absolute violation right hand side */
4953  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
4954  consdata->rhsviol = consdata->activity - consdata->rhs;
4955  else
4956  consdata->rhsviol = 0.0;
4957 
4958  switch( conshdlrdata->scaling )
4959  {
4960  case 'o' :
4961  /* no scaling */
4962  break;
4963 
4964  case 'g' :
4965  /* scale by sup-norm of gradient in current point */
4966  if( consdata->lhsviol > 0.0 || consdata->rhsviol > 0.0 )
4967  {
4968  SCIP_Real norm;
4969  norm = getGradientMaxElement(scip, cons, sol);
4970  if( norm > 1.0 )
4971  {
4972  consdata->lhsviol /= norm;
4973  consdata->rhsviol /= norm;
4974  }
4975  }
4976  break;
4977 
4978  case 's' :
4979  /* scale by left/right hand side of constraint */
4980  if( consdata->lhsviol > 0.0 )
4981  consdata->lhsviol /= MAX(1.0, REALABS(consdata->lhs));
4982 
4983  if( consdata->rhsviol > 0.0 )
4984  consdata->rhsviol /= MAX(1.0, REALABS(consdata->rhs));
4985 
4986  break;
4987 
4988  default :
4989  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
4990  SCIPABORT();
4991  return SCIP_INVALIDDATA; /*lint !e527*/
4992  }
4993 
4994  return SCIP_OKAY;
4995 }
4996 
4997 /** computes violation of a set of constraints */
4998 static
5000  SCIP* scip, /**< SCIP data structure */
5001  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5002  SCIP_CONS** conss, /**< constraints */
5003  int nconss, /**< number of constraints */
5004  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5005  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
5006  )
5007 {
5008  SCIP_CONSDATA* consdata;
5009  SCIP_Real viol;
5010  SCIP_Real maxviol;
5011  int c;
5012 
5013  assert(scip != NULL);
5014  assert(conss != NULL || nconss == 0);
5015  assert(maxviolcon != NULL);
5016 
5017  *maxviolcon = NULL;
5018 
5019  maxviol = 0.0;
5020 
5021  for( c = 0; c < nconss; ++c )
5022  {
5023  assert(conss != NULL);
5024  assert(conss[c] != NULL);
5025 
5026  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
5027 
5028  consdata = SCIPconsGetData(conss[c]);
5029  assert(consdata != NULL);
5030 
5031  viol = MAX(consdata->lhsviol, consdata->rhsviol);
5032  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
5033  {
5034  maxviol = viol;
5035  *maxviolcon = conss[c];
5036  }
5037  }
5038 
5039  return SCIP_OKAY;
5040 }
5041 
5042 /** tries to compute cut for multleft * <coefleft, x'> * multright <= rhs / (multright * <coefright, x'>) where x'=(x,1) */
5043 static
5045  SCIP* scip, /**< SCIP data structure */
5046  SCIP_CONS* cons, /**< constraint */
5047  SCIP_Real* ref, /**< reference solution where to generate the cut */
5048  SCIP_Real multleft, /**< multiplicator on lhs */
5049  SCIP_Real* coefleft, /**< coefficient for factor on lhs */
5050  SCIP_Real multright, /**< multiplicator on both sides */
5051  SCIP_Real* coefright, /**< coefficient for factor that goes to rhs */
5052  SCIP_Real rightminactivity, /**< minimal activity of <coefright, x> */
5053  SCIP_Real rightmaxactivity, /**< maximal activity of <coefright, x> */
5054  SCIP_Real rhs, /**< denominator on rhs */
5055  SCIP_Real* cutcoef, /**< array to store cut coefficients for quadratic variables */
5056  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5057  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5058  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5059  char* name /**< buffer to store name of cut */
5060  )
5061 {
5062  SCIP_CONSDATA* consdata;
5063  SCIP_Real constant;
5064  int i;
5065 
5066  assert(cutcoef != NULL);
5067  assert(rightminactivity * multright > 0.0);
5068  assert(rightmaxactivity * multright > 0.0);
5069  assert(multright == 1.0 || multright == -1.0);
5070 
5071  consdata = SCIPconsGetData(cons);
5072  assert(consdata != NULL);
5073 
5074  if( rhs > 0.0 )
5075  {
5076  /* if rhs > 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need secant:
5077  * 1 / multright*<coefright, x'> <= 1/minact + 1/maxact - 1/(minact * maxact) multright*<coefright, x'>
5078  * where [minact, maxact] = multright * [rightminactivity, rightmaxactivity]
5079  *
5080  * assuming multright is either -1 or 1, and substituting gives
5081  * multright/rightminactivity + multright/rightmaxactivity - multright/(rightminactivity * rightmaxactivity) *<coefright, x'>
5082  *
5083  * multiplying by rhs, gives the estimate
5084  * rhs / (multright * <coefright, x'>) <= rhs * multright * (1/rightminactivity + 1/rightmaxactivity - 1/(rightminactivity * rightmaxactivity) * <coefright, x'>)
5085  */
5086 
5087  /* cannot do if unbounded */
5088  if( SCIPisInfinity(scip, rightmaxactivity) )
5089  {
5090  *success = FALSE;
5091  return;
5092  }
5093 
5094  assert(SCIPisFeasLE(scip, rightminactivity, rightmaxactivity));
5095 
5096  constant = multleft * multright * coefleft[consdata->nquadvars];
5097  constant -= rhs * multright * (1.0 / rightminactivity + 1.0 / rightmaxactivity);
5098  constant += rhs * multright * coefright[consdata->nquadvars] / (rightminactivity * rightmaxactivity);
5099 
5100  for( i = 0; i < consdata->nquadvars; ++i )
5101  {
5102  cutcoef[i] = multleft * multright * coefleft[i];
5103  cutcoef[i] += rhs * multright / (rightminactivity * rightmaxactivity) * coefright[i];
5104  }
5105 
5106  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_factorablesecant_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5107  }
5108  else
5109  {
5110  SCIP_Real refvalue;
5111 
5112  /* if rhs < 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need linearization:
5113  * rhs / (multright * <coefright, x'>)
5114  * <= rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'> - multright * <coefright, ref'>)
5115  * = 2*rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'>)
5116  *
5117  * where ref' = (ref, 1)
5118  */
5119 
5120  /* compute <coefright, ref'> */
5121  refvalue = coefright[consdata->nquadvars];
5122  for( i = 0; i < consdata->nquadvars; ++i )
5123  refvalue += coefright[i] * ref[i];
5124 
5125  /* should not happen, since we checked activity of <coefright,x> before, and assume ref within bounds */
5126  assert(!SCIPisZero(scip, refvalue));
5127 
5128  constant = multleft * multright * coefleft[consdata->nquadvars];
5129  constant -= 2.0 * rhs / (multright * refvalue);
5130  constant += rhs / (refvalue * refvalue) * multright * coefright[consdata->nquadvars];
5131 
5132  for( i = 0; i < consdata->nquadvars; ++i )
5133  {
5134  cutcoef[i] = multleft * multright * coefleft[i];
5135  cutcoef[i] += rhs / (refvalue * refvalue) * multright * coefright[i];
5136  }
5137 
5138  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_factorablelinearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5139  }
5140 
5141  *cutrhs = -constant;
5142 
5143  /* @todo does not always need to be local */
5144  *islocal = TRUE;
5145  *success = TRUE;
5146 }
5147 
5148 /** tries to generate a cut if constraint quadratic function is factorable and there are no linear variables
5149  * (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
5150  */
5151 static
5153  SCIP* scip, /**< SCIP data structure */
5154  SCIP_CONS* cons, /**< constraint */
5155  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
5156  SCIP_Real* ref, /**< reference solution where to generate the cut */
5157  SCIP_Real* cutcoef, /**< array to store cut coefficients for quadratic variables */
5158  SCIP_Real* cutlhs, /**< buffer to store cut lhs */
5159  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5160  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5161  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5162  char* name /**< buffer to store name of cut */
5163  )
5164 {
5165  SCIP_CONSDATA* consdata;
5166  SCIP_Real leftminactivity;
5167  SCIP_Real leftmaxactivity;
5168  SCIP_Real rightminactivity;
5169  SCIP_Real rightmaxactivity;
5170  SCIP_Real multleft;
5171  SCIP_Real multright;
5172  SCIP_Real rhs;
5173  int i;
5174 
5175  assert(scip != NULL);
5176  assert(cons != NULL);
5177  assert(ref != NULL);
5178  assert(cutcoef != NULL);
5179  assert(cutlhs != NULL);
5180  assert(cutrhs != NULL);
5181  assert(islocal != NULL);
5182  assert(success != NULL);
5183  assert(name != NULL);
5184 
5185  consdata = SCIPconsGetData(cons);
5186  assert(consdata != NULL);
5187  assert(consdata->nlinvars == 0);
5188  assert(consdata->factorleft != NULL);
5189  assert(consdata->factorright != NULL);
5190 
5191  *success = FALSE;
5192  *cutlhs = -SCIPinfinity(scip);
5193 
5194  leftminactivity = consdata->factorleft[consdata->nquadvars];
5195  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
5196  rightminactivity = consdata->factorright[consdata->nquadvars];
5197  rightmaxactivity = consdata->factorright[consdata->nquadvars];
5198  for( i = 0; i < consdata->nquadvars; ++i )
5199  {
5200  if( !SCIPisInfinity(scip, -leftminactivity) )
5201  {
5202  if( consdata->factorleft[i] > 0.0 )
5203  {
5204  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5205  leftminactivity = -SCIPinfinity(scip);
5206  else
5207  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5208  }
5209  else if( consdata->factorleft[i] < 0.0 )
5210  {
5211  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5212  leftminactivity = -SCIPinfinity(scip);
5213  else
5214  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5215  }
5216  }
5217  if( !SCIPisInfinity(scip, leftmaxactivity) )
5218  {
5219  if( consdata->factorleft[i] > 0.0 )
5220  {
5221  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5222  leftmaxactivity = SCIPinfinity(scip);
5223  else
5224  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5225  }
5226  else if( consdata->factorleft[i] < 0.0 )
5227  {
5228  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5229  leftmaxactivity = SCIPinfinity(scip);
5230  else
5231  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5232  }
5233  }
5234 
5235  if( !SCIPisInfinity(scip, -rightminactivity) )
5236  {
5237  if( consdata->factorright[i] > 0.0 )
5238  {
5239  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5240  rightminactivity = -SCIPinfinity(scip);
5241  else
5242  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5243  }
5244  else if( consdata->factorright[i] < 0.0 )
5245  {
5246  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5247  rightminactivity = -SCIPinfinity(scip);
5248  else
5249  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5250  }
5251  }
5252  if( !SCIPisInfinity(scip, rightmaxactivity) )
5253  {
5254  if( consdata->factorright[i] > 0.0 )
5255  {
5256  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5257  rightmaxactivity = SCIPinfinity(scip);
5258  else
5259  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5260  }
5261  else if( consdata->factorright[i] < 0.0 )
5262  {
5263  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5264  rightmaxactivity = SCIPinfinity(scip);
5265  else
5266  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5267  }
5268  }
5269  }
5270 
5271  /* write violated constraints as multleft * factorleft * factorright <= rhs */
5272  if( violside == SCIP_SIDETYPE_RIGHT )
5273  {
5274  rhs = consdata->rhs;
5275  multleft = 1.0;
5276  }
5277  else
5278  {
5279  rhs = -consdata->lhs;
5280  multleft = -1.0;
5281  }
5282 
5283  if( SCIPisZero(scip, rhs) )
5284  {
5285  /* @todo do something for rhs == 0.0? */
5286  return SCIP_OKAY;
5287  }
5288 
5289  if( !SCIPisFeasPositive(scip, leftminactivity) && !SCIPisFeasNegative(scip, leftmaxactivity) )
5290  {
5291  /* left factor has 0 within activity bounds, or is very close, at least */
5292  if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5293  {
5294  /* right factor also has 0 within activity bounds, or is very close, at least
5295  * -> cannot separate
5296  */
5297  return SCIP_OKAY;
5298  }
5299 
5300  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5301  * such that multright * factorright > 0.0
5302  */
5303  if( rightminactivity < 0.0 )
5304  multright = -1.0;
5305  else
5306  multright = 1.0;
5307 
5308  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5309  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5310  }
5311  else if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5312  {
5313  /* left factor is bounded away from 0
5314  * right factor has 0 within activity bounds, or is very close, at least
5315  * -> so divide by left factor
5316  */
5317 
5318  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5319  * such that multright * factorleft > 0.0
5320  */
5321  if( leftminactivity < 0.0 )
5322  multright = -1.0;
5323  else
5324  multright = 1.0;
5325 
5326  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5327  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5328  }
5329  else if( SCIPisInfinity(scip, -leftminactivity) || SCIPisInfinity(scip, leftmaxactivity) ||
5330  (!SCIPisInfinity(scip, -rightminactivity) && !SCIPisInfinity(scip, rightmaxactivity) && rightmaxactivity - rightminactivity < leftmaxactivity - leftminactivity) )
5331  {
5332  /* both factors are bounded away from 0, but the right one has a smaller activity range, so divide by that one */
5333 
5334  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5335  * such that multright * factorright > 0.0
5336  */
5337  if( rightminactivity < 0.0 )
5338  multright = -1.0;
5339  else
5340  multright = 1.0;
5341 
5342  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5343  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5344  }
5345  else
5346  {
5347  /* both factors are bounded away from 0, but the left one has a smaller activity range, so divide by that one */
5348 
5349  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5350  * such that multright * factorleft > 0.0
5351  */
5352  if( leftminactivity < 0.0 )
5353  multright = -1.0;
5354  else
5355  multright = 1.0;
5356 
5357  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5358  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5359  }
5360 
5361  return SCIP_OKAY;
5362 }
5363 
5364 /* finds intersections of a parametric line (x,y) = (x0,y0) + t [(x1,y1) - (x0,y0)] on curves x*y = wl and x*y = wu
5365  * returns TRUE if unsuccessful and FALSE otherwise
5366  */
5367 static
5369  SCIP* scip,
5370  SCIP_Real x0,
5371  SCIP_Real y0_,
5372  SCIP_Real x1,
5373  SCIP_Real y1_,
5374  SCIP_Real wl,
5375  SCIP_Real wu,
5376  SCIP_Real* xl,
5377  SCIP_Real* yl,
5378  SCIP_Real* xu,
5379  SCIP_Real* yu
5380  )
5381 {
5382  SCIP_Real a;
5383  SCIP_Real b;
5384  SCIP_Real c;
5385  SCIP_Real tl;
5386  SCIP_Real tu;
5387 
5388  assert(wl == SCIP_INVALID || (xl != NULL && yl != NULL)); /*lint !e777 */
5389  assert(wu == SCIP_INVALID || (xu != NULL && yu != NULL)); /*lint !e777 */
5390 
5391  /* The parametric line is of the form
5392  *
5393  * x = x0 + t (x1-x0)
5394  * y = y0 + t (y1-y0)
5395  *
5396  * and for that to satisfy xy = wl and xy = wu we must have
5397  *
5398  * x0 y0 + t [x0 (y1-y0) + y0 (x1-x0)] + t^2 (x1-x0) (y1-y0) = wl
5399  * = wu
5400  *
5401  * or a t^2 + b t + c - wl = 0 for proper values of a,b,c.
5402  * a t^2 + b t + c - wu = 0
5403  *
5404  * Because of the way this procedure will be used, one of the two
5405  * solutions found we must always use the minimum nonnegative one
5406  */
5407 
5408  a = (x1 - x0) * (y1_ - y0_);
5409  c = x0 * y0_;
5410  b = x0 * y1_ + y0_ * x1 - 2.0 * c;
5411 
5412  tl = 0.0;
5413  tu = 0.0;
5414 
5415  if( !SCIPisZero(scip, (SCIP_Real)a) )
5416  {
5417  if( wl != SCIP_INVALID ) /*lint !e777 */
5418  {
5419  SCIP_Real tl1;
5420  SCIP_Real tl2;
5421  SCIP_Real denom;
5422 
5423  assert(b * b - 4.0 * a * (c - wl) >= 0.0);
5424  denom = sqrt(b * b - 4.0 * a * (c - wl));
5425  tl1 = (-b - denom) / (2.0 * a);
5426  tl2 = (-b + denom) / (2.0 * a);
5427  tl = (tl1 < 0.0) ? tl2 : tl1;
5428  }
5429 
5430  if( wu != SCIP_INVALID ) /*lint !e777 */
5431  {
5432  SCIP_Real tu1;
5433  SCIP_Real tu2;
5434  SCIP_Real denom;
5435 
5436  assert(b * b - 4.0 * a * (c - wu) >= 0.0);
5437  denom = sqrt(b * b - 4.0 * a * (c - wu));
5438  tu1 = (-b - denom) / (2.0 * a);
5439  tu2 = (-b + denom) / (2.0 * a);
5440  tu = (tu1 < 0.0) ? tu2 : tu1;
5441  }
5442  }
5443  else if( !SCIPisZero(scip, (SCIP_Real)b) )
5444  {
5445  if( wl != SCIP_INVALID ) /*lint !e777 */
5446  tl = (wl - c) / b;
5447  if( wu != SCIP_INVALID ) /*lint !e777 */
5448  tu = (wu - c) / b;
5449  }
5450  else
5451  {
5452  /* no or infinitely many solutions */
5453  return TRUE;
5454  }
5455 
5456  if( wl != SCIP_INVALID ) /*lint !e777 */
5457  {
5458  *xl = (SCIP_Real)(x0 + tl * (x1 - x0 ));
5459  *yl = (SCIP_Real)(y0_ + tl * (y1_ - y0_));
5460 
5461  if( !SCIPisRelEQ(scip, *xl * *yl, wl) )
5462  {
5463  SCIPdebugMessage("probable numerical difficulties, give up\n");
5464  return TRUE;
5465  }
5466  }
5467 
5468  if( wu != SCIP_INVALID ) /*lint !e777 */
5469  {
5470  *xu = (SCIP_Real)(x0 + tu * (x1 - x0));
5471  *yu = (SCIP_Real)(y0_ + tu * (y1_ - y0_));
5472 
5473  if( !SCIPisRelEQ(scip, *xu * *yu, wu) )
5474  {
5475  SCIPdebugMessage("probable numerical difficulties, give up\n");
5476  return TRUE;
5477  }
5478  }
5479 
5480  return FALSE;
5481 }
5482 
5483 /* generate coefficients for a plane through points (x1, y1_, x1*y1) and (x2, y2, x2*y2)
5484  * such that intersecting it with one of them (the first if whichuse is FALSE, the second otherwise)
5485  * gives a tangent to the curve x*y = k
5486  *
5487  * returns TRUE on error and FALSE on success
5488  */
5489 static
5491  SCIP* scip,
5492  SCIP_Real x1,
5493  SCIP_Real y1_,
5494  SCIP_Real x2,
5495  SCIP_Real y2,
5496  SCIP_Bool whichuse,
5497  SCIP_Real* cx,
5498  SCIP_Real* cy,
5499  SCIP_Real* cw
5500  )
5501 {
5502  SCIP_Real xd;
5503  SCIP_Real yd;
5504  SCIP_Real xo;
5505  SCIP_Real yo;
5506 
5507  assert(cx != NULL);
5508  assert(cy != NULL);
5509  assert(cw != NULL);
5510 
5511  /* the x-y slope of this constraint must be tangent to a curve x*y = k at (xD,yD) */
5512  if( !whichuse )
5513  {
5514  xd = x1;
5515  xo = x2;
5516  yd = y1_;
5517  yo = y2;
5518  }
5519  else
5520  {
5521  xd = x2;
5522  xo = x1;
5523  yd = y2;
5524  yo = y1_;
5525  }
5526 
5527  *cx = yd;
5528  *cy = xd;
5529 
5530  /* lift it so that it touches the other curve */
5531 
5532  /* if the two points are on the same curve, then no cut */
5533  if( SCIPisZero(scip, xo * yo - xd * yd) )
5534  return TRUE;
5535 
5536  /* should ALWAYS be negative */
5537  *cw = (2.0 * xd * yd - (*cx * xo + *cy * yo)) / (xo * yo - xd * yd);
5538 
5539  return FALSE;
5540 }
5541 
5542 /** computes coefficients of a lifted-tangent inequality for x*y = w
5543  * The code is an adaptation of the methods in exprMul-upperHull.cpp in Couenne/stable/0.4 rev773,
5544  * written by P. Belotti and licensed under Eclipse Public License.
5545  */
5546 static
5548  SCIP* scip, /**< SCIP data structure */
5549  SCIP_Real xl, /**< lower bound on x */
5550  SCIP_Real xu, /**< upper bound on x */
5551  SCIP_Real x0, /**< reference point for x */
5552  SCIP_Real yl, /**< lower bound on y */
5553  SCIP_Real yu, /**< upper bound on y */
5554  SCIP_Real y0_, /**< reference point for y */
5555  SCIP_Real wl, /**< lower bound on w */
5556  SCIP_Real wu, /**< upper bound on w */
5557  SCIP_Real w0, /**< reference point for w */
5558  SCIP_Real* cx, /**< buffer where to store cut coefficient for x */
5559  SCIP_Real* cy, /**< buffer where to store cut coefficient for y */
5560  SCIP_Real* cw, /**< buffer where to store cut coefficient for w */
5561  SCIP_Real* c0, /**< buffer where to store cut left-hand-side */
5562  SCIP_Bool* success /**< buffer where to indicate whether cut coefficients were computed */
5563  )
5564 {
5565  SCIP_Bool flipx;
5566  SCIP_Bool flipy;
5567  SCIP_Bool flipw;
5568  SCIP_Real tmp;
5569  SCIP_Real xlow;
5570  SCIP_Real ylow;
5571  SCIP_Real xupp;
5572  SCIP_Real yupp;
5573  SCIP_Real c0x;
5574  SCIP_Real c0y;
5575  SCIP_Real c0w;
5576 
5577  assert(scip != NULL);
5578  assert(cx != NULL);
5579  assert(cy != NULL);
5580  assert(cw != NULL);
5581  assert(c0 != NULL);
5582  assert(success != NULL);
5583 
5584  *success = FALSE;
5585  *cx = 0.0;
5586  *cy = 0.0;
5587  *cw = 0.0;
5588  *c0 = 0.0;
5589 
5590  SCIPdebugMessage("entering points:\n");
5591  SCIPdebugMessage("x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5592  SCIPdebugMessage("y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5593  SCIPdebugMessage("w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5594 
5595  /* generateCutLTI should have recognized these */
5596  assert(wl >= 0.0 || wu <= 0.0);
5597  assert(!SCIPisInfinity(scip, -wl));
5598  assert(!SCIPisInfinity(scip, wu));
5599 
5600  assert(SCIPisFeasGE(scip, x0, xl));
5601  assert(SCIPisFeasLE(scip, x0, xu));
5602  assert(SCIPisFeasGE(scip, y0_, yl));
5603  assert(SCIPisFeasLE(scip, y0_, yu));
5604 
5605  /* preliminary bound tightening */
5606  if( wl >= 0.0 )
5607  {
5608  if( xl >= 0.0 || yl >= 0.0 || SCIPisLT(scip, xl * yl, wl) )
5609  {
5610  xl = MAX(xl, 0.0);
5611  yl = MAX(yl, 0.0);
5612  }
5613  else if( xu <= 0.0 || yu <= 0.0 || SCIPisLT(scip, xu * yu, wl) )
5614  {
5615  xu = MIN(xu, 0.0);
5616  yu = MIN(yu, 0.0);
5617  }
5618  else
5619  {
5620  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yl and xu*yu are feasible
5621  * cannot generate cut for this
5622  */
5623  return;
5624  }
5625  }
5626  else
5627  {
5628  if( xl >= 0.0 || yu <= 0.0 || SCIPisGT(scip, xl * yu, wu) )
5629  {
5630  xl = MAX(xl, 0.0);
5631  yu = MIN(yu, 0.0);
5632  }
5633  else if( xu <= 0.0 || yl >= 0.0 || SCIPisGT(scip, xu * yl, wu))
5634  {
5635  xu = MIN(xu, 0.0);
5636  yl = MAX(yl, 0.0);
5637  }
5638  else
5639  {
5640  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yu and xu*yl are feasible
5641  * cannot generate cut for this
5642  */
5643  return;
5644  }
5645  }
5646 
5647  /* if x or y is fixed now or even infeasible, then do not think about a cut */
5648  if( SCIPisGE(scip, xl, xu) || SCIPisGE(scip, yl, yu) )
5649  return;
5650 
5651  /* reduce to positive orthant by flipping variables */
5652  if( xl < 0.0 )
5653  {
5654  flipx = TRUE;
5655  tmp = xu;
5656  xu = -xl;
5657  xl = -tmp;
5658  x0 = -x0;
5659  }
5660  else
5661  flipx = FALSE;
5662 
5663  if( yl < 0.0 )
5664  {
5665  flipy = TRUE;
5666  tmp = yu;
5667  yu = -yl;
5668  yl = -tmp;
5669  y0_ = -y0_;
5670  }
5671  else
5672  flipy = FALSE;
5673 
5674  if( flipx ^ flipy )
5675  {
5676  flipw = TRUE;
5677  tmp = wu;
5678  wu = -wl;
5679  wl = -tmp;
5680  w0 = -w0;
5681  }
5682  else
5683  flipw = FALSE;
5684 
5685  /* project refpoint into box not only for numerical reasons, but also due to preliminary bound tightening above */
5686  x0 = MIN(xu, MAX(x0, xl));
5687  y0_ = MIN(yu, MAX(y0_, yl));
5688  w0 = MIN(wu, MAX(w0, wl));
5689 
5690  SCIPdebugMessage("reduced points:\n");
5691  SCIPdebugMessage("x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5692  SCIPdebugMessage("y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5693  SCIPdebugMessage("w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5694 
5695  if( SCIPisGE(scip, xl * yl, wl) && SCIPisLE(scip, xu * yu, wu) )
5696  {
5697  SCIPdebugMessage("box for x and y inside feasible region -> nothing to separate\n");
5698  return;
5699  }
5700  if( SCIPisGE(scip, x0 * y0_, w0) )
5701  {
5702  SCIPdebugMessage("point to separate not below curve -> cannot separate\n");
5703  return;
5704  }
5705 
5706  /* find intersections of halfline from origin
5707  * return if no proper point could be found
5708  */
5709  if( generateCutLTIfindIntersection(scip, 0.0, 0.0, x0, y0_, wl, wu, &xlow, &ylow, &xupp, &yupp) )
5710  return;
5711 
5712  SCIPdebugMessage("intersections:\n");
5713  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5714  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5715 
5716  /* Case 1: If both are outside of bounding box, either NW or SE, then McCormick is sufficient, so return */
5717  if( (xlow <= xl && yupp >= yu) || (ylow <= yl && xupp >= xu) )
5718  return;
5719 
5720  /* There will be at least one cut. Define coefficients and rhs ---will have to change them back if (flipX || flipY) */
5721  if( xlow >= xl && xupp <= xu && ylow >= yl && yupp <= yu )
5722  {
5723  /* Case 2: both are inside. Easy lifting... */
5724  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5725  return;
5726 
5727  c0x = *cx * xlow;
5728  c0y = *cy * ylow;
5729  c0w = *cw * wl;
5730  }
5731  else if( xlow >= xl && ylow >= yl && (xupp > xu || yupp > yu) )
5732  {
5733  /* Case 3a and 3b: through lower curve, but not upper. */
5734  if( yupp > yu )
5735  {
5736  /* upper intersect is North; place it within box */
5737  assert(!SCIPisInfinity(scip, yu));
5738  yupp = yu;
5739  xupp = wu / yu;
5740  }
5741  else
5742  {
5743  /* upper intersect is East; place it within box */
5744  assert(!SCIPisInfinity(scip, xu));
5745  xupp = xu;
5746  yupp = wu / xu;
5747  }
5748 
5749  /* find intersection on low curve on half line through new point and (x0,y0_) */
5750  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow, &ylow, NULL, NULL) )
5751  return;
5752 
5753  /* check whether McCormick is sufficient */
5754  if( xlow < xl || ylow < yl )
5755  return;
5756 
5757  /* lift inequality on lower point */
5758  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5759  return;
5760 
5761  c0x = *cx * xlow;
5762  c0y = *cy * ylow;
5763  c0w = *cw * wl;
5764  }
5765  else if( xupp <= xu && yupp <= yu && (xlow < xl || ylow < yl) )
5766  {
5767  /* Case 4a and 4b: viceversa (lift for validity) */
5768  if( ylow < yl )
5769  {
5770  /* upper intersect is South; place it within box */
5771  assert(!SCIPisZero(scip, yl));
5772  ylow = yl;
5773  xlow = wl / yl;
5774  }
5775  else
5776  {
5777  /* upper intersect is West; place it within box */
5778  assert(!SCIPisZero(scip, xl));
5779  xlow = xl;
5780  ylow = wl / xl;
5781  }
5782 
5783  /* find intersection on low curve on half line through new point and (x0,y0) */
5784  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp, &yupp) )
5785  return;
5786 
5787  /* check whether McCormick is sufficient */
5788  if( xupp > xu || yupp > yu )
5789  return;
5790 
5791  /* lift inequality on UPPER point */
5792  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
5793  return;
5794 
5795  c0x = *cx * xupp;
5796  c0y = *cy * yupp;
5797  c0w = *cw * wu;
5798  }
5799  else if( (xlow < xl && xupp > xu) || (ylow < yl && yupp > yu) )
5800  {
5801  /* Case 5: both outside of bounding box, N and S or W and E. */
5802 #if 0
5803  SCIP_Real xlow2;
5804  SCIP_Real ylow2;
5805  SCIP_Real xupp2;
5806  SCIP_Real yupp2;
5807 #endif
5808 
5809  if( ylow < yl )
5810  {
5811  /* upper intersect is South; place it within box */
5812  assert(!SCIPisZero(scip, yl));
5813  assert(!SCIPisZero(scip, yu));
5814  ylow = yl;
5815  yupp = yu;
5816  xlow = wl / yl;
5817  xupp = wu / yu;
5818  }
5819  else
5820  {
5821  /* upper intersect is West; place it within box */
5822  assert(!SCIPisZero(scip, xl));
5823  assert(!SCIPisZero(scip, xu));
5824  xlow = xl;
5825  xupp = xu;
5826  ylow = wl / xl;
5827  yupp = wu / xu;
5828  }
5829 
5830  SCIPdebugMessage("New intersections:\n");
5831  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5832  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5833 
5834 #if 1
5835  /* Nothing to find. Just separate two inequalities at the same point, just using different support */
5836  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5837  {
5838  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
5839  return;
5840 
5841  c0x = *cx * xupp;
5842  c0y = *cy * yupp;
5843  c0w = *cw * wu;
5844  }
5845  else
5846  {
5847  c0x = *cx * xlow;
5848  c0y = *cy * ylow;
5849  c0w = *cw * wl;
5850  }
5851 
5852 #else
5853  /* find the intersection on the lower (upper) curve on the line through xLP and the upper (lower) point
5854  * this does not seem to work (cuts off solution at nous2), so it is disabled for now
5855  */
5856  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp2, &yupp2) ||
5857  generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp2, yupp2, FALSE, cx, cx, cw) )
5858  {
5859  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow2, &ylow2, NULL, NULL) ||
5860  generateCutLTIgenMulCoeff(scip, xlow2, ylow2, xupp, yupp, TRUE, cx, cy, cw) )
5861  return;
5862 
5863  c0x = *cx * xupp;
5864  c0y = *cy * yupp;
5865  c0w = *cw * wu;
5866  }
5867  else
5868  {
5869  c0x = *cx * xlow;
5870  c0y = *cy * ylow;
5871  c0w = *cw * wl;
5872  }
5873 #endif
5874  }
5875  else
5876  {
5877  SCIPdebugMessage("points are in a weird position:\n");
5878  SCIPdebugMessage("lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5879  SCIPdebugMessage("upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5880 
5881  return;
5882  }
5883 
5884  SCIPdebugMessage("cut w.r.t. reduced points: %gx-%g %+gy-%g %+gw-%g >= 0\n",
5885  *cx, c0x, *cy, c0y, *cw, c0w);
5886 
5887  /* re-transform back into original variables */
5888  if( flipx )
5889  *cx = -*cx;
5890  if( flipy )
5891  *cy = -*cy;
5892  if( flipw )
5893  *cw = -*cw;
5894 
5895  *c0 = c0x + c0y + c0w;
5896 
5897  *success = TRUE;
5898 }
5899 
5900 /** tries to generate a cut if constraint quadratic function is factorable and there are linear variables
5901  * computes what is called a lifted tangent inequality described in
5902  * Belotti, Miller, Namazifar, Lifted inequalities for bounded products of variables, SIAG/OPT Views-and-News 22:1, 2011
5903  */
5904 static
5906  SCIP* scip, /**< SCIP data structure */
5907  SCIP_CONS* cons, /**< constraint */
5908  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
5909  SCIP_Real* ref, /**< reference solution where to generate the cut */
5910  SCIP_SOL* sol, /**< solution that shall be cutoff, NULL for LP solution */
5911  SCIP_Real** cutcoeflin, /**< buffer to store pointer to array with coefficients for linear variables */
5912  SCIP_Real* cutcoefquad, /**< array to store cut coefficients for quadratic variables */
5913  SCIP_Real* cutlhs, /**< buffer to store cut lhs */
5914  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5915  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5916  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5917  char* name /**< buffer to store name of cut */
5918  )
5919 {
5920  SCIP_CONSDATA* consdata;
5921  SCIP_Real leftminactivity;
5922  SCIP_Real leftmaxactivity;
5923  SCIP_Real leftrefactivity;
5924  SCIP_Real rightminactivity;
5925  SCIP_Real rightmaxactivity;
5926  SCIP_Real rightrefactivity;
5927  SCIP_Real rhsminactivity;
5928  SCIP_Real rhsmaxactivity;
5929  SCIP_Real rhsrefactivity;
5930  SCIP_Real coefleft;
5931  SCIP_Real coefright;
5932  SCIP_Real coefrhs;
5933  int i;
5934 
5935  assert(scip != NULL);
5936  assert(cons != NULL);
5937  assert(ref != NULL);
5938  assert(cutcoeflin != NULL);
5939  assert(cutcoefquad != NULL);
5940  assert(cutlhs != NULL);
5941  assert(cutrhs != NULL);
5942  assert(islocal != NULL);
5943  assert(success != NULL);
5944  assert(name != NULL);
5945  /* currently only separate LP solution or solutions given as SCIP_SOL, i.e., no cutgeneration during initlp */
5946  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
5947 
5948  consdata = SCIPconsGetData(cons);
5949  assert(consdata != NULL);
5950  assert(consdata->nlinvars > 0);
5951  assert(consdata->factorleft != NULL);
5952  assert(consdata->factorright != NULL);
5953 
5954  *success = FALSE;
5955  *cutlhs = -SCIPinfinity(scip); /* for compiler */
5956 
5957  /* write violated constraints as factorleft * factorright '==' rhs
5958  * where rhs are constraint sides - activity bound of linear part
5959  */
5960  rhsminactivity = consdata->lhs;
5961  rhsmaxactivity = consdata->rhs;
5962  rhsrefactivity = (violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
5963 
5964  for( i = 0; i < consdata->nlinvars; ++i )
5965  {
5966  if( !SCIPisInfinity(scip, -rhsminactivity) )
5967  {
5968  if( consdata->lincoefs[i] < 0.0 )
5969  {
5970  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
5971  rhsminactivity = -SCIPinfinity(scip);
5972  else
5973  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
5974  }
5975  else
5976  {
5977  assert(consdata->lincoefs[i] > 0.0);
5978  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
5979  rhsminactivity = -SCIPinfinity(scip);
5980  else
5981  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
5982  }
5983  }
5984  if( !SCIPisInfinity(scip, rhsmaxactivity) )
5985  {
5986  if( consdata->lincoefs[i] < 0.0 )
5987  {
5988  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
5989  rhsmaxactivity = SCIPinfinity(scip);
5990  else
5991  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
5992  }
5993  else
5994  {
5995  assert(consdata->lincoefs[i] > 0.0);
5996  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
5997  rhsmaxactivity = SCIPinfinity(scip);
5998  else
5999  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6000  }
6001  }
6002  rhsrefactivity -= consdata->lincoefs[i] * SCIPgetSolVal(scip, sol, consdata->linvars[i]);
6003  }
6004 
6005  if( SCIPisInfinity(scip, -rhsminactivity) || SCIPisInfinity(scip, rhsmaxactivity) )
6006  {
6007  /* if right hand side is unbounded, then cannot do LTI */
6008  return SCIP_OKAY;
6009  }
6010 
6011  if( !SCIPisFeasPositive(scip, rhsminactivity) && !SCIPisFeasNegative(scip, rhsmaxactivity) )
6012  {
6013  /* if right hand side has 0 inside activity, then cannot do anything
6014  * if it has 0.0 as min or max activity, then a usual McCormick should be sufficient, too
6015  */
6016  return SCIP_OKAY;
6017  }
6018 
6019  leftminactivity = consdata->factorleft[consdata->nquadvars];
6020  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
6021  leftrefactivity = consdata->factorleft[consdata->nquadvars];
6022  rightminactivity = consdata->factorright[consdata->nquadvars];
6023  rightmaxactivity = consdata->factorright[consdata->nquadvars];
6024  rightrefactivity = consdata->factorright[consdata->nquadvars];
6025  for( i = 0; i < consdata->nquadvars; ++i )
6026  {
6027  if( !SCIPisInfinity(scip, -leftminactivity) )
6028  {
6029  if( consdata->factorleft[i] > 0.0 )
6030  {
6031  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6032  leftminactivity = -SCIPinfinity(scip);
6033  else
6034  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6035  }
6036  else if( consdata->factorleft[i] < 0.0 )
6037  {
6038  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6039  leftminactivity = -SCIPinfinity(scip);
6040  else
6041  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6042  }
6043  }
6044  if( !SCIPisInfinity(scip, leftmaxactivity) )
6045  {
6046  if( consdata->factorleft[i] > 0.0 )
6047  {
6048  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6049  leftmaxactivity = SCIPinfinity(scip);
6050  else
6051  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6052  }
6053  else if( consdata->factorleft[i] < 0.0 )
6054  {
6055  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6056  leftmaxactivity = SCIPinfinity(scip);
6057  else
6058  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6059  }
6060  }
6061  leftrefactivity += consdata->factorleft[i] * ref[i];
6062 
6063  if( !SCIPisInfinity(scip, -rightminactivity) )
6064  {
6065  if( consdata->factorright[i] > 0.0 )
6066  {
6067  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6068  rightminactivity = -SCIPinfinity(scip);
6069  else
6070  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6071  }
6072  else if( consdata->factorright[i] < 0.0 )
6073  {
6074  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6075  rightminactivity = -SCIPinfinity(scip);
6076  else
6077  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6078  }
6079  }
6080  if( !SCIPisInfinity(scip, rightmaxactivity) )
6081  {
6082  if( consdata->factorright[i] > 0.0 )
6083  {
6084  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6085  rightmaxactivity = SCIPinfinity(scip);
6086  else
6087  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6088  }
6089  else if( consdata->factorright[i] < 0.0 )
6090  {
6091  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6092  rightmaxactivity = SCIPinfinity(scip);
6093  else
6094  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6095  }
6096  }
6097  rightrefactivity += consdata->factorright[i] * ref[i];
6098  }
6099 
6100  /* if activities exceed "opposite" infinity, huge bounds seem to be involved, for which the below method is not prepared */
6101  if( SCIPisInfinity(scip, leftminactivity) || SCIPisInfinity(scip, -leftmaxactivity) ||
6102  SCIPisInfinity(scip, rightminactivity) || SCIPisInfinity(scip, -rightmaxactivity) )
6103  return SCIP_OKAY;
6104 
6105  /* if any of the factors is essentially fixed, give up and do usual method (numerically less sensitive, I hope) */
6106  if( SCIPisRelEQ(scip, leftminactivity, leftmaxactivity) || SCIPisRelEQ(scip, rightminactivity, rightmaxactivity) )
6107  return SCIP_OKAY;
6108 
6109  /* success can only be expected for separation of violated x*y <= w, assuming x>=0, y>=0
6110  * @todo we should check this early? */
6111 
6112  /* call Couenne magic */
6114  leftminactivity, leftmaxactivity, leftrefactivity,
6115  rightminactivity, rightmaxactivity, rightrefactivity,
6116  rhsminactivity, rhsmaxactivity, rhsrefactivity,
6117  &coefleft, &coefright, &coefrhs, cutlhs,
6118  success);
6119 
6120  if( !*success )
6121  return SCIP_OKAY;
6122 
6123  SCIPdebugMessage("LTI for x[%g,%g] * y[%g,%g] = w[%g,%g]: %gx %+gy %+gw >= %g; feas: %g\n",
6124  leftminactivity, leftmaxactivity, rightminactivity, rightmaxactivity, rhsminactivity, rhsmaxactivity,
6125  coefleft, coefright, coefrhs, *cutlhs,
6126  coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity - *cutlhs
6127  );
6128 
6129  if( coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity >= *cutlhs )
6130  {
6131  SCIPdebugMessage("does not cutoff point? :-(\n");
6132  *success = FALSE;
6133  return SCIP_OKAY;
6134  }
6135 
6136  /* setup cut coefs for
6137  * coefleft * leftfactor + coefright * rightfactor + coefrhs * w >= cutlhs, where conslhs - lincoefs <= w <= consrhs - lincoefs
6138  */
6139  for( i = 0; i < consdata->nquadvars; ++i )
6140  cutcoefquad[i] = coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i];
6141  assert(i == consdata->nquadvars);
6142  *cutlhs -= coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i];
6143 
6144  SCIP_CALL( SCIPallocBufferArray(scip, cutcoeflin, consdata->nlinvars) );
6145  for( i = 0; i < consdata->nlinvars; ++i )
6146  (*cutcoeflin)[i] = -coefrhs * consdata->lincoefs[i];
6147  if( coefrhs > 0.0 )
6148  {
6149  /* use coefrhs * w <= coefrhs * (consrhs - lincoefs) */
6150  assert(!SCIPisInfinity(scip, consdata->rhs));
6151  *cutlhs -= coefrhs * consdata->rhs;
6152  }
6153  else
6154  {
6155  /* use coefrhs * w <= coeflhs * (conslhs - lincoefs) */
6156  assert(!SCIPisInfinity(scip, -consdata->lhs));
6157  *cutlhs -= coefrhs * consdata->lhs;
6158  }
6159 
6160  *cutrhs = SCIPinfinity(scip);
6161  *islocal = TRUE;
6162 
6163  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_lti_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6164 
6165  *success = TRUE;
6166 
6167  return SCIP_OKAY;
6168 }
6169 
6170 /** computes coefficients of linearization of a square term in a reference point */
6171 static
6173  SCIP* scip, /**< SCIP data structure */
6174  SCIP_Real sqrcoef, /**< coefficient of square term */
6175  SCIP_Real refpoint, /**< point where to linearize */
6176  SCIP_Bool isint, /**< whether corresponding variable is a discrete variable, and thus linearization could be moved */
6177  SCIP_Real* lincoef, /**< buffer to add coefficient of linearization */
6178  SCIP_Real* linconstant, /**< buffer to add constant of linearization */
6179  SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
6180  )
6181 {
6182  assert(scip != NULL);
6183  assert(lincoef != NULL);
6184  assert(linconstant != NULL);
6185  assert(success != NULL);
6186 
6187  if( sqrcoef == 0.0 )
6188  return;
6189 
6190  if( SCIPisInfinity(scip, REALABS(refpoint)) )
6191  {
6192  *success = FALSE;
6193  return;
6194  }
6195 
6196  if( !isint || SCIPisIntegral(scip, refpoint) )
6197  {
6198  SCIP_Real tmp;
6199 
6200  /* sqrcoef * x^2 -> tangent in refpoint = sqrcoef * 2 * refpoint * (x - refpoint) */
6201 
6202  tmp = sqrcoef * refpoint;
6203 
6204  if( SCIPisInfinity(scip, 2.0 * REALABS(tmp)) )
6205  {
6206  *success = FALSE;
6207  return;
6208  }
6209 
6210  *lincoef += 2.0 * tmp;
6211  tmp *= refpoint;
6212  *linconstant -= tmp;
6213  }
6214  else
6215  {
6216  /* 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) */
6217  SCIP_Real f;
6218  SCIP_Real coef;
6219  SCIP_Real constant;
6220 
6221  f = SCIPfloor(scip, refpoint);
6222 
6223  coef = sqrcoef * (2.0 * f + 1.0);
6224  constant = -sqrcoef * f * (f + 1.0);
6225 
6226  if( SCIPisInfinity(scip, REALABS(coef)) || SCIPisInfinity(scip, REALABS(constant)) )
6227  {
6228  *success = FALSE;
6229  return;
6230  }
6231 
6232  *lincoef += coef;
6233  *linconstant += constant;
6234  }
6235 }
6236 
6237 /** computes coefficients of secant of a square term */
6238 static
6239 void addSquareSecant(
6240  SCIP* scip, /**< SCIP data structure */
6241  SCIP_Real sqrcoef, /**< coefficient of square term */
6242  SCIP_Real lb, /**< lower bound on variable */
6243  SCIP_Real ub, /**< upper bound on variable */
6244  SCIP_Real refpoint, /**< point for which to compute value of linearization */
6245  SCIP_Real* lincoef, /**< buffer to add coefficient of secant */
6246  SCIP_Real* linconstant, /**< buffer to add constant of secant */
6247  SCIP_Bool* success /**< buffer to set to FALSE if secant has failed due to large numbers or unboundedness */
6248  )
6249 {
6250  SCIP_Real coef;
6251  SCIP_Real constant;
6252 
6253  assert(scip != NULL);
6254  assert(!SCIPisInfinity(scip, lb));
6255  assert(!SCIPisInfinity(scip, -ub));
6256  assert(SCIPisLE(scip, lb, ub));
6257  assert(SCIPisLE(scip, lb, refpoint));
6258  assert(SCIPisGE(scip, ub, refpoint));
6259  assert(lincoef != NULL);
6260  assert(linconstant != NULL);
6261  assert(success != NULL);
6262 
6263  if( sqrcoef == 0.0 )
6264  return;
6265 
6266  if( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
6267  {
6268  /* unboundedness */
6269  *success = FALSE;
6270  return;
6271  }
6272 
6273  /* 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) */
6274 
6275  coef = sqrcoef * (lb + ub);
6276  constant = -sqrcoef * lb * ub;
6277  if( SCIPisInfinity(scip, REALABS(coef)) || SCIPisInfinity(scip, REALABS(constant)) )
6278  {
6279  *success = FALSE;
6280  return;
6281  }
6282 
6283  *lincoef += coef;
6284  *linconstant += constant;
6285 }
6286 
6287 /** computes coefficients of linearization of a bilinear term in a reference point */
6288 static
6290  SCIP* scip, /**< SCIP data structure */
6291  SCIP_Real bilincoef, /**< coefficient of bilinear term */
6292  SCIP_Real refpointx, /**< point where to linearize first variable */
6293  SCIP_Real refpointy, /**< point where to linearize second variable */
6294  SCIP_Real* lincoefx, /**< buffer to add coefficient of first variable in linearization */
6295  SCIP_Real* lincoefy, /**< buffer to add coefficient of second variable in linearization */
6296  SCIP_Real* linconstant, /**< buffer to add constant of linearization */
6297  SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
6298  )
6299 {
6300  SCIP_Real constant;
6301 
6302  assert(scip != NULL);
6303  assert(lincoefx != NULL);
6304  assert(lincoefy != NULL);
6305  assert(linconstant != NULL);
6306  assert(success != NULL);
6307 
6308  if( bilincoef == 0.0 )
6309  return;
6310 
6311  if( SCIPisInfinity(scip, REALABS(refpointx)) || SCIPisInfinity(scip, REALABS(refpointy)) )
6312  {
6313  *success = FALSE;
6314  return;
6315  }
6316 
6317  /* bilincoef * x * y -> bilincoef * (refpointx * refpointy + refpointy * (x - refpointx) + refpointx * (y - refpointy))
6318  * = -bilincoef * refpointx * refpointy + bilincoef * refpointy * x + bilincoef * refpointx * y
6319  */
6320 
6321  constant = -bilincoef * refpointx * refpointy;
6322 
6323  if( SCIPisInfinity(scip, REALABS(bilincoef * refpointx)) || SCIPisInfinity(scip, REALABS(bilincoef * refpointy)) || SCIPisInfinity(scip, REALABS(constant)) )
6324  {
6325  *success = FALSE;
6326  return;
6327  }
6328 
6329  *lincoefx += bilincoef * refpointy;
6330  *lincoefy += bilincoef * refpointx;
6331  *linconstant += constant;
6332 }
6333 
6334 /** computes coefficients of McCormick under- or overestimation of a bilinear term */
6335 static
6336 void addBilinMcCormick(
6337  SCIP* scip, /**< SCIP data structure */
6338  SCIP_Real bilincoef, /**< coefficient of bilinear term */
6339  SCIP_Real lbx, /**< lower bound on first variable */
6340  SCIP_Real ubx, /**< upper bound on first variable */
6341  SCIP_Real refpointx, /**< reference point for first variable */
6342  SCIP_Real lby, /**< lower bound on second variable */
6343  SCIP_Real uby, /**< upper bound on second variable */
6344  SCIP_Real refpointy, /**< reference point for second variable */
6345  SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
6346  SCIP_Real* lincoefx, /**< buffer to add coefficient of first variable in linearization */
6347  SCIP_Real* lincoefy, /**< buffer to add coefficient of second variable in linearization */
6348  SCIP_Real* linconstant, /**< buffer to add constant of linearization */
6349  SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
6350  )
6351 {
6352  SCIP_Real constant;
6353  SCIP_Real coefx;
6354  SCIP_Real coefy;
6355 
6356  assert(scip != NULL);
6357  assert(!SCIPisInfinity(scip, lbx));
6358  assert(!SCIPisInfinity(scip, -ubx));
6359  assert(!SCIPisInfinity(scip, lby));
6360  assert(!SCIPisInfinity(scip, -uby));
6361  assert(SCIPisLE(scip, lbx, ubx));
6362  assert(SCIPisLE(scip, lby, uby));
6363  assert(SCIPisLE(scip, lbx, refpointx));
6364  assert(SCIPisGE(scip, ubx, refpointx));
6365  assert(SCIPisLE(scip, lby, refpointy));
6366  assert(SCIPisGE(scip, uby, refpointy));
6367  assert(lincoefx != NULL);
6368  assert(lincoefy != NULL);
6369  assert(linconstant != NULL);
6370  assert(success != NULL);
6371 
6372  if( bilincoef == 0.0 )
6373  return;
6374 
6375  if( overestimate )
6376  bilincoef = -bilincoef;
6377 
6378  if( SCIPisRelEQ(scip, lbx, ubx) && SCIPisRelEQ(scip, lby, uby) )
6379  {
6380  /* both x and y are mostly fixed */
6381  SCIP_Real cand1;
6382  SCIP_Real cand2;
6383  SCIP_Real cand3;
6384  SCIP_Real cand4;
6385 
6386  coefx = 0.0;
6387  coefy = 0.0;
6388 
6389  /* estimate x * y by constant */
6390  cand1 = lbx * lby;
6391  cand2 = lbx * uby;
6392  cand3 = ubx * lby;
6393  cand4 = ubx * uby;
6394 
6395  if( bilincoef > 0.0 )
6396  constant = bilincoef * MAX( MAX(cand1, cand2), MAX(cand3, cand4) );
6397  else
6398  constant = bilincoef * MIN( MIN(cand1, cand2), MIN(cand3, cand4) );
6399  }
6400  else if( bilincoef > 0.0 )
6401  {
6402  /* either x or y is not fixed and coef > 0.0 */
6403  if( !SCIPisInfinity(scip, -lbx) && !SCIPisInfinity(scip, -lby) &&
6404  (SCIPisInfinity(scip, ubx) || SCIPisInfinity(scip, uby) || (uby - refpointy) * (ubx - refpointx) >= (refpointy - lby) * (refpointx - lbx)) )
6405  {
6406  if( SCIPisRelEQ(scip, lbx, ubx) )
6407  {
6408  /* x*y = lbx * y + (x-lbx) * y >= lbx * y + (x-lbx) * lby >= lbx * y + min{(ubx-lbx) * lby, 0 * lby} */
6409  coefx = 0.0;
6410  coefy = bilincoef * lbx;
6411  constant = bilincoef * (lby < 0.0 ? (ubx-lbx) * lby : 0.0);
6412  }
6413  else if( SCIPisRelEQ(scip, lby, uby) )
6414  {
6415  /* x*y = lby * x + (y-lby) * x >= lby * x + (y-lby) * lbx >= lby * x + min{(uby-lby) * lbx, 0 * lbx} */
6416  coefx = bilincoef * lby;
6417  coefy = 0.0;
6418  constant = bilincoef * (lbx < 0.0 ? (uby-lby) * lbx : 0.0);
6419  }
6420  else
6421  {
6422  coefx = bilincoef * lby;
6423  coefy = bilincoef * lbx;
6424  constant = -bilincoef * lbx * lby;
6425  }
6426  }
6427  else if( !SCIPisInfinity(scip, ubx) && !SCIPisInfinity(scip, uby) )
6428  {
6429  if( SCIPisRelEQ(scip, lbx, ubx) )
6430  {
6431  /* x*y = ubx * y + (x-ubx) * y >= ubx * y + (x-ubx) * uby >= ubx * y + min{(lbx-ubx) * uby, 0 * uby} */
6432  coefx = 0.0;
6433  coefy = bilincoef * ubx;
6434  constant = bilincoef * (uby > 0.0 ? (lbx-ubx) * uby : 0.0);
6435  }
6436  else if( SCIPisRelEQ(scip, lby, uby) )
6437  {
6438  /* x*y = uby * x + (y-uby) * x >= uby * x + (y-uby) * ubx >= uby * x + min{(lby-uby) * ubx, 0 * ubx} */
6439  coefx = bilincoef * uby;
6440  coefy = 0.0;
6441  constant = bilincoef * (ubx > 0.0 ? (lby-uby) * ubx : 0.0);
6442  }
6443  else
6444  {
6445  coefx = bilincoef * uby;
6446  coefy = bilincoef * ubx;
6447  constant = -bilincoef * ubx * uby;
6448  }
6449  }
6450  else
6451  {
6452  *success = FALSE;
6453  return;
6454  }
6455  }
6456  else
6457  {
6458  /* either x or y is not fixed and coef < 0.0 */
6459  if( !SCIPisInfinity(scip, ubx) && !SCIPisInfinity(scip, -lby) &&
6460  (SCIPisInfinity(scip, -lbx) || SCIPisInfinity(scip, uby) || (ubx - lbx) * (refpointy - lby) <= (uby - lby) * (refpointx - lbx)) )
6461  {
6462  if( SCIPisRelEQ(scip, lbx, ubx) )
6463  {
6464  /* x*y = ubx * y + (x-ubx) * y <= ubx * y + (x-ubx) * lby <= ubx * y + max{(lbx-ubx) * lby, 0 * lby} */
6465  coefx = 0.0;
6466  coefy = bilincoef * ubx;
6467  constant = bilincoef * (lby < 0.0 ? (lbx - ubx) * lby : 0.0);
6468  }
6469  else if( SCIPisRelEQ(scip, lby, uby) )
6470  {
6471  /* x*y = lby * x + (y-lby) * x <= lby * x + (y-lby) * ubx <= lby * x + max{(uby-lby) * ubx, 0 * ubx} */
6472  coefx = bilincoef * lby;
6473  coefy = 0.0;
6474  constant = bilincoef * (ubx > 0.0 ? (uby - lby) * ubx : 0.0);
6475  }
6476  else
6477  {
6478  coefx = bilincoef * lby;
6479  coefy = bilincoef * ubx;
6480  constant = -bilincoef * ubx * lby;
6481  }
6482  }
6483  else if( !SCIPisInfinity(scip, -lbx) && !SCIPisInfinity(scip, uby) )
6484  {
6485  if( SCIPisRelEQ(scip, lbx, ubx) )
6486  {
6487  /* x*y = lbx * y + (x-lbx) * y <= lbx * y + (x-lbx) * uby <= lbx * y + max{(ubx-lbx) * uby, 0 * uby} */
6488  coefx = 0.0;
6489  coefy = bilincoef * lbx;
6490  constant = bilincoef * (uby > 0.0 ? (ubx-lbx) * uby : 0.0);
6491  }
6492  else if( SCIPisRelEQ(scip, lby, uby) )
6493  {
6494  /* x*y = uby * x + (y-uby) * x <= uby * x + (y-uby) * lbx <= uby * x + max{(lby-uby) * lbx, 0 * lbx} */
6495  coefx = bilincoef * uby;
6496  coefy = 0.0;
6497  constant = bilincoef * (lbx < 0.0 ? (lby-uby) * lbx : 0.0);
6498  }
6499  else
6500  {
6501  coefx = bilincoef * uby;
6502  coefy = bilincoef * lbx;
6503  constant = -bilincoef * lbx * uby;
6504  }
6505  }
6506  else
6507  {
6508  *success = FALSE;
6509  return;
6510  }
6511  }
6512 
6513  if( SCIPisInfinity(scip, REALABS(coefx)) || SCIPisInfinity(scip, REALABS(coefy)) || SCIPisInfinity(scip, REALABS(constant)) )
6514  {
6515  *success = FALSE;
6516  return;
6517  }
6518 
6519  if( overestimate )
6520  {
6521  coefx = -coefx;
6522  coefy = -coefy;
6523  constant = -constant;
6524  }
6525 
6526  /* SCIPdebugMessage("%.20g * x[%.20g,%.20g] * y[%.20g,%.20g] %c= %.20g * x %+.20g * y %+.20g\n", bilincoef, lbx, ubx, lby, uby, overestimate ? '<' : '>', coefx, coefy, constant); */
6527 
6528  *lincoefx += coefx;
6529  *lincoefy += coefy;
6530  *linconstant += constant;
6531 }
6532 
6533 /** computes cut coefficients by linearizing a quadratic function */
6534 static
6536  SCIP* scip, /**< SCIP data structure */
6537  SCIP_CONS* cons, /**< constraint */
6538  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6539  SCIP_Real* ref, /**< reference solution where to generate the cut */
6540  SCIP_Real* coef, /**< array to store cut coefficients w.r.t. quadratic variables */
6541  SCIP_Real* lhs, /**< buffer to store left-hand-side of cut */
6542  SCIP_Real* rhs, /**< buffer to store right-hand-side of cut */
6543  SCIP_Bool* islocal, /**< buffer to set to TRUE if local bounds were used */
6544  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6545  char* name /**< buffer to store name for cut */
6546  )
6547 {
6548  SCIP_CONSDATA* consdata;
6549  SCIP_BILINTERM* bilinterm;
6550  SCIP_Real constant;
6551  SCIP_VAR* var;
6552  int var2pos;
6553  int j;
6554  int k;
6555 
6556  assert(scip != NULL);
6557  assert(cons != NULL);
6558  assert(ref != NULL);
6559  assert(coef != NULL);
6560  assert(lhs != NULL);
6561  assert(rhs != NULL);
6562  assert(islocal != NULL);
6563  assert(success != NULL);
6564 
6565  consdata = SCIPconsGetData(cons);
6566  assert(consdata != NULL);
6567 
6568  constant = 0.0;
6569  BMSclearMemoryArray(coef, consdata->nquadvars);
6570  *success = TRUE;
6571 
6572  /* do first-order Taylor for each term */
6573  for( j = 0; j < consdata->nquadvars && *success; ++j )
6574  {
6575  /* initialize coefficients to linear coefficients of quadratic variables */
6576  coef[j] += consdata->quadvarterms[j].lincoef;
6577 
6578  /* add linearization of square term */
6579  var = consdata->quadvarterms[j].var;
6580  addSquareLinearization(scip, consdata->quadvarterms[j].sqrcoef, ref[j], consdata->quadvarterms[j].nadjbilin == 0 && SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef[j], &constant, success);
6581 
6582  /* add linearization of bilinear terms that have var as first variable */
6583  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6584  {
6585  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6586  if( bilinterm->var1 != var )
6587  continue;
6588  assert(bilinterm->var2 != var);
6589  assert(consdata->sepabilinvar2pos != NULL);
6590 
6591  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6592  assert(var2pos >= 0);
6593  assert(var2pos < consdata->nquadvars);
6594  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6595 
6596  addBilinLinearization(scip, bilinterm->coef, ref[j], ref[var2pos], &coef[j], &coef[var2pos], &constant, success);
6597  }
6598  }
6599 
6600  if( !*success )
6601  {
6602  SCIPdebugMessage("no success in linearization of <%s> in reference point\n", SCIPconsGetName(cons));
6603  return SCIP_OKAY;
6604  }
6605 
6606  if( violside == SCIP_SIDETYPE_LEFT )
6607  {
6608  *lhs = consdata->lhs - constant;
6609  *rhs = SCIPinfinity(scip);
6610  }
6611  else
6612  {
6613  *lhs = -SCIPinfinity(scip);
6614  *rhs = consdata->rhs - constant;
6615  }
6616 
6617  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_side%d_linearization_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6618 
6619  return SCIP_OKAY;
6620 }
6621 
6622 /** computes cut coefficients for a nonconvex quadratic function */
6623 static
6625  SCIP* scip, /**< SCIP data structure */
6626  SCIP_CONS* cons, /**< constraint */
6627  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6628  SCIP_Real* ref, /**< reference solution where to generate the cut */
6629  SCIP_Real* coef, /**< array to store cut coefficients w.r.t. quadratic variables */
6630  SCIP_Real* lhs, /**< buffer to store left-hand-side of cut */
6631  SCIP_Real* rhs, /**< buffer to store right-hand-side of cut */
6632  SCIP_Bool* islocal, /**< buffer to set to TRUE if local bounds were used */
6633  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6634  char* name /**< buffer to store name for cut */
6635  )
6636 {
6637  SCIP_CONSDATA* consdata;
6638  SCIP_BILINTERM* bilinterm;
6639  SCIP_Real constant;
6640  SCIP_Real sqrcoef;
6641  SCIP_VAR* var;
6642  int var2pos;
6643  int j;
6644  int k;
6645 
6646  assert(scip != NULL);
6647  assert(cons != NULL);
6648  assert(ref != NULL);
6649  assert(coef != NULL);
6650  assert(lhs != NULL);
6651  assert(rhs != NULL);
6652  assert(islocal != NULL);
6653  assert(success != NULL);
6654 
6655  consdata = SCIPconsGetData(cons);
6656  assert(consdata != NULL);
6657 
6658  *islocal = TRUE;
6659  constant = 0.0;
6660  BMSclearMemoryArray(coef, consdata->nquadvars);
6661  *success = TRUE;
6662 
6663  /* underestimate (secant, McCormick) or linearize each term separately */
6664  for( j = 0; j < consdata->nquadvars && *success; ++j )
6665  {
6666  /* initialize coefficients to linear coefficients of quadratic variables */
6667  coef[j] += consdata->quadvarterms[j].lincoef;
6668 
6669  var = consdata->quadvarterms[j].var;
6670 
6671  sqrcoef = consdata->quadvarterms[j].sqrcoef;
6672  if( sqrcoef != 0.0 )
6673  {
6674  if( (violside == SCIP_SIDETYPE_LEFT && sqrcoef <= 0.0) || (violside == SCIP_SIDETYPE_RIGHT && sqrcoef > 0.0) )
6675  {
6676  /* convex -> linearize */
6677  addSquareLinearization(scip, sqrcoef, ref[j], SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef[j], &constant, success);
6678  }
6679  else
6680  {
6681  /* not convex -> secant approximation */
6682  addSquareSecant(scip, sqrcoef, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j], &coef[j], &constant, success);
6683  }
6684  }
6685 
6686  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6687  {
6688  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6689  if( bilinterm->var1 != var )
6690  continue;
6691  assert(bilinterm->var2 != var);
6692  assert(consdata->sepabilinvar2pos != NULL);
6693 
6694  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6695  assert(var2pos >= 0);
6696  assert(var2pos < consdata->nquadvars);
6697  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6698 
6699  addBilinMcCormick(scip, bilinterm->coef,
6700  SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j],
6701  SCIPvarGetLbLocal(bilinterm->var2), SCIPvarGetUbLocal(bilinterm->var2), ref[var2pos],
6702  violside == SCIP_SIDETYPE_LEFT, &coef[j], &coef[var2pos], &constant, success);
6703  }
6704  }
6705 
6706  if( !*success )
6707  {
6708  SCIPdebugMessage("no success to find estimator for nonconvex <%s>\n", SCIPconsGetName(cons));
6709  return SCIP_OKAY;
6710  }
6711 
6712  if( violside == SCIP_SIDETYPE_LEFT )
6713  {
6714  *lhs = consdata->lhs - constant;
6715  *rhs = SCIPinfinity(scip);
6716  }
6717  else
6718  {
6719  *lhs = -SCIPinfinity(scip);
6720  *rhs = consdata->rhs - constant;
6721  }
6722 
6723  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_side%d_estimation_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6724 
6725  return SCIP_OKAY;
6726 }
6727 
6728 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a given reference point */
6729 static
6731  SCIP* scip, /**< SCIP data structure */
6732  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6733  SCIP_CONS* cons, /**< constraint */
6734  SCIP_Real* ref, /**< reference solution where to generate the cut */
6735  SCIP_SOL* sol, /**< point that we aim to separate, or NULL for LP solution */
6736  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6737  SCIP_ROW** row, /**< storage for cut */
6738  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
6739  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
6740  SCIP_Real minefficacy /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
6741  )
6742 {
6743  SCIP_CONSHDLRDATA* conshdlrdata;
6744  SCIP_CONSDATA* consdata;
6745  SCIP_Bool islocal;
6746  char cutname[SCIP_MAXSTRLEN];
6747  SCIP_Real* lincoefs;
6748  SCIP_Real* coef;
6749  SCIP_Real lhs;
6750  SCIP_Real rhs;
6751  SCIP_Bool success;
6752  SCIP_Real mincoef;
6753  SCIP_Real maxcoef;
6754  SCIP_Real lincoefsmax;
6755  SCIP_Real lincoefsmin;
6756  SCIP_Real viol;
6757  SCIP_Real rowefficacy;
6758  SCIP_VAR* var;
6759  int j;
6760 
6761  assert(scip != NULL);
6762  assert(conshdlr != NULL);
6763  assert(cons != NULL);
6764  assert(ref != NULL);
6765  assert(row != NULL);
6766 
6767  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6768  assert(conshdlrdata != NULL);
6769 
6770  consdata = SCIPconsGetData(cons);
6771  assert(consdata != NULL);
6772  assert(violside != SCIP_SIDETYPE_LEFT || !SCIPisInfinity(scip, -consdata->lhs));
6773  assert(violside != SCIP_SIDETYPE_RIGHT || !SCIPisInfinity(scip, consdata->rhs));
6774 
6775  *row = NULL;
6776  SCIP_CALL( SCIPallocBufferArray(scip, &coef, consdata->nquadvars) );
6777  lincoefs = consdata->lincoefs;
6778  lincoefsmax = consdata->lincoefsmax;
6779  lincoefsmin = consdata->lincoefsmin;
6780  islocal = SCIPconsIsLocal(cons);
6781  success = FALSE;
6782  lhs = -SCIPinfinity(scip);
6783  rhs = SCIPinfinity(scip);
6784  cutname[0] = '\0';
6785 
6786  /* if constraint function is factorable, then try to use factorable form to generate cut */
6787  if( consdata->factorleft != NULL )
6788  {
6789  if( consdata->nlinvars == 0 )
6790  {
6791  SCIP_CALL( generateCutFactorable(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6792  }
6793  else if( sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
6794  {
6795  int i;
6796 
6797  /* generateCutLTI needs reference values also for the linear variables, which we only have if sol is given or LP has been solved */
6798  SCIP_CALL( generateCutLTI(scip, cons, violside, ref, sol, &lincoefs, coef, &lhs, &rhs, &islocal, &success, cutname) );
6799 
6800  /* in case of LTI cuts, we have to recompute the min and max of lincoefs, since they may have been modified */
6801  for( i = 0; i < consdata->nlinvars; ++i )
6802  {
6803  if( REALABS(lincoefs[i]) > lincoefsmax )
6804  lincoefsmax = REALABS(lincoefs[i]);
6805  if( REALABS(lincoefs[i]) < lincoefsmin )
6806  lincoefsmin = REALABS(lincoefs[i]);
6807  }
6808  }
6809  }
6810 
6811  /* if constraint is not factorable or failed to generate cut, try default method */
6812  if( !success )
6813  {
6814  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
6815 
6816  if( (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave) || (violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex) )
6817  {
6818  SCIP_CALL( generateCutConvex(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6819  }
6820  else
6821  {
6822  SCIP_CALL( generateCutNonConvex(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6823  }
6824  }
6825 
6826  /* cut should be one-sided, if any found */
6827  assert(!success || SCIPisInfinity(scip, -lhs) || SCIPisInfinity(scip, rhs));
6828 
6829  /* check if range of cut coefficients is ok
6830  * compute cut activity and violation in sol
6831  */
6832  mincoef = 0.0; /* only for lint */
6833  maxcoef = 0.0; /* only for compiler */
6834  viol = 0.0; /* only for compiler */
6835  if( success )
6836  {
6837  SCIP_Real constant;
6838  SCIP_Real abscoef;
6839  SCIP_Real roundcoef;
6840  int mincoefidx;
6841  SCIP_Real refactivity;
6842  SCIP_Real refactivitylinpart;
6843 
6844  /* compute activity of linear part in sol, if required
6845  * it is required if we need to check or return cut efficacy, for some debug output below, and some assert
6846  * round almost integral coefficients in integers, since this will happen when adding coefs to row (see comments below)
6847  */
6848  refactivitylinpart = 0.0;
6849 #if !defined(SCIP_DEBUG)
6850  if( !SCIPisInfinity(scip, -minefficacy) || efficacy != NULL )
6851 #endif
6852  for( j = 0; j < consdata->nlinvars; ++j )
6853  /* Loose variable have the best bound as LP solution value.
6854  * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
6855  * When this happens, their LP solution value changes to 0.0!
6856  * So when calculating the row activity, we treat loose variable as if they were already column variables.
6857  */
6858  if( SCIPvarGetStatus(consdata->linvars[j]) != SCIP_VARSTATUS_LOOSE )
6859  refactivitylinpart += (SCIPisIntegral(scip, lincoefs[j]) ? SCIPround(scip, lincoefs[j]) : lincoefs[j]) * SCIPgetSolVal(scip, sol, consdata->linvars[j]);
6860 
6861  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
6862 
6863  constant = 0.0;
6864  do
6865  {
6866  refactivity = refactivitylinpart;
6867  mincoefidx = -1;
6868  mincoef = lincoefsmin;
6869  maxcoef = lincoefsmax;
6870 
6871  for( j = 0; j < consdata->nquadvars; ++j )
6872  {
6873  /* coefficients smaller than epsilon are rounded to 0.0 when added to row
6874  * further, coefficients very close to integral values are rounded to integers when added to LP
6875  * both cases can be problematic if variable value is very large (bad numerics)
6876  * thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible)
6877  * i.e., estimate coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x)
6878  * if required bound of x is not finite, then do nothing
6879  */
6880  roundcoef = SCIPround(scip, coef[j]);
6881  if( SCIPisEQ(scip, coef[j], roundcoef) && coef[j] != roundcoef ) /*lint !e777*/
6882  {
6883  SCIP_Real xbnd;
6884 
6885  var = consdata->quadvarterms[j].var;
6886  if( !SCIPisInfinity(scip, rhs) )
6887  if( islocal )
6888  xbnd = coef[j] > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
6889  else
6890  xbnd = coef[j] > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
6891  else
6892  if( islocal )
6893  xbnd = coef[j] > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
6894  else
6895  xbnd = coef[j] > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
6896 
6897  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
6898  {
6899  SCIPdebugMessage("var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g and add constant %g\n",
6900  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef[j], roundcoef, (coef[j]-roundcoef) * xbnd);
6901  constant += (coef[j]-roundcoef) * xbnd;
6902  coef[j] = roundcoef;
6903  }
6904  }
6905 
6906  if( coef[j] == 0.0 )
6907  continue;
6908 
6909  /* As above: When calculating the row activity, we treat loose variable as if they were already column variables. */
6910  if( SCIPvarGetStatus(consdata->quadvarterms[j].var) != SCIP_VARSTATUS_LOOSE )
6911  refactivity += coef[j] * SCIPgetSolVal(scip, sol, consdata->quadvarterms[j].var);
6912 
6913  abscoef = REALABS(coef[j]);
6914  if( abscoef < mincoef )
6915  {
6916  mincoef = abscoef;
6917  mincoefidx = j;
6918  }
6919  if( abscoef > maxcoef )
6920  maxcoef = abscoef;
6921  }
6922 
6923  if( maxcoef < mincoef )
6924  {
6925  /* if all coefficients are zero, then mincoef and maxcoef are still at their initial values
6926  * thus, skip cut generation if its boring
6927  */
6928  assert(maxcoef == 0.0); /*lint !e777 */
6929  assert(mincoef == SCIPinfinity(scip)); /*lint !e777 */
6930 
6931  if( !SCIPisFeasPositive(scip, lhs) && !SCIPisFeasNegative(scip, rhs) )
6932  {
6933  SCIPdebugMessage("skip cut for constraint <%s> since all coefficients are zero and it's always satisfied\n", SCIPconsGetName(cons));
6934  success = FALSE;
6935  }
6936  else
6937  {
6938  /* cut will cutoff node */
6939  }
6940 
6941  break;
6942  }
6943 
6944  if( maxcoef / mincoef > conshdlrdata->cutmaxrange )
6945  {
6946  SCIPdebugMessage("cut coefficients for constraint <%s> have very large range: mincoef = %g maxcoef = %g\n", SCIPconsGetName(cons), mincoef, maxcoef);
6947  if( mincoefidx >= 0 )
6948  {
6949  var = consdata->quadvarterms[mincoefidx].var;
6950  /* try to eliminate coefficient with minimal absolute value by weakening cut and try again
6951  * since we use local bounds, we need to make the row local if they are different from their global counterpart
6952  */
6953  if( ((coef[mincoefidx] > 0.0 && !SCIPisInfinity(scip, rhs)) || (coef[mincoefidx] < 0.0 && !SCIPisInfinity(scip, -lhs))) &&
6954  !SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
6955  {
6956  SCIPdebugMessage("eliminate coefficient %g for <%s> [%g, %g]\n", coef[mincoefidx], SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6957  constant += coef[mincoefidx] * SCIPvarGetLbLocal(var);
6958  coef[mincoefidx] = 0.0;
6959  islocal |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
6960  continue;
6961  }
6962  else if( ((coef[mincoefidx] < 0.0 && !SCIPisInfinity(scip, rhs)) || (coef[mincoefidx] > 0.0 && !SCIPisInfinity(scip, -lhs))) &&
6963  !SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6964  {
6965  SCIPdebugMessage("eliminate coefficient %g for <%s> [%g, %g]\n", coef[mincoefidx], SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6966  constant += coef[mincoefidx] * SCIPvarGetUbLocal(var);
6967  coef[mincoefidx] = 0.0;
6968  islocal |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
6969  continue;
6970  }
6971  }
6972 
6973  SCIPdebugMessage("skip cut\n");
6974  success = FALSE;
6975  }
6976  break;
6977  }
6978  while( TRUE ); /*lint !e506 */
6979 
6980  if( !SCIPisInfinity(scip, -lhs) )
6981  {
6982  lhs -= constant;
6983  viol = lhs - refactivity;
6984  }
6985  if( !SCIPisInfinity(scip, rhs) )
6986  {
6987  rhs -= constant;
6988  viol = refactivity - rhs;
6989  }
6990  }
6991 
6992  if( success && SCIPisInfinity(scip, REALABS(lhs)) && SCIPisInfinity(scip, REALABS(rhs)) )
6993  {
6994  SCIPdebugMessage("skip cut for constraint <%s> because both sides are not finite: lhs = %g, rhs = %g\n", SCIPconsGetName(cons), lhs, rhs);
6995  success = FALSE;
6996  }
6997 
6998  /* check if reference point violates cut sufficiently */
6999  if( success )
7000  {
7001  rowefficacy = viol;
7002  switch( conshdlrdata->scaling )
7003  {
7004  case 'o' :
7005  break;
7006 
7007  case 'g' :
7008  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
7009  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too also we
7010  * use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium scaling) */
7011  rowefficacy /= MAX(1.0, maxcoef);
7012  break;
7013 
7014  case 's' :
7015  {
7016  SCIP_Real abslhs = REALABS(lhs);
7017 
7018  if( !SCIPisInfinity(scip, abslhs) )
7019  rowefficacy /= MAX(1.0, abslhs);
7020  else
7021  {
7022  SCIP_Real absrhs = REALABS(rhs);
7023 
7024  rowefficacy /= MAX(1.0, absrhs);
7025  }
7026 
7027  break;
7028  }
7029 
7030  default:
7031  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
7032  SCIPABORT();
7033  return SCIP_INVALIDDATA; /*lint !e527*/
7034  }
7035  }
7036 
7037  if( success && !SCIPisInfinity(scip, -minefficacy) && rowefficacy < minefficacy ) /*lint !e644*/
7038  {
7039  SCIPdebugMessage("skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), rowefficacy, minefficacy);
7040  success = FALSE;
7041  }
7042 
7043  /* generate row */
7044  if( success )
7045  {
7046  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, lhs, rhs, islocal && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
7047 
7048  /* add coefficients from linear part */
7049  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nlinvars, consdata->linvars, lincoefs) );
7050 
7051  /* add coefficients from quadratic part */
7052  assert(consdata->sepaquadvars != NULL || consdata->nquadvars == 0);
7053  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nquadvars, consdata->sepaquadvars, coef) );
7054 
7055  SCIPdebugMessage("found cut <%s>, lhs=%g, rhs=%g, mincoef=%g, maxcoef=%g, range=%g, nnz=%d, violation=%g, efficacy=%g\n",
7056  SCIProwGetName(*row), lhs, rhs,
7057  mincoef, maxcoef, maxcoef/mincoef,
7058  SCIProwGetNNonz(*row), viol, rowefficacy); /*lint !e414 */
7059 
7060  if( efficacy != NULL )
7061  {
7062  *efficacy = rowefficacy;
7063 
7064  /* check that our computed efficacy is > feastol, iff efficacy computed by row is > feastol
7065  * computing efficacy w.r.t. the LP solution makes only sense if the LP was solved to optimality (see bug 612)
7066  *
7067  * disabled these asserts as they can fail due to numerical reasons (cancelation when substracting big numbers),
7068  * as the order in which we add up the activity for the single terms can be different than the one that lp.c uses
7069  */
7070  /*
7071  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
7072  assert((conshdlrdata->scaling != 'g') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol)/MAX(1.0,SCIPgetRowMaxCoef(scip, *row)))));
7073  assert((conshdlrdata->scaling != 's') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol)/MAX(1.0,MIN(REALABS(lhs),REALABS(rhs))))));
7074  assert((conshdlrdata->scaling != 'o') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol))));
7075  */
7076  }
7077  }
7078 
7079  SCIPfreeBufferArray(scip, &coef);
7080 
7081  /* if coefficients for linear variables are different than those in constraint, then free array */
7082  if( lincoefs != consdata->lincoefs )
7083  {
7084  SCIPfreeBufferArray(scip, &lincoefs);
7085  }
7086 
7087  return SCIP_OKAY;
7088 }
7089 
7090 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a solution
7091  */
7092 static
7094  SCIP* scip, /**< SCIP data structure */
7095  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7096  SCIP_CONS* cons, /**< constraint */
7097  SCIP_SOL* sol, /**< solution where to generate cut, or NULL if LP solution should be used */
7098  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
7099  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7100  SCIP_ROW** row, /**< storage for cut */
7101  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
7102  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7103  SCIP_Real minefficacy /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
7104  )
7105 {
7106  SCIP_CONSDATA* consdata;
7107  SCIP_VAR* var;
7108  SCIP_Real lb;
7109  SCIP_Real ub;
7110  SCIP_Real* ref;
7111  int j;
7112 
7113  assert(scip != NULL);
7114  assert(conshdlr != NULL);
7115  assert(cons != NULL);
7116 
7117  consdata = SCIPconsGetData(cons);
7118  assert(consdata != NULL);
7119 
7120  if( refsol == NULL )
7121  refsol = sol;
7122 
7123  /* get reference point */
7124  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
7125  for( j = 0; j < consdata->nquadvars; ++j )
7126  {
7127  var = consdata->quadvarterms[j].var;
7128  lb = SCIPvarGetLbLocal(var);
7129  ub = SCIPvarGetUbLocal(var);
7130  /* do not like variables at infinity */
7131  assert(!SCIPisInfinity(scip, lb));
7132  assert(!SCIPisInfinity(scip, -ub));
7133 
7134  ref[j] = SCIPgetSolVal(scip, refsol, var);
7135  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
7136  }
7137 
7138  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
7139 
7140  SCIPfreeBufferArray(scip, &ref);
7141 
7142  return SCIP_OKAY;
7143 }
7144 
7145 /** tries to find a cut that intersects with an unbounded ray of the LP
7146  * for convex functions, we do this by linearizing in the feasible solution of the LPI
7147  * for nonconvex functions, we just call generateCutSol with the unbounded solution as reference point */
7148 static
7150  SCIP* scip, /**< SCIP data structure */
7151  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7152  SCIP_CONS* cons, /**< constraint */
7153  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7154  SCIP_ROW** row, /**< storage for cut */
7155  SCIP_Real* rowrayprod, /**< buffer to store product of ray with row coefficients, or NULL if not of interest */
7156  SCIP_Bool checkcurvmultivar /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7157  )
7158 {
7159  SCIP_CONSDATA* consdata;
7160  SCIP_BILINTERM* bilinterm;
7161  SCIP_VAR* var;
7162  SCIP_Real* ref;
7163  SCIP_Real matrixrayprod;
7164  SCIP_Real linrayprod;
7165  SCIP_Real quadrayprod;
7166  SCIP_Real rayval;
7167  int i;
7168  int j;
7169 
7170  assert(scip != NULL);
7171  assert(conshdlr != NULL);
7172  assert(cons != NULL);
7173  assert(row != NULL);
7175 
7176  consdata = SCIPconsGetData(cons);
7177  assert(consdata != NULL);
7178 
7179  *row = NULL;
7180 
7181  if( !SCIPhasPrimalRay(scip) )
7182  {
7183  SCIPdebugMessage("do not have primal ray, thus cannot resolve unboundedness\n");
7184  return SCIP_OKAY;
7185  }
7186 
7187  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
7188  if( (!consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
7189  (!consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
7190  {
7191  /* if not convex, just call generateCut and hope it's getting something useful */
7192  SCIP_CALL( generateCutSol(scip, conshdlr, cons, NULL, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
7193 
7194  /* compute product of cut coefficients with ray, if required */
7195  if( *row != NULL && rowrayprod != NULL )
7196  {
7197  *rowrayprod = 0.0;
7198  for( i = 0; i < SCIProwGetNNonz(*row); ++i )
7199  {
7200  assert(SCIProwGetCols(*row)[i] != NULL);
7201  var = SCIPcolGetVar(SCIProwGetCols(*row)[i]);
7202  assert(var != NULL);
7203 
7204  *rowrayprod += SCIProwGetVals(*row)[i] * SCIPgetPrimalRayVal(scip, var);
7205  }
7206  }
7207 
7208  return SCIP_OKAY;
7209  }
7210 
7211  /* we seek for a linearization of the quadratic function such that it intersects with the unbounded ray
7212  * that is, we need a reference point ref such that for the gradient g of xAx+bx in ref, we have
7213  * <g, ray> > 0.0 if rhs is finite and <g, ray> < 0.0 if lhs is finite
7214  * Since g = 2*A*ref + b, we have <g, ray> = <2*A*ref + b, ray> = <ref, 2*A*ray> + <b,ray>
7215  * 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)
7216  * <ref, 2*A*ray> + <b,ray> is sufficiently larger 0.0, we call generateCut for this point, otherwise, we scale up ref
7217  */
7218 
7219  quadrayprod = 0.0; /* <ref, 2*A*ray> */
7220  linrayprod = 0.0; /* <b, ray> */
7221  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
7222  for( i = 0; i < consdata->nquadvars; ++i )
7223  {
7224  var = consdata->quadvarterms[i].var;
7225  rayval = SCIPgetPrimalRayVal(scip, var);
7226 
7227  /* compute i-th entry of (2*A*ray) */
7228  matrixrayprod = 2.0 * consdata->quadvarterms[i].sqrcoef * rayval;
7229  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
7230  {
7231  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
7232  matrixrayprod += bilinterm->coef * SCIPgetPrimalRayVal(scip, bilinterm->var1 == var ? bilinterm->var2 : bilinterm->var1);
7233  }
7234 
7235  if( SCIPisPositive(scip, matrixrayprod) )
7236  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? 1.0 : -1.0);
7237  else if( SCIPisNegative(scip, matrixrayprod) )
7238  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? -1.0 : 1.0);
7239  else
7240  ref[i] = 0.0;
7241 
7242  quadrayprod += matrixrayprod * ref[i];
7243  linrayprod += consdata->quadvarterms[i].lincoef * rayval;
7244  }
7245  assert((violside == SCIP_SIDETYPE_RIGHT && quadrayprod >= 0.0) || (violside == SCIP_SIDETYPE_LEFT && quadrayprod <= 0.0));
7246 
7247  if( SCIPisZero(scip, quadrayprod) )
7248  {
7249  SCIPdebugMessage("ray is zero along cons <%s>\n", SCIPconsGetName(cons));
7250  SCIPfreeBufferArray(scip, &ref);
7251  return SCIP_OKAY;
7252  }
7253 
7254  /* add linear part to linrayprod */
7255  for( i = 0; i < consdata->nlinvars; ++i )
7256  linrayprod += consdata->lincoefs[i] * SCIPgetPrimalRayVal(scip, consdata->linvars[i]);
7257 
7258  SCIPdebugMessage("initially have <b,ray> = %g and <ref, 2*A*ref> = %g\n", linrayprod, quadrayprod);
7259 
7260  /* 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
7261  * if <b,ray> is zero, then we scale refpoint up if |<ref, 2*A*ray>| < 1.0
7262  */
7263  if( (!SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_RIGHT && quadrayprod < -2*linrayprod) ||
7264  ( !SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_LEFT && quadrayprod > -2*linrayprod) ||
7265  (SCIPisZero(scip, linrayprod) && REALABS(quadrayprod) < 1.0) )
7266  {
7267  SCIP_Real scale;
7268 
7269  if( !SCIPisZero(scip, linrayprod) )
7270  scale = 2*REALABS(linrayprod/quadrayprod); /*lint !e795 */
7271  else
7272  scale = 1.0/REALABS(quadrayprod);
7273 
7274  SCIPdebugMessage("scale refpoint by %g\n", scale);
7275  for( i = 0; i < consdata->nquadvars; ++i )
7276  ref[i] *= scale;
7277  quadrayprod *= scale;
7278  }
7279 
7280  if( rowrayprod != NULL )
7281  *rowrayprod = quadrayprod + linrayprod;
7282 
7283  SCIPdebugMessage("calling generateCut, expecting ray product %g\n", quadrayprod + linrayprod);
7284  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
7285 
7286  SCIPfreeBufferArray(scip, &ref);
7287 
7288  return SCIP_OKAY;
7289 }
7290 
7291 /** tries to separate solution or LP solution by a linear cut
7292  *
7293  * assumes that constraint violations have been computed
7294  */
7295 static
7297  SCIP* scip, /**< SCIP data structure */
7298  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
7299  SCIP_CONS** conss, /**< constraints */
7300  int nconss, /**< number of constraints */
7301  int nusefulconss, /**< number of constraints that seem to be useful */
7302  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7303  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
7304  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
7305  SCIP_RESULT* result, /**< result of separation */
7306  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 */
7307  )
7308 {
7309  SCIP_CONSHDLRDATA* conshdlrdata;
7310  SCIP_CONSDATA* consdata;
7311  SCIP_Real efficacy;
7312  SCIP_Real actminefficacy;
7313  SCIP_SIDETYPE violside;
7314  int c;
7315  SCIP_ROW* row;
7316 
7317  assert(scip != NULL);
7318  assert(conshdlr != NULL);
7319  assert(conss != NULL || nconss == 0);
7320  assert(nusefulconss <= nconss);
7321  assert(result != NULL);
7322 
7323  *result = SCIP_FEASIBLE;
7324 
7325  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7326  assert(conshdlrdata != NULL);
7327 
7328  if( bestefficacy != NULL )
7329  *bestefficacy = 0.0;
7330 
7331  for( c = 0; c < nconss; ++c )
7332  {
7333  assert(conss != NULL);
7334  consdata = SCIPconsGetData(conss[c]);
7335  assert(consdata != NULL);
7336 
7337  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7338  {
7339  /* we are not feasible anymore */
7340  if( *result == SCIP_FEASIBLE )
7341  *result = SCIP_DIDNOTFIND;
7342 
7343  violside = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT;
7344 
7345  /* actual minimal efficacy */
7346  actminefficacy = inenforcement && ((violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex ) || (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave))
7347  ? (SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip))
7348  : minefficacy;
7349 
7350  /* generate cut */
7351  if( sol == NULL && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
7352  {
7353  /* if the LP is unbounded, then we need a cut that cuts into the direction of a hopefully existing primal ray
7354  * 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
7355  * given a cut lhs <= <c,x> <= rhs, we check whether it imposes an upper bound on t and thus bounds the ray
7356  * 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>
7357  * similar, lhs > -infinity and <c,r> < 0 is good
7358  */
7359  SCIP_Real rayprod;
7360  SCIP_Real norm;
7361 
7362  rayprod = 0.0; /* for compiler */
7363  SCIP_CALL( generateCutUnboundedLP(scip, conshdlr, conss[c], violside, &row, &rayprod, conshdlrdata->checkcurvature) );
7364 
7365  if( row != NULL )
7366  {
7367  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) && SCIPisPositive(scip, rayprod) )
7368  efficacy = rayprod;
7369  else if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) && SCIPisNegative(scip, rayprod) )
7370  efficacy = -rayprod;
7371  else
7372  efficacy = 0.0;
7373 
7374  switch( conshdlrdata->scaling )
7375  {
7376  case 'o' :
7377  break;
7378 
7379  case 'g' :
7380  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding
7381  * cuts efficient which are only very slightly violated CPLEX does not seem to scale row
7382  * coefficients up too also we use infinity norm, since that seem to be the usual scaling strategy
7383  * in LP solvers (equilibrium scaling) */
7384  norm = SCIPgetRowMaxCoef(scip, row);
7385  efficacy /= MAX(1.0, norm);
7386  break;
7387 
7388  case 's' :
7389  {
7390  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
7391  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
7392  SCIP_Real minval = MIN(abslhs, absrhs);
7393 
7394  efficacy /= MAX(1.0, minval);
7395  break;
7396  }
7397 
7398  default:
7399  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
7400  SCIPABORT();
7401  return SCIP_INVALIDDATA; /*lint !e527*/
7402  }
7403  }
7404  }
7405  else
7406  {
7407  /* @todo If convex, can we easily move the refpoint closer to the feasible region to get a stronger cut?
7408  * E.g., use bisection on the line between LP solution and best primal (or LP interior)
7409  */
7410  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], sol, NULL, violside, &row, &efficacy, conshdlrdata->checkcurvature, actminefficacy) );
7411  /* @todo If generation failed not because of low efficacy, then probably because of numerical issues;
7412  * if the constraint is convex and we are desperate to get a cut, then we may try again with a better chosen reference point
7413  */
7414  }
7415 
7416  if( row == NULL ) /* failed to generate cut */
7417  continue;
7418 
7419  if( SCIPisGT(scip, efficacy, actminefficacy) && SCIPisCutApplicable(scip, row) ) /*lint !e644 */
7420  {
7421  SCIP_Bool infeasible;
7422 
7423  /* cut cuts off solution */
7424  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE /* forcecut */, &infeasible) );
7425  if( infeasible )
7426  {
7427  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(conss[c]));
7428  *result = SCIP_CUTOFF;
7429  }
7430  else
7431  {
7432  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy,
7433  SCIPconsGetName(conss[c]), consdata->lhsviol+consdata->rhsviol);
7434  *result = SCIP_SEPARATED;
7435  }
7436  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
7437 
7438  /* mark row as not removable from LP for current node, if in enforcement */
7439  if( inenforcement && !conshdlrdata->enfocutsremovable )
7440  SCIPmarkRowNotRemovableLocal(scip, row);
7441  }
7442  if( bestefficacy != NULL && efficacy > *bestefficacy )
7443  *bestefficacy = efficacy;
7444 
7445  SCIP_CALL( SCIPreleaseRow (scip, &row) );
7446  }
7447 
7448  if( *result == SCIP_CUTOFF )
7449  break;
7450 
7451  /* enforce only useful constraints
7452  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
7453  */
7454  if( c >= nusefulconss && *result == SCIP_SEPARATED )
7455  break;
7456  }
7457 
7458  return SCIP_OKAY;
7459 }
7460 
7461 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
7462  * 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
7463  * if separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only
7464  * if separatedlpsol is NULL, then cut is added to cutpool only
7465  */
7466 static
7468  SCIP* scip, /**< SCIP data structure */
7469  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
7470  SCIP_CONS** conss, /**< constraints */
7471  int nconss, /**< number of constraints */
7472  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
7473  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 */
7474  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
7475  )
7476 {
7477  SCIP_CONSHDLRDATA* conshdlrdata;
7478  SCIP_CONSDATA* consdata;
7479  SCIP_Bool addedtolp;
7480  SCIP_ROW* row;
7481  int c;
7482 
7483  assert(scip != NULL);
7484  assert(conshdlr != NULL);
7485  assert(conss != NULL || nconss == 0);
7486 
7487  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7488  assert(conshdlrdata != NULL);
7489 
7490  if( separatedlpsol != NULL )
7491  *separatedlpsol = FALSE;
7492 
7493  for( c = 0; c < nconss; ++c )
7494  {
7495  assert(conss[c] != NULL); /*lint !e613 */
7496 
7497  if( SCIPconsIsLocal(conss[c]) ) /*lint !e613 */
7498  continue;
7499 
7500  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
7501 
7502  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
7503  assert(consdata != NULL);
7504 
7505  if( consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
7506  {
7507  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_RIGHT, &row, NULL, conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
7508  }
7509  else if( consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
7510  {
7511  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_LEFT, &row, NULL, conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
7512  }
7513  else
7514  continue;
7515 
7516  if( row == NULL )
7517  continue;
7518 
7519  addedtolp = FALSE;
7520 
7521  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
7522  if( separatedlpsol != NULL )
7523  {
7524  SCIP_Real efficacy;
7525  SCIP_Real norm;
7526 
7527  efficacy = -SCIPgetRowLPFeasibility(scip, row);
7528  switch( conshdlrdata->scaling )
7529  {
7530  case 'o' :
7531  break;
7532 
7533  case 'g' :
7534  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
7535  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too
7536  * also we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
7537  * scaling) */
7538  norm = SCIPgetRowMaxCoef(scip, row);
7539  efficacy /= MAX(1.0, norm);
7540  break;
7541 
7542  case 's' :
7543  {
7544  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
7545  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
7546  SCIP_Real minval = MIN(abslhs, absrhs);
7547 
7548  efficacy /= MAX(1.0, minval);
7549  break;
7550  }
7551 
7552  default:
7553  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
7554  SCIPABORT();
7555  return SCIP_INVALIDDATA; /*lint !e527*/
7556  }
7557 
7558  if( efficacy >= minefficacy )
7559  {
7560  SCIP_Bool infeasible;
7561 
7562  *separatedlpsol = TRUE;
7563  addedtolp = TRUE;
7564  SCIP_CALL( SCIPaddCut(scip, NULL, row, TRUE, &infeasible) );
7565  assert( ! infeasible );
7566  SCIPdebugMessage("added linearization cut <%s> to LP, efficacy = %g\n", SCIProwGetName(row), efficacy);
7567  }
7568  }
7569 
7570  if( !SCIProwIsLocal(row) && !addedtolp )
7571  {
7572  SCIP_CALL( SCIPaddPoolCut(scip, row) );
7573  SCIPdebugMessage("added linearization cut <%s> to cutpool\n", SCIProwGetName(row));
7574  }
7575 
7576  SCIP_CALL( SCIPreleaseRow(scip, &row) );
7577  }
7578 
7579  return SCIP_OKAY;
7580 }
7581 
7582 /** processes the event that a new primal solution has been found */
7583 static
7584 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
7586  SCIP_CONSHDLRDATA* conshdlrdata;
7587  SCIP_CONSHDLR* conshdlr;
7588  SCIP_CONS** conss;
7589  int nconss;
7590  SCIP_SOL* sol;
7591 
7592  assert(scip != NULL);
7593  assert(event != NULL);
7594  assert(eventdata != NULL);
7595  assert(eventhdlr != NULL);
7596 
7597  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
7598 
7599  conshdlr = (SCIP_CONSHDLR*)eventdata;
7600 
7601  nconss = SCIPconshdlrGetNConss(conshdlr);
7602 
7603  if( nconss == 0 )
7604  return SCIP_OKAY;
7605 
7606  sol = SCIPeventGetSol(event);
7607  assert(sol != NULL);
7608 
7609  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7610  assert(conshdlrdata != NULL);
7611 
7612  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
7613  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
7614  * or are from the tree, but postprocessed via proposeFeasibleSolution
7615  */
7616  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
7617  return SCIP_OKAY;
7618 
7619  conss = SCIPconshdlrGetConss(conshdlr);
7620  assert(conss != NULL);
7621 
7622  SCIPdebugMessage("caught new sol event %x from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
7623 
7624  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
7625 
7626  return SCIP_OKAY;
7627 }
7628 
7629 /** computes the infeasibilities of variables from the convexification gaps in the constraints and notifies the branching rule about them
7630  */
7631 static
7633  SCIP* scip, /**< SCIP data structure */
7634  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7635  SCIP_CONS** conss, /**< constraints to check */
7636  int nconss, /**< number of constraints to check */
7637  int* nnotify /**< counter for number of notifications performed */
7638  )
7639 {
7640  SCIP_CONSDATA* consdata;
7641  int c;
7642  int j;
7643  SCIP_Bool xbinary;
7644  SCIP_Bool ybinary;
7645  SCIP_Bool xunbounded;
7646  SCIP_Bool yunbounded;
7647  SCIP_VAR* x;
7648  SCIP_VAR* y;
7649  SCIP_Real xlb;
7650  SCIP_Real xub;
7651  SCIP_Real xval;
7652  SCIP_Real ylb;
7653  SCIP_Real yub;
7654  SCIP_Real yval;
7655  SCIP_Real gap;
7656  SCIP_Real coef_;
7657 
7658  assert(scip != NULL);
7659  assert(conshdlr != NULL);
7660  assert(conss != NULL || nconss == 0);
7661 
7662  *nnotify = 0;
7663  yval = SCIP_INVALID;
7664  xval = SCIP_INVALID;
7665 
7666  for( c = 0; c < nconss; ++c )
7667  {
7668  assert(conss != NULL);
7669  consdata = SCIPconsGetData(conss[c]);
7670  assert(consdata != NULL);
7671 
7672  if( !consdata->nquadvars )
7673  continue;
7674 
7675  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
7676  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
7677  continue;
7678  SCIPdebugMessage("cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
7679 
7680  /* square terms */
7681  for( j = 0; j < consdata->nquadvars; ++j )
7682  {
7683  x = consdata->quadvarterms[j].var;
7684  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef < 0) ||
7685  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef > 0) )
7686  {
7687  xlb = SCIPvarGetLbLocal(x);
7688  xub = SCIPvarGetUbLocal(x);
7689  if( SCIPisRelEQ(scip, xlb, xub) )
7690  {
7691  SCIPdebugMessage("ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
7692  continue;
7693  }
7694 
7695  xval = SCIPgetSolVal(scip, NULL, x);
7696 
7697  /* if variable is at bounds, then no need to branch, since secant is exact there */
7698  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
7699  continue;
7700 
7701  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
7702  gap = SCIPinfinity(scip);
7703  else
7704  gap = (xval-xlb)*(xub-xval)/(1+2*ABS(xval));
7705  assert(!SCIPisFeasNegative(scip, gap));
7706  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(gap, 0.0), SCIP_INVALID) );
7707  ++*nnotify;
7708  }
7709  }
7710 
7711  /* bilinear terms */
7712  for( j = 0; j < consdata->nbilinterms; ++j )
7713  {
7714  /* if any of the variables if fixed, then it actually behaves like a linear term, so we don't need to branch on it */
7715  x = consdata->bilinterms[j].var1;
7716  xlb = SCIPvarGetLbLocal(x);
7717  xub = SCIPvarGetUbLocal(x);
7718  if( SCIPisRelEQ(scip, xlb, xub) )
7719  continue;
7720 
7721  y = consdata->bilinterms[j].var2;
7722  ylb = SCIPvarGetLbLocal(y);
7723  yub = SCIPvarGetUbLocal(y);
7724  if( SCIPisRelEQ(scip, ylb, yub) )
7725  continue;
7726 
7727  xunbounded = SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub);
7728  yunbounded = SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub);
7729 
7730  /* compute gap, if both variable are bounded */
7731  gap = SCIPinfinity(scip);
7732  if( !xunbounded && !yunbounded )
7733  {
7734  xval = SCIPgetSolVal(scip, NULL, x);
7735  yval = SCIPgetSolVal(scip, NULL, y);
7736 
7737  /* if both variables are at one of its bounds, then no need to branch, since McCormick is exact there */
7738  if( (SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub)) &&
7739  ( SCIPisLE(scip, yval, ylb) || SCIPisGE(scip, yval, yub)) )
7740  continue;
7741 
7742  xval = MAX(xlb, MIN(xval, xub));
7743  yval = MAX(ylb, MIN(yval, yub));
7744 
7745  coef_ = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? -consdata->bilinterms[j].coef : consdata->bilinterms[j].coef;
7746  if( coef_ > 0.0 )
7747  {
7748  if( (xub-xlb)*yval + (yub-ylb)*xval <= xub*yub - xlb*ylb )
7749  gap = (xval*yval - xlb*yval - ylb*xval + xlb*ylb) / (1+sqrt(xval*xval + yval*yval));
7750  else
7751  gap = (xval*yval - xval*yub - yval*xub + xub*yub) / (1+sqrt(xval*xval + yval*yval));
7752  }
7753  else
7754  { /* coef_ < 0 */
7755  if( (xub-xlb)*yval - (yub-ylb)*xval <= xub*ylb - xlb*yub )
7756  gap = -(xval*yval - xval*ylb - yval*xub + xub*ylb) / (1+sqrt(xval*xval + yval*yval));
7757  else
7758  gap = -(xval*yval - xval*yub - yval*xlb + xlb*yub) / (1+sqrt(xval*xval + yval*yval));
7759  }
7760 
7761  assert(!SCIPisNegative(scip, gap / MAX3(MAX(REALABS(xlb), REALABS(xub)), MAX(REALABS(ylb), REALABS(yub)), 1.0))); /*lint !e666*/
7762  if( gap < 0.0 )
7763  gap = 0.0;
7764  }
7765 
7766  /* if one of the variables is binary or integral with domain width 1, then branching on this makes the term linear, so prefer this */
7767  xbinary = SCIPvarIsBinary(x) || (SCIPvarIsIntegral(x) && xub - xlb < 1.5);
7768  ybinary = SCIPvarIsBinary(y) || (SCIPvarIsIntegral(y) && yub - ylb < 1.5);
7769  if( xbinary )
7770  {
7772  ++*nnotify;
7773  }
7774  if( ybinary )
7775  {
7777  ++*nnotify;
7778  }
7779  if( xbinary || ybinary )
7780  continue;
7781 
7782  /* if one of the variables is unbounded, then branch on it first */
7783  if( xunbounded )
7784  {
7786  ++*nnotify;
7787  }
7788  if( yunbounded )
7789  {
7791  ++*nnotify;
7792  }
7793  if( xunbounded || yunbounded )
7794  continue;
7795 
7796  /* if both variables are integral, prefer the one with the smaller domain, so variable gets fixed soon
7797  * does not seem to work well on tln instances, so disable for now and may look at it later again
7798  */
7799 #ifdef BRANCHTOLINEARITY
7800  if( SCIPvarIsIntegral(x) && SCIPvarIsIntegral(y) )
7801  {
7802  if( SCIPisLT(scip, xub-xlb, yub-ylb) )
7803  {
7805  ++*nnotify;
7806  continue;
7807  }
7808  if( SCIPisGT(scip, xub-xlb, yub-ylb) )
7809  {
7811  ++*nnotify;
7812  continue;
7813  }
7814  }
7815 #endif
7816 
7817  /* in the regular case, suggest those variables which are not at its bounds for branching
7818  * this is, because after branching both variables will be one the bounds, and McCormick will be exact then */
7819  if( !SCIPisLE(scip, xval, xlb) && !SCIPisGE(scip, xval, xub) )
7820  {
7822  ++*nnotify;
7823  }
7824  if( !SCIPisLE(scip, yval, ylb) && !SCIPisGE(scip, yval, yub) )
7825  {
7827  ++*nnotify;
7828  }
7829  }
7830  }
7831 
7832  SCIPdebugMessage("registered %d branching candidates\n", *nnotify);
7833 
7834  return SCIP_OKAY;
7835 }
7836 
7837 /** registers a quadratic variable from a violated constraint as branching candidate that has a large absolute value in the LP relaxation */
7838 static
7840  SCIP* scip, /**< SCIP data structure */
7841  SCIP_CONS** conss, /**< constraints */
7842  int nconss, /**< number of constraints */
7843  SCIP_VAR** brvar /**< buffer to store branching variable */
7844  )
7845 {
7846  SCIP_CONSDATA* consdata;
7847  SCIP_Real val;
7848  SCIP_Real brvarval;
7849  int i;
7850  int c;
7851 
7852  assert(scip != NULL);
7853  assert(conss != NULL || nconss == 0);
7854 
7855  *brvar = NULL;
7856  brvarval = -1.0;
7857 
7858  for( c = 0; c < nconss; ++c )
7859  {
7860  assert(conss != NULL);
7861  consdata = SCIPconsGetData(conss[c]);
7862  assert(consdata != NULL);
7863 
7864  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7865  continue;
7866 
7867  for( i = 0; i < consdata->nquadvars; ++i )
7868  {
7869  /* do not propose fixed variables */
7870  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7871  continue;
7872  val = SCIPgetSolVal(scip, NULL, consdata->quadvarterms[i].var);
7873  if( ABS(val) > brvarval )
7874  {
7875  brvarval = ABS(val);
7876  *brvar = consdata->quadvarterms[i].var;
7877  }
7878  }
7879  }
7880 
7881  if( *brvar != NULL )
7882  {
7883  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
7884  }
7885 
7886  return SCIP_OKAY;
7887 }
7888 
7889 /** replaces violated quadratic constraints where all quadratic variables are fixed by linear constraints */
7890 static
7892  SCIP* scip, /**< SCIP data structure */
7893  SCIP_CONS** conss, /**< constraints */
7894  int nconss, /**< number of constraints */
7895  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
7896  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
7897  SCIP_Bool* infeasible /**< whether we detected infeasibility */
7898  )
7899 {
7900  SCIP_CONS* cons;
7901  SCIP_CONSDATA* consdata;
7902  SCIP_RESULT checkresult;
7903  SCIP_Real constant;
7904  SCIP_Real val1;
7905  SCIP_Real val2;
7906  int i;
7907  int c;
7908 
7909  assert(scip != NULL);
7910  assert(conss != NULL || nconss == 0);
7911  assert(addedcons != NULL);
7912  assert(reduceddom != NULL);
7913  assert(infeasible != NULL);
7914 
7915  *addedcons = FALSE;
7916  *reduceddom = FALSE;
7917  *infeasible = FALSE;
7918 
7919  for( c = 0; c < nconss; ++c )
7920  {
7921  assert(conss != NULL);
7922  consdata = SCIPconsGetData(conss[c]);
7923  assert(consdata != NULL);
7924 
7925  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7926  continue;
7927 
7928  constant = 0.0;
7929 
7930  for( i = 0; i < consdata->nquadvars; ++i )
7931  {
7932  /* variables should be fixed if constraint is violated */
7933  assert(SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
7934 
7935  val1 = (SCIPvarGetUbLocal(consdata->quadvarterms[i].var) + SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) / 2.0;
7936  constant += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val1) * val1;
7937  }
7938 
7939  for( i = 0; i < consdata->nbilinterms; ++i )
7940  {
7941  val1 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var1) + SCIPvarGetLbLocal(consdata->bilinterms[i].var1)) / 2.0;
7942  val2 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var2) + SCIPvarGetLbLocal(consdata->bilinterms[i].var2)) / 2.0;
7943  constant += consdata->bilinterms[i].coef * val1 * val2;
7944  }
7945 
7946  /* check if we have a bound change */
7947  if ( consdata->nlinvars == 1 )
7948  {
7949  SCIP_Bool tightened;
7950  SCIP_Real coef;
7951  SCIP_Real lhs;
7952  SCIP_Real rhs;
7953 
7954  coef = *consdata->lincoefs;
7955 
7956  /* compute lhs/rhs */
7957  if ( SCIPisInfinity(scip, -consdata->lhs) )
7958  lhs = -SCIPinfinity(scip);
7959  else
7960  lhs = consdata->lhs - constant;
7961 
7962  if ( SCIPisInfinity(scip, consdata->rhs) )
7963  rhs = SCIPinfinity(scip);
7964  else
7965  rhs = consdata->rhs - constant;
7966 
7967  SCIPdebugMessage("Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(*consdata->linvars), rhs);
7968 
7969  /* possibly correct lhs/rhs */
7970  assert( ! SCIPisZero(scip, coef) );
7971  if ( coef >= 0.0 )
7972  {
7973  if ( ! SCIPisInfinity(scip, -lhs) )
7974  lhs /= coef;
7975  if ( ! SCIPisInfinity(scip, rhs) )
7976  rhs /= coef;
7977  }
7978  else
7979  {
7980  SCIP_Real h;
7981  h = rhs;
7982  if ( ! SCIPisInfinity(scip, -lhs) )
7983  rhs = lhs/coef;
7984  else
7985  rhs = SCIPinfinity(scip);
7986 
7987  if ( ! SCIPisInfinity(scip, h) )
7988  lhs = h/coef;
7989  else
7990  lhs = -SCIPinfinity(scip);
7991  }
7992  SCIPdebugMessage("Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(*consdata->linvars), rhs);
7993 
7994  if ( ! SCIPisInfinity(scip, -lhs) )
7995  {
7996  SCIP_CALL( SCIPtightenVarLb(scip, *consdata->linvars, lhs, TRUE, infeasible, &tightened) );
7997  if ( *infeasible )
7998  {
7999  SCIPdebugMessage("Lower bound leads to infeasibility.\n");
8000  return SCIP_OKAY;
8001  }
8002  if ( tightened )
8003  {
8004  SCIPdebugMessage("Lower boundx changed.\n");
8005  *reduceddom = TRUE;
8006  return SCIP_OKAY;
8007  }
8008  }
8009 
8010  if ( ! SCIPisInfinity(scip, rhs) )
8011  {
8012  SCIP_CALL( SCIPtightenVarUb(scip, *consdata->linvars, rhs, TRUE, infeasible, &tightened) );
8013  if ( *infeasible )
8014  {
8015  SCIPdebugMessage("Upper bound leads to infeasibility.\n");
8016  return SCIP_OKAY;
8017  }
8018  if ( tightened )
8019  {
8020  SCIPdebugMessage("Upper bound changed.\n");
8021  *reduceddom = TRUE;
8022  return SCIP_OKAY;
8023  }
8024  }
8025  }
8026  else
8027  {
8028  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
8029  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
8030  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : (consdata->lhs - constant)),
8031  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : (consdata->rhs - constant)),
8032  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
8033  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
8034  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
8035  SCIPconsIsStickingAtNode(conss[c])) );
8036 
8037  SCIPdebugMessage("replace quadratic constraint <%s> by linear constraint after all quadratic vars have been fixed\n", SCIPconsGetName(conss[c]) );
8038  SCIPdebugPrintCons(scip, cons, NULL);
8039 
8040  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
8041 
8042  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
8043  {
8044  SCIPdebugMessage("linear constraint is feasible and LP optimal, thus do not add\n");
8045  }
8046  else
8047  {
8048  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
8049  *addedcons = TRUE;
8050  }
8051  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
8052  }
8053  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
8054  }
8055 
8056  return SCIP_OKAY;
8057 }
8058 
8059 /* tightens a lower bound on a variable and checks the result */
8060 static
8062  SCIP* scip, /**< SCIP data structure */
8063  SCIP_CONS* cons, /**< constraint where we currently propagate */
8064  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8065  SCIP_VAR* var, /**< variable which domain we might reduce */
8066  SCIP_Real bnd, /**< new lower bound for variable */
8067  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
8068  int* nchgbds /**< counter to increase if a bound was tightened */
8069  )
8070 {
8071  SCIP_Bool infeas;
8072  SCIP_Bool tightened;
8073 
8074  assert(scip != NULL);
8075  assert(cons != NULL);
8076  assert(intervalinfty > 0.0);
8077  assert(bnd > -intervalinfty);
8078  assert(var != NULL);
8079  assert(result != NULL);
8080  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
8081  assert(nchgbds != NULL);
8082 
8083  /* new bound is no improvement */
8084  if( SCIPisHugeValue(scip, -bnd) || SCIPisLE(scip, bnd, SCIPvarGetLbLocal(var)) )
8085  return SCIP_OKAY;
8086 
8087  if( SCIPisInfinity(scip, bnd) )
8088  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
8089  *result = SCIP_CUTOFF;
8090  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8091  return SCIP_OKAY;
8092  }
8093 
8094  /* new lower bound is very low (between -intervalinfty and -SCIPinfinity()) */
8095  if( SCIPisInfinity(scip, -bnd) )
8096  return SCIP_OKAY;
8097 
8098  bnd = SCIPadjustedVarLb(scip, var, bnd);
8099  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
8100  if( infeas )
8101  {
8102  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));
8103  *result = SCIP_CUTOFF;
8104  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8105  return SCIP_OKAY;
8106  }
8107  if( tightened )
8108  {
8109  SCIPdebugMessage("%s tightened lower bound of variable <%s> in constraint <%s> to %g\n", SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
8110  ++*nchgbds;
8111  *result = SCIP_REDUCEDDOM;
8112  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8113  }
8114 
8115  return SCIP_OKAY;
8116 }
8117 
8118 /* tightens an upper bound on a variable and checks the result */
8119 static
8121  SCIP* scip, /**< SCIP data structure */
8122  SCIP_CONS* cons, /**< constraint where we currently propagate */
8123  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8124  SCIP_VAR* var, /**< variable which domain we might reduce */
8125  SCIP_Real bnd, /**< new upper bound for variable */
8126  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
8127  int* nchgbds /**< counter to increase if a bound was tightened */
8128  )
8129 {
8130  SCIP_Bool infeas;
8131  SCIP_Bool tightened;
8132 
8133  assert(scip != NULL);
8134  assert(cons != NULL);
8135  assert(intervalinfty > 0.0);
8136  assert(bnd < intervalinfty);
8137  assert(var != NULL);
8138  assert(result != NULL);
8139  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
8140  assert(nchgbds != NULL);
8141 
8142  /* new bound is no improvement */
8143  if( SCIPisHugeValue(scip, bnd) || SCIPisGE(scip, bnd, SCIPvarGetUbLocal(var)) )
8144  return SCIP_OKAY;
8145 
8146  if( SCIPisInfinity(scip, -bnd) )
8147  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
8148  *result = SCIP_CUTOFF;
8149  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8150  return SCIP_OKAY;
8151  }
8152 
8153  /* new upper bound is very high (between SCIPinfinity() and intervalinfty) */
8154  if( SCIPisInfinity(scip, bnd) )
8155  return SCIP_OKAY;
8156 
8157  bnd = SCIPadjustedVarUb(scip, var, bnd);
8158  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
8159  if( infeas )
8160  {
8161  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));
8162  *result = SCIP_CUTOFF;
8163  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8164  return SCIP_OKAY;
8165  }
8166  if( tightened )
8167  {
8168  SCIPdebugMessage("%s tightened upper bound of variable <%s> in constraint <%s> to %g\n", SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
8169  ++*nchgbds;
8170  *result = SCIP_REDUCEDDOM;
8171  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8172  }
8173 
8174  return SCIP_OKAY;
8175 }
8176 
8177 /** 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
8178  */
8179 static
8181  SCIP* scip, /**< SCIP data structure */
8182  SCIP_CONS* cons, /**< constraint where we currently propagate */
8183  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8184  SCIP_VAR* var, /**< variable which bounds with might tighten */
8185  SCIP_Real a, /**< coefficient in square term */
8186  SCIP_INTERVAL b, /**< coefficient in linear term */
8187  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
8188  SCIP_RESULT* result, /**< result of propagation */
8189  int* nchgbds /**< buffer where to add number of tightened bounds */
8190  )
8191 {
8192  SCIP_INTERVAL newrange;
8193 
8194  assert(scip != NULL);
8195  assert(cons != NULL);
8196  assert(var != NULL);
8197  assert(result != NULL);
8198  assert(nchgbds != NULL);
8199 
8200  /* compute solution of a*x^2 + b*x \in rhs */
8201  if( a == 0.0 && SCIPintervalGetInf(b) == 0.0 && SCIPintervalGetSup(b) == 0.0 )
8202  { /* relatively easy case: 0.0 \in rhs, thus check if infeasible or just redundant */
8203  if( SCIPintervalGetInf(rhs) > 0.0 || SCIPintervalGetSup(rhs) < 0.0 )
8204  {
8205  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
8206  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8207  *result = SCIP_CUTOFF;
8208  }
8209  return SCIP_OKAY;
8210  }
8211  else if( SCIPvarGetLbLocal(var) >= 0.0 )
8212  {
8213  SCIP_INTERVAL a_;
8214 
8215  /* need only positive solutions */
8216  SCIPintervalSet(&a_, a);
8217  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &newrange, a_, b, rhs);
8218  }
8219  else if( SCIPvarGetUbLocal(var) <= 0.0 )
8220  {
8221  /* need only negative solutions */
8222  SCIP_INTERVAL a_;
8223  SCIP_INTERVAL tmp;
8224  SCIPintervalSet(&a_, a);
8226  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &tmp, a_, tmp, rhs);
8227  if( SCIPintervalIsEmpty(tmp) )
8228  {
8229  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
8230  *result = SCIP_CUTOFF;
8231  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8232  return SCIP_OKAY;
8233  }
8235  }
8236  else
8237  {
8238  /* need both positive and negative solution */
8239  SCIP_INTERVAL a_;
8240  SCIPintervalSet(&a_, a);
8241  SCIPintervalSolveUnivariateQuadExpression(intervalinfty, &newrange, a_, b, rhs);
8242  }
8243 
8244  /* 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); */
8245 
8246  if( SCIPisInfinity(scip, SCIPintervalGetInf(newrange)) || SCIPisInfinity(scip, -SCIPintervalGetSup(newrange)) )
8247  { /* domain outside [-infty, +infty] -> declare node infeasible */
8248  SCIPdebugMessage("found <%s> infeasible because propagated domain of quadratic variable <%s> is outside of (-infty, +infty)\n", SCIPconsGetName(cons), SCIPvarGetName(var));
8249  *result = SCIP_CUTOFF;
8250  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8251  return SCIP_OKAY;
8252  }
8253 
8254  if( SCIPintervalIsEmpty(newrange) )
8255  {
8256  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
8257  *result = SCIP_CUTOFF;
8258  return SCIP_OKAY;
8259  }
8260 
8261  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(newrange)) )
8262  {
8263  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, SCIPintervalGetInf(newrange), result, nchgbds) );
8264  if( *result == SCIP_CUTOFF )
8265  return SCIP_OKAY;
8266  }
8267 
8268  if( !SCIPisInfinity(scip, SCIPintervalGetSup(newrange)) )
8269  {
8270  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, SCIPintervalGetSup(newrange), result, nchgbds) );
8271  if( *result == SCIP_CUTOFF )
8272  return SCIP_OKAY;
8273  }
8274 
8275  return SCIP_OKAY;
8276 }
8277 
8278 /* the new version below computes potentially tighter bounds, but also always adds a small safety area since it is not implemented roundingsafe,
8279  * this may be a reason why it gives worse results on one of two instances
8280  * further, I have only very few instances where one can expect a difference
8281  */
8282 #ifndef PROPBILINNEW
8283 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
8284  * NOTE that domain reductions for y are not deduced
8285  */
8286 static
8288  SCIP* scip, /**< SCIP data structure */
8289  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
8290  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8291  SCIP_VAR* x, /**< first variable */
8292  SCIP_Real xsqrcoef, /**< square coefficient of x */
8293  SCIP_Real xlincoef, /**< linear coefficient of x */
8294  SCIP_VAR* y, /**< second variable */
8295  SCIP_Real ysqrcoef, /**< square coefficient of y */
8296  SCIP_Real ylincoef, /**< linear coefficient of y */
8297  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
8298  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
8299  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
8300  int* nchgbds /**< counter to increment if domain reductions are found */
8301  )
8302 {
8303  SCIP_INTERVAL myrhs;
8304  SCIP_INTERVAL varbnds;
8305  SCIP_INTERVAL lincoef;
8306 
8307  assert(scip != NULL);
8308  assert(cons != NULL);
8309  assert(x != NULL);
8310  assert(y != NULL);
8311  assert(x != y);
8312  assert(result != NULL);
8313  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
8314  assert(nchgbds != NULL);
8315  assert(bilincoef != 0.0);
8316 
8317  if( SCIPintervalIsEntire(intervalinfty, rhs) )
8318  return SCIP_OKAY;
8319 
8320  /* try to find domain reductions for x */
8322 
8323  /* put ysqrcoef*y^2 + ylincoef * y into rhs */
8324  if( SCIPintervalGetSup(rhs) >= intervalinfty )
8325  {
8326  /* if rhs is unbounded by above, it is sufficient to get an upper bound on ysqrcoef*y^2 + ylincoef * y */
8327  SCIP_ROUNDMODE roundmode;
8328  SCIP_Real tmp;
8329 
8330  SCIPintervalSet(&lincoef, ylincoef);
8331  tmp = SCIPintervalQuadUpperBound(intervalinfty, ysqrcoef, lincoef, varbnds);
8332  roundmode = SCIPintervalGetRoundingMode();
8334  SCIPintervalSetBounds(&myrhs, SCIPintervalGetInf(rhs) - tmp, intervalinfty);
8335  SCIPintervalSetRoundingMode(roundmode);
8336  }
8337  else if( SCIPintervalGetInf(rhs) <= -intervalinfty )
8338  {
8339  /* if rhs is unbounded by below, it is sufficient to get a lower bound on ysqrcoef*y^2 + ylincoef * y */
8340  SCIP_ROUNDMODE roundmode;
8341  SCIP_Real tmp;
8342 
8343  SCIPintervalSet(&lincoef, -ylincoef);
8344  tmp = -SCIPintervalQuadUpperBound(intervalinfty, -ysqrcoef, lincoef, varbnds);
8345  roundmode = SCIPintervalGetRoundingMode();
8347  SCIPintervalSetBounds(&myrhs, -intervalinfty, SCIPintervalGetSup(rhs) - tmp);
8348  SCIPintervalSetRoundingMode(roundmode);
8349  }
8350  else
8351  {
8352  /* if rhs is bounded, we need both bounds on ysqrcoef*y^2 + ylincoef * y */
8353  SCIP_INTERVAL tmp;
8354 
8355  SCIPintervalSet(&lincoef, ylincoef);
8356  SCIPintervalQuad(intervalinfty, &tmp, ysqrcoef, lincoef, varbnds);
8357  SCIPintervalSub(intervalinfty, &myrhs, rhs, tmp);
8358  }
8359 
8360  /* create equation xsqrcoef * x^2 + (xlincoef + bilincoef * [ylb, yub]) * x \in myrhs */
8361  SCIPintervalMulScalar(intervalinfty, &lincoef, varbnds, bilincoef);
8362  SCIPintervalAddScalar(intervalinfty, &lincoef, lincoef, xlincoef);
8363 
8364  /* propagate bounds on x */
8365  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, x, xsqrcoef, lincoef, myrhs, result, nchgbds) );
8366 
8367  return SCIP_OKAY;
8368 }
8369 #else
8370 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
8371  * NOTE that domain reductions for y are not deduced
8372  */
8373 static
8375  SCIP* scip, /**< SCIP data structure */
8376  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
8377  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8378  SCIP_VAR* x, /**< first variable */
8379  SCIP_Real xsqrcoef, /**< square coefficient of x */
8380  SCIP_Real xlincoef, /**< linear coefficient of x */
8381  SCIP_VAR* y, /**< second variable */
8382  SCIP_Real ysqrcoef, /**< square coefficient of y */
8383  SCIP_Real ylincoef, /**< linear coefficient of y */
8384  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
8385  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
8386  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
8387  int* nchgbds /**< counter to increment if domain reductions are found */
8388  )
8389 {
8390  SCIP_INTERVAL xbnds;
8391  SCIP_INTERVAL ybnds;
8392 
8393  assert(scip != NULL);
8394  assert(cons != NULL);
8395  assert(x != NULL);
8396  assert(y != NULL);
8397  assert(x != y);
8398  assert(result != NULL);
8399  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
8400  assert(nchgbds != NULL);
8401  assert(bilincoef != 0.0);
8402 
8403  if( SCIPintervalIsEntire(intervalinfty, rhs) )
8404  return SCIP_OKAY;
8405 
8406  SCIPintervalSetBounds(&xbnds,
8407  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x))), /*lint !e666*/
8408  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)))); /*lint !e666*/
8409  SCIPintervalSetBounds(&ybnds,
8410  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))), /*lint !e666*/
8411  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))); /*lint !e666*/
8412 
8413  /* try to find domain reductions for x */
8414  SCIPintervalSolveBivariateQuadExpressionAllScalar(intervalinfty, &xbnds, xsqrcoef, ysqrcoef, bilincoef, xlincoef, ylincoef, rhs, xbnds, ybnds);
8415 
8416  if( SCIPintervalIsEmpty(xbnds) )
8417  {
8418  SCIPdebugMessage("found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(x));
8419  *result = SCIP_CUTOFF;
8420  return SCIP_OKAY;
8421  }
8422 
8423  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(xbnds)) )
8424  {
8425  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, x, SCIPintervalGetInf(xbnds), result, nchgbds) );
8426  if( *result == SCIP_CUTOFF )
8427  return SCIP_OKAY;
8428  }
8429 
8430  if( !SCIPisInfinity(scip, SCIPintervalGetSup(xbnds)) )
8431  {
8432  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, x, SCIPintervalGetSup(xbnds), result, nchgbds) );
8433  if( *result == SCIP_CUTOFF )
8434  return SCIP_OKAY;
8435  }
8436 
8437  return SCIP_OKAY;
8438 }
8439 #endif
8440 
8441 /** computes the minimal and maximal activity for the quadratic part in a constraint data
8442  * only sums up terms that contribute finite values
8443  * gives the number of terms that contribute infinite values
8444  * only computes those activities where the corresponding side of the constraint is finite
8445  */
8446 static
8448  SCIP* scip, /**< SCIP data structure */
8449  SCIP_CONSDATA* consdata, /**< constraint data */
8450  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
8451  SCIP_Real* minquadactivity, /**< minimal activity of quadratic variable terms where only terms with finite minimal activity contribute */
8452  SCIP_Real* maxquadactivity, /**< maximal activity of quadratic variable terms where only terms with finite maximal activity contribute */
8453  int* minactivityinf, /**< number of quadratic variables that contribute -infinity to minimal activity */
8454  int* maxactivityinf, /**< number of quadratic variables that contribute +infinity to maximal activity */
8455  SCIP_INTERVAL* quadactcontr /**< contribution of each quadratic variables to quadactivity */
8456  )
8457 { /*lint --e{666}*/
8458  SCIP_ROUNDMODE prevroundmode;
8459  int i;
8460  int j;
8461  int k;
8462  SCIP_INTERVAL tmp;
8463  SCIP_Real bnd;
8464  SCIP_INTERVAL xrng;
8465  SCIP_INTERVAL lincoef;
8466 
8467  assert(scip != NULL);
8468  assert(consdata != NULL);
8469  assert(minquadactivity != NULL);
8470  assert(maxquadactivity != NULL);
8471  assert(minactivityinf != NULL);
8472  assert(maxactivityinf != NULL);
8473  assert(quadactcontr != NULL);
8474 
8475  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
8476  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
8477  */
8478  *minquadactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
8479  *maxquadactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
8480 
8481  *minactivityinf = 0;
8482  *maxactivityinf = 0;
8483 
8484  if( consdata->nquadvars == 0 )
8485  {
8486  SCIPintervalSet(&consdata->quadactivitybounds, 0.0);
8487  return;
8488  }
8489 
8490  for( i = 0; i < consdata->nquadvars; ++i )
8491  {
8492  /* there should be no quadratic variables fixed at -/+ infinity due to our locks */
8493  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var)));
8494  assert(!SCIPisInfinity(scip, -SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
8495 
8496  SCIPintervalSetBounds(&quadactcontr[i], -intervalinfty, intervalinfty);
8497 
8498  SCIPintervalSetBounds(&xrng,
8499  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))),
8500  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))));
8501 
8502  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
8503  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
8504  {
8505  k = consdata->quadvarterms[i].adjbilin[j];
8506  if( consdata->bilinterms[k].var1 != consdata->quadvarterms[i].var )
8507  continue; /* handle this term later */
8508 
8509  SCIPintervalSetBounds(&tmp,
8510  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
8511  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
8512  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
8513  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
8514  }
8515 
8516  if( !SCIPisInfinity(scip, -consdata->lhs) )
8517  {
8518  /* compute maximal activity only if there is a finite left hand side */
8519  bnd = SCIPintervalQuadUpperBound(intervalinfty, consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
8520  if( SCIPisInfinity(scip, bnd) )
8521  {
8522  ++*maxactivityinf;
8523  }
8524  else if( SCIPisInfinity(scip, -bnd) )
8525  {
8526  /* if maximal activity is below value for -infinity, let's take -1e10 as upper bound on maximal activity
8527  * @todo Something better?
8528  */
8529  bnd = -sqrt(SCIPinfinity(scip));
8530  *maxquadactivity += bnd;
8531  quadactcontr[i].sup = bnd;
8532  }
8533  else
8534  {
8535  prevroundmode = SCIPintervalGetRoundingMode();
8537  *maxquadactivity += bnd;
8538  SCIPintervalSetRoundingMode(prevroundmode);
8539  quadactcontr[i].sup = bnd;
8540  }
8541  }
8542 
8543  if( !SCIPisInfinity(scip, consdata->rhs) )
8544  {
8545  /* compute minimal activity only if there is a finite right hand side */
8546  SCIPintervalSetBounds(&lincoef, -SCIPintervalGetSup(lincoef), -SCIPintervalGetInf(lincoef));
8547  bnd = -SCIPintervalQuadUpperBound(intervalinfty, -consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
8548 
8549  if( SCIPisInfinity(scip, -bnd) )
8550  {
8551  ++*minactivityinf;
8552  }
8553  else if( SCIPisInfinity(scip, bnd) )
8554  {
8555  /* if minimal activity is above value for infinity, let's take 1e10 as lower bound on minimal activity
8556  * @todo Something better?
8557  */
8558  bnd = sqrt(SCIPinfinity(scip));
8559  *minquadactivity += bnd;
8560  quadactcontr[i].inf = bnd;
8561  }
8562  else
8563  {
8564  prevroundmode = SCIPintervalGetRoundingMode();
8566  *minquadactivity += bnd;
8567  SCIPintervalSetRoundingMode(prevroundmode);
8568  quadactcontr[i].inf = bnd;
8569  }
8570  }
8571 
8572  }
8573 
8574  SCIPintervalSetBounds(&consdata->quadactivitybounds,
8575  (*minactivityinf > 0 ? -intervalinfty : *minquadactivity),
8576  (*maxactivityinf > 0 ? intervalinfty : *maxquadactivity));
8577  assert(!SCIPintervalIsEmpty(consdata->quadactivitybounds));
8578 }
8579 
8580 /** propagates bounds on a quadratic constraint */
8581 static
8583  SCIP* scip, /**< SCIP data structure */
8584  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8585  SCIP_CONS* cons, /**< constraint to process */
8586  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
8587  int* nchgbds, /**< buffer where to add the the number of changed bounds */
8588  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
8589  )
8590 { /*lint --e{666}*/
8591  SCIP_CONSDATA* consdata;
8592  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
8593  SCIP_INTERVAL consactivity; /* activity of linear plus quadratic part */
8594  SCIP_Real intervalinfty; /* infinity used for interval computation */
8595  SCIP_Real minquadactivity; /* lower bound on finite activities of quadratic part */
8596  SCIP_Real maxquadactivity; /* upper bound on finite activities of quadratic part */
8597  int quadminactinf; /* number of quadratic variables that contribute -infinity to minimal activity of quadratic term */
8598  int quadmaxactinf; /* number of quadratic variables that contribute +infinity to maximal activity of quadratic term */
8599  SCIP_INTERVAL* quadactcontr; /* contribution of each quadratic variable term to quadactivity */
8600 
8601  SCIP_VAR* var;
8602  SCIP_INTERVAL rhs; /* right hand side of quadratic equation */
8603  SCIP_INTERVAL tmp;
8604  SCIP_ROUNDMODE roundmode;
8605  SCIP_Real bnd;
8606  int i;
8607 
8608  assert(scip != NULL);
8609  assert(conshdlr != NULL);
8610  assert(cons != NULL);
8611  assert(result != NULL);
8612  assert(nchgbds != NULL);
8613  assert(redundant != NULL);
8614 
8615  consdata = SCIPconsGetData(cons);
8616  assert(consdata != NULL);
8617 
8618  *result = SCIP_DIDNOTRUN;
8619  *redundant = FALSE;
8620 
8621  if( consdata->ispropagated )
8622  return SCIP_OKAY;
8623 
8624  *result = SCIP_DIDNOTFIND;
8625 
8626  intervalinfty = 1000 * SCIPinfinity(scip) * SCIPinfinity(scip);
8627 
8628  quadactcontr = NULL;
8629  quadminactinf = -1;
8630  quadmaxactinf = -1;
8631 
8632  SCIPdebugMessage("start domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
8633 
8634  consdata->ispropagated = TRUE;
8635 
8636  /* make sure we have activity of linear term and that they are consistent */
8637  consdataUpdateLinearActivity(scip, consdata, intervalinfty);
8638  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
8639  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
8640  assert(consdata->minlinactivityinf >= 0);
8641  assert(consdata->maxlinactivityinf >= 0);
8642 
8643  /* sort quadratic variable terms, in case we need to search for terms occuring in bilinear terms later
8644  * we sort here already, since we rely on a constant variable order during this method
8645  */
8646  if( consdata->nbilinterms > 0 )
8647  {
8648  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
8649  }
8650 
8651  /* compute activity of quad term part, if not up to date
8652  * in that case, we also collect the contribution of each quad var term for later */
8653  if( SCIPintervalIsEmpty(consdata->quadactivitybounds) )
8654  {
8655  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
8656  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
8657  assert(!SCIPintervalIsEmpty(consdata->quadactivitybounds));
8658  }
8659 
8660  SCIPdebugMessage("linear activity: [%g, %g] quadratic activity: [%g, %g]\n",
8661  (consdata->minlinactivityinf > 0 ? -SCIPinfinity(scip) : consdata->minlinactivity),
8662  (consdata->maxlinactivityinf > 0 ? SCIPinfinity(scip) : consdata->maxlinactivity),
8663  consdata->quadactivitybounds.inf, consdata->quadactivitybounds.sup);
8664 
8665  /* extend constraint bounds by epsilon to avoid some numerical difficulties */
8666  SCIPintervalSetBounds(&consbounds,
8667  -infty2infty(SCIPinfinity(scip), intervalinfty, -consdata->lhs+SCIPepsilon(scip)),
8668  +infty2infty(SCIPinfinity(scip), intervalinfty, consdata->rhs+SCIPepsilon(scip)));
8669 
8670  /* check redundancy and infeasibility */
8671  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity, consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity);
8672  SCIPintervalAdd(intervalinfty, &consactivity, consactivity, consdata->quadactivitybounds);
8673  if( SCIPintervalIsSubsetEQ(intervalinfty, consactivity, consbounds) )
8674  {
8675  SCIPdebugMessage("found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
8676  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
8677  *redundant = TRUE;
8678  goto CLEANUP;
8679  }
8680 
8681  /* was SCIPintervalAreDisjoint(consbounds, consactivity), but that would allow violations up to eps only
8682  * we need to decide feasibility w.r.t. feastol (but still want to propagate w.r.t. eps)
8683  */
8684  if( SCIPisFeasGT(scip, consbounds.inf, consactivity.sup) || SCIPisFeasLT(scip, consbounds.sup, consactivity.inf) )
8685  {
8686  SCIPdebugMessage("found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
8687  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
8688  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
8689  *result = SCIP_CUTOFF;
8690  goto CLEANUP;
8691  }
8692 
8693  /* propagate linear part \in rhs = consbounds - quadactivity (use the one from consdata, since that includes infinities) */
8694  SCIPintervalSub(intervalinfty, &rhs, consbounds, consdata->quadactivitybounds);
8695  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
8696  {
8697  SCIP_Real coef;
8698 
8699  for( i = 0; i < consdata->nlinvars; ++i )
8700  {
8701  coef = consdata->lincoefs[i];
8702  var = consdata->linvars[i];
8703 
8704  /* skip fixed variables
8705  * @todo is that a good or a bad idea?
8706  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
8707  */
8708  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
8709  continue;
8710 
8711  if( coef > 0.0 )
8712  {
8713  if( SCIPintervalGetSup(rhs) < intervalinfty )
8714  {
8715  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
8716  /* try to tighten the upper bound on var x */
8717  if( consdata->minlinactivityinf == 0 )
8718  {
8719  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
8720  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
8721  roundmode = SCIPintervalGetRoundingMode();
8723  bnd = SCIPintervalGetSup(rhs);
8724  bnd -= consdata->minlinactivity;
8725  bnd += coef * SCIPvarGetLbLocal(var);
8726  bnd /= coef;
8727  SCIPintervalSetRoundingMode(roundmode);
8728  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8729  if( *result == SCIP_CUTOFF )
8730  break;
8731  }
8732  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
8733  {
8734  /* x was the variable that made the minimal linear activity equal -infinity, so
8735  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
8736  roundmode = SCIPintervalGetRoundingMode();
8738  bnd = SCIPintervalGetSup(rhs);
8739  bnd -= consdata->minlinactivity;
8740  bnd /= coef;
8741  SCIPintervalSetRoundingMode(roundmode);
8742  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8743  if( *result == SCIP_CUTOFF )
8744  break;
8745  }
8746  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
8747  }
8748 
8749  if( SCIPintervalGetInf(rhs) > -intervalinfty )
8750  {
8751  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
8752  /* try to tighten the lower bound on var x */
8753  if( consdata->maxlinactivityinf == 0 )
8754  {
8755  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
8756  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
8757  roundmode = SCIPintervalGetRoundingMode();
8759  bnd = SCIPintervalGetInf(rhs);
8760  bnd -= consdata->maxlinactivity;
8761  bnd += coef * SCIPvarGetUbLocal(var);
8762  bnd /= coef;
8763  SCIPintervalSetRoundingMode(roundmode);
8764  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8765  if( *result == SCIP_CUTOFF )
8766  break;
8767  }
8768  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
8769  {
8770  /* x was the variable that made the maximal linear activity equal infinity, so
8771  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
8772  roundmode = SCIPintervalGetRoundingMode();
8774  bnd = SCIPintervalGetInf(rhs);
8775  bnd -= consdata->maxlinactivity;
8776  bnd /= coef;
8777  SCIPintervalSetRoundingMode(roundmode);
8778  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8779  if( *result == SCIP_CUTOFF )
8780  break;
8781  }
8782  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
8783  }
8784  }
8785  else
8786  {
8787  assert(coef < 0.0 );
8788  if( SCIPintervalGetInf(rhs) > -intervalinfty )
8789  {
8790  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
8791  /* try to tighten the upper bound on var x */
8792  if( consdata->maxlinactivityinf == 0 )
8793  {
8794  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
8795  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
8796  roundmode = SCIPintervalGetRoundingMode();
8798  bnd = consdata->maxlinactivity;
8799  bnd += (-coef) * SCIPvarGetLbLocal(var);
8800  bnd -= SCIPintervalGetInf(rhs);
8801  bnd /= (-coef);
8802  SCIPintervalSetRoundingMode(roundmode);
8803  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8804  if( *result == SCIP_CUTOFF )
8805  break;
8806  }
8807  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
8808  {
8809  /* x was the variable that made the maximal linear activity equal infinity, so
8810  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
8811  roundmode = SCIPintervalGetRoundingMode();
8813  bnd = consdata->maxlinactivity;
8814  bnd -= SCIPintervalGetInf(rhs);
8815  bnd /= (-coef);
8816  SCIPintervalSetRoundingMode(roundmode);
8817  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8818  if( *result == SCIP_CUTOFF )
8819  break;
8820  }
8821  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
8822  }
8823 
8824  if( SCIPintervalGetSup(rhs) < intervalinfty )
8825  {
8826  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
8827  /* try to tighten the lower bound on var x */
8828  if( consdata->minlinactivityinf == 0 )
8829  {
8830  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
8831  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
8832  roundmode = SCIPintervalGetRoundingMode();
8834  bnd = consdata->minlinactivity;
8835  bnd += (-coef) * SCIPvarGetUbLocal(var);
8836  bnd -= SCIPintervalGetSup(rhs);
8837  bnd /= (-coef);
8838  SCIPintervalSetRoundingMode(roundmode);
8839  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8840  if( *result == SCIP_CUTOFF )
8841  break;
8842  }
8843  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
8844  {
8845  /* x was the variable that made the maximal linear activity equal -infinity, so
8846  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
8847  roundmode = SCIPintervalGetRoundingMode();
8849  bnd = consdata->minlinactivity;
8850  bnd -= SCIPintervalGetSup(rhs);
8851  bnd /= (-coef);
8852  SCIPintervalSetRoundingMode(roundmode);
8853  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
8854  if( *result == SCIP_CUTOFF )
8855  break;
8856  }
8857  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
8858  }
8859  }
8860  }
8861  if( *result == SCIP_CUTOFF )
8862  goto CLEANUP;
8863  }
8864 
8865  /* propagate quadratic part \in rhs = consbounds - linactivity */
8866  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
8867  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
8868  consdataUpdateLinearActivity(scip, consdata, intervalinfty); /* make sure, activities of linear part did not become invalid by above bound changes, if any */
8869  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
8870  SCIPintervalSetBounds(&tmp,
8871  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
8872  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity));
8873  SCIPintervalSub(intervalinfty, &rhs, consbounds, tmp);
8874  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
8875  {
8876  if( consdata->nquadvars == 1 )
8877  {
8878  /* quadratic part is just a*x^2+b*x -> a common case that we treat directly */
8879  SCIP_INTERVAL lincoef; /* linear coefficient of quadratic equation */
8880 
8881  assert(consdata->nbilinterms == 0);
8882 
8883  var = consdata->quadvarterms[0].var;
8884  SCIPintervalSet(&lincoef, consdata->quadvarterms[0].lincoef);
8885 
8886  /* propagate a*x^2 + b*x \in rhs */
8887  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[0].sqrcoef, lincoef, rhs, result, nchgbds) );
8888  }
8889  else if( consdata->nbilinterms == 1 && consdata->nquadvars == 2 )
8890  {
8891  /* quadratic part is just ax*x^2+bx*x + ay*y^2+by*y + c*xy -> a common case that we treat directly */
8892  assert(consdata->bilinterms[0].var1 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var1 == consdata->quadvarterms[1].var);
8893  assert(consdata->bilinterms[0].var2 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var2 == consdata->quadvarterms[1].var);
8894 
8895  /* 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 */
8896  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
8897  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
8898  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
8899  consdata->bilinterms[0].coef,
8900  rhs, result, nchgbds) );
8901  if( *result != SCIP_CUTOFF )
8902  {
8903  /* 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 */
8904  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
8905  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
8906  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
8907  consdata->bilinterms[0].coef,
8908  rhs, result, nchgbds) );
8909  }
8910  }
8911  else
8912  {
8913  /* general case */
8914 
8915  /* compute "advanced" information on quad var term activities, if not up-to-date */
8916  if( quadminactinf == -1 )
8917  {
8918  assert(quadactcontr == NULL);
8919  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
8920  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
8921  }
8922  assert(quadactcontr != NULL);
8923  assert(quadminactinf >= 0);
8924  assert(quadmaxactinf >= 0);
8925 
8926  /* if the quad activities are not hopelessly unbounded on useful sides, try to deduce domain reductions on quad vars */
8927  if( (SCIPintervalGetSup(rhs) < intervalinfty && quadminactinf <= 1) ||
8928  ( SCIPintervalGetInf(rhs) > -intervalinfty && quadmaxactinf <= 1) )
8929  {
8930  SCIP_INTERVAL lincoef;
8931  SCIP_INTERVAL rhs2;
8932  int j;
8933  int k;
8934 
8935  for( i = 0; i < consdata->nquadvars; ++i )
8936  {
8937  var = consdata->quadvarterms[i].var;
8938 
8939  /* skip fixed variables
8940  * @todo is that a good or a bad idea?
8941  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
8942  */
8943  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
8944  continue;
8945 
8946  /* compute rhs2 such that we can propagate quadvarterm(x_i) \in rhs2 */
8947 
8948  /* setup rhs2.sup = rhs.sup - (quadactivity.inf - quadactcontr[i].inf), if everything were finite
8949  * if only quadactcontr[i].inf is infinite (i.e., the other i are all finite), we just get rhs2.sup = rhs.sup
8950  * otherwise we get rhs2.sup = infinity */
8951  if( SCIPintervalGetSup(rhs) < intervalinfty )
8952  {
8953  if( quadminactinf == 0 || (quadminactinf == 1 && SCIPintervalGetInf(quadactcontr[i]) <= -intervalinfty) )
8954  {
8955  roundmode = SCIPintervalGetRoundingMode();
8957  rhs2.sup = rhs.sup - minquadactivity; /*lint !e644*/
8958  /* if the residual quad min activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
8959  if( quadminactinf == 0 && SCIPintervalGetInf(quadactcontr[i]) != 0.0 )
8960  rhs2.sup += SCIPintervalGetInf(quadactcontr[i]);
8961  SCIPintervalSetRoundingMode(roundmode);
8962  }
8963  else
8964  {
8965  /* there are either >= 2 quad var terms contributing -infinity, or there is one which is not i */
8966  rhs2.sup = intervalinfty;
8967  }
8968  }
8969  else
8970  {
8971  rhs2.sup = intervalinfty;
8972  }
8973 
8974  /* setup rhs2.inf = rhs.inf - (quadactivity.sup - quadactcontr[i].sup), see also above */
8975  if( SCIPintervalGetInf(rhs) > -intervalinfty )
8976  {
8977  if( quadmaxactinf == 0 || (quadmaxactinf == 1 && SCIPintervalGetSup(quadactcontr[i]) >= intervalinfty) )
8978  {
8979  roundmode = SCIPintervalGetRoundingMode();
8981  rhs2.inf = rhs.inf - maxquadactivity; /*lint !e644*/
8982  /* if the residual quad max activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
8983  if( quadmaxactinf == 0 && SCIPintervalGetSup(quadactcontr[i]) != 0.0 )
8984  rhs2.inf += SCIPintervalGetSup(quadactcontr[i]);
8985  SCIPintervalSetRoundingMode(roundmode);
8986  }
8987  else
8988  {
8989  /* there are either >= 2 quad var terms contributing infinity, or there is one which is not i */
8990  rhs2.inf = -intervalinfty;
8991  }
8992  }
8993  else
8994  {
8995  rhs2.inf = -intervalinfty;
8996  }
8997  assert(!SCIPintervalIsEmpty(rhs2));
8998 
8999  /* if rhs2 is entire, then there is nothing we could propagate */
9000  if( SCIPintervalIsEntire(intervalinfty, rhs2) )
9001  continue;
9002 
9003  /* assemble linear coefficient for quad equation a*x^2 + b*x \in rhs2 */
9004  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
9005  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
9006  {
9007  k = consdata->quadvarterms[i].adjbilin[j];
9008 #if 1
9009  if( consdata->bilinterms[k].var1 == var )
9010  {
9011  /* bilinear term k contributes to the activity of quad var term i, so just add bounds to linear coef */
9012  SCIPintervalSetBounds(&tmp,
9013  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9014  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9015  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9016  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9017 
9018  }
9019  else
9020  {
9021  /* bilinear term k does not contribute to the activity of quad var term i
9022  * so bounds on term k are contained in rhs2
9023  * if they are finite, we try to remove them from rhs2 and update lincoef instead
9024  * 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
9025  * HOWEVER: when computing rhs2, we may not just have added the bounds for the bilinear term, but for the associated quadratic term
9026  * for this complete term, we used SCIPintervalQuad to compute the bounds
9027  * since we do not want to repeat a call to SCIPintervalQuad for that quadratic term with bilinear term k removed,
9028  * we only remove the bounds for the bilinear term k from rhs2 if the associated quadratic term consists only of this bilinear term,
9029  * i.e., the quadratic term corresponding to var1 should be only var1*var2, but have no square or linear coefs or other bilinear terms
9030  * (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)
9031  */
9032  SCIP_INTERVAL me;
9033  SCIP_INTERVAL bilinbounds;
9034  int otherpos;
9035 
9036  assert(consdata->bilinterms[k].var2 == var);
9037 
9038  assert(consdata->quadvarssorted);
9039  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[k].var1, &otherpos) );
9040  assert(otherpos >= 0);
9041  assert(consdata->quadvarterms[otherpos].var == consdata->bilinterms[k].var1);
9042 
9043  if( (consdata->quadvarterms[otherpos].sqrcoef != 0.0) || consdata->quadvarterms[otherpos].lincoef != 0.0 || consdata->quadvarterms[otherpos].nadjbilin > 1 )
9044  continue;
9045 
9046  /* set tmp to bounds of other variable and multiply with bilin coef */
9047  SCIPintervalSetBounds(&tmp,
9048  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))),
9049  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))));
9050  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9051 
9052  /* set me to bounds of i'th variable */
9054  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9055  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9056 
9057  /* remove me*tmp from rhs2 */
9058 
9059  roundmode = SCIPintervalGetRoundingMode();
9060 
9061  if( rhs2.inf > -intervalinfty )
9062  {
9063  /* need upward rounding for SCIPintervalMulSup */
9065  SCIPintervalMulSup(intervalinfty, &bilinbounds, me, tmp);
9066  /* rhs2.inf += bilinbounds.sup, but we are in upward rounding */
9067  if( bilinbounds.sup < intervalinfty )
9068  rhs2.inf = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.inf) - bilinbounds.sup);
9069  }
9070 
9071  if( rhs2.sup < intervalinfty )
9072  {
9073  /* need downward rounding for SCIPintervalMulInf */
9075  SCIPintervalMulInf(intervalinfty, &bilinbounds, me, tmp);
9076  /* rhs2.sup += bilinbounds.inf, but we are in downward rounding */
9077  if( bilinbounds.inf > -intervalinfty )
9078  rhs2.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.sup) - bilinbounds.inf);
9079  }
9080 
9081  SCIPintervalSetRoundingMode(roundmode);
9082 
9083  /* add tmp to lincoef */
9084  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9085  }
9086 #else
9087  if( consdata->bilinterms[k].var1 != var )
9088  continue; /* this term does not contribute to the activity of quad var term i */
9089 
9090  SCIPintervalSetBounds(&tmp,
9091  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9092  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9093  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9094  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9095 #endif
9096  }
9097 
9098  /* deduce domain reductions for x_i */
9099  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[i].sqrcoef, lincoef, rhs2, result, nchgbds) );
9100  if( *result == SCIP_CUTOFF )
9101  goto CLEANUP;
9102  }
9103  }
9104  }
9105  }
9106 
9107  CLEANUP:
9108  SCIPfreeBufferArrayNull(scip, &quadactcontr);
9109 
9110  return SCIP_OKAY;
9111 }
9112 
9113 /** calls domain propagation for a set of constraints */
9114 static
9116  SCIP* scip, /**< SCIP data structure */
9117  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9118  SCIP_CONS** conss, /**< constraints to process */
9119  int nconss, /**< number of constraints */
9120  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
9121  int* nchgbds /**< buffer where to add the the number of changed bounds */
9122  )
9123 {
9124  SCIP_CONSHDLRDATA* conshdlrdata;
9125  SCIP_RESULT propresult;
9126  SCIP_Bool redundant;
9127  int c;
9128  int roundnr;
9129  SCIP_Bool success;
9130  int maxproprounds;
9131 
9132  assert(scip != NULL);
9133  assert(conshdlr != NULL);
9134  assert(conss != NULL || nconss == 0);
9135  assert(result != NULL);
9136  assert(nchgbds != NULL);
9137 
9139 
9140  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9141  assert(conshdlrdata != NULL);
9142 
9143  *result = SCIP_DIDNOTFIND;
9144  roundnr = 0;
9145  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
9146  maxproprounds = conshdlrdata->maxproproundspresolve;
9147  else
9148  maxproprounds = conshdlrdata->maxproprounds;
9149 
9150  do
9151  {
9152  success = FALSE;
9153  ++roundnr;
9154 
9155  SCIPdebugMessage("starting domain propagation round %d of %d for %d constraints\n", roundnr, maxproprounds, nconss);
9156 
9157  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
9158  {
9159  assert(conss != NULL);
9160  if( !SCIPconsIsEnabled(conss[c]) )
9161  continue;
9162 
9163  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
9164  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
9165  {
9166  *result = propresult;
9167  success = TRUE;
9168  }
9169  if( redundant )
9170  {
9171  SCIPdebugMessage("deleting constraint <%s> locally\n", SCIPconsGetName(conss[c]));
9172  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
9173  }
9174  }
9175 
9176  }
9177  while( success && *result != SCIP_CUTOFF && roundnr < maxproprounds );
9178 
9179  return SCIP_OKAY;
9180 }
9181 
9182 /* checks for a linear variable that can be increase or decreased without harming feasibility */
9183 static
9185  SCIP* scip, /**< SCIP data structure */
9186  SCIP_CONSDATA* consdata /**< constraint data */
9187  )
9188 {
9189  int i;
9190  int poslock;
9191  int neglock;
9192 
9193  consdata->linvar_maydecrease = -1;
9194  consdata->linvar_mayincrease = -1;
9195 
9196  /* check for a linear variable that can be increase or decreased without harming feasibility */
9197  for( i = 0; i < consdata->nlinvars; ++i )
9198  {
9199  /* compute locks of i'th linear variable */
9200  assert(consdata->lincoefs[i] != 0.0);
9201  if( consdata->lincoefs[i] > 0.0 )
9202  {
9203  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
9204  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
9205  }
9206  else
9207  {
9208  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
9209  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
9210  }
9211 
9212  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - neglock == 0 )
9213  {
9214  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
9215  /* if we have already one candidate, then take the one where the loss in the objective function is less */
9216  if( (consdata->linvar_maydecrease < 0) ||
9217  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
9218  consdata->linvar_maydecrease = i;
9219  }
9220 
9221  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - poslock == 0 )
9222  {
9223  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
9224  /* if we have already one candidate, then take the one where the loss in the objective function is less */
9225  if( (consdata->linvar_mayincrease < 0) ||
9226  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
9227  consdata->linvar_mayincrease = i;
9228  }
9229  }
9230 
9231 #ifdef SCIP_DEBUG
9232  if( consdata->linvar_mayincrease >= 0 )
9233  {
9234  SCIPdebugMessage("may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
9235  }
9236  if( consdata->linvar_maydecrease >= 0 )
9237  {
9238  SCIPdebugMessage("may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
9239  }
9240 #endif
9241 }
9242 
9243 /** Given a solution where every quadratic constraint is either feasible or can be made feasible by
9244  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
9245  * The method assumes that this is always possible and that not all constraints are feasible already.
9246  */
9247 static
9249  SCIP* scip, /**< SCIP data structure */
9250  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9251  SCIP_CONS** conss, /**< constraints to process */
9252  int nconss, /**< number of constraints */
9253  SCIP_SOL* sol, /**< solution to process */
9254  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
9255  )
9256 {
9257  SCIP_CONSHDLRDATA* conshdlrdata;
9258  SCIP_CONSDATA* consdata;
9259  char origscaling;
9260  SCIP_SOL* newsol;
9261  SCIP_VAR* var;
9262  int c;
9263  SCIP_Real viol;
9264  SCIP_Real delta;
9265  SCIP_Real gap;
9266 
9267  assert(scip != NULL);
9268  assert(conshdlr != NULL);
9269  assert(conss != NULL || nconss == 0);
9270  assert(success != NULL);
9271 
9272  *success = FALSE;
9273 
9274  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9275  assert(conshdlrdata != NULL);
9276 
9277  if( sol != NULL )
9278  {
9279  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
9280  }
9281  else
9282  {
9283  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
9284  }
9285  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
9286  SCIPdebugMessage("attempt to make solution from <%s> feasible by shifting linear variable\n",
9287  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
9288 
9289  origscaling = conshdlrdata->scaling;
9290  for( c = 0; c < nconss; ++c )
9291  {
9292  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
9293  assert(consdata != NULL);
9294 
9295  /* recompute violation of solution in case solution has changed
9296  * get absolution violation and sign
9297  * @todo avoid doing it this way
9298  */
9299  conshdlrdata->scaling = 'o';
9300  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
9301  {
9302  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
9303  viol = consdata->lhs - consdata->activity;
9304  }
9305  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
9306  {
9307  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
9308  viol = consdata->rhs - consdata->activity;
9309  }
9310  else
9311  continue; /* constraint is satisfied */
9312 
9313  assert(viol != 0.0);
9314  if( consdata->linvar_mayincrease >= 0 &&
9315  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
9316  {
9317  /* have variable where increasing makes the constraint less violated */
9318  var = consdata->linvars[consdata->linvar_mayincrease];
9319  /* compute how much we would like to increase var */
9320  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
9321  assert(delta > 0.0);
9322  /* if var has an upper bound, may need to reduce delta */
9323  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
9324  {
9325  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
9326  delta = MIN(MAX(0.0, gap), delta);
9327  }
9328  if( SCIPisPositive(scip, delta) )
9329  {
9330  /* if variable is integral, round delta up so that it will still have an integer value */
9331  if( SCIPvarIsIntegral(var) )
9332  delta = SCIPceil(scip, delta);
9333 
9334  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
9335  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
9336 
9337  /* adjust constraint violation, if satisfied go on to next constraint */
9338  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
9339  if( SCIPisZero(scip, viol) )
9340  continue;
9341  }
9342  }
9343 
9344  assert(viol != 0.0);
9345  if( consdata->linvar_maydecrease >= 0 &&
9346  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
9347  {
9348  /* have variable where decreasing makes constraint less violated */
9349  var = consdata->linvars[consdata->linvar_maydecrease];
9350  /* compute how much we would like to decrease var */
9351  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
9352  assert(delta < 0.0);
9353  /* if var has a lower bound, may need to reduce delta */
9354  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
9355  {
9356  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
9357  delta = MAX(MIN(0.0, gap), delta);
9358  }
9359  if( SCIPisNegative(scip, delta) )
9360  {
9361  /* if variable is integral, round delta down so that it will still have an integer value */
9362  if( SCIPvarIsIntegral(var) )
9363  delta = SCIPfloor(scip, delta);
9364  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
9365  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
9366 
9367  /* adjust constraint violation, if satisfied go on to next constraint */
9368  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
9369  if( SCIPisZero(scip, viol) )
9370  continue;
9371  }
9372  }
9373 
9374  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
9375  break;
9376  }
9377  conshdlrdata->scaling = origscaling;
9378 
9379  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
9380  * then pass it to the trysol heuristic
9381  */
9382  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
9383  {
9384  SCIPdebugMessage("pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
9385 
9386  assert(conshdlrdata->trysolheur != NULL);
9387  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
9388 
9389  *success = TRUE;
9390  }
9391 
9392  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
9393 
9394  return SCIP_OKAY;
9395 }
9396 
9397 /** tries to upgrade a nonlinear constraint into a quadratic constraint */
9398 static
9399 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
9401  SCIP_EXPRGRAPH* exprgraph;
9402  SCIP_EXPRGRAPHNODE* node;
9403  int i;
9404 
9405  assert(nupgdconss != NULL);
9406  assert(upgdconss != NULL);
9407 
9408  *nupgdconss = 0;
9409 
9410  node = SCIPgetExprgraphNodeNonlinear(scip, cons);
9411 
9412  /* no interest in linear constraints */
9413  if( node == NULL )
9414  return SCIP_OKAY;
9415 
9416  /* if a quadratic expression has been simplified, then all children of the node should be variables */
9418  return SCIP_OKAY;
9419 
9420  switch( SCIPexprgraphGetNodeOperator(node) )
9421  {
9422  case SCIP_EXPR_VARIDX:
9423  case SCIP_EXPR_CONST:
9424  case SCIP_EXPR_PLUS:
9425  case SCIP_EXPR_MINUS:
9426  case SCIP_EXPR_SUM:
9427  case SCIP_EXPR_LINEAR:
9428  /* these should not appear as exprgraphnodes after constraint presolving */
9429  return SCIP_OKAY;
9430 
9431  case SCIP_EXPR_DIV:
9432  case SCIP_EXPR_SQRT:
9433  case SCIP_EXPR_REALPOWER:
9434  case SCIP_EXPR_INTPOWER:
9435  case SCIP_EXPR_SIGNPOWER:
9436  case SCIP_EXPR_EXP:
9437  case SCIP_EXPR_LOG:
9438  case SCIP_EXPR_SIN:
9439  case SCIP_EXPR_COS:
9440  case SCIP_EXPR_TAN:
9441  /* case SCIP_EXPR_ERF: */
9442  /* case SCIP_EXPR_ERFI: */
9443  case SCIP_EXPR_MIN:
9444  case SCIP_EXPR_MAX:
9445  case SCIP_EXPR_ABS:
9446  case SCIP_EXPR_SIGN:
9447  case SCIP_EXPR_PRODUCT:
9448  case SCIP_EXPR_POLYNOMIAL:
9449  /* these do not look like an quadratic expression (assuming the expression graph simplifier did run) */
9450  return SCIP_OKAY;
9451 
9452  case SCIP_EXPR_MUL:
9453  case SCIP_EXPR_SQUARE:
9454  case SCIP_EXPR_QUADRATIC:
9455  /* these mean that we have something quadratic */
9456  break;
9457 
9458  case SCIP_EXPR_PARAM:
9459  case SCIP_EXPR_LAST:
9460  default:
9461  SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
9462  return SCIP_OKAY;
9463  }
9464 
9465  /* setup a quadratic constraint */
9466 
9467  if( upgdconsssize < 1 )
9468  {
9469  /* request larger upgdconss array */
9470  *nupgdconss = -1;
9471  return SCIP_OKAY;
9472  }
9473 
9474  *nupgdconss = 1;
9475  SCIP_CALL( SCIPcreateConsQuadratic(scip, &upgdconss[0], SCIPconsGetName(cons),
9477  0, NULL, 0, NULL,
9478  SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
9482  assert(!SCIPconsIsStickingAtNode(cons));
9483 
9484  exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
9485 
9486  /* add variables from expression tree as "quadratic" variables to quadratic constraint */
9487  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
9488  {
9489  assert(SCIPexprgraphGetNodeChildren(node)[i] != NULL);
9490  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, upgdconss[0], (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[i]), 0.0, 0.0) );
9491  }
9492 
9493  switch( SCIPexprgraphGetNodeOperator(node) )
9494  {
9495  case SCIP_EXPR_MUL:
9496  /* expression is product of two variables, so add bilinear term to constraint */
9497  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
9498 
9499  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
9502  1.0) );
9503 
9504  break;
9505 
9506  case SCIP_EXPR_SQUARE:
9507  /* expression is square of a variable, so change square coefficient of quadratic variable */
9508  assert(SCIPexprgraphGetNodeNChildren(node) == 1);
9509 
9510  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
9512  1.0) );
9513 
9514  break;
9515 
9516  case SCIP_EXPR_QUADRATIC:
9517  {
9518  /* expression is quadratic */
9519  SCIP_QUADELEM* quadelems;
9520  int nquadelems;
9521  SCIP_Real* lincoefs;
9522 
9524  nquadelems = SCIPexprgraphGetNodeQuadraticNQuadElements(node);
9526 
9528 
9529  if( lincoefs != NULL )
9530  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
9531  if( lincoefs[i] != 0.0 )
9532  {
9533  /* linear term */
9534  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, upgdconss[0],
9536  lincoefs[i]) );
9537  }
9538 
9539  for( i = 0; i < nquadelems; ++i )
9540  {
9541  assert(quadelems[i].idx1 < SCIPexprgraphGetNodeNChildren(node));
9542  assert(quadelems[i].idx2 < SCIPexprgraphGetNodeNChildren(node));
9543 
9544  if( quadelems[i].idx1 == quadelems[i].idx2 )
9545  {
9546  /* square term */
9547  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
9548  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
9549  quadelems[i].coef) );
9550  }
9551  else
9552  {
9553  /* bilinear term */
9554  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
9555  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
9556  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx2]),
9557  quadelems[i].coef) );
9558  }
9559  }
9560 
9561  break;
9562  }
9563 
9564  default:
9565  SCIPerrorMessage("you should not be here\n");
9566  return SCIP_ERROR;
9567  } /*lint !e788 */
9568 
9569  return SCIP_OKAY;
9570 }
9571 
9572 /*
9573  * Callback methods of constraint handler
9574  */
9575 
9576 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
9577 static
9578 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
9579 { /*lint --e{715}*/
9580  assert(scip != NULL);
9581  assert(conshdlr != NULL);
9582  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
9583 
9584  /* call inclusion method of constraint handler */
9586 
9587  *valid = TRUE;
9588 
9589  return SCIP_OKAY;
9590 }
9591 
9592 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
9593 static
9594 SCIP_DECL_CONSFREE(consFreeQuadratic)
9596  SCIP_CONSHDLRDATA* conshdlrdata;
9597  int i;
9598 
9599  assert(scip != NULL);
9600  assert(conshdlr != NULL);
9601 
9602  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9603  assert(conshdlrdata != NULL);
9604 
9605  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
9606  {
9607  assert(conshdlrdata->quadconsupgrades[i] != NULL);
9608  SCIPfreeMemory(scip, &conshdlrdata->quadconsupgrades[i]);
9609  }
9610  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->quadconsupgrades);
9611 
9612  SCIPfreeMemory(scip, &conshdlrdata);
9613 
9614  return SCIP_OKAY;
9615 }
9616 
9617 /** initialization method of constraint handler (called after problem was transformed) */
9618 static
9619 SCIP_DECL_CONSINIT(consInitQuadratic)
9620 { /*lint --e{715} */
9621  SCIP_CONSHDLRDATA* conshdlrdata;
9622  int c;
9623 
9624  assert(scip != NULL);
9625  assert(conshdlr != NULL);
9626 
9627  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9628  assert(conshdlrdata != NULL);
9629 
9630  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
9631  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
9632 
9633  /* catch variable events */
9634  for( c = 0; c < nconss; ++c )
9635  {
9636  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[c]) );
9637  }
9638 
9639  return SCIP_OKAY;
9640 }
9641 
9642 
9643 /** deinitialization method of constraint handler (called before transformed problem is freed) */
9644 static
9645 SCIP_DECL_CONSEXIT(consExitQuadratic)
9646 { /*lint --e{715} */
9647  SCIP_CONSHDLRDATA* conshdlrdata;
9648  int c;
9649 
9650  assert(scip != NULL);
9651  assert(conshdlr != NULL);
9652 
9653  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9654  assert(conshdlrdata != NULL);
9655 
9656  /* drop variable events */
9657  for( c = 0; c < nconss; ++c )
9658  {
9659  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, conss[c]) );
9660  }
9661 
9662  conshdlrdata->subnlpheur = NULL;
9663  conshdlrdata->trysolheur = NULL;
9664 
9665  return SCIP_OKAY;
9666 }
9667 
9668 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
9669 #if 0
9670 static
9671 SCIP_DECL_CONSINITPRE(consInitpreQuadratic)
9672 { /*lint --e{715}*/
9673  SCIP_CONSHDLRDATA* conshdlrdata;
9674  SCIP_CONSDATA* consdata;
9675  int c;
9676 
9677  assert(scip != NULL);
9678  assert(conshdlr != NULL);
9679  assert(conss != NULL || nconss == 0);
9680 
9681  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9682  assert(conshdlrdata != NULL);
9683 
9684  return SCIP_OKAY;
9685 }
9686 #endif
9687 
9688 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
9689 static
9690 SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
9691 { /*lint --e{715}*/
9692  SCIP_CONSDATA* consdata;
9693  int c;
9694 #ifndef NDEBUG
9695  int i;
9696 #endif
9697 
9698  assert(scip != NULL);
9699  assert(conshdlr != NULL);
9700  assert(conss != NULL || nconss == 0);
9701 
9702  for( c = 0; c < nconss; ++c )
9703  {
9704  assert(conss != NULL);
9705  consdata = SCIPconsGetData(conss[c]);
9706  assert(consdata != NULL);
9707 
9708  if( !consdata->isremovedfixings )
9709  {
9710  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
9711  }
9712 
9713  /* make sure we do not have duplicate bilinear terms, quad var terms, or linear vars */
9714  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
9715  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
9716  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
9717 
9718  assert(consdata->isremovedfixings);
9719  assert(consdata->linvarsmerged);
9720  assert(consdata->quadvarsmerged);
9721  assert(consdata->bilinmerged);
9722 
9723 #ifndef NDEBUG
9724  for( i = 0; i < consdata->nlinvars; ++i )
9725  assert(SCIPvarIsActive(consdata->linvars[i]));
9726 
9727  for( i = 0; i < consdata->nquadvars; ++i )
9728  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
9729 #endif
9730 
9731  /* tell SCIP that we have something nonlinear */
9732  if( SCIPconsIsAdded(conss[c]) && consdata->nquadvars > 0 )
9733  SCIPenableNLP(scip);
9734  }
9735 
9736  return SCIP_OKAY;
9737 }
9738 
9739 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin)
9740  *
9741  * NOTE: also called from SCIPcreateConsQuadratic(2) during solving stage
9742  */
9743 static
9744 SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
9746  SCIP_CONSHDLRDATA* conshdlrdata;
9747  SCIP_CONSDATA* consdata;
9748  int c;
9749  int i;
9750 
9751  assert(scip != NULL);
9752  assert(conshdlr != NULL);
9753  assert(conss != NULL || nconss == 0);
9754 
9755  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9756  assert(conshdlrdata != NULL);
9757 
9758  for( c = 0; c < nconss; ++c )
9759  {
9760  assert(conss != NULL);
9761  consdata = SCIPconsGetData(conss[c]);
9762  assert(consdata != NULL);
9763 
9764  /* check for a linear variable that can be increase or decreased without harming feasibility */
9765  consdataFindUnlockedLinearVar(scip, consdata);
9766 
9767  /* setup lincoefsmin, lincoefsmax */
9768  consdata->lincoefsmin = SCIPinfinity(scip);
9769  consdata->lincoefsmax = 0.0;
9770  for( i = 0; i < consdata->nlinvars; ++i )
9771  {
9772  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666 */
9773  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666 */
9774  }
9775 
9776  /* add nlrow representation to NLP, if NLP had been constructed */
9777  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
9778  {
9779  if( consdata->nlrow == NULL )
9780  {
9781  SCIP_CALL( createNlRow(scip, conss[c]) );
9782  assert(consdata->nlrow != NULL);
9783  }
9784  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
9785  }
9786 
9787  /* setup sepaquadvars and sepabilinvar2pos */
9788  assert(consdata->sepaquadvars == NULL);
9789  assert(consdata->sepabilinvar2pos == NULL);
9790  if( consdata->nquadvars > 0 )
9791  {
9792  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepaquadvars, consdata->nquadvars) );
9793  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms) );
9794 
9795  /* make sure, quadratic variable terms are sorted */
9796  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
9797 
9798  for( i = 0; i < consdata->nquadvars; ++i )
9799  consdata->sepaquadvars[i] = consdata->quadvarterms[i].var;
9800 
9801  for( i = 0; i < consdata->nbilinterms; ++i )
9802  {
9803  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &consdata->sepabilinvar2pos[i]) );
9804  }
9805  }
9806 
9807  if( conshdlrdata->checkfactorable )
9808  {
9809  /* check if constraint function is factorable, i.e., can be written as product of two linear functions */
9810  SCIP_CALL( checkFactorable(scip, conss[c]) );
9811  }
9812  }
9813 
9814  conshdlrdata->newsoleventfilterpos = -1;
9815  if( nconss != 0 && conshdlrdata->linearizeheursol )
9816  {
9817  SCIP_EVENTHDLR* eventhdlr;
9818 
9819  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
9820  assert(eventhdlr != NULL);
9821 
9822  /* @todo Should we catch every new solution or only new *best* solutions */
9823  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
9824  }
9825 
9826  if( nconss != 0 && !SCIPisIpoptAvailableIpopt() && !SCIPisInRestart(scip) )
9827  {
9828  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");
9829  }
9830 
9831  /* reset flags and counters */
9832  conshdlrdata->sepanlp = FALSE;
9833  conshdlrdata->lastenfolpnode = NULL;
9834  conshdlrdata->nenfolprounds = 0;
9835 
9836  return SCIP_OKAY;
9837 }
9838 
9839 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
9840 static
9841 SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
9842 { /*lint --e{715}*/
9843  SCIP_CONSHDLRDATA* conshdlrdata;
9844  SCIP_CONSDATA* consdata;
9845  int c;
9846 
9847  assert(scip != NULL);
9848  assert(conshdlr != NULL);
9849  assert(conss != NULL || nconss == 0);
9850 
9851  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9852  assert(conshdlrdata != NULL);
9853 
9854  if( conshdlrdata->newsoleventfilterpos >= 0 )
9855  {
9856  SCIP_EVENTHDLR* eventhdlr;
9857 
9858  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
9859  assert(eventhdlr != NULL);
9860 
9861  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
9862  conshdlrdata->newsoleventfilterpos = -1;
9863  }
9864 
9865  for( c = 0; c < nconss; ++c )
9866  {
9867  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
9868  assert(consdata != NULL);
9869 
9870  /* free nonlinear row representation */
9871  if( consdata->nlrow != NULL )
9872  {
9873  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
9874  }
9875 
9876  assert(consdata->sepaquadvars != NULL || consdata->nquadvars == 0);
9877  assert(consdata->sepabilinvar2pos != NULL || consdata->nquadvars == 0);
9878  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepaquadvars, consdata->nquadvars);
9879  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms);
9880 
9881  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorleft, consdata->nquadvars + 1);
9882  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorright, consdata->nquadvars + 1);
9883  }
9884 
9885  return SCIP_OKAY;
9886 }
9887 
9888 /** frees specific constraint data */
9889 static
9890 SCIP_DECL_CONSDELETE(consDeleteQuadratic)
9892  SCIP_CONSHDLRDATA* conshdlrdata;
9893 
9894  assert(scip != NULL);
9895  assert(conshdlr != NULL);
9896  assert(cons != NULL);
9897  assert(consdata != NULL);
9898  assert(SCIPconsGetData(cons) == *consdata);
9899 
9900  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9901  assert(conshdlrdata != NULL);
9902 
9903  if( SCIPconsIsTransformed(cons) )
9904  {
9905  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
9906  }
9907 
9908  SCIP_CALL( consdataFree(scip, consdata) );
9909 
9910  assert(*consdata == NULL);
9911 
9912  return SCIP_OKAY;
9913 }
9914 
9915 /** transforms constraint data into data belonging to the transformed problem */
9916 static
9917 SCIP_DECL_CONSTRANS(consTransQuadratic)
9918 {
9919  SCIP_CONSDATA* sourcedata;
9920  SCIP_CONSDATA* targetdata;
9921  int i;
9922 
9923  sourcedata = SCIPconsGetData(sourcecons);
9924  assert(sourcedata != NULL);
9925 
9926  SCIP_CALL( consdataCreate(scip, &targetdata,
9927  sourcedata->lhs, sourcedata->rhs,
9928  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
9929  sourcedata->nquadvars, sourcedata->quadvarterms,
9930  sourcedata->nbilinterms, sourcedata->bilinterms,
9931  FALSE) );
9932 
9933  for( i = 0; i < targetdata->nlinvars; ++i )
9934  {
9935  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
9936  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
9937  }
9938 
9939  for( i = 0; i < targetdata->nquadvars; ++i )
9940  {
9941  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->quadvarterms[i].var, &targetdata->quadvarterms[i].var) );
9942  SCIP_CALL( SCIPcaptureVar(scip, targetdata->quadvarterms[i].var) );
9943  }
9944 
9945  for( i = 0; i < targetdata->nbilinterms; ++i )
9946  {
9947  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var1, &targetdata->bilinterms[i].var1) );
9948  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var2, &targetdata->bilinterms[i].var2) );
9949 
9950  if( SCIPvarCompare(targetdata->bilinterms[i].var1, targetdata->bilinterms[i].var2) > 0 )
9951  {
9952  SCIP_VAR* tmp;
9953  tmp = targetdata->bilinterms[i].var2;
9954  targetdata->bilinterms[i].var2 = targetdata->bilinterms[i].var1;
9955  targetdata->bilinterms[i].var1 = tmp;
9956  }
9957  }
9958 
9959  /* create target constraint */
9960  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
9961  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
9962  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
9963  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
9964  SCIPconsIsStickingAtNode(sourcecons)) );
9965 
9966  SCIPdebugMessage("created transformed quadratic constraint ");
9967  SCIPdebugPrintCons(scip, *targetcons, NULL);
9968 
9969  return SCIP_OKAY;
9970 }
9971 
9972 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
9973 static
9974 SCIP_DECL_CONSINITLP(consInitlpQuadratic)
9976  SCIP_CONSHDLRDATA* conshdlrdata;
9977  SCIP_CONSDATA* consdata;
9978  SCIP_VAR* var;
9979  SCIP_ROW* row;
9980  SCIP_Real* x;
9981  int c;
9982  int i;
9983 
9984  assert(scip != NULL);
9985  assert(conshdlr != NULL);
9986  assert(conss != NULL || nconss == 0);
9987 
9988  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9989  assert(conshdlrdata != NULL);
9990 
9991  for( c = 0; c < nconss; ++c )
9992  {
9993  assert(conss[c] != NULL); /*lint !e613 */
9994 
9995  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
9996 
9997  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
9998  assert(consdata != NULL);
9999 
10000  row = NULL;
10001 
10002  if( consdata->nquadvars == 0 )
10003  {
10004  SCIP_Bool infeasible;
10005 
10006  /* if we are actually linear, add the constraint as row to the LP */
10007  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
10008  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613 */
10009  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
10010  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
10011  assert( ! infeasible );
10012  SCIP_CALL( SCIPreleaseRow (scip, &row) );
10013  continue;
10014  }
10015 
10016  /* alloc memory for reference point */
10017  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nquadvars) );
10018 
10019  /* for convex parts, add linearizations in 5 points */
10020  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
10021  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
10022  {
10023  SCIP_Real lb;
10024  SCIP_Real ub;
10025  SCIP_Real lambda;
10026  int k;
10027 
10028  for( k = 0; k < 5; ++k )
10029  {
10030  lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
10031  for( i = 0; i < consdata->nquadvars; ++i )
10032  {
10033  var = consdata->quadvarterms[i].var;
10034  lb = SCIPvarGetLbGlobal(var);
10035  ub = SCIPvarGetUbGlobal(var);
10036 
10037  if( ub > -INITLPMAXVARVAL )
10038  lb = MAX(lb, -INITLPMAXVARVAL);
10039  if( lb < INITLPMAXVARVAL )
10040  ub = MIN(ub, INITLPMAXVARVAL);
10041 
10042  /* make bounds finite */
10043  if( SCIPisInfinity(scip, -lb) )
10044  lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
10045  if( SCIPisInfinity(scip, ub) )
10046  ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
10047 
10049  x[i] = lambda * ub + (1.0 - lambda) * lb;
10050  else
10051  x[i] = lambda * lb + (1.0 - lambda) * ub;
10052  }
10053 
10054  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, consdata->isconvex ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT, &row, NULL, FALSE, -SCIPinfinity(scip)) ); /*lint !e613 */
10055  if( row != NULL )
10056  {
10057  SCIP_Bool infeasible;
10058 
10059  SCIPdebugMessage("initlp adds row <%s> for lambda = %g of conss <%s>\n", SCIProwGetName(row), lambda, SCIPconsGetName(conss[c])); /*lint !e613 */
10060  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
10061 
10062  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
10063  assert( ! infeasible );
10064 
10065  SCIP_CALL( SCIPreleaseRow (scip, &row) );
10066  }
10067  }
10068  }
10069 
10070  /* for concave parts, add underestimator w.r.t. at most 2 reference points */
10071  if( (!consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
10072  (!consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
10073  {
10074  SCIP_Bool unbounded;
10075  SCIP_Bool possquare;
10076  SCIP_Bool negsquare;
10077  SCIP_Real lb;
10078  SCIP_Real ub;
10079  SCIP_Real lambda;
10080  int k;
10081 
10082  unbounded = FALSE; /* whether there are unbounded variables */
10083  possquare = FALSE; /* whether there is a positive square term */
10084  negsquare = FALSE; /* whether there is a negative square term */
10085  for( k = 0; k < 2; ++k )
10086  {
10087  /* set reference point to 0 projected on bounds for unbounded variables or in between lower and upper bound for bounded variables
10088  * in the first round, we set it closer to the best bound for one part of the variables, in the second closer to the best bound for the other part of the variables
10089  * additionally, we use slightly different weights for each variable
10090  * the reason for the latter is, that for a bilinear term with bounded variables, there are always two linear underestimators
10091  * if the same weight is used for both variables of a product, then rounding and luck decides which underestimator is chosen
10092  * of course, the possible number of cuts is something in the order of 2^nquadvars, and we choose two of them here
10093  */
10094  for( i = 0; i < consdata->nquadvars; ++i )
10095  {
10096  var = consdata->quadvarterms[i].var;
10097  lb = SCIPvarGetLbGlobal(var);
10098  ub = SCIPvarGetUbGlobal(var);
10099 
10100  if( SCIPisInfinity(scip, -lb) )
10101  {
10102  if( SCIPisInfinity(scip, ub) )
10103  x[i] = 0.0;
10104  else
10105  x[i] = MIN(0.0, ub);
10106  unbounded = TRUE;
10107  }
10108  else
10109  {
10110  if( SCIPisInfinity(scip, ub) )
10111  {
10112  x[i] = MAX(0.0, lb);
10113  unbounded = TRUE;
10114  }
10115  else
10116  {
10117  lambda = 0.4 + 0.2 * ((i+k)%2) + 0.01 * i / (double)consdata->nquadvars;
10118  x[i] = lambda * SCIPvarGetBestBoundLocal(var) + (1.0-lambda) * SCIPvarGetWorstBoundLocal(var);
10119  }
10120  }
10121 
10122  possquare |= consdata->quadvarterms[i].sqrcoef > 0.0; /*lint !e514 */
10123  negsquare |= consdata->quadvarterms[i].sqrcoef < 0.0; /*lint !e514 */
10124  }
10125 
10126  if( !consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
10127  {
10128  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_RIGHT, &row, NULL, conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
10129  if( row != NULL )
10130  {
10131  SCIP_Bool infeasible;
10132 
10133  SCIPdebugMessage("initlp adds row <%s> for rhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
10134  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
10135 
10136  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
10137  assert( ! infeasible );
10138 
10139  SCIP_CALL( SCIPreleaseRow (scip, &row) );
10140  }
10141  }
10142  if( !consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
10143  {
10144  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_LEFT, &row, NULL, conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
10145  if( row != NULL )
10146  {
10147  SCIP_Bool infeasible;
10148 
10149  SCIPdebugMessage("initlp adds row <%s> for lhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
10150  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
10151 
10152  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
10153  assert( ! infeasible );
10154 
10155  SCIP_CALL( SCIPreleaseRow (scip, &row) );
10156  }
10157  }
10158 
10159  /* if there are unbounded variables, then there is typically only at most one possible underestimator, so don't try another round
10160  * 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 */
10161  if( unbounded ||
10162  (consdata->nbilinterms == 0 && (!possquare || SCIPisInfinity(scip, consdata->rhs))) ||
10163  (consdata->nbilinterms == 0 && (!negsquare || SCIPisInfinity(scip, -consdata->lhs))) )
10164  break;
10165  }
10166  }
10167 
10168  SCIPfreeBufferArray(scip, &x);
10169  }
10170 
10171  return SCIP_OKAY;
10172 }
10173 
10174 /** separation method of constraint handler for LP solutions */
10175 static
10176 SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
10177 {
10178  SCIP_CONSHDLRDATA* conshdlrdata;
10179  SCIP_CONS* maxviolcon;
10180 
10181  assert(scip != NULL);
10182  assert(conshdlr != NULL);
10183  assert(conss != NULL || nconss == 0);
10184  assert(result != NULL);
10185 
10186  *result = SCIP_DIDNOTFIND;
10187 
10188  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10189  assert(conshdlrdata != NULL);
10190 
10191  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
10192  if( maxviolcon == NULL )
10193  return SCIP_OKAY;
10194 
10195  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
10196  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
10197  */
10198  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
10199  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) || (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
10200  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
10201  {
10202  SCIP_CONSDATA* consdata;
10203  SCIP_NLPSOLSTAT solstat;
10204  SCIP_Bool solvednlp;
10205  int c;
10206 
10207  solstat = SCIPgetNLPSolstat(scip);
10208  solvednlp = FALSE;
10209  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
10210  {
10211  /* NLP is not solved yet, so we might want to do this
10212  * but first check whether there is a violated constraint side which corresponds to a convex function
10213  */
10214  for( c = 0; c < nconss; ++c )
10215  {
10216  assert(conss[c] != NULL); /*lint !e613 */
10217 
10218  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
10219  assert(consdata != NULL);
10220 
10221  /* skip feasible constraints */
10222  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10223  continue;
10224 
10225  /* make sure curvature has been checked */
10226  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
10227 
10228  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->isconvex) ||
10229  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->isconcave) )
10230  break;
10231  }
10232 
10233  if( c < nconss )
10234  {
10235  /* try to solve NLP and update solstat */
10236 
10237  /* ensure linear conss are in NLP */
10238  if( conshdlrdata->subnlpheur != NULL )
10239  {
10240  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
10241  }
10242 
10243  /* set LP solution as starting values, if available */
10245  {
10247  }
10248 
10249  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
10250  SCIP_CALL( SCIPsolveNLP(scip) );
10251 
10252  solstat = SCIPgetNLPSolstat(scip);
10253  SCIPdebugMessage("solved NLP relax, solution status: %d\n", solstat);
10254 
10255  solvednlp = TRUE;
10256  }
10257  }
10258 
10259  conshdlrdata->sepanlp = TRUE;
10260 
10261  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
10262  {
10263  SCIPdebugMessage("NLP relaxation is globally infeasible, thus can cutoff node\n");
10264  *result = SCIP_CUTOFF;
10265  return SCIP_OKAY;
10266  }
10267 
10268  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
10269  {
10270  /* if we have feasible NLP solution, generate linearization cuts there */
10271  SCIP_Bool lpsolseparated;
10272  SCIP_SOL* nlpsol;
10273 
10274  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
10275  assert(nlpsol != NULL);
10276 
10277  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
10278  if( solvednlp && conshdlrdata->trysolheur != NULL )
10279  {
10280  int nfracvars;
10281 
10282  nfracvars = 0;
10283  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
10284  {
10285  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
10286  }
10287 
10288  if( nfracvars == 0 )
10289  {
10290  SCIPdebugMessage("pass solution with obj. value %g to trysol\n", SCIPgetSolOrigObj(scip, nlpsol));
10291  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
10292  }
10293  }
10294 
10295  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, conshdlrdata->mincutefficacysepa) );
10296 
10297  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
10298 
10299  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
10300  if( lpsolseparated )
10301  {
10302  SCIPdebugMessage("linearization cuts separate LP solution\n");
10303  *result = SCIP_SEPARATED;
10304 
10305  return SCIP_OKAY;
10306  }
10307  }
10308  }
10309  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
10310  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
10311  */
10312 
10313  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
10314 
10315  return SCIP_OKAY;
10316 }
10317 
10318 /** separation method of constraint handler for arbitrary primal solutions */
10319 static
10320 SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
10322  SCIP_CONSHDLRDATA* conshdlrdata;
10323  SCIP_CONS* maxviolcon;
10324 
10325  assert(scip != NULL);
10326  assert(conshdlr != NULL);
10327  assert(conss != NULL || nconss == 0);
10328  assert(sol != NULL);
10329  assert(result != NULL);
10330 
10331  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10332  assert(conshdlrdata != NULL);
10333 
10334  *result = SCIP_DIDNOTFIND;
10335 
10336  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &maxviolcon) );
10337  if( maxviolcon == NULL )
10338  return SCIP_OKAY;
10339 
10340  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
10341 
10342  return SCIP_OKAY;
10343 }
10344 
10345 /** constraint enforcing method of constraint handler for LP solutions */
10346 static
10347 SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
10348 { /*lint --e{715}*/
10349  SCIP_CONSHDLRDATA* conshdlrdata;
10350  SCIP_CONSDATA* consdata;
10351  SCIP_CONS* maxviolcon;
10352  SCIP_Real maxviol;
10353  SCIP_RESULT propresult;
10354  SCIP_RESULT separateresult;
10355  int nchgbds;
10356  int nnotify;
10357  SCIP_Real sepaefficacy;
10358  SCIP_Real minefficacy;
10359  SCIP_Real leastpossibleefficacy;
10360 
10361  assert(scip != NULL);
10362  assert(conshdlr != NULL);
10363  assert(conss != NULL || nconss == 0);
10364 
10365  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10366  assert(conshdlrdata != NULL);
10367 
10368  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
10369  if( maxviolcon == NULL )
10370  {
10371  *result = SCIP_FEASIBLE;
10372  return SCIP_OKAY;
10373  }
10374 
10375  *result = SCIP_INFEASIBLE;
10376 
10377  consdata = SCIPconsGetData(maxviolcon);
10378  assert(consdata != NULL);
10379  maxviol = consdata->lhsviol + consdata->rhsviol;
10380  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
10381 
10382  SCIPdebugMessage("enfolp with max violation %g in cons <%s>\n", maxviol, SCIPconsGetName(maxviolcon));
10383 
10384  /* if we are above the 100'th enforcement round for this node, something is strange
10385  * (maybe the LP does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
10386  * 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
10387  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
10388  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
10389  * we only increment nenfolprounds until 101 to avoid an overflow
10390  */
10391  if( conshdlrdata->lastenfolpnode == SCIPgetCurrentNode(scip) )
10392  {
10393  if( conshdlrdata->nenfolprounds > 100 )
10394  {
10395  if( SCIPisStopped(scip) )
10396  {
10397  SCIP_NODE* child;
10398 
10399  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
10400  *result = SCIP_BRANCHED;
10401 
10402  return SCIP_OKAY;
10403  }
10404  }
10405 
10406  ++conshdlrdata->nenfolprounds;
10407 
10408  /* cut off the current subtree, if a limit on the enforcement rounds should be applied. At this point, feasible
10409  * solutions might get cut off; the enfolplimit parameter should therefore only be set if SCIP is used as a
10410  * heuristic solver and when the returned result (infeasible, optimal, the gap) can be ignored
10411  */
10412  if( conshdlrdata->enfolplimit != -1 && conshdlrdata->nenfolprounds > conshdlrdata->enfolplimit )
10413  {
10415  "cut off subtree because enforcement limit was reached; this might lead to incorrect results\n");
10416  *result = SCIP_CUTOFF;
10417  return SCIP_OKAY;
10418  }
10419  }
10420  else
10421  {
10422  conshdlrdata->lastenfolpnode = SCIPgetCurrentNode(scip);
10423  conshdlrdata->nenfolprounds = 0;
10424  }
10425 
10426  /* run domain propagation */
10427  nchgbds = 0;
10428  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
10429  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
10430  {
10431  SCIPdebugMessage("propagation succeeded (%s)\n", propresult == SCIP_CUTOFF ? "cutoff" : "reduceddom");
10432  *result = propresult;
10433  return SCIP_OKAY;
10434  }
10435 
10436  /* we would like a cut that is efficient enough that it is not redundant in the LP (>feastol)
10437  * however, if the maximal violation is very small, also the best cut efficacy cannot be large
10438  * thus, in the latter case, we are also happy if the efficacy is at least, say, 75% of the maximal violation
10439  * but in any case we need an efficacy that is at least feastol
10440  */
10441  minefficacy = MIN(0.75*maxviol, conshdlrdata->mincutefficacyenfofac * SCIPfeastol(scip)); /*lint !e666 */
10442  minefficacy = MAX(minefficacy, SCIPfeastol(scip)); /*lint !e666 */
10443  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, minefficacy, TRUE, &separateresult, &sepaefficacy) );
10444  if( separateresult == SCIP_CUTOFF )
10445  {
10446  SCIPdebugMessage("separation found cutoff\n");
10447  *result = SCIP_CUTOFF;
10448  return SCIP_OKAY;
10449  }
10450  if( separateresult == SCIP_SEPARATED )
10451  {
10452  SCIPdebugMessage("separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, minefficacy);
10453  *result = SCIP_SEPARATED;
10454  return SCIP_OKAY;
10455  }
10456 
10457  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
10458  * -> collect variables for branching
10459  */
10460 
10461  SCIPdebugMessage("separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, minefficacy, maxviol);
10462 
10463  /* find branching candidates */
10464  SCIP_CALL( registerVariableInfeasibilities(scip, conshdlr, conss, nconss, &nnotify) );
10465 
10466  /* if sepastore can decrease LP feasibility tolerance, we can add cuts with efficacy in [eps, feastol] */
10467  leastpossibleefficacy = SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip);
10468  if( nnotify == 0 && !solinfeasible && minefficacy > leastpossibleefficacy )
10469  {
10470  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
10471  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, leastpossibleefficacy, TRUE, &separateresult, &sepaefficacy) );
10472  if( separateresult == SCIP_CUTOFF )
10473  {
10474  SCIPdebugMessage("separation found cutoff\n");
10475  *result = SCIP_CUTOFF;
10476  return SCIP_OKAY;
10477  }
10478  if( separateresult == SCIP_SEPARATED )
10479  {
10480  SCIPdebugMessage("separation fallback succeeded, efficacy = %g\n", sepaefficacy);
10481  *result = SCIP_SEPARATED;
10482  return SCIP_OKAY;
10483  }
10484  }
10485 
10486  if( nnotify == 0 && !solinfeasible )
10487  {
10488  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
10489  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
10490  */
10491  SCIP_VAR* brvar = NULL;
10492  SCIP_CALL( registerLargeLPValueVariableForBranching(scip, conss, nconss, &brvar) );
10493  if( brvar == NULL )
10494  {
10495  /* fallback 3: all quadratic variables seem to be fixed -> replace by linear constraint */
10496  SCIP_Bool addedcons;
10497  SCIP_Bool reduceddom;
10498  SCIP_Bool infeasible;
10499 
10500  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
10501  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
10502  * when it enforces the new constraints again and nothing resolves the infeasiblity that we declare here thus,
10503  * we only add them if considered violated, and otherwise claim the solution is feasible (but print a
10504  * warning) */
10505  if ( infeasible )
10506  *result = SCIP_CUTOFF;
10507  else if ( addedcons )
10508  *result = SCIP_CONSADDED;
10509  else if ( reduceddom )
10510  *result = SCIP_REDUCEDDOM;
10511  else
10512  {
10513  *result = SCIP_FEASIBLE;
10514  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
10515  assert(!SCIPisInfinity(scip, maxviol));
10516  }
10517  return SCIP_OKAY;
10518  }
10519  else
10520  {
10521  SCIPdebugMessage("Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
10522  SCIPvarGetName(brvar), SCIPgetSolVal(scip, NULL, brvar));
10523  nnotify = 1;
10524  }
10525  }
10526 
10527  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
10528  return SCIP_OKAY;
10529 }
10530 
10531 
10532 /** constraint enforcing method of constraint handler for pseudo solutions */
10533 static
10534 SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
10535 { /*lint --e{715}*/
10536  SCIP_CONS* maxviolcon;
10537  SCIP_CONSDATA* consdata;
10538  SCIP_RESULT propresult;
10539  SCIP_VAR* var;
10540  int c;
10541  int i;
10542  int nchgbds;
10543  int nnotify;
10544 
10545  assert(scip != NULL);
10546  assert(conss != NULL || nconss == 0);
10547 
10548  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
10549  if( maxviolcon == NULL )
10550  {
10551  *result = SCIP_FEASIBLE;
10552  return SCIP_OKAY;
10553  }
10554 
10555  *result = SCIP_INFEASIBLE;
10556 
10557  SCIPdebugMessage("enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcon));
10558 
10559  /* run domain propagation */
10560  nchgbds = 0;
10561  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
10562  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
10563  {
10564  *result = propresult;
10565  return SCIP_OKAY;
10566  }
10567 
10568  /* we are not feasible and we cannot proof that the whole node is infeasible
10569  * -> collect all variables in violated constraints for branching
10570  */
10571  nnotify = 0;
10572  for( c = 0; c < nconss; ++c )
10573  {
10574  assert(conss != NULL);
10575  consdata = SCIPconsGetData(conss[c]);
10576  assert(consdata != NULL);
10577 
10578  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10579  continue;
10580 
10581  for( i = 0; i < consdata->nlinvars; ++i )
10582  {
10583  var = consdata->linvars[i];
10584  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10585  {
10586  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
10587  ++nnotify;
10588  }
10589  }
10590 
10591  for( i = 0; i < consdata->nquadvars; ++i )
10592  {
10593  var = consdata->quadvarterms[i].var;
10594  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10595  {
10596  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
10597  ++nnotify;
10598  }
10599  }
10600  }
10601 
10602  if( nnotify == 0 )
10603  {
10604  SCIPdebugMessage("All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
10605  *result = SCIP_SOLVELP;
10606  }
10607 
10608  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
10609  return SCIP_OKAY;
10610 }
10611 
10612 /** domain propagation method of constraint handler */
10613 static
10614 SCIP_DECL_CONSPROP(consPropQuadratic)
10616  int nchgbds;
10617 
10618  assert(scip != NULL);
10619  assert(conshdlr != NULL);
10620  assert(conss != NULL || nconss == 0);
10621  assert(result != NULL);
10622 
10623  nchgbds = 0;
10624  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, result, &nchgbds) );
10625 
10626  return SCIP_OKAY;
10627 } /*lint !e715 */
10628 
10629 /** presolving method of constraint handler */
10630 static
10631 SCIP_DECL_CONSPRESOL(consPresolQuadratic)
10632 { /*lint --e{715,788}*/
10633  SCIP_CONSHDLRDATA* conshdlrdata;
10634  SCIP_CONSDATA* consdata;
10635  SCIP_RESULT solveresult;
10636  SCIP_Bool redundant;
10637  SCIP_Bool havechange;
10638  SCIP_Bool doreformulations;
10639  int c;
10640  int i;
10641 
10642  assert(scip != NULL);
10643  assert(conshdlr != NULL);
10644  assert(conss != NULL || nconss == 0);
10645  assert(result != NULL);
10646 
10647  *result = SCIP_DIDNOTFIND;
10648 
10649  /* if other presolvers did not find enough changes for another presolving round,
10650  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
10651  * otherwise, we wait with these
10652  * @todo first do all usual presolving steps, then check SCIPisPresolveFinished(scip), and if true then do reformulations (and usual steps again)
10653  */
10654  doreformulations = (nrounds > 0 || SCIPconshdlrWasPresolvingDelayed(conshdlr)) && SCIPisPresolveFinished(scip);
10655  SCIPdebugMessage("presolving will %swait with reformulation\n", doreformulations ? "not " : "");
10656 
10657  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10658  assert(conshdlrdata != NULL);
10659 
10660  for( c = 0; c < nconss; ++c )
10661  {
10662  assert(conss != NULL);
10663  consdata = SCIPconsGetData(conss[c]);
10664  assert(consdata != NULL);
10665 
10666  SCIPdebugMessage("process constraint <%s>\n", SCIPconsGetName(conss[c]));
10667  SCIPdebugPrintCons(scip, conss[c], NULL);
10668 
10669  if( !consdata->initialmerge )
10670  {
10671  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
10672  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
10673  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
10674  consdata->initialmerge = TRUE;
10675  }
10676 
10677  havechange = FALSE;
10678 #ifdef CHECKIMPLINBILINEAR
10679  if( consdata->isimpladded )
10680  {
10681  int nbilinremoved;
10682  SCIP_CALL( presolveApplyImplications(scip, conss[c], &nbilinremoved) );
10683  if( nbilinremoved > 0 )
10684  {
10685  *nchgcoefs += nbilinremoved;
10686  havechange = TRUE;
10687  *result = SCIP_SUCCESS;
10688  }
10689  assert(!consdata->isimpladded);
10690  }
10691 #endif
10692  /* 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
10693  * we want to do this before (multi)aggregated variables are replaced, since that may change structure, e.g., introduce bilinear terms
10694  */
10695  if( !consdata->ispresolved || !consdata->ispropagated || nnewchgvartypes > 0 )
10696  {
10697  SCIP_Bool upgraded;
10698 
10699  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10700  if( upgraded )
10701  {
10702  *result = SCIP_SUCCESS;
10703  continue;
10704  }
10705  }
10706 
10707  if( !consdata->isremovedfixings )
10708  {
10709  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
10710  assert(consdata->isremovedfixings);
10711  havechange = TRUE;
10712  }
10713 
10714  /* try to "solve" the constraint, e.g., reduce to a variable aggregation */
10715  SCIP_CALL( presolveSolve(scip, conss[c], &solveresult, &redundant, naggrvars) );
10716  if( solveresult == SCIP_CUTOFF )
10717  {
10718  SCIPdebugMessage("solving constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
10719  *result = SCIP_CUTOFF;
10720  return SCIP_OKAY;
10721  }
10722  if( redundant )
10723  {
10724  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, conss[c]) );
10725  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
10726  ++*ndelconss;
10727  *result = SCIP_SUCCESS;
10728  break;
10729  }
10730  if( solveresult == SCIP_SUCCESS )
10731  {
10732  *result = SCIP_SUCCESS;
10733  havechange = TRUE;
10734  }
10735 
10736  /* @todo divide constraint by gcd of coefficients if all are integral */
10737 
10738  if( doreformulations )
10739  {
10740  int naddconss_old;
10741 
10742  naddconss_old = *naddconss;
10743 
10744  SCIP_CALL( presolveTryAddAND(scip, conshdlr, conss[c], naddconss) );
10745  assert(*naddconss >= naddconss_old);
10746 
10747  if( *naddconss == naddconss_old )
10748  {
10749  /* user not so empathic about AND, or we don't have products of two binaries, so try this more general reformulation */
10750  SCIP_CALL( presolveTryAddLinearReform(scip, conshdlr, conss[c], naddconss) );
10751  assert(*naddconss >= naddconss_old);
10752  }
10753 
10754  if( conshdlrdata->disaggregate )
10755  {
10756  /* try disaggregation, if enabled */
10757  SCIP_CALL( presolveDisaggregate(scip, conshdlr, conss[c], naddconss) );
10758  }
10759 
10760  if( *naddconss > naddconss_old )
10761  {
10762  /* if something happened, report success and cleanup constraint */
10763  *result = SCIP_SUCCESS;
10764  havechange = TRUE;
10765  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
10766  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
10767  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
10768  }
10769  }
10770 
10771  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
10772  {
10773  /* all variables fixed or removed, constraint function is 0.0 now */
10774  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, conss[c]) ); /* well, there shouldn't be any variables left anyway */
10775  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
10776  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
10777  { /* left hand side positive or right hand side negative */
10778  SCIPdebugMessage("constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
10779  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
10780  ++*ndelconss;
10781  *result = SCIP_CUTOFF;
10782  return SCIP_OKAY;
10783  }
10784 
10785  /* left and right hand side are consistent */
10786  SCIPdebugMessage("constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
10787  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
10788  ++*ndelconss;
10789  *result = SCIP_SUCCESS;
10790  continue;
10791  }
10792 
10793  if( !consdata->ispropagated )
10794  {
10795  /* try domain propagation if there were bound changes or constraint has changed (in which case, processVarEvents may have set ispropagated to false) */
10796  SCIP_RESULT propresult;
10797  int roundnr;
10798 
10799  roundnr = 0;
10800  do
10801  {
10802  ++roundnr;
10803 
10804  SCIPdebugMessage("starting domain propagation round %d of %d\n", roundnr, conshdlrdata->maxproproundspresolve);
10805 
10806  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
10807 
10808  if( propresult == SCIP_CUTOFF )
10809  {
10810  SCIPdebugMessage("propagation on constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
10811  *result = SCIP_CUTOFF;
10812  return SCIP_OKAY;
10813  }
10814 
10815  /* delete constraint if found redundant by bound tightening */
10816  if( redundant )
10817  {
10818  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, conss[c]) );
10819  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
10820  ++*ndelconss;
10821  *result = SCIP_SUCCESS;
10822  break;
10823  }
10824 
10825  if( propresult == SCIP_REDUCEDDOM )
10826  {
10827  *result = SCIP_SUCCESS;
10828  havechange = TRUE;
10829  }
10830 
10831  }
10832  while( !consdata->ispropagated && roundnr < conshdlrdata->maxproproundspresolve );
10833 
10834  if( redundant )
10835  continue;
10836  }
10837 
10838  /* check if we have a single linear continuous variable that we can make implicit integer */
10839  if( (nnewchgvartypes != 0 || havechange || !consdata->ispresolved)
10840  && (SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->lhs)) )
10841  {
10842  int ncontvar;
10843  SCIP_VAR* candidate;
10844  SCIP_Bool fail;
10845 
10846  fail = FALSE;
10847  candidate = NULL;
10848  ncontvar = 0;
10849 
10850  for( i = 0; !fail && i < consdata->nlinvars; ++i )
10851  {
10852  if( !SCIPisIntegral(scip, consdata->lincoefs[i]) )
10853  {
10854  fail = TRUE;
10855  }
10856  else if( SCIPvarGetType(consdata->linvars[i]) == SCIP_VARTYPE_CONTINUOUS )
10857  {
10858  if( ncontvar > 0 ) /* now at 2nd continuous variable */
10859  fail = TRUE;
10860  else if( SCIPisEQ(scip, ABS(consdata->lincoefs[i]), 1.0) )
10861  candidate = consdata->linvars[i];
10862  ++ncontvar;
10863  }
10864  }
10865  for( i = 0; !fail && i < consdata->nquadvars; ++i )
10866  fail = SCIPvarGetType(consdata->quadvarterms[i].var) == SCIP_VARTYPE_CONTINUOUS ||
10867  !SCIPisIntegral(scip, consdata->quadvarterms[i].lincoef) ||
10868  !SCIPisIntegral(scip, consdata->quadvarterms[i].sqrcoef);
10869  for( i = 0; !fail && i < consdata->nbilinterms; ++i )
10870  fail = !SCIPisIntegral(scip, consdata->bilinterms[i].coef);
10871 
10872  if( !fail && candidate != NULL )
10873  {
10874  SCIP_Bool infeasible;
10875 
10876  SCIPdebugMessage("make variable <%s> implicit integer due to constraint <%s>\n", SCIPvarGetName(candidate), SCIPconsGetName(conss[c]));
10877 
10878  SCIP_CALL( SCIPchgVarType(scip, candidate, SCIP_VARTYPE_IMPLINT, &infeasible) );
10879  if( infeasible )
10880  {
10881  SCIPdebugMessage("infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(candidate));
10882  *result = SCIP_CUTOFF;
10883 
10884  return SCIP_OKAY;
10885  }
10886 
10887  ++(*nchgvartypes);
10888  *result = SCIP_SUCCESS;
10889  havechange = TRUE;
10890  }
10891  }
10892 
10893  /* call upgrade methods again if constraint has been changed */
10894  if( havechange )
10895  {
10896  SCIP_Bool upgraded;
10897 
10898  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
10899  if( upgraded )
10900  {
10901  *result = SCIP_SUCCESS;
10902  continue;
10903  }
10904  }
10905 
10906  consdata->ispresolved = TRUE;
10907  }
10908 
10909  /* if we did not try reformulations, ensure that presolving is called again even if there were only a few changes (< abortfac) */
10910  if( !doreformulations )
10911  *result = SCIP_DELAYED;
10912 
10913  return SCIP_OKAY;
10914 }
10915 
10916 /** variable rounding lock method of constraint handler */
10917 static
10918 SCIP_DECL_CONSLOCK(consLockQuadratic)
10919 { /*lint --e{715}*/
10920  SCIP_CONSDATA* consdata;
10921  SCIP_Bool haslb;
10922  SCIP_Bool hasub;
10923  int i;
10924 
10925  assert(scip != NULL);
10926  assert(cons != NULL);
10927 
10928  consdata = SCIPconsGetData(cons);
10929  assert(consdata != NULL);
10930 
10931  haslb = !SCIPisInfinity(scip, -consdata->lhs);
10932  hasub = !SCIPisInfinity(scip, consdata->rhs);
10933 
10934  for( i = 0; i < consdata->nlinvars; ++i )
10935  {
10936  if( consdata->lincoefs[i] > 0 )
10937  {
10938  if( haslb )
10939  {
10940  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
10941  }
10942  if( hasub )
10943  {
10944  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
10945  }
10946  }
10947  else
10948  {
10949  if( haslb )
10950  {
10951  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
10952  }
10953  if( hasub )
10954  {
10955  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
10956  }
10957  }
10958  }
10959 
10960  for( i = 0; i < consdata->nquadvars; ++i )
10961  {
10962  /* @todo try to be more clever, but variable locks that depend on the bounds of other variables are not trival to maintain */
10963  SCIP_CALL( SCIPaddVarLocks(scip, consdata->quadvarterms[i].var, nlockspos+nlocksneg, nlockspos+nlocksneg) );
10964  }
10965 
10966  return SCIP_OKAY;
10967 }
10968 
10969 /** constraint display method of constraint handler */
10970 static
10971 SCIP_DECL_CONSPRINT(consPrintQuadratic)
10972 { /*lint --e{715}*/
10973  SCIP_CONSDATA* consdata;
10974 
10975  assert(scip != NULL);
10976  assert(cons != NULL);
10977 
10978  consdata = SCIPconsGetData(cons);
10979  assert(consdata != NULL);
10980 
10981  /* print left hand side for ranged rows */
10982  if( !SCIPisInfinity(scip, -consdata->lhs)
10983  && !SCIPisInfinity(scip, consdata->rhs)
10984  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10985  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
10986 
10987  /* print coefficients and variables */
10988  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
10989  {
10990  SCIPinfoMessage(scip, file, "0 ");
10991  }
10992  else
10993  {
10994  SCIP_VAR*** monomialvars;
10995  SCIP_Real** monomialexps;
10996  SCIP_Real* monomialcoefs;
10997  int* monomialnvars;
10998  int nmonomials;
10999  int monomialssize;
11000  int j;
11001 
11002  monomialssize = consdata->nlinvars + 2 * consdata->nquadvars + consdata->nbilinterms;
11003  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, monomialssize) );
11004  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps, monomialssize) );
11005  SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, monomialssize) );
11006  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, monomialssize) );
11007 
11008  nmonomials = 0;
11009  for( j = 0; j < consdata->nlinvars; ++j )
11010  {
11011  assert(nmonomials < monomialssize);
11012 
11013  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
11014 
11015  monomialvars[nmonomials][0] = consdata->linvars[j];
11016  monomialexps[nmonomials] = NULL;
11017  monomialcoefs[nmonomials] = consdata->lincoefs[j];
11018  monomialnvars[nmonomials] = 1;
11019  ++nmonomials;
11020  }
11021 
11022  for( j = 0; j < consdata->nquadvars; ++j )
11023  {
11024  if( consdata->quadvarterms[j].lincoef != 0.0 )
11025  {
11026  assert(nmonomials < monomialssize);
11027 
11028  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
11029 
11030  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
11031  monomialexps[nmonomials] = NULL;
11032  monomialcoefs[nmonomials] = consdata->quadvarterms[j].lincoef;
11033  monomialnvars[nmonomials] = 1;
11034  ++nmonomials;
11035  }
11036 
11037  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
11038  {
11039  assert(nmonomials < monomialssize);
11040 
11041  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
11042  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps[nmonomials], 1) ); /*lint !e866 */
11043 
11044  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
11045  monomialexps[nmonomials][0] = 2.0;
11046  monomialcoefs[nmonomials] = consdata->quadvarterms[j].sqrcoef;
11047  monomialnvars[nmonomials] = 1;
11048  ++nmonomials;
11049  }
11050  }
11051 
11052  for( j = 0; j < consdata->nbilinterms; ++j )
11053  {
11054  assert(nmonomials < monomialssize);
11055 
11056  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 2) ); /*lint !e866 */
11057 
11058  monomialvars[nmonomials][0] = consdata->bilinterms[j].var1;
11059  monomialvars[nmonomials][1] = consdata->bilinterms[j].var2;
11060  monomialexps[nmonomials] = NULL;
11061  monomialcoefs[nmonomials] = consdata->bilinterms[j].coef;
11062  monomialnvars[nmonomials] = 2;
11063  ++nmonomials;
11064  }
11065 
11066  SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, monomialexps, monomialcoefs, monomialnvars, nmonomials, TRUE) );
11067 
11068  for( j = 0; j < nmonomials; ++j )
11069  {
11070  SCIPfreeBufferArray(scip, &monomialvars[j]);
11071  SCIPfreeBufferArrayNull(scip, &monomialexps[j]);
11072  }
11073 
11074  SCIPfreeBufferArray(scip, &monomialvars);
11075  SCIPfreeBufferArray(scip, &monomialexps);
11076  SCIPfreeBufferArray(scip, &monomialcoefs);
11077  SCIPfreeBufferArray(scip, &monomialnvars);
11078  }
11079 
11080  /* print right hand side */
11081  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11082  {
11083  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
11084  }
11085  else if( !SCIPisInfinity(scip, consdata->rhs) )
11086  {
11087  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
11088  }
11089  else if( !SCIPisInfinity(scip, -consdata->lhs) )
11090  {
11091  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
11092  }
11093  else
11094  {
11095  /* should be ignored by parser */
11096  SCIPinfoMessage(scip, file, " [free]");
11097  }
11098 
11099  return SCIP_OKAY;
11100 }
11101 
11102 /** feasibility check method of constraint handler for integral solutions */
11103 static
11104 SCIP_DECL_CONSCHECK(consCheckQuadratic)
11105 { /*lint --e{715}*/
11106  SCIP_CONSHDLRDATA* conshdlrdata;
11107  SCIP_CONSDATA* consdata;
11108  SCIP_Real maxviol;
11109  int c;
11110  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
11111 
11112  assert(scip != NULL);
11113  assert(conss != NULL || nconss == 0);
11114  assert(result != NULL);
11115 
11116  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11117  assert(conshdlrdata != NULL);
11118 
11119  *result = SCIP_FEASIBLE;
11120 
11121  maxviol = 0.0;
11122  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
11124  for( c = 0; c < nconss; ++c )
11125  {
11126  assert(conss != NULL);
11127  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
11128 
11129  consdata = SCIPconsGetData(conss[c]);
11130  assert(consdata != NULL);
11131 
11132  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11133  {
11134  *result = SCIP_INFEASIBLE;
11135  if( printreason )
11136  {
11137  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11138  SCIPinfoMessage(scip, NULL, ";\n");
11139  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
11140  {
11141  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
11142  }
11143  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11144  {
11145  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
11146  }
11147  }
11148  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible )
11149  return SCIP_OKAY;
11150  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
11151  maxviol = consdata->lhsviol + consdata->rhsviol;
11152 
11153  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11154  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
11155  maypropfeasible = FALSE;
11156 
11157  if( maypropfeasible )
11158  {
11159  /* update information on linear variables that may be in- or decreased */
11160  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
11161  consdataFindUnlockedLinearVar(scip, consdata);
11162 
11163  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
11164  {
11165  /* check if there is a variable which may help to get the left hand side satisfied
11166  * if there is no such var, then we cannot get feasible */
11167  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
11168  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
11169  maypropfeasible = FALSE;
11170  }
11171  else
11172  {
11173  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
11174  /* check if there is a variable which may help to get the right hand side satisfied
11175  * if there is no such var, then we cannot get feasible */
11176  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
11177  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
11178  maypropfeasible = FALSE;
11179  }
11180  }
11181  }
11182  }
11183 
11184  if( *result == SCIP_INFEASIBLE && maypropfeasible )
11185  {
11186  SCIP_Bool success;
11187 
11188  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11189 
11190  /* do not pass solution to NLP heuristic if we made it feasible this way */
11191  if( success )
11192  return SCIP_OKAY;
11193  }
11194 
11195  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL )
11196  {
11197  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11198  }
11199 
11200  return SCIP_OKAY;
11201 }
11202 
11203 /** constraint copying method of constraint handler */
11204 static
11205 SCIP_DECL_CONSCOPY(consCopyQuadratic)
11207  SCIP_CONSDATA* consdata;
11208  SCIP_CONSDATA* targetconsdata;
11209  SCIP_VAR** linvars;
11210  SCIP_QUADVARTERM* quadvarterms;
11211  SCIP_BILINTERM* bilinterms;
11212  int i;
11213  int j;
11214  int k;
11215 
11216  assert(scip != NULL);
11217  assert(cons != NULL);
11218  assert(sourcescip != NULL);
11219  assert(sourceconshdlr != NULL);
11220  assert(sourcecons != NULL);
11221  assert(varmap != NULL);
11222  assert(valid != NULL);
11223 
11224  consdata = SCIPconsGetData(sourcecons);
11225  assert(consdata != NULL);
11226 
11227  linvars = NULL;
11228  quadvarterms = NULL;
11229  bilinterms = NULL;
11230 
11231  *valid = TRUE;
11232 
11233  if( consdata->nlinvars != 0 )
11234  {
11235  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
11236  for( i = 0; i < consdata->nlinvars; ++i )
11237  {
11238  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
11239  assert(!(*valid) || linvars[i] != NULL);
11240 
11241  /* we do not copy, if a variable is missing */
11242  if( !(*valid) )
11243  goto TERMINATE;
11244  }
11245  }
11246 
11247  if( consdata->nbilinterms != 0 )
11248  {
11249  SCIP_CALL( SCIPallocBufferArray(sourcescip, &bilinterms, consdata->nbilinterms) );
11250  }
11251 
11252  if( consdata->nquadvars != 0 )
11253  {
11254  SCIP_CALL( SCIPallocBufferArray(sourcescip, &quadvarterms, consdata->nquadvars) );
11255  for( i = 0; i < consdata->nquadvars; ++i )
11256  {
11257  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->quadvarterms[i].var, &quadvarterms[i].var, varmap, consmap, global, valid) );
11258  assert(!(*valid) || quadvarterms[i].var != NULL);
11259 
11260  /* we do not copy, if a variable is missing */
11261  if( !(*valid) )
11262  goto TERMINATE;
11263 
11264  quadvarterms[i].lincoef = consdata->quadvarterms[i].lincoef;
11265  quadvarterms[i].sqrcoef = consdata->quadvarterms[i].sqrcoef;
11266  quadvarterms[i].eventdata = NULL;
11267  quadvarterms[i].nadjbilin = consdata->quadvarterms[i].nadjbilin;
11268  quadvarterms[i].adjbilin = consdata->quadvarterms[i].adjbilin;
11269 
11270  assert(consdata->nbilinterms != 0 || consdata->quadvarterms[i].nadjbilin == 0);
11271 
11272  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
11273  {
11274  assert(bilinterms != NULL);
11275 
11276  k = consdata->quadvarterms[i].adjbilin[j];
11277  assert(consdata->bilinterms[k].var1 != NULL);
11278  assert(consdata->bilinterms[k].var2 != NULL);
11279  if( consdata->bilinterms[k].var1 == consdata->quadvarterms[i].var )
11280  {
11281  assert(consdata->bilinterms[k].var2 != consdata->quadvarterms[i].var);
11282  bilinterms[k].var1 = quadvarterms[i].var;
11283  }
11284  else
11285  {
11286  assert(consdata->bilinterms[k].var2 == consdata->quadvarterms[i].var);
11287  bilinterms[k].var2 = quadvarterms[i].var;
11288  }
11289  bilinterms[k].coef = consdata->bilinterms[k].coef;
11290  }
11291  }
11292  }
11293 
11294  assert(stickingatnode == FALSE);
11295  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name ? name : SCIPconsGetName(sourcecons),
11296  consdata->nlinvars, linvars, consdata->lincoefs,
11297  consdata->nquadvars, quadvarterms,
11298  consdata->nbilinterms, bilinterms,
11299  consdata->lhs, consdata->rhs,
11300  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11301 
11302  /* copy information on curvature */
11303  targetconsdata = SCIPconsGetData(*cons);
11304  targetconsdata->isconvex = consdata->isconvex;
11305  targetconsdata->isconcave = consdata->isconcave;
11306  targetconsdata->iscurvchecked = consdata->iscurvchecked;
11307 
11308  TERMINATE:
11309  SCIPfreeBufferArrayNull(sourcescip, &quadvarterms);
11310  SCIPfreeBufferArrayNull(sourcescip, &bilinterms);
11311  SCIPfreeBufferArrayNull(sourcescip, &linvars);
11312 
11313  return SCIP_OKAY;
11314 }
11315 
11316 /** constraint parsing method of constraint handler */
11317 static
11318 SCIP_DECL_CONSPARSE(consParseQuadratic)
11319 { /*lint --e{715}*/
11320  SCIP_VAR*** monomialvars;
11321  SCIP_Real** monomialexps;
11322  SCIP_Real* monomialcoefs;
11323  char* endptr;
11324  int* monomialnvars;
11325  int nmonomials;
11326 
11327  SCIP_Real lhs;
11328  SCIP_Real rhs;
11329 
11330  assert(scip != NULL);
11331  assert(success != NULL);
11332  assert(str != NULL);
11333  assert(name != NULL);
11334  assert(cons != NULL);
11335 
11336  /* set left and right hand side to their default values */
11337  lhs = -SCIPinfinity(scip);
11338  rhs = SCIPinfinity(scip);
11339 
11340  (*success) = FALSE;
11341 
11342  /* return of string empty */
11343  if( !*str )
11344  return SCIP_OKAY;
11345 
11346  /* ignore whitespace */
11347  while( isspace((unsigned char)*str) )
11348  ++str;
11349 
11350  /* check for left hand side */
11351  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
11352  {
11353  /* there is a number coming, maybe it is a left-hand-side */
11354  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
11355  {
11356  SCIPerrorMessage("error parsing number from <%s>\n", str);
11357  return SCIP_OKAY;
11358  }
11359 
11360  /* ignore whitespace */
11361  while( isspace((unsigned char)*endptr) )
11362  ++endptr;
11363 
11364  if( endptr[0] != '<' || endptr[1] != '=' )
11365  {
11366  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
11367  lhs = -SCIPinfinity(scip);
11368  }
11369  else
11370  {
11371  /* it was indeed a left-hand-side, so continue parsing after it */
11372  str = endptr + 2;
11373 
11374  /* ignore whitespace */
11375  while( isspace((unsigned char)*str) )
11376  ++str;
11377  }
11378  }
11379 
11380  SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, &endptr, success) );
11381 
11382  if( *success )
11383  {
11384  /* check for right hand side */
11385  str = endptr;
11386 
11387  /* ignore whitespace */
11388  while( isspace((unsigned char)*str) )
11389  ++str;
11390 
11391  if( *str && str[0] == '<' && str[1] == '=' )
11392  {
11393  /* we seem to get a right-hand-side */
11394  str += 2;
11395 
11396  if( !SCIPstrToRealValue(str, &rhs, &endptr) )
11397  {
11398  SCIPerrorMessage("error parsing right-hand-side from %s\n", str);
11399  *success = FALSE;
11400  }
11401  }
11402  else if( *str && str[0] == '>' && str[1] == '=' )
11403  {
11404  /* we seem to get a left-hand-side */
11405  str += 2;
11406 
11407  /* we should not have a left-hand-side already */
11408  assert(SCIPisInfinity(scip, -lhs));
11409 
11410  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
11411  {
11412  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
11413  *success = FALSE;
11414  }
11415  }
11416  else if( *str && str[0] == '=' && str[1] == '=' )
11417  {
11418  /* we seem to get a left- and right-hand-side */
11419  str += 2;
11420 
11421  /* we should not have a left-hand-side already */
11422  assert(SCIPisInfinity(scip, -lhs));
11423 
11424  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
11425  {
11426  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
11427  *success = FALSE;
11428  }
11429  else
11430  {
11431  rhs = lhs;
11432  }
11433  }
11434  }
11435 
11436  if( *success )
11437  {
11438  int i;
11439 
11440  /* setup constraint */
11441  assert(stickingatnode == FALSE);
11442  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL,
11443  0, NULL, NULL, NULL, lhs, rhs,
11444  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11445 
11446  for( i = 0; i < nmonomials; ++i )
11447  {
11448  if( monomialnvars[i] == 0 )
11449  {
11450  /* constant monomial */
11451  SCIPaddConstantQuadratic(scip, *cons, monomialcoefs[i]);
11452  }
11453  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 1.0 )
11454  {
11455  /* linear monomial */
11456  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, *cons, monomialvars[i][0], monomialcoefs[i]) );
11457  }
11458  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 2.0 )
11459  {
11460  /* square monomial */
11461  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, monomialvars[i][0], 0.0, monomialcoefs[i]) );
11462  }
11463  else if( monomialnvars[i] == 2 && monomialexps[i][0] == 1.0 && monomialexps[i][1] == 1.0 )
11464  {
11465  /* bilinear term */
11466  SCIP_VAR* var1;
11467  SCIP_VAR* var2;
11468  int pos;
11469 
11470  var1 = monomialvars[i][0];
11471  var2 = monomialvars[i][1];
11472  if( var1 == var2 )
11473  {
11474  /* actually a square term */
11475  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, monomialcoefs[i]) );
11476  }
11477  else
11478  {
11479  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var1, &pos) );
11480  if( pos == -1 )
11481  {
11482  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, 0.0) );
11483  }
11484 
11485  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var2, &pos) );
11486  if( pos == -1 )
11487  {
11488  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var2, 0.0, 0.0) );
11489  }
11490  }
11491 
11492  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, *cons, var1, var2, monomialcoefs[i]) );
11493  }
11494  else
11495  {
11496  SCIPerrorMessage("polynomial in quadratic constraint does not have degree at most 2\n");
11497  *success = FALSE;
11498  SCIP_CALL( SCIPreleaseCons(scip, cons) );
11499  break;
11500  }
11501  }
11502  }
11503 
11504  SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
11505 
11506  return SCIP_OKAY;
11507 }
11508 
11509 /** constraint method of constraint handler which returns the variables (if possible) */
11510 static
11511 SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
11512 { /*lint --e{715}*/
11513  SCIP_CONSDATA* consdata;
11514 
11515  assert(cons != NULL);
11516  assert(success != NULL);
11517 
11518  consdata = SCIPconsGetData(cons);
11519  assert(consdata != NULL);
11520 
11521  if( varssize < consdata->nlinvars + consdata->nquadvars )
11522  (*success) = FALSE;
11523  else
11524  {
11525  int i;
11526 
11527  assert(vars != NULL);
11528 
11529  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
11530 
11531  for( i = 0; i < consdata->nquadvars; ++i )
11532  vars[consdata->nlinvars+i] = consdata->quadvarterms[i].var;
11533 
11534  (*success) = TRUE;
11535  }
11536 
11537  return SCIP_OKAY;
11538 }
11539 
11540 /** constraint method of constraint handler which returns the number of variables (if possible) */
11541 static
11542 SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
11543 { /*lint --e{715}*/
11544  SCIP_CONSDATA* consdata;
11545 
11546  assert(cons != NULL);
11547  assert(success != NULL);
11548 
11549  consdata = SCIPconsGetData(cons);
11550  assert(consdata != NULL);
11551 
11552  (*nvars) = consdata->nlinvars + consdata->nquadvars;
11553  (*success) = TRUE;
11554 
11555  return SCIP_OKAY;
11556 }
11557 
11558 
11559 /*
11560  * constraint specific interface methods
11561  */
11562 
11563 /** creates the handler for quadratic constraints and includes it in SCIP */
11565  SCIP* scip /**< SCIP data structure */
11566  )
11567 {
11568  SCIP_CONSHDLRDATA* conshdlrdata;
11569  SCIP_CONSHDLR* conshdlr;
11570 
11571  /* create quadratic constraint handler data */
11572  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
11573  BMSclearMemory(conshdlrdata);
11574 
11575  /* include constraint handler */
11578  consEnfolpQuadratic, consEnfopsQuadratic, consCheckQuadratic, consLockQuadratic,
11579  conshdlrdata) );
11580  assert(conshdlr != NULL);
11581 
11582 
11583  /* set non-fundamental callbacks via specific setter functions */
11584  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyQuadratic, consCopyQuadratic) );
11585  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteQuadratic) );
11586  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitQuadratic) );
11587  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreQuadratic) );
11588  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolQuadratic) );
11589  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeQuadratic) );
11590  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsQuadratic) );
11591  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsQuadratic) );
11592  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitQuadratic) );
11593  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolQuadratic) );
11594  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpQuadratic) );
11595  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseQuadratic) );
11596  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolQuadratic, CONSHDLR_MAXPREROUNDS, CONSHDLR_DELAYPRESOL) );
11597  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintQuadratic) );
11598  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropQuadratic, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
11600  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpQuadratic, consSepasolQuadratic, CONSHDLR_SEPAFREQ,
11602  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransQuadratic) );
11603 
11604  /* add quadratic constraint handler parameters */
11605  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/replacebinaryprod",
11606  "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)",
11607  &conshdlrdata->replacebinaryprodlength, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
11608 
11609  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/empathy4and",
11610  "empathy level for using the AND constraint handler: 0 always avoid using AND; 1 use AND sometimes; 2 use AND as often as possible",
11611  &conshdlrdata->empathy4and, FALSE, 0, 0, 2, NULL, NULL) );
11612 
11613  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/binreforminitial",
11614  "whether to make non-varbound linear constraints added due to replacing products with binary variables initial",
11615  &conshdlrdata->binreforminitial, TRUE, FALSE, NULL, NULL) );
11616 
11617  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/binreformmaxcoef",
11618  "limit (as factor on 1/feastol) on coefficients and coef. range in linear constraints created when replacing products with binary variables",
11619  &conshdlrdata->binreformmaxcoef, TRUE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
11620 
11621  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/minefficacysepa",
11622  "minimal efficacy for a cut to be added to the LP during separation; overwrites separating/efficacy",
11623  &conshdlrdata->mincutefficacysepa, TRUE, 0.0001, 0.0, SCIPinfinity(scip), NULL, NULL) );
11624 
11625  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/minefficacyenfofac",
11626  "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)",
11627  &conshdlrdata->mincutefficacyenfofac, TRUE, 2.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
11628 
11629  SCIP_CALL( SCIPaddCharParam(scip, "constraints/"CONSHDLR_NAME"/scaling",
11630  "whether scaling of infeasibility is 'o'ff, by sup-norm of function 'g'radient, or by left/right hand 's'ide",
11631  &conshdlrdata->scaling, TRUE, 'o', "ogs", NULL, NULL) );
11632 
11633  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/cutmaxrange",
11634  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
11635  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
11636 
11637  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/linearizeheursol",
11638  "whether linearizations of convex quadratic constraints should be added to cutpool in a solution found by some heuristic",
11639  &conshdlrdata->linearizeheursol, TRUE, TRUE, NULL, NULL) );
11640 
11641  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/checkcurvature",
11642  "whether multivariate quadratic functions should be checked for convexity/concavity",
11643  &conshdlrdata->checkcurvature, FALSE, TRUE, NULL, NULL) );
11644 
11645  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/checkfactorable",
11646  "whether constraint functions should be checked to be factorable",
11647  &conshdlrdata->checkfactorable, TRUE, TRUE, NULL, NULL) );
11648 
11649  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/linfeasshift",
11650  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
11651  &conshdlrdata->linfeasshift, TRUE, TRUE, NULL, NULL) );
11652 
11653  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/disaggregate",
11654  "whether to disaggregate quadratic parts that decompose into a sum of non-overlapping quadratic terms",
11655  &conshdlrdata->disaggregate, TRUE, FALSE, NULL, NULL) );
11656 
11657  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/maxproprounds",
11658  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve",
11659  &conshdlrdata->maxproprounds, TRUE, 1, 0, INT_MAX, NULL, NULL) );
11660 
11661  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/maxproproundspresolve",
11662  "limit on number of propagation rounds for a single constraint within one round of SCIP presolve",
11663  &conshdlrdata->maxproproundspresolve, TRUE, 10, 0, INT_MAX, NULL, NULL) );
11664 
11665  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/enfolplimit",
11666  "maximum number of enforcement rounds before declaring the LP relaxation infeasible (-1: no limit); WARNING: changing this parameter might lead to incorrect results!",
11667  &conshdlrdata->enfolplimit, TRUE, -1, -1, INT_MAX, NULL, NULL) );
11668 
11669  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/sepanlpmincont",
11670  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
11671  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
11672 
11673  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/enfocutsremovable",
11674  "are cuts added during enforcement removable from the LP in the same node?",
11675  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
11676 
11677  conshdlrdata->eventhdlr = NULL;
11678  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr),CONSHDLR_NAME"_boundchange", "signals a bound change to a quadratic constraint",
11679  processVarEvent, NULL) );
11680  assert(conshdlrdata->eventhdlr != NULL);
11681 
11682  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
11683  processNewSolutionEvent, NULL) );
11684 
11685  /* include the quadratic constraint upgrade in the nonlinear constraint handler */
11687 
11688  return SCIP_OKAY;
11689 }
11690 
11691 /** includes a quadratic constraint update method into the quadratic constraint handler */
11693  SCIP* scip, /**< SCIP data structure */
11694  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
11695  int priority, /**< priority of upgrading method */
11696  SCIP_Bool active, /**< should the upgrading method be active by default? */
11697  const char* conshdlrname /**< name of the constraint handler */
11698  )
11699 {
11700  SCIP_CONSHDLR* conshdlr;
11701  SCIP_CONSHDLRDATA* conshdlrdata;
11702  SCIP_QUADCONSUPGRADE* quadconsupgrade;
11703  char paramname[SCIP_MAXSTRLEN];
11704  char paramdesc[SCIP_MAXSTRLEN];
11705  int i;
11706 
11707  assert(quadconsupgd != NULL);
11708  assert(conshdlrname != NULL );
11709 
11710  /* find the quadratic constraint handler */
11711  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11712  if( conshdlr == NULL )
11713  {
11714  SCIPerrorMessage("quadratic constraint handler not found\n");
11715  return SCIP_PLUGINNOTFOUND;
11716  }
11717 
11718  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11719  assert(conshdlrdata != NULL);
11720 
11721  if( !conshdlrdataHasUpgrade(scip, conshdlrdata, quadconsupgd, conshdlrname) )
11722  {
11723  /* create a quadratic constraint upgrade data object */
11724  SCIP_CALL( SCIPallocMemory(scip, &quadconsupgrade) );
11725  quadconsupgrade->quadconsupgd = quadconsupgd;
11726  quadconsupgrade->priority = priority;
11727  quadconsupgrade->active = active;
11728 
11729  /* insert quadratic constraint upgrade method into constraint handler data */
11730  assert(conshdlrdata->nquadconsupgrades <= conshdlrdata->quadconsupgradessize);
11731  if( conshdlrdata->nquadconsupgrades+1 > conshdlrdata->quadconsupgradessize )
11732  {
11733  int newsize;
11734 
11735  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nquadconsupgrades+1);
11736  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->quadconsupgrades, newsize) );
11737  conshdlrdata->quadconsupgradessize = newsize;
11738  }
11739  assert(conshdlrdata->nquadconsupgrades+1 <= conshdlrdata->quadconsupgradessize);
11740 
11741  for( i = conshdlrdata->nquadconsupgrades; i > 0 && conshdlrdata->quadconsupgrades[i-1]->priority < quadconsupgrade->priority; --i )
11742  conshdlrdata->quadconsupgrades[i] = conshdlrdata->quadconsupgrades[i-1];
11743  assert(0 <= i && i <= conshdlrdata->nquadconsupgrades);
11744  conshdlrdata->quadconsupgrades[i] = quadconsupgrade;
11745  conshdlrdata->nquadconsupgrades++;
11746 
11747  /* adds parameter to turn on and off the upgrading step */
11748  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/"CONSHDLR_NAME"/upgrade/%s", conshdlrname);
11749  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable quadratic upgrading for constraint handler <%s>", conshdlrname);
11751  paramname, paramdesc,
11752  &quadconsupgrade->active, FALSE, active, NULL, NULL) );
11753  }
11754 
11755  return SCIP_OKAY;
11756 }
11757 
11758 /** Creates and captures a quadratic constraint.
11759  *
11760  * The constraint should be given in the form
11761  * \f[
11762  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_jz_j \leq u,
11763  * \f]
11764  * where \f$x_i = y_j = z_k\f$ is possible.
11765  *
11766  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11767  */
11769  SCIP* scip, /**< SCIP data structure */
11770  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11771  const char* name, /**< name of constraint */
11772  int nlinvars, /**< number of linear terms (n) */
11773  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
11774  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
11775  int nquadterms, /**< number of quadratic terms (m) */
11776  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
11777  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
11778  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
11779  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
11780  SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
11781  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
11782  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
11783  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
11784  * Usually set to TRUE. */
11785  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
11786  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11787  SCIP_Bool check, /**< should the constraint be checked for feasibility?
11788  * TRUE for model constraints, FALSE for additional, redundant constraints. */
11789  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
11790  * Usually set to TRUE. */
11791  SCIP_Bool local, /**< is constraint only valid locally?
11792  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
11793  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
11794  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
11795  * adds coefficients to this constraint. */
11796  SCIP_Bool dynamic, /**< is constraint subject to aging?
11797  * Usually set to FALSE. Set to TRUE for own cuts which
11798  * are separated as constraints. */
11799  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
11800  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
11801  )
11802 {
11803  SCIP_CONSHDLR* conshdlr;
11804  SCIP_CONSDATA* consdata;
11805  SCIP_HASHMAP* quadvaridxs;
11806  SCIP_Real sqrcoef;
11807  int i;
11808  int var1pos;
11809  int var2pos;
11810 
11811  int nbilinterms;
11812 
11813  assert(modifiable == FALSE); /* we do not support column generation */
11814 
11815  /* find the quadratic constraint handler */
11816  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11817  if( conshdlr == NULL )
11818  {
11819  SCIPerrorMessage("quadratic constraint handler not found\n");
11820  return SCIP_PLUGINNOTFOUND;
11821  }
11822 
11823  /* create constraint data and constraint */
11824  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
11825 
11826  consdata->lhs = lhs;
11827  consdata->rhs = rhs;
11828 
11829  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
11830  local, modifiable, dynamic, removable, FALSE) );
11831 
11832  /* add quadratic variables and remember their indices */
11833  SCIP_CALL( SCIPhashmapCreate(&quadvaridxs, SCIPblkmem(scip), SCIPcalcHashtableSize(5 * nquadterms)) );
11834  nbilinterms = 0;
11835  for( i = 0; i < nquadterms; ++i )
11836  {
11837  if( SCIPisZero(scip, quadcoefs[i]) )
11838  continue;
11839 
11840  /* if it is actually a square term, remember it's coefficient */
11841  if( quadvars1[i] == quadvars2[i] )
11842  sqrcoef = quadcoefs[i];
11843  else
11844  sqrcoef = 0.0;
11845 
11846  /* add quadvars1[i], if not in there already */
11847  if( !SCIPhashmapExists(quadvaridxs, quadvars1[i]) )
11848  {
11849  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars1[i], 0.0, sqrcoef, FALSE) );
11850  assert(consdata->nquadvars >= 0);
11851  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars1[i]);
11852 
11853  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars1[i], (void*)(size_t)(consdata->nquadvars-1)) );
11854  }
11855  else if( !SCIPisZero(scip, sqrcoef) )
11856  {
11857  /* if it's there already, but we got a square coefficient, add it to the previous one */
11858  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]);
11859  assert(consdata->quadvarterms[var1pos].var == quadvars1[i]);
11860  consdata->quadvarterms[var1pos].sqrcoef += sqrcoef;
11861  }
11862 
11863  if( quadvars1[i] == quadvars2[i] )
11864  continue;
11865 
11866  /* add quadvars2[i], if not in there already */
11867  if( !SCIPhashmapExists(quadvaridxs, quadvars2[i]) )
11868  {
11869  assert(sqrcoef == 0.0);
11870  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars2[i], 0.0, 0.0, FALSE) );
11871  assert(consdata->nquadvars >= 0);
11872  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars2[i]);
11873 
11874  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars2[i], (void*)(size_t)(consdata->nquadvars-1)) );
11875  }
11876 
11877  ++nbilinterms;
11878  }
11879 
11880  /* add bilinear terms, if we saw any */
11881  if( nbilinterms > 0 )
11882  {
11883  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, nbilinterms) );
11884  for( i = 0; i < nquadterms; ++i )
11885  {
11886  if( SCIPisZero(scip, quadcoefs[i]) )
11887  continue;
11888 
11889  /* square terms have been taken care of already */
11890  if( quadvars1[i] == quadvars2[i] )
11891  continue;
11892 
11893  assert(SCIPhashmapExists(quadvaridxs, quadvars1[i]));
11894  assert(SCIPhashmapExists(quadvaridxs, quadvars2[i]));
11895 
11896  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]);
11897  var2pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars2[i]);
11898 
11899  SCIP_CALL( addBilinearTerm(scip, *cons, var1pos, var2pos, quadcoefs[i]) );
11900  }
11901  }
11902 
11903  /* add linear variables */
11904  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
11905  for( i = 0; i < nlinvars; ++i )
11906  {
11907  if( SCIPisZero(scip, lincoefs[i]) )
11908  continue;
11909 
11910  /* if it's a linear coefficient for a quadratic variable, add it there, otherwise add as linear variable */
11911  if( SCIPhashmapExists(quadvaridxs, linvars[i]) )
11912  {
11913  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, linvars[i]);
11914  assert(consdata->quadvarterms[var1pos].var == linvars[i]);
11915  consdata->quadvarterms[var1pos].lincoef += lincoefs[i];
11916  }
11917  else
11918  {
11919  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) );
11920  }
11921  }
11922 
11923  if( SCIPisTransformed(scip) )
11924  {
11925  SCIP_CONSHDLRDATA* conshdlrdata = SCIPconshdlrGetData(conshdlr);
11926  assert(conshdlrdata != NULL);
11927  assert(conshdlrdata->eventhdlr != NULL);
11928 
11929  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, *cons) );
11930  }
11931 
11932  SCIPhashmapFree(&quadvaridxs);
11933 
11934  /* merge duplicate bilinear terms, move quad terms that are linear to linear vars */
11935  SCIP_CALL( mergeAndCleanBilinearTerms(scip, *cons) );
11936  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, *cons) );
11937  SCIP_CALL( mergeAndCleanLinearVars(scip, *cons) );
11938 
11939  SCIPdebugMessage("created quadratic constraint ");
11940  SCIPdebugPrintCons(scip, *cons, NULL);
11941 
11942  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
11943  {
11944  SCIP_CALL( consInitsolQuadratic(scip, conshdlr, cons, 1) );
11945  }
11946 
11947  return SCIP_OKAY;
11948 }
11949 
11950 /** creates and captures a quadratic constraint with all its
11951  * flags set to their default values.
11952  *
11953  * The constraint should be given in the form
11954  * \f[
11955  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_jz_j \leq u,
11956  * \f]
11957  * where \f$x_i = y_j = z_k\f$ is possible.
11958  *
11959  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11960  */
11962  SCIP* scip, /**< SCIP data structure */
11963  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11964  const char* name, /**< name of constraint */
11965  int nlinvars, /**< number of linear terms (n) */
11966  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
11967  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
11968  int nquadterms, /**< number of quadratic terms (m) */
11969  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
11970  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
11971  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
11972  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
11973  SCIP_Real rhs /**< right hand side of quadratic equation (u) */
11974  )
11975 {
11976  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, nlinvars, linvars, lincoefs,
11977  nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
11978  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
11979 
11980  return SCIP_OKAY;
11981 }
11982 
11983 /** Creates and captures a quadratic constraint.
11984  *
11985  * The constraint should be given in the form
11986  * \f[
11987  * \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.
11988  * \f]
11989  *
11990  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
11991  */
11993  SCIP* scip, /**< SCIP data structure */
11994  SCIP_CONS** cons, /**< pointer to hold the created constraint */
11995  const char* name, /**< name of constraint */
11996  int nlinvars, /**< number of linear terms (n) */
11997  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
11998  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
11999  int nquadvarterms, /**< number of quadratic terms (m) */
12000  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
12001  int nbilinterms, /**< number of bilinear terms (p) */
12002  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
12003  SCIP_Real lhs, /**< constraint left hand side (ell) */
12004  SCIP_Real rhs, /**< constraint right hand side (u) */
12005  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
12006  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
12007  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
12008  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
12009  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
12010  SCIP_Bool local, /**< is constraint only valid locally? */
12011  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
12012  SCIP_Bool dynamic, /**< is constraint dynamic? */
12013  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
12014  )
12015 {
12016  SCIP_CONSHDLR* conshdlr;
12017  SCIP_CONSDATA* consdata;
12018 
12019  assert(modifiable == FALSE); /* we do not support column generation */
12020  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12021  assert(nquadvarterms == 0 || quadvarterms != NULL);
12022  assert(nbilinterms == 0 || bilinterms != NULL);
12023 
12024  /* find the quadratic constraint handler */
12025  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12026  if( conshdlr == NULL )
12027  {
12028  SCIPerrorMessage("quadratic constraint handler not found\n");
12029  return SCIP_PLUGINNOTFOUND;
12030  }
12031 
12032  /* create constraint data */
12033  SCIP_CALL( consdataCreate(scip, &consdata, lhs, rhs,
12034  nlinvars, linvars, lincoefs, nquadvarterms, quadvarterms, nbilinterms, bilinterms,
12035  TRUE) );
12036 
12037  /* create constraint */
12038  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
12039  local, modifiable, dynamic, removable, FALSE) );
12040 
12041  if( SCIPisTransformed(scip) )
12042  {
12043  SCIP_CONSHDLRDATA* conshdlrdata = SCIPconshdlrGetData(conshdlr);
12044  assert(conshdlrdata != NULL);
12045  assert(conshdlrdata->eventhdlr != NULL);
12046 
12047  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, *cons) );
12048  }
12049 
12050  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
12051  {
12052  SCIP_CALL( consInitsolQuadratic(scip, conshdlr, cons, 1) );
12053  }
12054 
12055  return SCIP_OKAY;
12056 }
12057 
12058 /** creates and captures a quadratic constraint in its most basic version, i.e.,
12059  * all constraint flags are set to their default values.
12060  *
12061  * The constraint should be given in the form
12062  * \f[
12063  * \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.
12064  * \f]
12065  *
12066  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12067  */
12069  SCIP* scip, /**< SCIP data structure */
12070  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12071  const char* name, /**< name of constraint */
12072  int nlinvars, /**< number of linear terms (n) */
12073  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
12074  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
12075  int nquadvarterms, /**< number of quadratic terms (m) */
12076  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
12077  int nbilinterms, /**< number of bilinear terms (p) */
12078  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
12079  SCIP_Real lhs, /**< constraint left hand side (ell) */
12080  SCIP_Real rhs /**< constraint right hand side (u) */
12081  )
12082 {
12083  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name, nlinvars, linvars, lincoefs,
12084  nquadvarterms, quadvarterms, nbilinterms, bilinterms, lhs, rhs,
12085  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
12086 
12087  return SCIP_OKAY;
12088 }
12089 
12090 
12091 /** Adds a constant to the constraint function, that is, subtracts a constant from both sides */
12093  SCIP* scip, /**< SCIP data structure */
12094  SCIP_CONS* cons, /**< constraint */
12095  SCIP_Real constant /**< constant to subtract from both sides */
12096  )
12097 {
12098  SCIP_CONSDATA* consdata;
12099 
12100  assert(scip != NULL);
12101  assert(cons != NULL);
12102  assert(!SCIPisInfinity(scip, REALABS(constant)));
12103 
12104  consdata = SCIPconsGetData(cons);
12105  assert(consdata != NULL);
12106  assert(consdata->lhs <= consdata->rhs);
12107 
12108  if( !SCIPisInfinity(scip, -consdata->lhs) )
12109  consdata->lhs -= constant;
12110  if( !SCIPisInfinity(scip, consdata->rhs) )
12111  consdata->rhs -= constant;
12112 
12113  if( consdata->lhs > consdata->rhs )
12114  {
12115  assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
12116  consdata->lhs = consdata->rhs;
12117  }
12118 }
12119 
12120 /** Adds a linear variable with coefficient to a quadratic constraint.
12121  */
12123  SCIP* scip, /**< SCIP data structure */
12124  SCIP_CONS* cons, /**< constraint */
12125  SCIP_VAR* var, /**< variable */
12126  SCIP_Real coef /**< coefficient of variable */
12127  )
12128 {
12129  assert(scip != NULL);
12130  assert(cons != NULL);
12131  assert(var != NULL);
12132  assert(!SCIPisInfinity(scip, REALABS(coef)));
12133 
12134  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
12135 
12136  return SCIP_OKAY;
12137 }
12138 
12139 /** Adds a quadratic variable with linear and square coefficient to a quadratic constraint.
12140  */
12142  SCIP* scip, /**< SCIP data structure */
12143  SCIP_CONS* cons, /**< constraint */
12144  SCIP_VAR* var, /**< variable */
12145  SCIP_Real lincoef, /**< linear coefficient of variable */
12146  SCIP_Real sqrcoef /**< square coefficient of variable */
12147  )
12148 {
12149  assert(scip != NULL);
12150  assert(cons != NULL);
12151  assert(var != NULL);
12152  assert(!SCIPisInfinity(scip, REALABS(lincoef)));
12153  assert(!SCIPisInfinity(scip, REALABS(sqrcoef)));
12154 
12155  SCIP_CALL( addQuadVarTerm(scip, cons, var, lincoef, sqrcoef, SCIPconsIsTransformed(cons)) );
12156 
12157  return SCIP_OKAY;
12158 }
12159 
12160 /** Adds a linear coefficient for a quadratic variable.
12161  *
12162  * Variable will be added with square coefficient 0.0 if not existing yet.
12163  */
12165  SCIP* scip, /**< SCIP data structure */
12166  SCIP_CONS* cons, /**< constraint */
12167  SCIP_VAR* var, /**< variable */
12168  SCIP_Real coef /**< value to add to linear coefficient of variable */
12169  )
12170 {
12171  SCIP_CONSDATA* consdata;
12172  int pos;
12173 
12174  assert(scip != NULL);
12175  assert(cons != NULL);
12176  assert(var != NULL);
12177  assert(!SCIPisInfinity(scip, REALABS(coef)));
12178 
12179  if( SCIPisZero(scip, coef) )
12180  return SCIP_OKAY;
12181 
12182  consdata = SCIPconsGetData(cons);
12183  assert(consdata != NULL);
12184 
12185  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
12186  if( pos < 0 )
12187  {
12188  SCIP_CALL( addQuadVarTerm(scip, cons, var, coef, 0.0, SCIPconsIsTransformed(cons)) );
12189  return SCIP_OKAY;
12190  }
12191  assert(pos < consdata->nquadvars);
12192  assert(consdata->quadvarterms[pos].var == var);
12193 
12194  consdata->quadvarterms[pos].lincoef += coef;
12195 
12196  /* update flags and invalid activities */
12197  consdata->ispropagated = FALSE;
12198  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].lincoef);
12199 
12200  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
12201  consdata->activity = SCIP_INVALID;
12202 
12203  return SCIP_OKAY;
12204 }
12205 
12206 /** Adds a square coefficient for a quadratic variable.
12207  *
12208  * Variable will be added with linear coefficient 0.0 if not existing yet.
12209  */
12211  SCIP* scip, /**< SCIP data structure */
12212  SCIP_CONS* cons, /**< constraint */
12213  SCIP_VAR* var, /**< variable */
12214  SCIP_Real coef /**< value to add to square coefficient of variable */
12215  )
12216 {
12217  SCIP_CONSDATA* consdata;
12218  int pos;
12219 
12220  assert(scip != NULL);
12221  assert(cons != NULL);
12222  assert(var != NULL);
12223  assert(!SCIPisInfinity(scip, REALABS(coef)));
12224 
12225  if( SCIPisZero(scip, coef) )
12226  return SCIP_OKAY;
12227 
12228  consdata = SCIPconsGetData(cons);
12229  assert(consdata != NULL);
12230 
12231  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
12232  if( pos < 0 )
12233  {
12234  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef, SCIPconsIsTransformed(cons)) );
12235  return SCIP_OKAY;
12236  }
12237  assert(pos < consdata->nquadvars);
12238  assert(consdata->quadvarterms[pos].var == var);
12239 
12240  consdata->quadvarterms[pos].sqrcoef += coef;
12241 
12242  /* update flags and invalid activities */
12243  consdata->isconvex = FALSE;
12244  consdata->isconcave = FALSE;
12245  consdata->iscurvchecked = FALSE;
12246  consdata->ispropagated = FALSE;
12247  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].sqrcoef);
12248 
12249  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
12250  consdata->activity = SCIP_INVALID;
12251 
12252  return SCIP_OKAY;
12253 }
12254 
12255 /** Adds a bilinear term to a quadratic constraint.
12256  *
12257  * Variables will be added with linear and square coefficient 0.0 if not existing yet.
12258  * If variables are equal, only the square coefficient of the variable is updated.
12259  */
12261  SCIP* scip, /**< SCIP data structure */
12262  SCIP_CONS* cons, /**< constraint */
12263  SCIP_VAR* var1, /**< first variable */
12264  SCIP_VAR* var2, /**< second variable */
12265  SCIP_Real coef /**< coefficient of bilinear term */
12266  )
12267 {
12268  SCIP_CONSDATA* consdata;
12269  int var1pos;
12270  int var2pos;
12271 
12272  assert(scip != NULL);
12273  assert(cons != NULL);
12274  assert(var1 != NULL);
12275  assert(var2 != NULL);
12276  assert(!SCIPisInfinity(scip, REALABS(coef)));
12277 
12278  if( var1 == var2 )
12279  {
12280  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, cons, var1, coef) );
12281  return SCIP_OKAY;
12282  }
12283 
12284  consdata = SCIPconsGetData(cons);
12285  assert(consdata != NULL);
12286 
12287  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
12288  if( var1pos < 0 )
12289  {
12290  SCIP_CALL( addQuadVarTerm(scip, cons, var1, 0.0, 0.0, SCIPconsIsTransformed(cons)) );
12291  var1pos = consdata->nquadvars-1;
12292  }
12293 
12294  if( !consdata->quadvarssorted )
12295  {
12296  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
12297  /* sorting may change the position of var1 */
12298  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
12299  assert(var1pos >= 0);
12300  }
12301 
12302  assert(consdata->quadvarssorted);
12303  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var2, &var2pos) );
12304  if( var2pos < 0 )
12305  {
12306  SCIP_CALL( addQuadVarTerm(scip, cons, var2, 0.0, 0.0, SCIPconsIsTransformed(cons)) );
12307  var2pos = consdata->nquadvars-1;
12308  }
12309 
12310  assert(consdata->quadvarterms[var1pos].var == var1);
12311  assert(consdata->quadvarterms[var2pos].var == var2);
12312 
12313  SCIP_CALL( addBilinearTerm(scip, cons, var1pos, var2pos, coef) );
12314 
12315  return SCIP_OKAY;
12316 }
12317 
12318 /** Gets the quadratic constraint as a nonlinear row representation.
12319  */
12321  SCIP* scip, /**< SCIP data structure */
12322  SCIP_CONS* cons, /**< constraint */
12323  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
12324  )
12325 {
12326  SCIP_CONSDATA* consdata;
12327 
12328  assert(cons != NULL);
12329  assert(nlrow != NULL);
12330 
12331  consdata = SCIPconsGetData(cons);
12332  assert(consdata != NULL);
12333 
12334  if( consdata->nlrow == NULL )
12335  {
12336  SCIP_CALL( createNlRow(scip, cons) );
12337  }
12338  assert(consdata->nlrow != NULL);
12339  *nlrow = consdata->nlrow;
12340 
12341  return SCIP_OKAY;
12342 }
12343 
12344 /** Gets the number of variables in the linear term of a quadratic constraint.
12345  */
12347  SCIP* scip, /**< SCIP data structure */
12348  SCIP_CONS* cons /**< constraint */
12349  )
12350 {
12351  assert(cons != NULL);
12352  assert(SCIPconsGetData(cons) != NULL);
12353 
12354  return SCIPconsGetData(cons)->nlinvars;
12355 }
12356 
12357 /** Gets the variables in the linear part of a quadratic constraint.
12358  * Length is given by SCIPgetNLinearVarsQuadratic.
12359  */
12361  SCIP* scip, /**< SCIP data structure */
12362  SCIP_CONS* cons /**< constraint */
12363  )
12364 {
12365  assert(cons != NULL);
12366  assert(SCIPconsGetData(cons) != NULL);
12367 
12368  return SCIPconsGetData(cons)->linvars;
12369 }
12370 
12371 /** Gets the coefficients in the linear part of a quadratic constraint.
12372  * Length is given by SCIPgetNLinearVarsQuadratic.
12373  */
12375  SCIP* scip, /**< SCIP data structure */
12376  SCIP_CONS* cons /**< constraint */
12377  )
12378 {
12379  assert(cons != NULL);
12380  assert(SCIPconsGetData(cons) != NULL);
12381 
12382  return SCIPconsGetData(cons)->lincoefs;
12383 }
12384 
12385 /** Gets the number of quadratic variable terms of a quadratic constraint.
12386  */
12388  SCIP* scip, /**< SCIP data structure */
12389  SCIP_CONS* cons /**< constraint */
12390  )
12391 {
12392  assert(cons != NULL);
12393  assert(SCIPconsGetData(cons) != NULL);
12394 
12395  return SCIPconsGetData(cons)->nquadvars;
12396 }
12397 
12398 /** Gets the quadratic variable terms of a quadratic constraint.
12399  * Length is given by SCIPgetNQuadVarTermsQuadratic.
12400  */
12402  SCIP* scip, /**< SCIP data structure */
12403  SCIP_CONS* cons /**< constraint */
12404  )
12405 {
12406  assert(cons != NULL);
12407  assert(SCIPconsGetData(cons) != NULL);
12408 
12409  return SCIPconsGetData(cons)->quadvarterms;
12410 }
12411 
12412 /** Ensures that quadratic variable terms are sorted. */
12414  SCIP* scip, /**< SCIP data structure */
12415  SCIP_CONS* cons /**< constraint */
12416  )
12417 {
12418  assert(cons != NULL);
12419  assert(SCIPconsGetData(cons) != NULL);
12420 
12422 
12423  return SCIP_OKAY;
12424 }
12425 
12426 /** Finds the position of a quadratic variable term for a given variable.
12427  *
12428  * @note If the quadratic variable terms have not been sorted before, then a search may reorder the current order of the terms.
12429  */
12431  SCIP* scip, /**< SCIP data structure */
12432  SCIP_CONS* cons, /**< constraint */
12433  SCIP_VAR* var, /**< variable to search for */
12434  int* pos /**< buffer to store position of quadvarterm for var, or -1 if not found */
12435  )
12436 {
12437  assert(cons != NULL);
12438  assert(SCIPconsGetData(cons) != NULL);
12439  assert(var != NULL);
12440  assert(pos != NULL);
12441 
12442  SCIP_CALL( consdataFindQuadVarTerm(scip, SCIPconsGetData(cons), var, pos) );
12443 
12444  return SCIP_OKAY;
12445 }
12446 
12447 /** Gets the number of bilinear terms of a quadratic constraint.
12448  */
12450  SCIP* scip, /**< SCIP data structure */
12451  SCIP_CONS* cons /**< constraint */
12452  )
12453 {
12454  assert(cons != NULL);
12455  assert(SCIPconsGetData(cons) != NULL);
12456 
12457  return SCIPconsGetData(cons)->nbilinterms;
12458 }
12459 
12460 /** Gets the bilinear terms of a quadratic constraint.
12461  * Length is given by SCIPgetNBilinTermQuadratic.
12462  */
12464  SCIP* scip, /**< SCIP data structure */
12465  SCIP_CONS* cons /**< constraint */
12466  )
12467 {
12468  assert(cons != NULL);
12469  assert(SCIPconsGetData(cons) != NULL);
12470 
12471  return SCIPconsGetData(cons)->bilinterms;
12472 }
12473 
12474 /** Gets the left hand side of a quadratic constraint.
12475  */
12477  SCIP* scip, /**< SCIP data structure */
12478  SCIP_CONS* cons /**< constraint */
12479  )
12480 {
12481  assert(cons != NULL);
12482  assert(SCIPconsGetData(cons) != NULL);
12483 
12484  return SCIPconsGetData(cons)->lhs;
12485 }
12486 
12487 /** Gets the right hand side of a quadratic constraint.
12488  */
12490  SCIP* scip, /**< SCIP data structure */
12491  SCIP_CONS* cons /**< constraint */
12492  )
12493 {
12494  assert(cons != NULL);
12495  assert(SCIPconsGetData(cons) != NULL);
12496 
12497  return SCIPconsGetData(cons)->rhs;
12498 }
12499 
12500 /** Check the quadratic function of a quadratic constraint for its semi-definiteness, if not done yet.
12501  */
12503  SCIP* scip, /**< SCIP data structure */
12504  SCIP_CONS* cons /**< constraint */
12505  )
12506 {
12507  assert(cons != NULL);
12508 
12509  SCIP_CALL( checkCurvature(scip, cons, TRUE) );
12510 
12511  return SCIP_OKAY;
12512 }
12513 
12514 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) convex.
12515  */
12517  SCIP* scip, /**< SCIP data structure */
12518  SCIP_CONS* cons /**< constraint */
12519  )
12520 {
12521  SCIP_Bool determined;
12522 
12523  assert(cons != NULL);
12524  assert(SCIPconsGetData(cons) != NULL);
12525 
12526  checkCurvatureEasy(scip, cons, &determined, FALSE);
12527  assert(determined);
12528 
12529  return (SCIPconsGetData(cons)->isconvex);
12530 }
12531 
12532 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) concave.
12533  */
12535  SCIP* scip, /**< SCIP data structure */
12536  SCIP_CONS* cons /**< constraint */
12537  )
12538 {
12539  SCIP_Bool determined;
12540 
12541  assert(cons != NULL);
12542  assert(SCIPconsGetData(cons) != NULL);
12543 
12544  checkCurvatureEasy(scip, cons, &determined, FALSE);
12545  assert(determined);
12546 
12547  return (SCIPconsGetData(cons)->isconcave);
12548 }
12549 
12550 /** Computes the violation of a constraint by a solution */
12552  SCIP* scip, /**< SCIP data structure */
12553  SCIP_CONS* cons, /**< constraint */
12554  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
12555  SCIP_Real* violation /**< pointer to store violation of constraint */
12556  )
12557 {
12558  SCIP_CONSHDLR* conshdlr;
12559  SCIP_CONSDATA* consdata;
12560 
12561  assert(scip != NULL);
12562  assert(cons != NULL);
12563  assert(violation != NULL);
12564 
12565  conshdlr = SCIPconsGetHdlr(cons);
12566  assert(conshdlr != NULL);
12567 
12568  SCIP_CALL( computeViolation(scip, conshdlr, cons, sol) );
12569 
12570  consdata = SCIPconsGetData(cons);
12571  assert(consdata != NULL);
12572 
12573  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
12574 
12575  return SCIP_OKAY;
12576 }
12577 
12578 /** Indicates whether the quadratic constraint is local w.r.t. the current local bounds.
12579  *
12580  * That is, checks whether each variable with a square term is fixed and for each bilinear term at least one variable is fixed.
12581  */
12583  SCIP* scip, /**< SCIP data structure */
12584  SCIP_CONS* cons /**< constraint */
12585 )
12586 {
12587  SCIP_CONSDATA* consdata;
12588  SCIP_VAR* var1;
12589  SCIP_VAR* var2;
12590  int i;
12591 
12592  assert(scip != NULL);
12593  assert(cons != NULL);
12594 
12595  consdata = SCIPconsGetData(cons);
12596  assert(consdata != NULL);
12597 
12598  /* check all square terms */
12599  for( i = 0; i < consdata->nquadvars; ++i )
12600  {
12601  if( consdata->quadvarterms[i].sqrcoef == 0.0 )
12602  continue;
12603 
12604  var1 = consdata->quadvarterms[i].var;
12605  assert(var1 != NULL);
12606 
12607  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) )
12608  return FALSE;
12609  }
12610 
12611  for( i = 0; i < consdata->nbilinterms; ++i )
12612  {
12613  var1 = consdata->bilinterms[i].var1;
12614  var2 = consdata->bilinterms[i].var2;
12615 
12616  assert(var1 != NULL);
12617  assert(var2 != NULL);
12618 
12619  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) &&
12620  ! SCIPisRelEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
12621  return FALSE;
12622  }
12623 
12624  return TRUE;
12625 }
12626 
12627 /** Adds the constraint to an NLPI problem. */
12629  SCIP* scip, /**< SCIP data structure */
12630  SCIP_CONS* cons, /**< constraint */
12631  SCIP_NLPI* nlpi, /**< interface to NLP solver */
12632  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
12633  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
12634  SCIP_Bool names /**< whether to pass constraint names to NLPI */
12635  )
12636 {
12637  SCIP_CONSDATA* consdata;
12638  int nlininds;
12639  int* lininds;
12640  SCIP_Real* linvals;
12641  int nquadelems;
12642  SCIP_QUADELEM* quadelems;
12643  SCIP_VAR* othervar;
12644  const char* name;
12645  int j;
12646  int l;
12647  int lincnt;
12648  int quadcnt;
12649  int idx1;
12650  int idx2;
12651 
12652  assert(scip != NULL);
12653  assert(cons != NULL);
12654  assert(nlpi != NULL);
12655  assert(nlpiprob != NULL);
12656  assert(scipvar2nlpivar != NULL);
12657 
12658  consdata = SCIPconsGetData(cons);
12659  assert(consdata != NULL);
12660 
12661  /* count nonzeros in quadratic part */
12662  nlininds = consdata->nlinvars;
12663  nquadelems = consdata->nbilinterms;
12664  for( j = 0; j < consdata->nquadvars; ++j )
12665  {
12666  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
12667  ++nquadelems;
12668  if( consdata->quadvarterms[j].lincoef != 0.0 )
12669  ++nlininds;
12670  }
12671 
12672  /* setup linear part */
12673  lininds = NULL;
12674  linvals = NULL;
12675  lincnt = 0;
12676  if( nlininds > 0 )
12677  {
12678  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
12679  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
12680 
12681  for( j = 0; j < consdata->nlinvars; ++j )
12682  {
12683  linvals[j] = consdata->lincoefs[j];
12684  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->linvars[j]));
12685  lininds[j] = (int) (size_t) SCIPhashmapGetImage(scipvar2nlpivar, consdata->linvars[j]);
12686  }
12687 
12688  lincnt = consdata->nlinvars;
12689  }
12690 
12691  /* setup quadratic part */
12692  quadelems = NULL;
12693  if( nquadelems > 0 )
12694  {
12695  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
12696  }
12697  quadcnt = 0;
12698 
12699  for( j = 0; j < consdata->nquadvars; ++j )
12700  {
12701  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->quadvarterms[j].var));
12702  idx1 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, consdata->quadvarterms[j].var);
12703  if( consdata->quadvarterms[j].lincoef != 0.0 )
12704  {
12705  assert(lininds != NULL);
12706  assert(linvals != NULL);
12707  lininds[lincnt] = idx1;
12708  linvals[lincnt] = consdata->quadvarterms[j].lincoef;
12709  ++lincnt;
12710  }
12711 
12712  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
12713  {
12714  assert(quadcnt < nquadelems);
12715  assert(quadelems != NULL);
12716  quadelems[quadcnt].idx1 = idx1;
12717  quadelems[quadcnt].idx2 = idx1;
12718  quadelems[quadcnt].coef = consdata->quadvarterms[j].sqrcoef;
12719  ++quadcnt;
12720  }
12721 
12722  for( l = 0; l < consdata->quadvarterms[j].nadjbilin; ++l )
12723  {
12724  othervar = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].var2;
12725  /* if othervar is on position 2, then we process this bilinear term later (or it was processed already) */
12726  if( othervar == consdata->quadvarterms[j].var )
12727  continue;
12728 
12729  assert(quadcnt < nquadelems);
12730  assert(quadelems != NULL);
12731  assert(SCIPhashmapExists(scipvar2nlpivar, othervar));
12732  idx2 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, othervar);
12733  quadelems[quadcnt].idx1 = MIN(idx1, idx2);
12734  quadelems[quadcnt].idx2 = MAX(idx1, idx2);
12735  quadelems[quadcnt].coef = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].coef;
12736  ++quadcnt;
12737  }
12738  }
12739 
12740  assert(quadcnt == nquadelems);
12741  assert(lincnt == nlininds);
12742 
12743  name = names ? SCIPconsGetName(cons) : NULL;
12744 
12745  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
12746  &consdata->lhs, &consdata->rhs,
12747  &nlininds, &lininds, &linvals ,
12748  &nquadelems, &quadelems,
12749  NULL, NULL, &name) );
12750 
12751  SCIPfreeBufferArrayNull(scip, &quadelems);
12752  SCIPfreeBufferArrayNull(scip, &lininds);
12753  SCIPfreeBufferArrayNull(scip, &linvals);
12754 
12755  return SCIP_OKAY;
12756 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:51
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:16679
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31608
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38254
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:16183
static SCIP_Bool conshdlrdataHasUpgrade(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), const char *conshdlrname)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:38397
static SCIP_RETCODE mergeAndCleanLinearVars(SCIP *scip, SCIP_CONS *cons)
static SCIP_Bool generateCutLTIgenMulCoeff(SCIP *scip, SCIP_Real x1, SCIP_Real y1_, SCIP_Real x2, SCIP_Real y2, SCIP_Bool whichuse, SCIP_Real *cx, SCIP_Real *cy, SCIP_Real *cw)
void SCIPintervalMulSup(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_Real lhs, SCIP_Real rhs, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Bool capturevars)
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:10071
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:5600
static SCIP_RETCODE propagateBoundsQuadVar(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real a, SCIP_INTERVAL b, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
SCIP_Bool SCIPconsIsLocked(SCIP_CONS *cons)
Definition: cons.c:7876
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:5332
static SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:23286
SCIP_BILINTERM * SCIPgetBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
static void consdataMoveLinearVar(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_EXPRGRAPH * SCIPgetExprgraphNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2192
static SCIP_RETCODE consdataSortBilinTerms(SCIP *scip, SCIP_CONSDATA *consdata)
primal heuristic that tries a given solution
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:15788
int SCIPvarGetNBinImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:16662
SCIP_VAR * var2
#define MAXDNOM
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:48
static SCIP_RETCODE separatePoint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Real *bestefficacy)
static SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip.c:20892
static SCIP_RETCODE consdataEnsureQuadVarTermsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
Constraint handler for variable bound constraints .
static SCIP_RETCODE generateCutNonConvex(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_Real *coef, SCIP_Real *lhs, SCIP_Real *rhs, SCIP_Bool *islocal, SCIP_Bool *success, char *name)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:38360
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:591
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:19206
static SCIP_RETCODE propagateBoundsBilinearTerm(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *x, SCIP_Real xsqrcoef, SCIP_Real xlincoef, SCIP_VAR *y, SCIP_Real ysqrcoef, SCIP_Real ylincoef, SCIP_Real bilincoef, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:30926
SCIP_RETCODE SCIPgetViolationQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12169
SCIP_QUADVARTERM * SCIPgetQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:9751
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:10913
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:15968
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1206
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip.c:13986
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38667
static SCIP_DECL_SORTINDCOMP(quadVarTermComp)
SCIP_Real SCIPgetRelaxFeastolFactor(SCIP *scip)
Definition: scip.c:28836
#define SCIP_MAXSTRLEN
Definition: def.h:196
static SCIP_RETCODE replaceQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_VAR *var, SCIP_Real coef, SCIP_Real offset)
#define SCIP_DECL_CONSINITPRE(x)
Definition: type_cons.h:113
#define CONSHDLR_DELAYPROP
SCIP_VAR * var1
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip.c:4990
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4239
SCIP_RETCODE SCIPaddBilinTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
#define NULL
Definition: lpi_spx.cpp:129
SCIP_RETCODE SCIPcreateConsBasicQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:16426
SCIP_Bool SCIPconshdlrWasPresolvingDelayed(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4812
#define CONSHDLR_PROPFREQ
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4209
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1111
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_VAR **quadvars, int nquadelems, SCIP_QUADELEM *quadelems, SCIP_EXPRTREE *expression, SCIP_Real lhs, SCIP_Real rhs)
Definition: scip.c:27037
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:940
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:7786
static SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:18637
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:18583
internal methods for NLPI solver interfaces
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool SCIPintervalIsEmpty(SCIP_INTERVAL operand)
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5078
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:16380
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:236
static SCIP_RETCODE generateCutConvex(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_Real *coef, SCIP_Real *lhs, SCIP_Real *rhs, SCIP_Bool *islocal, SCIP_Bool *success, char *name)
static void consdataUpdateLinearActivityUbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
static SCIP_RETCODE dropLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_RETCODE SCIPsortQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
static void addBilinMcCormick(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:15670
static SCIP_RETCODE generateCut(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Real *ref, SCIP_SOL *sol, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *efficacy, SCIP_Bool checkcurvmultivar, SCIP_Real minefficacy)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:5562
static void consdataUpdateLinearActivityLbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
static SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
#define CONSHDLR_MAXPREROUNDS
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
static SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip.c:7110
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:7846
#define FALSE
Definition: def.h:52
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31902
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:1864
static SCIP_Real getGradientMaxElement(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
#define INITLPMAXVARVAL
SCIP_RETCODE SCIPaddQuadVarLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPwriteVarsPolynomial(SCIP *scip, FILE *file, SCIP_VAR ***monomialvars, SCIP_Real **monomialexps, SCIP_Real *monomialcoefs, int *monomialnvars, int nmonomials, SCIP_Bool type)
Definition: scip.c:14276
static SCIP_RETCODE presolveSolve(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result, SCIP_Bool *redundant, int *naggrvars)
SCIP_BOUNDTYPE SCIPvarGetBestBoundType(SCIP_VAR *var)
Definition: var.c:16482
int SCIPgetNBinVars(SCIP *scip)
Definition: scip.c:10116
#define SCIP_DECL_QUADCONSUPGD(x)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:7209
#define CONSHDLR_SEPAPRIORITY
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:7579
#define TRUE
Definition: def.h:51
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7577
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:30273
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPsolveNLP(SCIP *scip)
Definition: scip.c:26443
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip.c:26466
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:5539
static void consdataFindUnlockedLinearVar(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_Bool delaypresol)
Definition: scip.c:5271
static void checkCurvatureEasy(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *determined, SCIP_Bool checkmultivariate)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
SCIP_VAR ** SCIPgetLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip.c:28238
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:25564
static SCIP_RETCODE removeBilinearTermsPos(SCIP *scip, SCIP_CONS *cons, int nterms, int *termposs)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:19185
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:24136
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol)
SCIP_RETCODE SCIPaddQuadVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
SCIP_DECL_QUADCONSUPGD((*quadconsupgd))
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:31775
SCIP_Real SCIPselectSimpleValue(SCIP_Real lb, SCIP_Real ub, SCIP_Longint maxdnom)
Definition: misc.c:7132
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:19214
static SCIP_RETCODE presolveTryAddAND(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
Constraint handler for "and" constraints, .
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:16227
SCIP_Bool SCIPisLinearLocalQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddToNlpiProblemQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *nlpiprob, SCIP_HASHMAP *scipvar2nlpivar, SCIP_Bool names)
static SCIP_RETCODE mergeAndCleanBilinearTerms(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetRhsNonlinear(SCIP *scip, SCIP_CONS *cons)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:1923
static SCIP_RETCODE chgLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_Real newcoef)
static SCIP_RETCODE propagateBoundsCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_RESULT *result, int *nchgbds, SCIP_Bool *redundant)
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:10251
static SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING timingmask)
Definition: scip.c:5036
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:7776
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:7716
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:23934
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:28256
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:22651
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
static SCIP_RETCODE dropQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:99
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:19215
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty)
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:25739
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11177
SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
Definition: scip.c:26586
SCIP_Real SCIPgetLhsNonlinear(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE lockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_RETCODE SCIPincludeConshdlrQuadratic(SCIP *scip)
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:5103
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:7706
SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
static SCIP_RETCODE unlockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31855
static void addSquareSecant(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real lb, SCIP_Real ub, SCIP_Real refpoint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip.c:7339
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:95
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip.c:26334
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:5127
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3388
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:15907
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:1966
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3414
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:15979
SCIP_Bool SCIPisIpoptAvailableIpopt(void)
SCIP_RETCODE SCIPcreateConsQuadratic(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12229
static SCIP_RETCODE consdataSortQuadVarTerms(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3893
#define CONSHDLR_EAGERFREQ
static void addSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
void SCIPaddConstantQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real constant)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:33378
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1096
SCIP_Real coef
Definition: type_expr.h:101
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:118
SCIP_Real inf
Definition: intervalarith.h:38
SCIP_RETCODE SCIPincludeNonlinconsUpgrade(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)), SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)), int priority, SCIP_Bool active, const char *conshdlrname)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38273
static SCIP_RETCODE addQuadVarTerm(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef, SCIP_Bool catchevents)
static SCIP_RETCODE checkCurvature(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkmultivariate)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:15930
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip.c:1690
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:19183
static SCIP_RETCODE presolveTryAddLinearReform(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
static void generateCutFactorableDo(SCIP *scip, SCIP_CONS *cons, SCIP_Real *ref, SCIP_Real multleft, SCIP_Real *coefleft, SCIP_Real multright, SCIP_Real *coefright, SCIP_Real rightminactivity, SCIP_Real rightmaxactivity, SCIP_Real rhs, SCIP_Real *cutcoef, SCIP_Real *cutrhs, SCIP_Bool *islocal, SCIP_Bool *success, char *name)
SCIP_RETCODE SCIPcheckCurvatureQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real * SCIPgetLinearCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:38755
static SCIP_DECL_CONSEXIT(consExitQuadratic)
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:38421
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip.c:15319
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:7816
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:19159
static void propagateBoundsGetQuadActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty, SCIP_Real *minquadactivity, SCIP_Real *maxquadactivity, int *minactivityinf, int *maxactivityinf, SCIP_INTERVAL *quadactcontr)
int SCIPgetNLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addLinearizationCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *ref, SCIP_Bool *separatedlpsol, SCIP_Real minefficacy)
SCIP_Real SCIPgetPrimalRayVal(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:33273
#define SCIPerrorMessage
Definition: pub_message.h:45
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:19221
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:18647
interval arithmetics for provable bounds
static SCIP_RETCODE removeFixedVariables(SCIP *scip, SCIP_CONS *cons)
#define SCIPdebugPrintf
Definition: pub_message.h:80
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:19207
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:17713
static SCIP_RETCODE generateCutSol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_SOL *refsol, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *efficacy, SCIP_Bool checkcurvmultivar, SCIP_Real minefficacy)
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:69
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
SCIP_Bool SCIPisInRestart(SCIP *scip)
Definition: scip.c:13949
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:38767
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss)
SCIP_RETCODE SCIPcheckCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_RESULT *result)
Definition: scip.c:23568
static SCIP_DECL_CONSDELETE(consDeleteQuadratic)
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3873
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:964
static SCIP_DECL_CONSPARSE(consParseQuadratic)
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:37705
static SCIP_RETCODE catchQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:15989
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip.c:26083
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38292
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:25827
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip.c:17898
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28351
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:37940
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
static SCIP_DECL_CONSCHECK(consCheckQuadratic)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7557
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:15999
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:63
static SCIP_DECL_CONSPRESOL(consPresolQuadratic)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:38470
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:18746
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:146
static SCIP_DECL_CONSTRANS(consTransQuadratic)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:1882
constraint handler for quadratic constraints
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:5247
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:19189
static SCIP_RETCODE generateCutFactorable(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_Real *cutcoef, SCIP_Real *cutlhs, SCIP_Real *cutrhs, SCIP_Bool *islocal, SCIP_Bool *success, char *name)
SCIP_RETCODE SCIPfindQuadVarTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, int *pos)
#define CONSHDLR_CHECKPRIORITY
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:16694
#define REALABS(x)
Definition: def.h:146
SCIP_Bool SCIPisConcaveQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddLinearVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPenableNLP(SCIP *scip)
Definition: scip.c:26068
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:16159
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:38349
struct SCIP_QuadVarEventData SCIP_QUADVAREVENTDATA
#define SCIP_CALL(x)
Definition: def.h:258
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_CONS **maxviolcon)
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip.c:4936
#define CONSHDLR_ENFOPRIORITY
SCIP_Real sup
Definition: intervalarith.h:39
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:34128
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_RETCODE SCIPaddLinearConsToNlpHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_Bool addcombconss, SCIP_Bool addcontconss)
Definition: heur_subnlp.c:2224
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:18696
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:29454
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38705
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:246
static void getImpliedBounds(SCIP_VAR *x, SCIP_Bool xval, SCIP_VAR *y, SCIP_INTERVAL *resultant)
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:49
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:97
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7587
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:15130
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
Definition: scip.c:38372
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:96
static SCIP_RETCODE consdataEnsureAdjBilinSize(SCIP *scip, SCIP_QUADVARTERM *quadvarterm, int num)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11453
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
Definition: scip.c:35202
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38311
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12332
Ipopt NLP interface.
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip.c:20694
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1181
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:18371
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:15097
static SCIP_RETCODE propagateBoundsTightenVarUb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:16436
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip.c:983
SCIP_RETCODE SCIPaddLinearCoefsToNlRow(SCIP *scip, SCIP_NLROW *nlrow, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:27259
#define CONSHDLR_NEEDSCONS
unsigned int SCIP_EVENTTYPE
Definition: type_event.h:125
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip.c:1020
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip.c:22476
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38537
static SCIP_DECL_CONSINITLP(consInitlpQuadratic)
#define SCIP_Bool
Definition: def.h:49
static SCIP_DECL_CONSFREE(consFreeQuadratic)
static SCIP_RETCODE presolveDisaggregate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13747
#define CONSHDLR_DELAYSEPA
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:16648
static const char * paramname[]
Definition: lpi_msk.c:4129
SCIP_Real SCIPvarGetBestBoundLocal(SCIP_VAR *var)
Definition: var.c:16456
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:790
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:7796
SCIP_RETCODE SCIPcreateConsBasicQuadratic(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs)
#define NONLINCONSUPGD_PRIORITY
constraint handler for nonlinear constraints
void SCIPintervalSolveBivariateQuadExpressionAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:19222
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:7650
static SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
static SCIP_RETCODE replaceByLinearConstraints(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *addedcons, SCIP_Bool *reduceddom, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip.c:31124
static SCIP_RETCODE registerLargeLPValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_VAR **brvar)
methods for debugging
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:7806
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:7906
SCIP_Real * SCIPgetCoefsLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real coef
int SCIPgetNQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPgetNlRowQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:16147
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:5355
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:25703
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
#define SCIPreallocMemoryArray(scip, ptr, newnum)
Definition: scip.h:19167
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:102
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:16171
#define infty2infty(infty1, infty2, val)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
Constraint handler for linear constraints in their most general form, .
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_NAME
#define BMSclearMemory(ptr)
Definition: memory.h:97
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:19204
SCIP_Real SCIPvarGetWorstBoundLocal(SCIP_VAR *var)
Definition: var.c:16469
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip.c:33535
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip.c:31734
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:6729
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:34833
SCIP_Bool SCIPhasPrimalRay(SCIP *scip)
Definition: scip.c:33255
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12261
SCIP_RETCODE SCIPparseVarsPolynomial(SCIP *scip, const char *str, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int *nmonomials, char **endptr, SCIP_Bool *success)
Definition: scip.c:14689
static void generateCutLTIcomputeCoefs(SCIP *scip, SCIP_Real xl, SCIP_Real xu, SCIP_Real x0, SCIP_Real yl, SCIP_Real yu, SCIP_Real y0_, SCIP_Real wl, SCIP_Real wu, SCIP_Real w0, SCIP_Real *cx, SCIP_Real *cy, SCIP_Real *cw, SCIP_Real *c0, SCIP_Bool *success)
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1256
static SCIP_Bool generateCutLTIfindIntersection(SCIP *scip, SCIP_Real x0, SCIP_Real y0_, SCIP_Real x1, SCIP_Real y1_, SCIP_Real wl, SCIP_Real wu, SCIP_Real *xl, SCIP_Real *yl, SCIP_Real *xu, SCIP_Real *yu)
static void addBilinLinearization(SCIP *scip, SCIP_Real bilincoef, SCIP_Real refpointx, SCIP_Real refpointy, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12344
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38330
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:33424
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:5309
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:10850
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:15953
SCIP_QUADVAREVENTDATA * eventdata
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip.c:5175
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2258
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:38482
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:19176
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:16370
static SCIP_RETCODE addBilinearTerm(SCIP *scip, SCIP_CONS *cons, int var1pos, int var2pos, SCIP_Real coef)
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:33344
static void consdataMoveQuadVarTerm(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:5516
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:3636
static SCIP_RETCODE consdataCreateEmpty(SCIP *scip, SCIP_CONSDATA **consdata)
static SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip.c:27144
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1239
#define CONSHDLR_DESC
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNIntVars(SCIP *scip)
Definition: scip.c:10161
SCIP_RETCODE SCIPcreateConsAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_and.c:4915
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:38433
static SCIP_DECL_CONSCOPY(consCopyQuadratic)
static SCIP_DECL_CONSINIT(consInitQuadratic)
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingModeUpwards(void)
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:18593
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:5199
static SCIP_RETCODE generateCutLTI(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_SOL *sol, SCIP_Real **cutcoeflin, SCIP_Real *cutcoefquad, SCIP_Real *cutlhs, SCIP_Real *cutrhs, SCIP_Bool *islocal, SCIP_Bool *success, char *name)
NLP local search primal heuristic using sub-SCIPs.
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38686
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:17642
void SCIPfreeParseVarsPolynomialData(SCIP *scip, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int nmonomials)
Definition: scip.c:15041
#define SCIP_Real
Definition: def.h:123
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:7736
SCIP_RETCODE SCIPaddCharParam(SCIP *scip, const char *name, const char *desc, char *valueptr, SCIP_Bool isadvanced, char defaultvalue, const char *allowedvalues, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3498
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:18477
#define MIN(x, y)
Definition: memory.c:59
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:25276
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:30898
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:26010
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:38724
static SCIP_RETCODE checkFactorable(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeQuadconsUpgrade(SCIP *scip, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:19198
SCIP_RETCODE SCIPnlpiAddConstraints(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nconss, const SCIP_Real *lhss, const SCIP_Real *rhss, const int *nlininds, int *const *lininds, SCIP_Real *const *linvals, const int *nquadelems, SCIP_QUADELEM *const *quadelems, int *const *exprvaridxs, SCIP_EXPRTREE *const *exprtrees, const char **names)
Definition: nlpi.c:268
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12179
#define SCIP_INVALID
Definition: def.h:142
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:37733
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:25414
void SCIPsortInt(int *intarray, int len)
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:26411
static SCIP_RETCODE propagateBoundsTightenVarLb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE delLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIP_Longint
Definition: def.h:107
static SCIP_RETCODE consdataEnsureBilinSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
int SCIPgetNNlpis(SCIP *scip)
Definition: scip.c:8116
static SCIP_RETCODE registerVariableInfeasibilities(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip.c:17866
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:917
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:245
static SCIP_DECL_CONSLOCK(consLockQuadratic)
#define CONSHDLR_DELAYPRESOL
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:5151
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
Definition: scip.c:38494
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:17590
SCIP_RETCODE SCIPcreateConsQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
SCIP_RETCODE SCIPaddSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:39080
int SCIP_ROUNDMODE
Definition: intervalarith.h:45
void SCIPintervalMulInf(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:18558
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:48
static SCIP_DECL_EVENTEXEC(processVarEvent)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16052
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip.c:30565
static SCIP_RETCODE addLinearCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPaddConsLocal(SCIP *scip, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip.c:11372
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:16708
#define CONSHDLR_PROP_TIMING
static SCIP_DECL_CONSPROP(consPropQuadratic)
static SCIP_RETCODE delQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos)
static SCIP_DECL_CONSPRINT(consPrintQuadratic)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:38001
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:1901
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:98
static SCIP_RETCODE presolveDisaggregateMarkComponent(SCIP *scip, SCIP_CONSDATA *consdata, int quadvaridx, SCIP_HASHMAP *var2component, int componentnr)
#define CONSHDLR_SEPAFREQ
SCIP_Real SCIPgetLhsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE propagateBounds(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_RESULT *result, int *nchgbds)
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12368
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:18407
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:38409
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1120
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3470
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:5585
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:7644
#define SCIPfreeMemoryArrayNull(scip, ptr)
Definition: scip.h:19179
#define SCIPABORT()
Definition: def.h:230
static SCIP_RETCODE consdataFindQuadVarTerm(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR *var, int *pos)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:7726
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:6595
static SCIP_RETCODE mergeAndCleanQuadVarTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:7756
SCIP_RETCODE LapackDsyev(SCIP_Bool computeeigenvectors, int N, SCIP_Real *a, SCIP_Real *w)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3159
SCIP_Real SCIPgetRhsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE consdataEnsureLinearVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
void SCIPintervalSetRoundingModeDownwards(void)
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:33310
SCIP_Bool SCIPisConvexQuadratic(SCIP *scip, SCIP_CONS *cons)
void SCIPintervalSolveUnivariateQuadExpressionPositive(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:31403
static SCIP_RETCODE generateCutUnboundedLP(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *rowrayprod, SCIP_Bool checkcurvmultivar)
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
enum SCIP_SideType SCIP_SIDETYPE
Definition: type_lp.h:58
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12356