Scippy

SCIP

Solving Constraint Integer Programs

cons_quadratic.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2017 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_quadratic.c
17  * @brief constraint handler for quadratic constraints \f$\textrm{lhs} \leq \sum_{i,j=1}^n a_{i,j} x_i x_j + \sum_{i=1}^n b_i x_i \leq \textrm{rhs}\f$
18  * @author Stefan Vigerske
19  * @author Benjamin Mueller
20  * @author Felipe Serrano
21  *
22  * @todo SCIP might fix linear variables on +/- infinity; remove them in presolve and take care later
23  * @todo round constraint sides to integers if all coefficients and variables are (impl.) integer
24  * @todo constraints in one variable should be replaced by linear or bounddisjunction constraint
25  * @todo check if some quadratic terms appear in several constraints and try to simplify (e.g., nous1)
26  * @todo skip separation in enfolp if for current LP (check LP id) was already separated
27  * @todo watch unbounded variables to enable/disable propagation
28  * @todo sort order in bilinvar1/bilinvar2 such that the var which is involved in more terms is in bilinvar1, and use this info propagate and AddLinearReform
29  * @todo underestimate for multivariate concave quadratic terms as in cons_nonlinear
30  */
31 
32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33 
34 #include <assert.h>
35 #include <string.h> /* for strcmp */
36 #include <ctype.h> /* for isspace */
37 #include <math.h>
38 
39 #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"
45 #include "scip/intervalarith.h"
46 #include "scip/heur_subnlp.h"
47 #include "scip/heur_trysol.h"
48 #include "scip/debug.h"
49 #include "nlpi/nlpi.h"
50 #include "nlpi/nlpi_ipopt.h"
51 
52 /* constraint handler properties */
53 #define CONSHDLR_NAME "quadratic"
54 #define CONSHDLR_DESC "quadratic constraints of the form lhs <= b' x + x' A x <= rhs"
55 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
56 #define CONSHDLR_ENFOPRIORITY -50 /**< priority of the constraint handler for constraint enforcing */
57 #define CONSHDLR_CHECKPRIORITY -4000000 /**< priority of the constraint handler for checking feasibility */
58 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
59 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
60 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
61  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
62 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
63 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
64 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators 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 /**< propagation timing mask of the constraint handler */
68 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
69 
70 #define MAXDNOM 10000LL /**< maximal denominator for simple rational fixed values */
71 #define NONLINCONSUPGD_PRIORITY 40000 /**< priority of upgrading nonlinear constraints */
72 #define INITLPMAXVARVAL 1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
73 
74 /* Activating this define enables reformulation of bilinear terms x*y with implications from x to y into linear terms.
75  * 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,
76  * then the implication may not be enforced in a solution.
77  * This issue need to be fixed before this feature can be enabled.
78  */
79 /* #define CHECKIMPLINBILINEAR */
80 
81 /* enable new propagation for bivariate quadratic terms */
82 #define PROPBILINNEW
83 
84 /* epsilon for differentiating between a boundary and interior point */
85 #define INTERIOR_EPS 1e-1
86 
87 /* scaling factor for gauge function */
88 #define GAUGESCALE 0.99999
89 
90 /*
91  * Data structures
92  */
93 
94 /** eventdata for variable bound change events in quadratic constraints */
95 struct SCIP_QuadVarEventData
96 {
97  SCIP_CONS* cons; /**< the constraint */
98  int varidx; /**< the index of the variable which bound change is caught, positive for linear variables, negative for quadratic variables */
99  int filterpos; /**< position of eventdata in SCIP's event filter */
100 };
101 
102 /** Data of a quadratic constraint. */
103 struct SCIP_ConsData
104 {
105  SCIP_Real lhs; /**< left hand side of constraint */
106  SCIP_Real rhs; /**< right hand side of constraint */
107 
108  int nlinvars; /**< number of linear variables */
109  int linvarssize; /**< length of linear variable arrays */
110  SCIP_VAR** linvars; /**< linear variables */
111  SCIP_Real* lincoefs; /**< coefficients of linear variables */
112  SCIP_QUADVAREVENTDATA** lineventdata; /**< eventdata for bound change of linear variable */
113 
114  int nquadvars; /**< number of variables in quadratic terms */
115  int quadvarssize; /**< length of quadratic variable terms arrays */
116  SCIP_QUADVARTERM* quadvarterms; /**< array with quadratic variable terms */
117 
118  int nbilinterms; /**< number of bilinear terms */
119  int bilintermssize; /**< length of bilinear term arrays */
120  SCIP_BILINTERM* bilinterms; /**< bilinear terms array */
121 
122  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
123 
124  unsigned int linvarssorted:1; /**< are the linear variables already sorted? */
125  unsigned int linvarsmerged:1; /**< are equal linear variables already merged? */
126  unsigned int quadvarssorted:1; /**< are the quadratic variables already sorted? */
127  unsigned int quadvarsmerged:1; /**< are equal quadratic variables already merged? */
128  unsigned int bilinsorted:1; /**< are the bilinear terms already sorted? */
129  unsigned int bilinmerged:1; /**< are equal bilinear terms (and bilinear terms with zero coefficient) already merged? */
130 
131  unsigned int isconvex:1; /**< is quadratic function is convex ? */
132  unsigned int isconcave:1; /**< is quadratic function is concave ? */
133  unsigned int iscurvchecked:1; /**< is quadratic function checked on convexity or concavity ? */
134  unsigned int isremovedfixings:1; /**< did we removed fixed/aggr/multiaggr variables ? */
135  unsigned int ispropagated:1; /**< was the constraint propagated with respect to the current bounds ? */
136  unsigned int ispresolved:1; /**< did we checked for possibilities of upgrading or implicit integer variables ? */
137  unsigned int initialmerge:1; /**< did we perform an initial merge and clean in presolving yet ? */
138 #ifdef CHECKIMPLINBILINEAR
139  unsigned int isimpladded:1; /**< has there been an implication added for a binary variable in a bilinear term? */
140 #endif
141  unsigned int isgaugeavailable:1; /**< is the gauge function computed? */
142  unsigned int isedavailable:1; /**< is the eigen decomposition of A available? */
143 
144  SCIP_Real minlinactivity; /**< sum of minimal activities of all linear terms with finite minimal activity */
145  SCIP_Real maxlinactivity; /**< sum of maximal activities of all linear terms with finite maximal activity */
146  int minlinactivityinf; /**< number of linear terms with infinite minimal activity */
147  int maxlinactivityinf; /**< number of linear terms with infinity maximal activity */
148  SCIP_INTERVAL quadactivitybounds; /**< bounds on the activity of the quadratic term, if up to date, otherwise empty interval */
149  SCIP_Real activity; /**< activity of quadratic function w.r.t. current solution */
150  SCIP_Real lhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
151  SCIP_Real rhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
152 
153  int linvar_maydecrease; /**< index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
154  int linvar_mayincrease; /**< index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
155 
156  SCIP_VAR** sepaquadvars; /**< variables corresponding to quadvarterms to use in separation, only available in solving stage */
157  int* sepabilinvar2pos; /**< position of second variable in bilinear terms to use in separation, only available in solving stage */
158  SCIP_Real lincoefsmin; /**< minimal absolute value of coefficients in linear part, only available in solving stage */
159  SCIP_Real lincoefsmax; /**< maximal absolute value of coefficients in linear part, only available in solving stage */
160 
161  SCIP_Real* factorleft; /**< coefficients of left factor if constraint function is factorable */
162  SCIP_Real* factorright; /**< coefficients of right factor if constraint function is factorable */
163 
164  SCIP_Real* gaugecoefs; /**< coefficients of the gauge function */
165  SCIP_Real gaugeconst; /**< constant of the gauge function */
166  SCIP_Real* interiorpoint; /**< interior point of the region defined by the convex function */
167  SCIP_Real interiorpointval; /**< function value at interior point */
168 
169  SCIP_Real* eigenvalues; /**< eigenvalues of A */
170  SCIP_Real* eigenvectors; /**< orthonormal eigenvectors of A; if A = P D P^T, then eigenvectors is P^T */
171  SCIP_Real* bp; /**< stores b * P where b are the linear coefficients of the quadratic vars */
172 };
173 
174 /** quadratic constraint update method */
176 {
177  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)); /**< method to call for upgrading quadratic constraint */
178  int priority; /**< priority of upgrading method */
179  SCIP_Bool active; /**< is upgrading enabled */
180 };
181 typedef struct SCIP_QuadConsUpgrade SCIP_QUADCONSUPGRADE; /**< quadratic constraint update method */
183 /** constraint handler data */
184 struct SCIP_ConshdlrData
185 {
186  int replacebinaryprodlength; /**< length of linear term which when multiplied with a binary variable is replaced by an auxiliary variable and an equivalent linear formulation */
187  int empathy4and; /**< how much empathy we have for using the AND constraint handler: 0 avoid always; 1 use sometimes; 2 use as often as possible */
188  SCIP_Bool binreforminitial; /**< whether to make constraints added due to replacing products with binary variables initial */
189  SCIP_Real binreformmaxcoef; /**< factor on 1/feastol to limit coefficients and coef range in linear constraints created by binary reformulation */
190  SCIP_Real mincutefficacysepa; /**< minimal efficacy of a cut in order to add it to relaxation during separation */
191  SCIP_Real mincutefficacyenfofac; /**< minimal target efficacy of a cut in order to add it to relaxation during enforcement as factor of feasibility tolerance (may be ignored) */
192  char scaling; /**< scaling method of constraints in feasibility check */
193  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
194  SCIP_Bool linearizeheursol; /**< whether linearizations of convex quadratic constraints should be added to cutpool when some heuristics finds a new solution */
195  SCIP_Bool checkcurvature; /**< whether functions should be checked for convexity/concavity */
196  SCIP_Bool checkfactorable; /**< whether functions should be checked to be factorable */
197  char checkquadvarlocks; /**< whether quadratic variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction) */
198  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
199  SCIP_Bool disaggregate; /**< whether to disaggregate quadratic constraints */
200  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve */
201  int maxproproundspresolve; /**< limit on number of propagation rounds for a single constraint within one presolving round */
202  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
203  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
204  SCIP_Bool gaugecuts; /**< should convex quadratics generated strong cuts via gauge function? */
205  SCIP_Bool projectedcuts; /**< should convex quadratics generated strong cuts via projections? */
206  char interiorcomputation;/**< how the interior point should be computed: 'a'ny point per constraint,
207  * 'm'ost interior per constraint
208  */
209  char branchscoring; /**< method to use to compute score of branching candidates */
210  int enfolplimit; /**< maximum number of enforcement round before declaring the LP relaxation
211  * infeasible (-1: no limit); WARNING: if this parameter is not set to -1,
212  * SCIP might declare sub-optimal solutions optimal or feasible instances
213  * infeasible; thus, the result returned by SCIP might be incorrect!
214  */
215  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
216  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
217  SCIP_EVENTHDLR* eventhdlr; /**< our handler for variable bound change events */
218  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
219  SCIP_Bool sepanlp; /**< where linearization of the NLP relaxation solution added? */
220  SCIP_NODE* lastenfonode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
221  int nenforounds; /**< counter on number of enforcement rounds for the current node */
222  SCIP_QUADCONSUPGRADE** quadconsupgrades; /**< quadratic constraint upgrade methods for specializing quadratic constraints */
223  int quadconsupgradessize; /**< size of quadconsupgrade array */
224  int nquadconsupgrades; /**< number of quadratic constraint upgrade methods */
225 };
226 
227 
228 /*
229  * local methods for managing quadratic constraint update methods
230  */
231 
232 
233 /** checks whether a quadratic constraint upgrade method has already be registered */
234 static
236  SCIP* scip, /**< SCIP data structure */
237  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
238  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
239  const char* conshdlrname /**< name of the constraint handler */
240  )
241 {
242  int i;
243 
244  assert(scip != NULL);
245  assert(conshdlrdata != NULL);
246  assert(quadconsupgd != NULL);
247  assert(conshdlrname != NULL);
248 
249  for( i = conshdlrdata->nquadconsupgrades - 1; i >= 0; --i )
250  {
251  if( conshdlrdata->quadconsupgrades[i]->quadconsupgd == quadconsupgd )
252  {
253  SCIPwarningMessage(scip, "Try to add already known upgrade message for constraint handler <%s>.\n", conshdlrname);
254  return TRUE;
255  }
256  }
257 
258  return FALSE;
259 }
260 
261 /*
262  * Local methods
263  */
264 
265 /** translate from one value of infinity to another
266  *
267  * if val is >= infty1, then give infty2, else give val
268  */
269 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
271 /** catches variable bound change events on a linear variable in a quadratic constraint */
272 static
274  SCIP* scip, /**< SCIP data structure */
275  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
276  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
277  int linvarpos /**< position of variable in linear variables array */
278  )
279 {
280  SCIP_CONSDATA* consdata;
281  SCIP_QUADVAREVENTDATA* eventdata;
282  SCIP_EVENTTYPE eventtype;
283 
284  assert(scip != NULL);
285  assert(eventhdlr != NULL);
286  assert(cons != NULL);
287 
288  consdata = SCIPconsGetData(cons);
289  assert(consdata != NULL);
290 
291  assert(linvarpos >= 0);
292  assert(linvarpos < consdata->nlinvars);
293  assert(consdata->lineventdata != NULL);
294 
295  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
296 
297  eventdata->cons = cons;
298  eventdata->varidx = linvarpos;
299 
300  eventtype = SCIP_EVENTTYPE_VARFIXED;
301  if( !SCIPisInfinity(scip, consdata->rhs) )
302  {
303  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
304  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
305  if( consdata->lincoefs[linvarpos] > 0.0 )
306  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
307  else
308  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
309  }
310  if( !SCIPisInfinity(scip, -consdata->lhs) )
311  {
312  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
313  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
314  if( consdata->lincoefs[linvarpos] > 0.0 )
315  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
316  else
317  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
318  }
319 
320  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
321 
322  consdata->lineventdata[linvarpos] = eventdata;
323 
324  /* invalidate activity information
325  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
326  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
327  */
328  consdata->minlinactivity = SCIP_INVALID;
329  consdata->maxlinactivity = SCIP_INVALID;
330  consdata->minlinactivityinf = -1;
331  consdata->maxlinactivityinf = -1;
332 
333  return SCIP_OKAY;
334 }
335 
336 /** drops variable bound change events on a linear variable in a quadratic constraint */
337 static
339  SCIP* scip, /**< SCIP data structure */
340  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
341  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
342  int linvarpos /**< position of variable in linear variables array */
343  )
344 {
345  SCIP_CONSDATA* consdata;
346  SCIP_EVENTTYPE eventtype;
347 
348  assert(scip != NULL);
349  assert(eventhdlr != NULL);
350  assert(cons != NULL);
351 
352  consdata = SCIPconsGetData(cons);
353  assert(consdata != NULL);
354 
355  assert(linvarpos >= 0);
356  assert(linvarpos < consdata->nlinvars);
357  assert(consdata->lineventdata != NULL);
358  assert(consdata->lineventdata[linvarpos] != NULL);
359  assert(consdata->lineventdata[linvarpos]->cons == cons);
360  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
361  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
362 
363  eventtype = SCIP_EVENTTYPE_VARFIXED;
364  if( !SCIPisInfinity(scip, consdata->rhs) )
365  {
366  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
367  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
368  if( consdata->lincoefs[linvarpos] > 0.0 )
369  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
370  else
371  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
372  }
373  if( !SCIPisInfinity(scip, -consdata->lhs) )
374  {
375  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
376  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
377  if( consdata->lincoefs[linvarpos] > 0.0 )
378  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
379  else
380  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
381  }
382 
383  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
384 
385  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866 */
386 
387  return SCIP_OKAY;
388 }
389 
390 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
391 static
393  SCIP* scip, /**< SCIP data structure */
394  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
395  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
396  int quadvarpos /**< position of variable in quadratic variables array */
397  )
398 {
399  SCIP_CONSDATA* consdata;
400  SCIP_QUADVAREVENTDATA* eventdata;
401  SCIP_EVENTTYPE eventtype;
402 
403  assert(scip != NULL);
404  assert(eventhdlr != NULL);
405  assert(cons != NULL);
406 
407  consdata = SCIPconsGetData(cons);
408  assert(consdata != NULL);
409 
410  assert(quadvarpos >= 0);
411  assert(quadvarpos < consdata->nquadvars);
412  assert(consdata->quadvarterms[quadvarpos].eventdata == NULL);
413 
414  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
415 
417 #ifdef CHECKIMPLINBILINEAR
418  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
419 #endif
420  eventdata->cons = cons;
421  eventdata->varidx = -quadvarpos-1;
422  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
423 
424  consdata->quadvarterms[quadvarpos].eventdata = eventdata;
425 
426  /* invalidate activity information
427  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
428  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
429  */
430  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
431 
432  return SCIP_OKAY;
433 }
434 
435 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
436 static
438  SCIP* scip, /**< SCIP data structure */
439  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
440  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
441  int quadvarpos /**< position of variable in quadratic variables array */
442  )
443 {
444  SCIP_CONSDATA* consdata;
445  SCIP_EVENTTYPE eventtype;
446 
447  assert(scip != NULL);
448  assert(eventhdlr != NULL);
449  assert(cons != NULL);
450 
451  consdata = SCIPconsGetData(cons);
452  assert(consdata != NULL);
453 
454  assert(quadvarpos >= 0);
455  assert(quadvarpos < consdata->nquadvars);
456  assert(consdata->quadvarterms[quadvarpos].eventdata != NULL);
457  assert(consdata->quadvarterms[quadvarpos].eventdata->cons == cons);
458  assert(consdata->quadvarterms[quadvarpos].eventdata->varidx == -quadvarpos-1);
459  assert(consdata->quadvarterms[quadvarpos].eventdata->filterpos >= 0);
460 
462 #ifdef CHECKIMPLINBILINEAR
463  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
464 #endif
465 
466  SCIP_CALL( SCIPdropVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->quadvarterms[quadvarpos].eventdata, consdata->quadvarterms[quadvarpos].eventdata->filterpos) );
467 
468  SCIPfreeBlockMemory(scip, &consdata->quadvarterms[quadvarpos].eventdata);
469 
470  return SCIP_OKAY;
471 }
472 
473 /** catch variable events */
474 static
476  SCIP* scip, /**< SCIP data structure */
477  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
478  SCIP_CONS* cons /**< constraint for which to catch bound change events */
479  )
480 {
481  SCIP_CONSDATA* consdata;
482  SCIP_VAR* var;
483  int i;
484 
485  assert(scip != NULL);
486  assert(cons != NULL);
487  assert(eventhdlr != NULL);
488 
489  consdata = SCIPconsGetData(cons);
490  assert(consdata != NULL);
491  assert(consdata->lineventdata == NULL);
492 
493  /* we will update isremovedfixings, so reset it to TRUE first */
494  consdata->isremovedfixings = TRUE;
495 
496  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
497  for( i = 0; i < consdata->nlinvars; ++i )
498  {
499  SCIP_CALL( catchLinearVarEvents(scip, eventhdlr, cons, i) );
500 
501  var = consdata->linvars[i];
502  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
503  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
504  }
505 
506  for( i = 0; i < consdata->nquadvars; ++i )
507  {
508  assert(consdata->quadvarterms[i].eventdata == NULL);
509 
510  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, i) );
511 
512  var = consdata->quadvarterms[i].var;
513  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
514  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
515  }
516 
517  consdata->ispropagated = FALSE;
518 
519  return SCIP_OKAY;
520 }
521 
522 /** drop variable events */
523 static
525  SCIP* scip, /**< SCIP data structure */
526  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
527  SCIP_CONS* cons /**< constraint for which to drop bound change events */
528  )
529 {
530  SCIP_CONSDATA* consdata;
531  int i;
532 
533  assert(scip != NULL);
534  assert(eventhdlr != NULL);
535  assert(cons != NULL);
536 
537  consdata = SCIPconsGetData(cons);
538  assert(consdata != NULL);
539 
540  if( consdata->lineventdata != NULL )
541  {
542  for( i = 0; i < consdata->nlinvars; ++i )
543  {
544  if( consdata->lineventdata[i] != NULL )
545  {
546  SCIP_CALL( dropLinearVarEvents(scip, eventhdlr, cons, i) );
547  }
548  }
549  SCIPfreeBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize);
550  }
551 
552  for( i = 0; i < consdata->nquadvars; ++i )
553  {
554  if( consdata->quadvarterms[i].eventdata != NULL )
555  {
556  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, i) );
557  }
558  }
559 
560  return SCIP_OKAY;
561 }
562 
563 /** locks a linear variable in a constraint */
564 static
566  SCIP* scip, /**< SCIP data structure */
567  SCIP_CONS* cons, /**< constraint where to lock a variable */
568  SCIP_VAR* var, /**< variable to lock */
569  SCIP_Real coef /**< coefficient of variable in constraint */
570  )
571 {
572  SCIP_CONSDATA* consdata;
573 
574  assert(scip != NULL);
575  assert(cons != NULL);
576  assert(var != NULL);
577  assert(coef != 0.0);
578 
579  consdata = SCIPconsGetData(cons);
580  assert(consdata != NULL);
581 
582  if( coef > 0.0 )
583  {
584  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
585  }
586  else
587  {
588  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
589  }
590 
591  return SCIP_OKAY;
592 }
593 
594 /** unlocks a linear variable in a constraint */
595 static
597  SCIP* scip, /**< SCIP data structure */
598  SCIP_CONS* cons, /**< constraint where to unlock a variable */
599  SCIP_VAR* var, /**< variable to unlock */
600  SCIP_Real coef /**< coefficient of variable in constraint */
601  )
602 {
603  SCIP_CONSDATA* consdata;
604 
605  assert(scip != NULL);
606  assert(cons != NULL);
607  assert(var != NULL);
608  assert(coef != 0.0);
609 
610  consdata = SCIPconsGetData(cons);
611  assert(consdata != NULL);
612 
613  if( coef > 0.0 )
614  {
615  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
616  }
617  else
618  {
619  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
620  }
621 
622  return SCIP_OKAY;
623 }
624 
625 /** locks a quadratic variable in a constraint */
626 static
628  SCIP* scip, /**< SCIP data structure */
629  SCIP_CONS* cons, /**< constraint where to lock a variable */
630  SCIP_VAR* var /**< variable to lock */
631  )
632 {
633  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
634 
635  return SCIP_OKAY;
636 }
637 
638 /** unlocks a quadratic variable in a constraint */
639 static
641  SCIP* scip, /**< SCIP data structure */
642  SCIP_CONS* cons, /**< constraint where to unlock a variable */
643  SCIP_VAR* var /**< variable to unlock */
644  )
645 {
646  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
647 
648  return SCIP_OKAY;
649 }
650 
651 /** computes the minimal and maximal activity for the linear part in a constraint data
652  *
653  * Only sums up terms that contribute finite values.
654  * Gives the number of terms that contribute infinite values.
655  * Only computes those activities where the corresponding side of the constraint is finite.
656  */
657 static
659  SCIP* scip, /**< SCIP data structure */
660  SCIP_CONSDATA* consdata, /**< constraint data */
661  SCIP_Real intervalinfty /**< infinity value used in interval operations */
662  )
663 { /*lint --e{666}*/
664  SCIP_ROUNDMODE prevroundmode;
665  int i;
666  SCIP_Real bnd;
667 
668  assert(scip != NULL);
669  assert(consdata != NULL);
670 
671  /* if variable bounds are not strictly consistent, then the activity update methods may yield inconsistent activities
672  * in this case, we also recompute the activities
673  */
674  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID && /*lint !e777 */
675  (consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity) )
676  {
677  /* activities should be up-to-date */
678  assert(consdata->minlinactivityinf >= 0);
679  assert(consdata->maxlinactivityinf >= 0);
680  return;
681  }
682 
683  consdata->minlinactivityinf = 0;
684  consdata->maxlinactivityinf = 0;
685 
686  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
687  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
688  */
689  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
690  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
691 
692  if( consdata->nlinvars == 0 )
693  return;
694 
695  /* if the activities computed here should be still up-to-date after bound changes,
696  * variable events need to be caught */
697  assert(consdata->lineventdata != NULL);
698 
699  prevroundmode = SCIPintervalGetRoundingMode();
700 
701  if( !SCIPisInfinity(scip, consdata->rhs) )
702  {
703  /* compute minimal activity only if there is a finite right hand side */
705 
706  for( i = 0; i < consdata->nlinvars; ++i )
707  {
708  assert(consdata->lineventdata[i] != NULL);
709  if( consdata->lincoefs[i] >= 0.0 )
710  {
711  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
712  if( SCIPisInfinity(scip, -bnd) )
713  {
714  ++consdata->minlinactivityinf;
715  continue;
716  }
717  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
718  }
719  else
720  {
721  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
722  if( SCIPisInfinity(scip, bnd) )
723  {
724  ++consdata->minlinactivityinf;
725  continue;
726  }
727  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
728  }
729  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
730  }
731  }
732 
733  if( !SCIPisInfinity(scip, -consdata->lhs) )
734  {
735  /* compute maximal activity only if there is a finite left hand side */
737 
738  for( i = 0; i < consdata->nlinvars; ++i )
739  {
740  assert(consdata->lineventdata[i] != NULL);
741  if( consdata->lincoefs[i] >= 0.0 )
742  {
743  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
744  if( SCIPisInfinity(scip, bnd) )
745  {
746  ++consdata->maxlinactivityinf;
747  continue;
748  }
749  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
750  }
751  else
752  {
753  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
754  if( SCIPisInfinity(scip, -bnd) )
755  {
756  ++consdata->maxlinactivityinf;
757  continue;
758  }
759  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
760  }
761  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
762  }
763  }
764 
765  SCIPintervalSetRoundingMode(prevroundmode);
766 
767  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
768 }
769 
770 /** update the linear activities after a change in the lower bound of a variable */
771 static
773  SCIP* scip, /**< SCIP data structure */
774  SCIP_CONSDATA* consdata, /**< constraint data */
775  SCIP_Real coef, /**< coefficient of variable in constraint */
776  SCIP_Real oldbnd, /**< previous lower bound of variable */
777  SCIP_Real newbnd /**< new lower bound of variable */
778  )
779 {
780  SCIP_ROUNDMODE prevroundmode;
781 
782  assert(scip != NULL);
783  assert(consdata != NULL);
784  /* we can't deal with lower bounds at infinity */
785  assert(!SCIPisInfinity(scip, oldbnd));
786  assert(!SCIPisInfinity(scip, newbnd));
787 
788  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
789 
790  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
791  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
792  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
793  */
794 
795  if( coef > 0.0 )
796  {
797  /* we should only be called if rhs is finite */
798  assert(!SCIPisInfinity(scip, consdata->rhs));
799 
800  /* we have no min activities computed so far, so cannot update */
801  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
802  return;
803 
804  prevroundmode = SCIPintervalGetRoundingMode();
806 
807  /* update min activity */
808  if( SCIPisInfinity(scip, -oldbnd) )
809  {
810  --consdata->minlinactivityinf;
811  assert(consdata->minlinactivityinf >= 0);
812  }
813  else
814  {
815  SCIP_Real minuscoef;
816  minuscoef = -coef;
817  consdata->minlinactivity += minuscoef * oldbnd;
818  }
819 
820  if( SCIPisInfinity(scip, -newbnd) )
821  {
822  ++consdata->minlinactivityinf;
823  }
824  else
825  {
826  consdata->minlinactivity += coef * newbnd;
827  }
828 
829  SCIPintervalSetRoundingMode(prevroundmode);
830  }
831  else
832  {
833  /* we should only be called if lhs is finite */
834  assert(!SCIPisInfinity(scip, -consdata->lhs));
835 
836  /* we have no max activities computed so far, so cannot update */
837  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
838  return;
839 
840  prevroundmode = SCIPintervalGetRoundingMode();
842 
843  /* update max activity */
844  if( SCIPisInfinity(scip, -oldbnd) )
845  {
846  --consdata->maxlinactivityinf;
847  assert(consdata->maxlinactivityinf >= 0);
848  }
849  else
850  {
851  SCIP_Real minuscoef;
852  minuscoef = -coef;
853  consdata->maxlinactivity += minuscoef * oldbnd;
854  }
855 
856  if( SCIPisInfinity(scip, -newbnd) )
857  {
858  ++consdata->maxlinactivityinf;
859  }
860  else
861  {
862  consdata->maxlinactivity += coef * newbnd;
863  }
864 
865  SCIPintervalSetRoundingMode(prevroundmode);
866  }
867 }
868 
869 /** update the linear activities after a change in the upper bound of a variable */
870 static
872  SCIP* scip, /**< SCIP data structure */
873  SCIP_CONSDATA* consdata, /**< constraint data */
874  SCIP_Real coef, /**< coefficient of variable in constraint */
875  SCIP_Real oldbnd, /**< previous lower bound of variable */
876  SCIP_Real newbnd /**< new lower bound of variable */
877  )
878 {
879  SCIP_ROUNDMODE prevroundmode;
880 
881  assert(scip != NULL);
882  assert(consdata != NULL);
883  /* we can't deal with upper bounds at -infinity */
884  assert(!SCIPisInfinity(scip, -oldbnd));
885  assert(!SCIPisInfinity(scip, -newbnd));
886 
887  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
888 
889  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
890  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
891  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
892  */
893 
894  if( coef > 0.0 )
895  {
896  /* we should only be called if lhs is finite */
897  assert(!SCIPisInfinity(scip, -consdata->lhs));
898 
899  /* we have no max activities computed so far, so cannot update */
900  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
901  return;
902 
903  prevroundmode = SCIPintervalGetRoundingMode();
905 
906  /* update max activity */
907  if( SCIPisInfinity(scip, oldbnd) )
908  {
909  --consdata->maxlinactivityinf;
910  assert(consdata->maxlinactivityinf >= 0);
911  }
912  else
913  {
914  SCIP_Real minuscoef;
915  minuscoef = -coef;
916  consdata->maxlinactivity += minuscoef * oldbnd;
917  }
918 
919  if( SCIPisInfinity(scip, newbnd) )
920  {
921  ++consdata->maxlinactivityinf;
922  }
923  else
924  {
925  consdata->maxlinactivity += coef * newbnd;
926  }
927 
928  SCIPintervalSetRoundingMode(prevroundmode);
929  }
930  else
931  {
932  /* we should only be called if rhs is finite */
933  assert(!SCIPisInfinity(scip, consdata->rhs));
934 
935  /* we have no min activities computed so far, so cannot update */
936  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
937  return;
938 
939  prevroundmode = SCIPintervalGetRoundingMode();
941 
942  /* update min activity */
943  if( SCIPisInfinity(scip, oldbnd) )
944  {
945  --consdata->minlinactivityinf;
946  assert(consdata->minlinactivityinf >= 0);
947  }
948  else
949  {
950  SCIP_Real minuscoef;
951  minuscoef = -coef;
952  consdata->minlinactivity += minuscoef * oldbnd;
953  }
954 
955  if( SCIPisInfinity(scip, newbnd) )
956  {
957  ++consdata->minlinactivityinf;
958  }
959  else
960  {
961  consdata->minlinactivity += coef * newbnd;
962  }
963 
964  SCIPintervalSetRoundingMode(prevroundmode);
965  }
966 }
967 
968 /** returns whether a quadratic variable domain can be reduced to its lower or upper bound; this is the case if the
969  * quadratic variable is in just one single quadratic constraint and (sqrcoef > 0 and LHS = -infinity), or
970  * (sqrcoef < 0 and RHS = +infinity) hold
971  */
972 static
974  SCIP* scip, /**< SCIP data structure */
975  SCIP_CONSDATA* consdata, /**< constraint data */
976  int idx /**< index of quadratic variable */
977  )
978 {
979  SCIP_VAR* var;
980  SCIP_Real quadcoef;
981  SCIP_Bool haslhs;
982  SCIP_Bool hasrhs;
983 
984  assert(scip != NULL);
985  assert(consdata != NULL);
986  assert(idx >= 0 && idx < consdata->nquadvars);
987 
988  var = consdata->quadvarterms[idx].var;
989  assert(var != NULL);
990 
991  quadcoef = consdata->quadvarterms[idx].sqrcoef;
992  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
993  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
994 
995  return SCIPvarGetNLocksDown(var) == 1 && SCIPvarGetNLocksUp(var) == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
996  && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && ((quadcoef < 0.0 && !haslhs) || (quadcoef > 0.0 && !hasrhs));
997 }
998 
999 /** processes variable fixing or bound change event */
1000 static
1001 SCIP_DECL_EVENTEXEC(processVarEvent)
1003  SCIP_CONS* cons;
1004  SCIP_CONSDATA* consdata;
1005  SCIP_EVENTTYPE eventtype;
1006  int varidx;
1007 
1008  assert(scip != NULL);
1009  assert(event != NULL);
1010  assert(eventdata != NULL);
1011  assert(eventhdlr != NULL);
1012 
1013  cons = ((SCIP_QUADVAREVENTDATA*)eventdata)->cons;
1014  assert(cons != NULL);
1015  consdata = SCIPconsGetData(cons);
1016  assert(consdata != NULL);
1017 
1018  varidx = ((SCIP_QUADVAREVENTDATA*)eventdata)->varidx;
1019  assert(varidx < 0 || varidx < consdata->nlinvars);
1020  assert(varidx >= 0 || -varidx-1 < consdata->nquadvars);
1021 
1022  eventtype = SCIPeventGetType(event);
1023 
1024  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1025  {
1026  if( varidx < 0 )
1027  {
1028  SCIP_QUADVARTERM* quadvarterm;
1029  SCIP_VAR* var;
1030 
1031  quadvarterm = &consdata->quadvarterms[-varidx-1];
1032  var = quadvarterm->var;
1033 
1034  /* if an integer variable x with a x^2 is tightened to [0,1], then we can replace the x^2 by x, which is done in mergeAndCleanQuadVarTerms()
1035  * we currently do this only if the binary variable does not show up in any bilinear terms
1036  * unfortunately, SCIP does not have an eventtype for vartype changes (nor do they always count as presolve reductions) and the bounds are
1037  * not updated yet when this event is processed, so we cannot use SCIPvarIsBinary here to check if the tightened integer variable will be binary
1038  */
1039  if( SCIPgetStage(scip) < SCIP_STAGE_SOLVING && SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER && quadvarterm->sqrcoef != 0.0 && quadvarterm->nadjbilin == 0 &&
1040  ( ((eventtype & SCIP_EVENTTYPE_LBTIGHTENED) && SCIPeventGetNewbound(event) > -0.5 && SCIPvarGetUbGlobal(var) < 1.5) ||
1041  ((eventtype & SCIP_EVENTTYPE_UBTIGHTENED) && SCIPeventGetNewbound(event) < 1.5 && SCIPvarGetLbGlobal(var) > -0.5) ) )
1042  {
1043  consdata->quadvarsmerged = FALSE;
1044  consdata->initialmerge = FALSE;
1045  }
1046 
1047  /* mark activity bounds for quad term as not up to date anymore */
1048  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
1049  }
1050  else
1051  {
1052  /* update activity bounds for linear terms */
1053  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
1054  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1055  else
1056  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1057  }
1058 
1059  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1060  {
1061  SCIP_VAR* var;
1062 
1063  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
1064  consdata->ispropagated = FALSE;
1065 
1066  var = varidx < 0 ? consdata->quadvarterms[-varidx-1].var : consdata->linvars[varidx];
1067  assert(var != NULL);
1068 
1069  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
1070  consdata->isremovedfixings = FALSE;
1071  }
1072  }
1073 
1074  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1075  {
1076  consdata->isremovedfixings = FALSE;
1077  }
1078 
1079 #ifdef CHECKIMPLINBILINEAR
1080  if( eventtype & SCIP_EVENTTYPE_IMPLADDED )
1081  {
1082  assert(varidx < 0); /* we catch impladded events only for quadratic variables */
1083  /* 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 */
1084  if( SCIPvarIsBinary(SCIPeventGetVar(event)) && consdata->quadvarterms[-varidx-1].nadjbilin > 0 )
1085  consdata->isimpladded = TRUE;
1086  }
1087 #endif
1088 
1089  return SCIP_OKAY;
1090 }
1091 
1092 /** ensures, that linear vars and coefs arrays can store at least num entries */
1093 static
1095  SCIP* scip, /**< SCIP data structure */
1096  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1097  int num /**< minimum number of entries to store */
1098  )
1099 {
1100  assert(scip != NULL);
1101  assert(consdata != NULL);
1102  assert(consdata->nlinvars <= consdata->linvarssize);
1103 
1104  if( num > consdata->linvarssize )
1105  {
1106  int newsize;
1107 
1108  newsize = SCIPcalcMemGrowSize(scip, num);
1109  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1110  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1111  if( consdata->lineventdata != NULL )
1112  {
1113  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1114  }
1115  consdata->linvarssize = newsize;
1116  }
1117  assert(num <= consdata->linvarssize);
1118 
1119  return SCIP_OKAY;
1120 }
1121 
1122 /** ensures, that quadratic variable terms array can store at least num entries */
1123 static
1125  SCIP* scip, /**< SCIP data structure */
1126  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1127  int num /**< minimum number of entries to store */
1128  )
1129 {
1130  assert(scip != NULL);
1131  assert(consdata != NULL);
1132  assert(consdata->nquadvars <= consdata->quadvarssize);
1133 
1134  if( num > consdata->quadvarssize )
1135  {
1136  int newsize;
1137 
1138  newsize = SCIPcalcMemGrowSize(scip, num);
1139  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->quadvarterms, consdata->quadvarssize, newsize) );
1140  consdata->quadvarssize = newsize;
1141  }
1142  assert(num <= consdata->quadvarssize);
1143 
1144  return SCIP_OKAY;
1145 }
1146 
1147 /** ensures, that adjacency array can store at least num entries */
1148 static
1150  SCIP* scip, /**< SCIP data structure */
1151  SCIP_QUADVARTERM* quadvarterm, /**< quadratic variable term */
1152  int num /**< minimum number of entries to store */
1153  )
1154 {
1155  assert(scip != NULL);
1156  assert(quadvarterm != NULL);
1157  assert(quadvarterm->nadjbilin <= quadvarterm->adjbilinsize);
1158 
1159  if( num > quadvarterm->adjbilinsize )
1160  {
1161  int newsize;
1162 
1163  newsize = SCIPcalcMemGrowSize(scip, num);
1164  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvarterm->adjbilin, quadvarterm->adjbilinsize, newsize) );
1165  quadvarterm->adjbilinsize = newsize;
1166  }
1167  assert(num <= quadvarterm->adjbilinsize);
1168 
1169  return SCIP_OKAY;
1170 }
1171 
1172 /** ensures, that bilinear term arrays can store at least num entries */
1173 static
1175  SCIP* scip, /**< SCIP data structure */
1176  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1177  int num /**< minimum number of entries to store */
1178  )
1179 {
1180  assert(scip != NULL);
1181  assert(consdata != NULL);
1182  assert(consdata->nbilinterms <= consdata->bilintermssize);
1183 
1184  if( num > consdata->bilintermssize )
1185  {
1186  int newsize;
1187 
1188  newsize = SCIPcalcMemGrowSize(scip, num);
1189  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize, newsize) );
1190  consdata->bilintermssize = newsize;
1191  }
1192  assert(num <= consdata->bilintermssize);
1193 
1194  return SCIP_OKAY;
1195 }
1196 
1197 /** creates empty constraint data structure */
1198 static
1200  SCIP* scip, /**< SCIP data structure */
1201  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1202  )
1203 {
1204  assert(scip != NULL);
1205  assert(consdata != NULL);
1206 
1207  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1208  BMSclearMemory(*consdata);
1209 
1210  (*consdata)->lhs = -SCIPinfinity(scip);
1211  (*consdata)->rhs = SCIPinfinity(scip);
1212 
1213  (*consdata)->linvarssorted = TRUE;
1214  (*consdata)->linvarsmerged = TRUE;
1215  (*consdata)->quadvarssorted = TRUE;
1216  (*consdata)->quadvarsmerged = TRUE;
1217  (*consdata)->bilinsorted = TRUE;
1218  (*consdata)->bilinmerged = TRUE;
1219 
1220  (*consdata)->isremovedfixings = TRUE;
1221  (*consdata)->ispropagated = TRUE;
1222  (*consdata)->initialmerge = FALSE;
1223 
1224  (*consdata)->linvar_maydecrease = -1;
1225  (*consdata)->linvar_mayincrease = -1;
1226 
1227  (*consdata)->minlinactivity = SCIP_INVALID;
1228  (*consdata)->maxlinactivity = SCIP_INVALID;
1229  (*consdata)->minlinactivityinf = -1;
1230  (*consdata)->maxlinactivityinf = -1;
1231 
1232  (*consdata)->isgaugeavailable = FALSE;
1233  (*consdata)->isedavailable = FALSE;
1234 
1235  return SCIP_OKAY;
1236 }
1237 
1238 /** creates constraint data structure */
1239 static
1241  SCIP* scip, /**< SCIP data structure */
1242  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1243  SCIP_Real lhs, /**< left hand side of constraint */
1244  SCIP_Real rhs, /**< right hand side of constraint */
1245  int nlinvars, /**< number of linear variables */
1246  SCIP_VAR** linvars, /**< array of linear variables */
1247  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1248  int nquadvars, /**< number of quadratic variables */
1249  SCIP_QUADVARTERM* quadvarterms, /**< array of quadratic variable terms */
1250  int nbilinterms, /**< number of bilinear terms */
1251  SCIP_BILINTERM* bilinterms, /**< array of bilinear terms */
1252  SCIP_Bool capturevars /**< whether we should capture variables */
1253  )
1254 {
1255  int i;
1256 
1257  assert(scip != NULL);
1258  assert(consdata != NULL);
1259 
1260  assert(nlinvars == 0 || linvars != NULL);
1261  assert(nlinvars == 0 || lincoefs != NULL);
1262  assert(nquadvars == 0 || quadvarterms != NULL);
1263  assert(nbilinterms == 0 || bilinterms != NULL);
1264 
1265  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1266  BMSclearMemory(*consdata);
1267 
1268  (*consdata)->minlinactivity = SCIP_INVALID;
1269  (*consdata)->maxlinactivity = SCIP_INVALID;
1270  (*consdata)->minlinactivityinf = -1;
1271  (*consdata)->maxlinactivityinf = -1;
1272 
1273  (*consdata)->lhs = lhs;
1274  (*consdata)->rhs = rhs;
1275 
1276  if( nlinvars > 0 )
1277  {
1278  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1279  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1280  (*consdata)->nlinvars = nlinvars;
1281  (*consdata)->linvarssize = nlinvars;
1282 
1283  if( capturevars )
1284  for( i = 0; i < nlinvars; ++i )
1285  {
1286  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1287  }
1288  }
1289  else
1290  {
1291  (*consdata)->linvarssorted = TRUE;
1292  (*consdata)->linvarsmerged = TRUE;
1293  (*consdata)->minlinactivity = 0.0;
1294  (*consdata)->maxlinactivity = 0.0;
1295  (*consdata)->minlinactivityinf = 0;
1296  (*consdata)->maxlinactivityinf = 0;
1297  }
1298 
1299  if( nquadvars > 0 )
1300  {
1301  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms, quadvarterms, nquadvars) );
1302 
1303  for( i = 0; i < nquadvars; ++i )
1304  {
1305  (*consdata)->quadvarterms[i].eventdata = NULL;
1306  if( quadvarterms[i].nadjbilin )
1307  {
1308  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms[i].adjbilin, quadvarterms[i].adjbilin, quadvarterms[i].nadjbilin) );
1309  (*consdata)->quadvarterms[i].adjbilinsize = quadvarterms[i].nadjbilin;
1310  }
1311  else
1312  {
1313  assert((*consdata)->quadvarterms[i].nadjbilin == 0);
1314  (*consdata)->quadvarterms[i].adjbilin = NULL;
1315  (*consdata)->quadvarterms[i].adjbilinsize = 0;
1316  }
1317  if( capturevars )
1318  {
1319  SCIP_CALL( SCIPcaptureVar(scip, quadvarterms[i].var) );
1320  }
1321  }
1322 
1323  (*consdata)->nquadvars = nquadvars;
1324  (*consdata)->quadvarssize = nquadvars;
1325  SCIPintervalSetEmpty(&(*consdata)->quadactivitybounds);
1326  }
1327  else
1328  {
1329  (*consdata)->quadvarssorted = TRUE;
1330  (*consdata)->quadvarsmerged = TRUE;
1331  SCIPintervalSet(&(*consdata)->quadactivitybounds, 0.0);
1332  }
1333 
1334  if( nbilinterms > 0 )
1335  {
1336  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->bilinterms, bilinterms, nbilinterms) );
1337  (*consdata)->nbilinterms = nbilinterms;
1338  (*consdata)->bilintermssize = nbilinterms;
1339  }
1340  else
1341  {
1342  (*consdata)->bilinsorted = TRUE;
1343  (*consdata)->bilinmerged = TRUE;
1344  }
1345 
1346  (*consdata)->linvar_maydecrease = -1;
1347  (*consdata)->linvar_mayincrease = -1;
1348 
1349  (*consdata)->activity = SCIP_INVALID;
1350  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1351  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1352 
1353  (*consdata)->isgaugeavailable = FALSE;
1354 
1355  return SCIP_OKAY;
1356 }
1357 
1358 /** frees constraint data structure */
1359 static
1361  SCIP* scip, /**< SCIP data structure */
1362  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1363  )
1364 {
1365  int i;
1366 
1367  assert(scip != NULL);
1368  assert(consdata != NULL);
1369  assert(*consdata != NULL);
1370 
1371  /* free sepa arrays, may exists if constraint is deleted in solving stage */
1372  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepaquadvars, (*consdata)->nquadvars);
1373  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepabilinvar2pos, (*consdata)->nbilinterms);
1374 
1375  /* release linear variables and free linear part */
1376  if( (*consdata)->linvarssize > 0 )
1377  {
1378  for( i = 0; i < (*consdata)->nlinvars; ++i )
1379  {
1380  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1381  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1382  }
1383  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1384  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1385  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1386  }
1387  assert((*consdata)->linvars == NULL);
1388  assert((*consdata)->lincoefs == NULL);
1389  assert((*consdata)->lineventdata == NULL);
1390 
1391  /* release quadratic variables and free quadratic variable term part */
1392  for( i = 0; i < (*consdata)->nquadvars; ++i )
1393  {
1394  assert((*consdata)->quadvarterms[i].eventdata == NULL); /* variable events should have been dropped earlier */
1395  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms[i].adjbilin, (*consdata)->quadvarterms[i].adjbilinsize);
1396  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->quadvarterms[i].var) );
1397  }
1398  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms, (*consdata)->quadvarssize);
1399 
1400  /* free bilinear terms */
1401  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilinterms, (*consdata)->bilintermssize);
1402 
1403  /* free nonlinear row representation */
1404  if( (*consdata)->nlrow != NULL )
1405  {
1406  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1407  }
1408 
1409  /* free interior point information, may exists if constraint is deleted in solving stage */
1410  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->interiorpoint, (*consdata)->nquadvars);
1411  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->gaugecoefs, (*consdata)->nquadvars);
1412 
1413  /* free eigen decomposition information */
1414  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvalues, (*consdata)->nquadvars);
1415  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvectors, (int)((*consdata)->nquadvars*(*consdata)->nquadvars));
1416  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bp, (*consdata)->nquadvars);
1417 
1418  SCIPfreeBlockMemory(scip, consdata);
1419  *consdata = NULL;
1420 
1421  return SCIP_OKAY;
1422 }
1423 
1424 /** sorts linear part of constraint data */
1425 static
1427  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1428  )
1429 {
1430  assert(consdata != NULL);
1431 
1432  if( consdata->linvarssorted )
1433  return;
1434 
1435  if( consdata->nlinvars <= 1 )
1436  {
1437  consdata->linvarssorted = TRUE;
1438  return;
1439  }
1440 
1441  if( consdata->lineventdata == NULL )
1442  {
1443  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1444  }
1445  else
1446  {
1447  int i;
1448 
1449  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1450 
1451  /* update variable indices in event data */
1452  for( i = 0; i < consdata->nlinvars; ++i )
1453  if( consdata->lineventdata[i] != NULL )
1454  consdata->lineventdata[i]->varidx = i;
1455  }
1456 
1457  consdata->linvarssorted = TRUE;
1458 }
1459 
1460 #ifdef SCIP_DISABLED_CODE /* no-one needs this routine currently */
1461 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1462 static
1463 int consdataFindLinearVar(
1464  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1465  SCIP_VAR* var /**< variable to search for */
1466  )
1467 {
1468  int pos;
1469 
1470  assert(consdata != NULL);
1471  assert(var != NULL);
1472 
1473  if( consdata->nlinvars == 0 )
1474  return -1;
1475 
1476  consdataSortLinearVars(consdata);
1477 
1478  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1479  pos = -1;
1480 
1481  return pos;
1482 }
1483 #endif
1484 
1485 /** index comparison method for quadratic variable terms: compares two indices of the quadratic variable set in the quadratic constraint */
1486 static
1487 SCIP_DECL_SORTINDCOMP(quadVarTermComp)
1488 { /*lint --e{715}*/
1489  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1490 
1491  assert(consdata != NULL);
1492  assert(0 <= ind1 && ind1 < consdata->nquadvars);
1493  assert(0 <= ind2 && ind2 < consdata->nquadvars);
1494 
1495  return SCIPvarCompare(consdata->quadvarterms[ind1].var, consdata->quadvarterms[ind2].var);
1496 }
1497 
1498 /** sorting of quadratic variable terms */
1499 static
1501  SCIP* scip, /**< SCIP data structure */
1502  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1503  )
1504 {
1505  int* perm;
1506  int i;
1507  int nexti;
1508  int v;
1509  SCIP_QUADVARTERM quadterm;
1510 
1511  assert(scip != NULL);
1512  assert(consdata != NULL);
1513 
1514  if( consdata->quadvarssorted )
1515  return SCIP_OKAY;
1516 
1517  if( consdata->nquadvars == 0 )
1518  {
1519  consdata->quadvarssorted = TRUE;
1520  return SCIP_OKAY;
1521  }
1522 
1523  /* get temporary memory to store the sorted permutation */
1524  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nquadvars) );
1525 
1526  /* call bubble sort */
1527  SCIPsort(perm, quadVarTermComp, (void*)consdata, consdata->nquadvars);
1528 
1529  /* permute the quadratic variable terms according to the resulting permutation */
1530  for( v = 0; v < consdata->nquadvars; ++v )
1531  {
1532  if( perm[v] != v )
1533  {
1534  quadterm = consdata->quadvarterms[v];
1535 
1536  i = v;
1537  do
1538  {
1539  assert(0 <= perm[i] && perm[i] < consdata->nquadvars);
1540  assert(perm[i] != i);
1541  consdata->quadvarterms[i] = consdata->quadvarterms[perm[i]];
1542  if( consdata->quadvarterms[i].eventdata != NULL )
1543  {
1544  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1545  }
1546  nexti = perm[i];
1547  perm[i] = i;
1548  i = nexti;
1549  }
1550  while( perm[i] != v );
1551  consdata->quadvarterms[i] = quadterm;
1552  if( consdata->quadvarterms[i].eventdata != NULL )
1553  {
1554  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1555  }
1556  perm[i] = i;
1557  }
1558  }
1559  consdata->quadvarssorted = TRUE;
1560 
1561  /* free temporary memory */
1562  SCIPfreeBufferArray(scip, &perm);
1563 
1564  return SCIP_OKAY;
1565 }
1566 
1567 /** returns the position of variable in the quadratic variable terms array of a constraint, or -1 if not found */
1568 static
1570  SCIP* scip, /**< SCIP data structure */
1571  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1572  SCIP_VAR* var, /**< variable to search for */
1573  int* pos /**< buffer where to store position of var in quadvarterms array, or -1 if not found */
1574  )
1575 {
1576  int left;
1577  int right;
1578  int cmpres;
1579 
1580  assert(consdata != NULL);
1581  assert(var != NULL);
1582  assert(pos != NULL);
1583 
1584  if( consdata->nquadvars == 0 )
1585  {
1586  *pos = -1;
1587  return SCIP_OKAY;
1588  }
1589 
1590  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
1591 
1592  left = 0;
1593  right = consdata->nquadvars - 1;
1594  while( left <= right )
1595  {
1596  int middle;
1597 
1598  middle = (left+right)/2;
1599  assert(0 <= middle && middle < consdata->nquadvars);
1600 
1601  cmpres = SCIPvarCompare(var, consdata->quadvarterms[middle].var);
1602 
1603  if( cmpres < 0 )
1604  right = middle - 1;
1605  else if( cmpres > 0 )
1606  left = middle + 1;
1607  else
1608  {
1609  *pos = middle;
1610  return SCIP_OKAY;
1611  }
1612  }
1613  assert(left == right+1);
1614 
1615  *pos = -1;
1616 
1617  return SCIP_OKAY;
1618 }
1619 
1620 /** index comparison method for bilinear terms: compares two index pairs of the bilinear term set in the quadratic constraint */
1621 static
1622 SCIP_DECL_SORTINDCOMP(bilinTermComp)
1623 { /*lint --e{715}*/
1624  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1625  int var1cmp;
1626 
1627  assert(consdata != NULL);
1628  assert(0 <= ind1 && ind1 < consdata->nbilinterms);
1629  assert(0 <= ind2 && ind2 < consdata->nbilinterms);
1630 
1631  var1cmp = SCIPvarCompare(consdata->bilinterms[ind1].var1, consdata->bilinterms[ind2].var1);
1632  if( var1cmp != 0 )
1633  return var1cmp;
1634 
1635  return SCIPvarCompare(consdata->bilinterms[ind1].var2, consdata->bilinterms[ind2].var2);
1636 }
1637 
1638 #ifndef NDEBUG
1639 /** checks if all bilinear terms are sorted correctly */
1640 static
1642  SCIP_CONSDATA* consdata
1643  )
1644 {
1645  int i;
1646 
1647  assert(consdata != NULL);
1648 
1649  /* nothing to check if the bilinear terms have not been sorted yet */
1650  if( !consdata->bilinsorted )
1651  return TRUE;
1652 
1653  for( i = 0; i < consdata->nbilinterms - 1; ++i )
1654  {
1655  if( bilinTermComp(consdata, i, i+1) > 0 )
1656  return FALSE;
1657  }
1658  return TRUE;
1659 }
1660 #endif
1661 
1662 /** sorting of bilinear terms */
1663 static
1665  SCIP* scip, /**< SCIP data structure */
1666  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1667  )
1668 {
1669  int* perm;
1670  int* invperm;
1671  int i;
1672  int nexti;
1673  int v;
1674  SCIP_BILINTERM bilinterm;
1675 
1676  assert(scip != NULL);
1677  assert(consdata != NULL);
1678 
1679  if( consdata->bilinsorted )
1680  return SCIP_OKAY;
1681 
1682  if( consdata->nbilinterms == 0 )
1683  {
1684  consdata->bilinsorted = TRUE;
1685  return SCIP_OKAY;
1686  }
1687 
1688  /* get temporary memory to store the sorted permutation and the inverse permutation */
1689  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nbilinterms) );
1690  SCIP_CALL( SCIPallocBufferArray(scip, &invperm, consdata->nbilinterms) );
1691 
1692  /* call bubble sort */
1693  SCIPsort(perm, bilinTermComp, (void*)consdata, consdata->nbilinterms);
1694 
1695  /* compute inverted permutation */
1696  for( v = 0; v < consdata->nbilinterms; ++v )
1697  {
1698  assert(0 <= perm[v] && perm[v] < consdata->nbilinterms);
1699  invperm[perm[v]] = v;
1700  }
1701 
1702  /* permute the bilinear terms according to the resulting permutation */
1703  for( v = 0; v < consdata->nbilinterms; ++v )
1704  {
1705  if( perm[v] != v )
1706  {
1707  bilinterm = consdata->bilinterms[v];
1708 
1709  i = v;
1710  do
1711  {
1712  assert(0 <= perm[i] && perm[i] < consdata->nbilinterms);
1713  assert(perm[i] != i);
1714  consdata->bilinterms[i] = consdata->bilinterms[perm[i]];
1715  nexti = perm[i];
1716  perm[i] = i;
1717  i = nexti;
1718  }
1719  while( perm[i] != v );
1720  consdata->bilinterms[i] = bilinterm;
1721  perm[i] = i;
1722  }
1723  }
1724 
1725  /* update the adjacency information in the quadratic variable terms */
1726  for( v = 0; v < consdata->nquadvars; ++v )
1727  for( i = 0; i < consdata->quadvarterms[v].nadjbilin; ++i )
1728  consdata->quadvarterms[v].adjbilin[i] = invperm[consdata->quadvarterms[v].adjbilin[i]];
1729 
1730  consdata->bilinsorted = TRUE;
1731  assert(consdataCheckBilinTermsSort(consdata));
1732 
1733  /* free temporary memory */
1734  SCIPfreeBufferArray(scip, &invperm);
1735  SCIPfreeBufferArray(scip, &perm);
1736 
1737  return SCIP_OKAY;
1738 }
1739 
1740 /** moves a linear variable from one position to another */
1741 static
1743  SCIP_CONSDATA* consdata, /**< constraint data */
1744  int oldpos, /**< position of variable that shall be moved */
1745  int newpos /**< new position of variable */
1746  )
1747 {
1748  assert(consdata != NULL);
1749  assert(oldpos >= 0);
1750  assert(oldpos < consdata->nlinvars);
1751  assert(newpos >= 0);
1752  assert(newpos < consdata->linvarssize);
1753 
1754  if( newpos == oldpos )
1755  return;
1756 
1757  consdata->linvars [newpos] = consdata->linvars [oldpos];
1758  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1759 
1760  if( consdata->lineventdata != NULL )
1761  {
1762  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1763 
1764  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1765  consdata->lineventdata[newpos]->varidx = newpos;
1766 
1767  consdata->lineventdata[oldpos] = NULL;
1768  }
1769 
1770  consdata->linvarssorted = FALSE;
1771 }
1772 
1773 /** moves a quadratic variable from one position to another */
1774 static
1776  SCIP_CONSDATA* consdata, /**< constraint data */
1777  int oldpos, /**< position of variable that shall be moved */
1778  int newpos /**< new position of variable */
1779  )
1780 {
1781  assert(consdata != NULL);
1782  assert(oldpos >= 0);
1783  assert(oldpos < consdata->nquadvars);
1784  assert(newpos >= 0);
1785  assert(newpos < consdata->quadvarssize);
1786 
1787  if( newpos == oldpos )
1788  return;
1789 
1790  assert(newpos >= consdata->nquadvars || consdata->quadvarterms[newpos].eventdata == NULL);
1791 
1792  consdata->quadvarterms[newpos] = consdata->quadvarterms[oldpos];
1793 
1794  if( consdata->quadvarterms[newpos].eventdata != NULL )
1795  {
1796  consdata->quadvarterms[newpos].eventdata->varidx = -newpos-1;
1797  consdata->quadvarterms[oldpos].eventdata = NULL;
1798  }
1799 
1800  consdata->quadvarssorted = FALSE;
1801 }
1802 
1803 /** adds linear coefficient in quadratic constraint */
1804 static
1806  SCIP* scip, /**< SCIP data structure */
1807  SCIP_CONS* cons, /**< quadratic constraint */
1808  SCIP_VAR* var, /**< variable of constraint entry */
1809  SCIP_Real coef /**< coefficient of constraint entry */
1810  )
1811 {
1812  SCIP_CONSDATA* consdata;
1813  SCIP_Bool transformed;
1814 
1815  assert(scip != NULL);
1816  assert(cons != NULL);
1817  assert(var != NULL);
1818 
1819  /* ignore coefficient if it is nearly zero */
1820  if( SCIPisZero(scip, coef) )
1821  return SCIP_OKAY;
1822 
1823  consdata = SCIPconsGetData(cons);
1824  assert(consdata != NULL);
1825 
1826  /* are we in the transformed problem? */
1827  transformed = SCIPconsIsTransformed(cons);
1828 
1829  /* always use transformed variables in transformed constraints */
1830  if( transformed )
1831  {
1832  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1833  }
1834  assert(var != NULL);
1835  assert(transformed == SCIPvarIsTransformed(var));
1836 
1837  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1838  consdata->linvars [consdata->nlinvars] = var;
1839  consdata->lincoefs[consdata->nlinvars] = coef;
1840 
1841  ++consdata->nlinvars;
1842 
1843  /* catch variable events */
1844  if( SCIPconsIsEnabled(cons) )
1845  {
1846  SCIP_CONSHDLR* conshdlr;
1847  SCIP_CONSHDLRDATA* conshdlrdata;
1848 
1849  /* get event handler */
1850  conshdlr = SCIPconsGetHdlr(cons);
1851  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1852  assert(conshdlrdata != NULL);
1853  assert(conshdlrdata->eventhdlr != NULL);
1854 
1855  assert(consdata->lineventdata != NULL);
1856  consdata->lineventdata[consdata->nlinvars-1] = NULL;
1857 
1858  /* catch bound change events of variable */
1859  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nlinvars-1) );
1860  }
1861 
1862  /* invalidate activity information */
1863  consdata->activity = SCIP_INVALID;
1864  consdata->minlinactivity = SCIP_INVALID;
1865  consdata->maxlinactivity = SCIP_INVALID;
1866  consdata->minlinactivityinf = -1;
1867  consdata->maxlinactivityinf = -1;
1868 
1869  /* invalidate nonlinear row */
1870  if( consdata->nlrow != NULL )
1871  {
1872  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1873  }
1874 
1875  /* install rounding locks for new variable */
1876  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1877 
1878  /* capture new variable */
1879  SCIP_CALL( SCIPcaptureVar(scip, var) );
1880 
1881  consdata->ispropagated = FALSE;
1882  consdata->ispresolved = FALSE;
1883  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
1884  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
1885  if( consdata->nlinvars == 1 )
1886  consdata->linvarssorted = TRUE;
1887  else
1888  consdata->linvarssorted = consdata->linvarssorted && (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1889  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1890  consdata->linvarsmerged = FALSE;
1891 
1892  return SCIP_OKAY;
1893 }
1894 
1895 /** deletes linear coefficient at given position from quadratic constraint data */
1896 static
1898  SCIP* scip, /**< SCIP data structure */
1899  SCIP_CONS* cons, /**< quadratic constraint */
1900  int pos /**< position of coefficient to delete */
1901  )
1902 {
1903  SCIP_CONSDATA* consdata;
1904  SCIP_VAR* var;
1905  SCIP_Real coef;
1906 
1907  assert(scip != NULL);
1908  assert(cons != NULL);
1909 
1910  consdata = SCIPconsGetData(cons);
1911  assert(consdata != NULL);
1912  assert(0 <= pos && pos < consdata->nlinvars);
1913 
1914  var = consdata->linvars[pos];
1915  coef = consdata->lincoefs[pos];
1916  assert(var != NULL);
1917 
1918  /* remove rounding locks for deleted variable */
1919  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1920 
1921  /* if we catch variable events, drop the events on the variable */
1922  if( consdata->lineventdata != NULL )
1923  {
1924  SCIP_CONSHDLR* conshdlr;
1925  SCIP_CONSHDLRDATA* conshdlrdata;
1926 
1927  /* get event handler */
1928  conshdlr = SCIPconsGetHdlr(cons);
1929  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1930  assert(conshdlrdata != NULL);
1931  assert(conshdlrdata->eventhdlr != NULL);
1932 
1933  /* drop bound change events of variable */
1934  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
1935  }
1936 
1937  /* release variable */
1938  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
1939 
1940  /* move the last variable to the free slot */
1941  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
1942 
1943  --consdata->nlinvars;
1944 
1945  /* invalidate activity */
1946  consdata->activity = SCIP_INVALID;
1947  consdata->minlinactivity = SCIP_INVALID;
1948  consdata->maxlinactivity = SCIP_INVALID;
1949  consdata->minlinactivityinf = -1;
1950  consdata->maxlinactivityinf = -1;
1951 
1952  /* invalidate nonlinear row */
1953  if( consdata->nlrow != NULL )
1954  {
1955  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1956  }
1957 
1958  consdata->ispropagated = FALSE;
1959  consdata->ispresolved = FALSE;
1960 
1961  return SCIP_OKAY;
1962 }
1963 
1964 /** changes linear coefficient value at given position of quadratic constraint */
1965 static
1967  SCIP* scip, /**< SCIP data structure */
1968  SCIP_CONS* cons, /**< quadratic constraint */
1969  int pos, /**< position of linear coefficient to change */
1970  SCIP_Real newcoef /**< new value of linear coefficient */
1971  )
1972 {
1973  SCIP_CONSHDLR* conshdlr;
1974  SCIP_CONSHDLRDATA* conshdlrdata;
1975  SCIP_CONSDATA* consdata;
1976  SCIP_VAR* var;
1977  SCIP_Real coef;
1978 
1979  assert(scip != NULL);
1980  assert(cons != NULL);
1981  assert(!SCIPisZero(scip, newcoef));
1982 
1983  conshdlrdata = NULL;
1984 
1985  consdata = SCIPconsGetData(cons);
1986  assert(consdata != NULL);
1987  assert(0 <= pos);
1988  assert(pos < consdata->nlinvars);
1989  assert(!SCIPisZero(scip, newcoef));
1990 
1991  var = consdata->linvars[pos];
1992  coef = consdata->lincoefs[pos];
1993  assert(var != NULL);
1994  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
1995 
1996  /* invalidate activity */
1997  consdata->activity = SCIP_INVALID;
1998  consdata->minlinactivity = SCIP_INVALID;
1999  consdata->maxlinactivity = SCIP_INVALID;
2000  consdata->minlinactivityinf = -1;
2001  consdata->maxlinactivityinf = -1;
2002 
2003  /* invalidate nonlinear row */
2004  if( consdata->nlrow != NULL )
2005  {
2006  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2007  }
2008 
2009  /* if necessary, remove the rounding locks and event catching of the variable */
2010  if( newcoef * coef < 0.0 )
2011  {
2012  if( SCIPconsIsLocked(cons) )
2013  {
2014  assert(SCIPconsIsTransformed(cons));
2015 
2016  /* remove rounding locks for variable with old coefficient */
2017  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
2018  }
2019 
2020  if( consdata->lineventdata[pos] != NULL )
2021  {
2022  /* get event handler */
2023  conshdlr = SCIPconsGetHdlr(cons);
2024  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2025  assert(conshdlrdata != NULL);
2026  assert(conshdlrdata->eventhdlr != NULL);
2027 
2028  /* drop bound change events of variable */
2029  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2030  }
2031  }
2032 
2033  /* change the coefficient */
2034  consdata->lincoefs[pos] = newcoef;
2035 
2036  /* if necessary, install the rounding locks and event catching of the variable again */
2037  if( newcoef * coef < 0.0 )
2038  {
2039  if( SCIPconsIsLocked(cons) )
2040  {
2041  /* install rounding locks for variable with new coefficient */
2042  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
2043  }
2044 
2045  if( conshdlrdata != NULL )
2046  {
2047  assert(SCIPconsIsEnabled(cons));
2048 
2049  /* catch bound change events of variable */
2050  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2051  }
2052  }
2053 
2054  consdata->ispropagated = FALSE;
2055  consdata->ispresolved = FALSE;
2056 
2057  return SCIP_OKAY;
2058 }
2059 
2060 /** adds quadratic variable term to quadratic constraint */
2061 static
2063  SCIP* scip, /**< SCIP data structure */
2064  SCIP_CONS* cons, /**< quadratic constraint */
2065  SCIP_VAR* var, /**< variable to add */
2066  SCIP_Real lincoef, /**< linear coefficient of variable */
2067  SCIP_Real sqrcoef /**< square coefficient of variable */
2068  )
2069 {
2070  SCIP_CONSDATA* consdata;
2071  SCIP_Bool transformed;
2072  SCIP_QUADVARTERM* quadvarterm;
2073 
2074  assert(scip != NULL);
2075  assert(cons != NULL);
2076  assert(var != NULL);
2077 
2078  consdata = SCIPconsGetData(cons);
2079  assert(consdata != NULL);
2080 
2081  /* are we in the transformed problem? */
2082  transformed = SCIPconsIsTransformed(cons);
2083 
2084  /* always use transformed variables in transformed constraints */
2085  if( transformed )
2086  {
2087  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
2088  }
2089  assert(var != NULL);
2090  assert(transformed == SCIPvarIsTransformed(var));
2091 
2092  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars+1) );
2093 
2094  quadvarterm = &consdata->quadvarterms[consdata->nquadvars];
2095  quadvarterm->var = var;
2096  quadvarterm->lincoef = lincoef;
2097  quadvarterm->sqrcoef = sqrcoef;
2098  quadvarterm->adjbilinsize = 0;
2099  quadvarterm->nadjbilin = 0;
2100  quadvarterm->adjbilin = NULL;
2101  quadvarterm->eventdata = NULL;
2102 
2103  ++consdata->nquadvars;
2104 
2105  /* capture variable */
2106  SCIP_CALL( SCIPcaptureVar(scip, var) );
2107 
2108  /* catch variable events, if we do so */
2109  if( SCIPconsIsEnabled(cons) )
2110  {
2111  SCIP_CONSHDLR* conshdlr;
2112  SCIP_CONSHDLRDATA* conshdlrdata;
2113 
2114  /* get event handler */
2115  conshdlr = SCIPconsGetHdlr(cons);
2116  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2117  assert(conshdlrdata != NULL);
2118  assert(conshdlrdata->eventhdlr != NULL);
2119 
2120  /* catch bound change events of variable */
2121  SCIP_CALL( catchQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nquadvars-1) );
2122  }
2123 
2124  /* invalidate activity information */
2125  consdata->activity = SCIP_INVALID;
2126  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2127 
2128  /* invalidate nonlinear row */
2129  if( consdata->nlrow != NULL )
2130  {
2131  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2132  }
2133 
2134  /* install rounding locks for new variable */
2135  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2136 
2137  consdata->ispropagated = FALSE;
2138  consdata->ispresolved = FALSE;
2139  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2140  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2141  if( consdata->nquadvars == 1 )
2142  consdata->quadvarssorted = TRUE;
2143  else
2144  consdata->quadvarssorted = consdata->quadvarssorted &&
2145  (SCIPvarCompare(consdata->quadvarterms[consdata->nquadvars-2].var, consdata->quadvarterms[consdata->nquadvars-1].var) == -1);
2146  /* also set to FALSE if nquadvars == 1, since the new variable should be checked for linearity and other stuff in mergeAndClean ... */
2147  consdata->quadvarsmerged = FALSE;
2148 
2149  consdata->iscurvchecked = FALSE;
2150 
2151  return SCIP_OKAY;
2152 }
2153 
2154 /** deletes quadratic variable term at given position from quadratic constraint data */
2155 static
2157  SCIP* scip, /**< SCIP data structure */
2158  SCIP_CONS* cons, /**< quadratic constraint */
2159  int pos /**< position of term to delete */
2160  )
2161 {
2162  SCIP_CONSDATA* consdata;
2163  SCIP_VAR* var;
2164 
2165  assert(scip != NULL);
2166  assert(cons != NULL);
2167 
2168  consdata = SCIPconsGetData(cons);
2169  assert(consdata != NULL);
2170  assert(0 <= pos && pos < consdata->nquadvars);
2171 
2172  var = consdata->quadvarterms[pos].var;
2173  assert(var != NULL);
2174  assert(consdata->quadvarterms[pos].nadjbilin == 0);
2175 
2176  /* remove rounding locks for deleted variable */
2177  SCIP_CALL( unlockQuadraticVariable(scip, cons, var) );
2178 
2179  /* if we catch variable events, drop the events on the variable */
2180  if( consdata->quadvarterms[pos].eventdata != NULL )
2181  {
2182  SCIP_CONSHDLR* conshdlr;
2183  SCIP_CONSHDLRDATA* conshdlrdata;
2184 
2185  /* get event handler */
2186  conshdlr = SCIPconsGetHdlr(cons);
2187  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2188  assert(conshdlrdata != NULL);
2189  assert(conshdlrdata->eventhdlr != NULL);
2190 
2191  /* drop bound change events of variable */
2192  SCIP_CALL( dropQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2193  }
2194 
2195  /* release variable */
2196  SCIP_CALL( SCIPreleaseVar(scip, &consdata->quadvarterms[pos].var) );
2197 
2198  /* free adjacency array */
2199  SCIPfreeBlockMemoryArrayNull(scip, &consdata->quadvarterms[pos].adjbilin, consdata->quadvarterms[pos].adjbilinsize);
2200 
2201  /* move the last variable term to the free slot */
2202  consdataMoveQuadVarTerm(consdata, consdata->nquadvars-1, pos);
2203 
2204  --consdata->nquadvars;
2205 
2206  /* invalidate activity */
2207  consdata->activity = SCIP_INVALID;
2208  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2209 
2210  /* invalidate nonlinear row */
2211  if( consdata->nlrow != NULL )
2212  {
2213  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2214  }
2215 
2216  consdata->ispropagated = FALSE;
2217  consdata->ispresolved = FALSE;
2218  consdata->iscurvchecked = FALSE;
2219 
2220  return SCIP_OKAY;
2221 }
2222 
2223 /** replace variable in quadratic variable term at given position of quadratic constraint data
2224  *
2225  * Allows to replace x by coef*y+offset, thereby maintaining linear and square coefficients and bilinear terms.
2226  */
2227 static
2229  SCIP* scip, /**< SCIP data structure */
2230  SCIP_CONS* cons, /**< quadratic constraint */
2231  int pos, /**< position of term to replace */
2232  SCIP_VAR* var, /**< new variable */
2233  SCIP_Real coef, /**< linear coefficient of new variable */
2234  SCIP_Real offset /**< offset of new variable */
2235  )
2236 {
2237  SCIP_CONSDATA* consdata;
2238  SCIP_QUADVARTERM* quadvarterm;
2239  SCIP_EVENTHDLR* eventhdlr;
2240  SCIP_BILINTERM* bilinterm;
2241  SCIP_Real constant;
2242 
2243  int i;
2244  SCIP_VAR* var2;
2245 
2246  consdata = SCIPconsGetData(cons);
2247  assert(consdata != NULL);
2248  assert(pos >= 0);
2249  assert(pos < consdata->nquadvars);
2250 
2251  quadvarterm = &consdata->quadvarterms[pos];
2252 
2253  /* remove rounding locks for old variable */
2254  SCIP_CALL( unlockQuadraticVariable(scip, cons, quadvarterm->var) );
2255 
2256  /* if we catch variable events, drop the events on the old variable */
2257  if( quadvarterm->eventdata != NULL )
2258  {
2259  SCIP_CONSHDLR* conshdlr;
2260  SCIP_CONSHDLRDATA* conshdlrdata;
2261 
2262  /* get event handler */
2263  conshdlr = SCIPconsGetHdlr(cons);
2264  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2265  assert(conshdlrdata != NULL);
2266  assert(conshdlrdata->eventhdlr != NULL);
2267 
2268  eventhdlr = conshdlrdata->eventhdlr;
2269 
2270  /* drop bound change events of variable */
2271  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, pos) );
2272  }
2273  else
2274  {
2275  eventhdlr = NULL;
2276  }
2277 
2278  /* compute constant and put into lhs/rhs */
2279  constant = quadvarterm->lincoef * offset + quadvarterm->sqrcoef * offset * offset;
2280  if( constant != 0.0 )
2281  {
2282  /* maintain constant part */
2283  if( !SCIPisInfinity(scip, -consdata->lhs) )
2284  consdata->lhs -= constant;
2285  if( !SCIPisInfinity(scip, consdata->rhs) )
2286  consdata->rhs -= constant;
2287  }
2288 
2289  /* update linear and square coefficient */
2290  quadvarterm->lincoef *= coef;
2291  quadvarterm->lincoef += 2.0 * quadvarterm->sqrcoef * coef * offset;
2292  quadvarterm->sqrcoef *= coef * coef;
2293 
2294  /* update bilinear terms */
2295  for( i = 0; i < quadvarterm->nadjbilin; ++i )
2296  {
2297  bilinterm = &consdata->bilinterms[quadvarterm->adjbilin[i]];
2298 
2299  if( bilinterm->var1 == quadvarterm->var )
2300  {
2301  bilinterm->var1 = var;
2302  var2 = bilinterm->var2;
2303  }
2304  else
2305  {
2306  assert(bilinterm->var2 == quadvarterm->var);
2307  bilinterm->var2 = var;
2308  var2 = bilinterm->var1;
2309  }
2310 
2311  if( var == var2 )
2312  {
2313  /* looks like we actually have a square term here */
2314  quadvarterm->lincoef += bilinterm->coef * offset;
2315  quadvarterm->sqrcoef += bilinterm->coef * coef;
2316  /* deleting bilinear terms is expensive, since it requires updating adjacency information
2317  * thus, for now we just set the coefficient to 0.0 and clear in later when the bilinear terms are merged */
2318  bilinterm->coef = 0.0;
2319  continue;
2320  }
2321 
2322  /* swap var1 and var2 if they are in wrong order */
2323  if( SCIPvarCompare(bilinterm->var1, bilinterm->var2) > 0 )
2324  {
2325  SCIP_VAR* tmp;
2326  tmp = bilinterm->var1;
2327  bilinterm->var1 = bilinterm->var2;
2328  bilinterm->var2 = tmp;
2329  }
2330  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2331 
2332  if( offset != 0.0 )
2333  {
2334  /* need to find var2 and add offset*bilinterm->coef to linear coefficient */
2335  int var2pos;
2336 
2337  var2pos = 0;
2338  while( consdata->quadvarterms[var2pos].var != var2 )
2339  {
2340  ++var2pos;
2341  assert(var2pos < consdata->nquadvars);
2342  }
2343 
2344  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2345  }
2346 
2347  bilinterm->coef *= coef;
2348  }
2349 
2350  /* release old variable */
2351  SCIP_CALL( SCIPreleaseVar(scip, &quadvarterm->var) );
2352 
2353  /* set new variable */
2354  quadvarterm->var = var;
2355 
2356  /* capture new variable */
2357  SCIP_CALL( SCIPcaptureVar(scip, quadvarterm->var) );
2358 
2359  /* catch variable events, if we do so */
2360  if( eventhdlr != NULL )
2361  {
2362  assert(SCIPconsIsEnabled(cons));
2363 
2364  /* catch bound change events of variable */
2365  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, pos) );
2366  }
2367 
2368  /* invalidate activity information */
2369  consdata->activity = SCIP_INVALID;
2370  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2371 
2372  /* invalidate nonlinear row */
2373  if( consdata->nlrow != NULL )
2374  {
2375  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2376  }
2377 
2378  /* install rounding locks for new variable */
2379  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2380 
2381  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2382  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2383  consdata->quadvarssorted = (consdata->nquadvars == 1);
2384  consdata->quadvarsmerged = FALSE;
2385  consdata->bilinsorted &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2386  consdata->bilinmerged &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2387 
2388  consdata->ispropagated = FALSE;
2389  consdata->ispresolved = FALSE;
2390  consdata->iscurvchecked = FALSE;
2391 
2392  return SCIP_OKAY;
2393 }
2394 
2395 /** adds a bilinear term to quadratic constraint */
2396 static
2398  SCIP* scip, /**< SCIP data structure */
2399  SCIP_CONS* cons, /**< quadratic constraint */
2400  int var1pos, /**< position of first variable in quadratic variables array */
2401  int var2pos, /**< position of second variable in quadratic variables array */
2402  SCIP_Real coef /**< coefficient of bilinear term */
2403  )
2404 {
2405  SCIP_CONSDATA* consdata;
2406  SCIP_BILINTERM* bilinterm;
2407 
2408  assert(scip != NULL);
2409  assert(cons != NULL);
2410 
2411  if( var1pos == var2pos )
2412  {
2413  SCIPerrorMessage("tried to add bilinear term where both variables are the same\n");
2414  return SCIP_INVALIDDATA;
2415  }
2416 
2417  consdata = SCIPconsGetData(cons);
2418  assert(consdata != NULL);
2419 
2420  /* check if the bilinear terms are sorted */
2421  assert(consdataCheckBilinTermsSort(consdata));
2422 
2423  assert(var1pos >= 0);
2424  assert(var1pos < consdata->nquadvars);
2425  assert(var2pos >= 0);
2426  assert(var2pos < consdata->nquadvars);
2427 
2428  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nbilinterms + 1) );
2429 
2430  bilinterm = &consdata->bilinterms[consdata->nbilinterms];
2431  if( SCIPvarCompare(consdata->quadvarterms[var1pos].var, consdata->quadvarterms[var2pos].var) < 0 )
2432  {
2433  bilinterm->var1 = consdata->quadvarterms[var1pos].var;
2434  bilinterm->var2 = consdata->quadvarterms[var2pos].var;
2435  }
2436  else
2437  {
2438  bilinterm->var1 = consdata->quadvarterms[var2pos].var;
2439  bilinterm->var2 = consdata->quadvarterms[var1pos].var;
2440  }
2441  bilinterm->coef = coef;
2442 
2443  if( bilinterm->var1 == bilinterm->var2 )
2444  {
2445  SCIPerrorMessage("tried to add bilinear term where both variables are the same, but appear at different positions in quadvarterms array\n");
2446  return SCIP_INVALIDDATA;
2447  }
2448  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2449 
2450  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var1pos], consdata->quadvarterms[var1pos].nadjbilin + 1) );
2451  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var2pos], consdata->quadvarterms[var2pos].nadjbilin + 1) );
2452 
2453  consdata->quadvarterms[var1pos].adjbilin[consdata->quadvarterms[var1pos].nadjbilin] = consdata->nbilinterms;
2454  consdata->quadvarterms[var2pos].adjbilin[consdata->quadvarterms[var2pos].nadjbilin] = consdata->nbilinterms;
2455  ++consdata->quadvarterms[var1pos].nadjbilin;
2456  ++consdata->quadvarterms[var2pos].nadjbilin;
2457 
2458  ++consdata->nbilinterms;
2459 
2460  /* invalidate activity information */
2461  consdata->activity = SCIP_INVALID;
2462  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2463 
2464  /* invalidate nonlinear row */
2465  if( consdata->nlrow != NULL )
2466  {
2467  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2468  }
2469 
2470  consdata->ispropagated = FALSE;
2471  consdata->ispresolved = FALSE;
2472  if( consdata->nbilinterms == 1 )
2473  {
2474  consdata->bilinsorted = TRUE;
2475 
2476  /* we have to take care of the bilinear term in mergeAndCleanBilinearTerms() if the coefficient is zero */
2477  consdata->bilinmerged = !SCIPisZero(scip, consdata->bilinterms[0].coef);
2478  }
2479  else
2480  {
2481  consdata->bilinsorted = consdata->bilinsorted
2482  && (bilinTermComp(consdata, consdata->nbilinterms-2, consdata->nbilinterms-1) <= 0);
2483  consdata->bilinmerged = FALSE;
2484  }
2485 
2486  consdata->iscurvchecked = FALSE;
2487 
2488  /* check if the bilinear terms are sorted */
2489  assert(consdataCheckBilinTermsSort(consdata));
2490 
2491  return SCIP_OKAY;
2492 }
2493 
2494 /** removes a set of bilinear terms and updates adjacency information in quad var terms
2495  *
2496  * Note: this function sorts the given array termposs.
2497  */
2498 static
2500  SCIP* scip, /**< SCIP data structure */
2501  SCIP_CONS* cons, /**< quadratic constraint */
2502  int nterms, /**< number of terms to delete */
2503  int* termposs /**< indices of terms to delete */
2504  )
2505 {
2506  SCIP_CONSDATA* consdata;
2507  int* newpos;
2508  int i;
2509  int j;
2510  int offset;
2511 
2512  assert(scip != NULL);
2513  assert(cons != NULL);
2514  assert(nterms == 0 || termposs != NULL);
2515 
2516  if( nterms == 0 )
2517  return SCIP_OKAY;
2518 
2519  consdata = SCIPconsGetData(cons);
2520  assert(consdata != NULL);
2521 
2522  SCIPsortInt(termposs, nterms);
2523 
2524  SCIP_CALL( SCIPallocBufferArray(scip, &newpos, consdata->nbilinterms) );
2525 
2526  i = 0;
2527  offset = 0;
2528  for( j = 0; j < consdata->nbilinterms; ++j )
2529  {
2530  /* if j'th term is deleted, increase offset and continue */
2531  if( i < nterms && j == termposs[i] )
2532  {
2533  ++offset;
2534  ++i;
2535  newpos[j] = -1;
2536  continue;
2537  }
2538 
2539  /* otherwise, move it forward and remember new position */
2540  if( offset > 0 )
2541  consdata->bilinterms[j-offset] = consdata->bilinterms[j];
2542  newpos[j] = j - offset;
2543  }
2544  assert(offset == nterms);
2545 
2546  /* update adjacency and activity information in quad var terms */
2547  for( i = 0; i < consdata->nquadvars; ++i )
2548  {
2549  offset = 0;
2550  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2551  {
2552  assert(consdata->quadvarterms[i].adjbilin[j] < consdata->nbilinterms);
2553  if( newpos[consdata->quadvarterms[i].adjbilin[j]] == -1 )
2554  {
2555  /* corresponding bilinear term was deleted, thus increase offset */
2556  ++offset;
2557  }
2558  else
2559  {
2560  /* update index of j'th bilinear term and store at position j-offset */
2561  consdata->quadvarterms[i].adjbilin[j-offset] = newpos[consdata->quadvarterms[i].adjbilin[j]];
2562  }
2563  }
2564  consdata->quadvarterms[i].nadjbilin -= offset;
2565  /* some bilinear term was removed, so invalidate activity bounds */
2566  }
2567 
2568  consdata->nbilinterms -= nterms;
2569 
2570  SCIPfreeBufferArray(scip, &newpos);
2571 
2572  /* some quad vars may be linear now */
2573  consdata->quadvarsmerged = FALSE;
2574 
2575  consdata->ispropagated = FALSE;
2576  consdata->ispresolved = FALSE;
2577  consdata->iscurvchecked = FALSE;
2578 
2579  /* invalidate activity */
2580  consdata->activity = SCIP_INVALID;
2581  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2582 
2583  /* invalidate nonlinear row */
2584  if( consdata->nlrow != NULL )
2585  {
2586  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2587  }
2588 
2589  return SCIP_OKAY;
2590 }
2591 
2592 /** merges quad var terms that correspond to the same variable and does additional cleanup
2593  *
2594  * If a quadratic variable terms is actually linear, makes a linear term out of it
2595  * also replaces squares of binary variables by the binary variables, i.e., adds sqrcoef to lincoef.
2596  */
2597 static
2599  SCIP* scip, /**< SCIP data structure */
2600  SCIP_CONS* cons /**< quadratic constraint */
2601  )
2602 {
2603  SCIP_QUADVARTERM* quadvarterm;
2604  SCIP_CONSDATA* consdata;
2605  int i;
2606  int j;
2607 
2608  assert(scip != NULL);
2609  assert(cons != NULL);
2610 
2611  consdata = SCIPconsGetData(cons);
2612 
2613  if( consdata->quadvarsmerged )
2614  return SCIP_OKAY;
2615 
2616  if( consdata->nquadvars == 0 )
2617  {
2618  consdata->quadvarsmerged = TRUE;
2619  return SCIP_OKAY;
2620  }
2621 
2622  i = 0;
2623  while( i < consdata->nquadvars )
2624  {
2625  /* make sure quad var terms are sorted (do this in every round, since we may move variables around) */
2626  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
2627 
2628  quadvarterm = &consdata->quadvarterms[i];
2629 
2630  for( j = i+1; j < consdata->nquadvars && consdata->quadvarterms[j].var == quadvarterm->var; ++j )
2631  {
2632  /* add quad var term j to current term i */
2633  quadvarterm->lincoef += consdata->quadvarterms[j].lincoef;
2634  quadvarterm->sqrcoef += consdata->quadvarterms[j].sqrcoef;
2635  if( consdata->quadvarterms[j].nadjbilin > 0 )
2636  {
2637  /* move adjacency information from j to i */
2638  SCIP_CALL( consdataEnsureAdjBilinSize(scip, quadvarterm, quadvarterm->nadjbilin + consdata->quadvarterms[j].nadjbilin) );
2639  BMScopyMemoryArray(&quadvarterm->adjbilin[quadvarterm->nadjbilin], consdata->quadvarterms[j].adjbilin, consdata->quadvarterms[j].nadjbilin); /*lint !e866*/
2640  quadvarterm->nadjbilin += consdata->quadvarterms[j].nadjbilin;
2641  consdata->quadvarterms[j].nadjbilin = 0;
2642  }
2643  consdata->quadvarterms[j].lincoef = 0.0;
2644  consdata->quadvarterms[j].sqrcoef = 0.0;
2645  /* mark that activity information in quadvarterm is not up to date anymore */
2646  }
2647 
2648  /* remove quad var terms i+1..j-1 backwards */
2649  for( j = j-1; j > i; --j )
2650  {
2651  SCIP_CALL( delQuadVarTermPos(scip, cons, j) );
2652  }
2653 
2654  /* for binary variables, x^2 = x
2655  * however, we may destroy convexity of a quadratic term that involves also bilinear terms
2656  * thus, we do this step only if the variable does not appear in any bilinear term */
2657  if( quadvarterm->sqrcoef != 0.0 && SCIPvarIsBinary(quadvarterm->var) && quadvarterm->nadjbilin == 0 )
2658  {
2659  SCIPdebugMsg(scip, "replace square of binary variable by itself: <%s>^2 --> <%s>\n", SCIPvarGetName(quadvarterm->var), SCIPvarGetName(quadvarterm->var));
2660  quadvarterm->lincoef += quadvarterm->sqrcoef;
2661  quadvarterm->sqrcoef = 0.0;
2662 
2663  /* invalidate nonlinear row */
2664  if( consdata->nlrow != NULL )
2665  {
2666  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2667  }
2668  }
2669 
2670  /* if its 0.0 or linear, get rid of it */
2671  if( SCIPisZero(scip, quadvarterm->sqrcoef) && quadvarterm->nadjbilin == 0 )
2672  {
2673  if( !SCIPisZero(scip, quadvarterm->lincoef) )
2674  {
2675  /* seem to be a linear term now, thus add as linear term */
2676  SCIP_CALL( addLinearCoef(scip, cons, quadvarterm->var, quadvarterm->lincoef) );
2677  }
2678  /* remove term at pos i */
2679  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2680  }
2681  else
2682  {
2683  ++i;
2684  }
2685  }
2686 
2687  consdata->quadvarsmerged = TRUE;
2688  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2689 
2690  return SCIP_OKAY;
2691 }
2692 
2693 /** merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
2694 static
2696  SCIP* scip, /**< SCIP data structure */
2697  SCIP_CONS* cons /**< quadratic constraint */
2698  )
2699 {
2700  SCIP_CONSDATA* consdata;
2701  SCIP_Real newcoef;
2702  int i;
2703  int j;
2704  int qvarpos;
2705 
2706  assert(scip != NULL);
2707  assert(cons != NULL);
2708 
2709  consdata = SCIPconsGetData(cons);
2710 
2711  if( consdata->linvarsmerged )
2712  return SCIP_OKAY;
2713 
2714  if( consdata->nlinvars == 0 )
2715  {
2716  consdata->linvarsmerged = TRUE;
2717  return SCIP_OKAY;
2718  }
2719 
2720  i = 0;
2721  while( i < consdata->nlinvars )
2722  {
2723  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
2724  consdataSortLinearVars(consdata);
2725 
2726  /* sum up coefficients that correspond to variable i */
2727  newcoef = consdata->lincoefs[i];
2728  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
2729  newcoef += consdata->lincoefs[j];
2730  /* delete the additional variables in backward order */
2731  for( j = j-1; j > i; --j )
2732  {
2733  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
2734  }
2735 
2736  /* check if there is already a quadratic variable term with this variable */
2737  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->linvars[i], &qvarpos) );
2738  if( qvarpos >= 0)
2739  {
2740  /* add newcoef to linear coefficient of quadratic variable and mark linear variable as to delete */
2741  assert(qvarpos < consdata->nquadvars);
2742  assert(consdata->quadvarterms[qvarpos].var == consdata->linvars[i]);
2743  consdata->quadvarterms[qvarpos].lincoef += newcoef;
2744  newcoef = 0.0;
2745  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2746  }
2747 
2748  /* delete also entry at position i, if it became zero (or was zero before) */
2749  if( SCIPisZero(scip, newcoef) )
2750  {
2751  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2752  }
2753  else
2754  {
2755  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
2756  ++i;
2757  }
2758  }
2759 
2760  consdata->linvarsmerged = TRUE;
2761 
2762  return SCIP_OKAY;
2763 }
2764 
2765 /** merges bilinear terms with same variables into a single term, removes bilinear terms with coefficient 0.0 */
2766 static
2768  SCIP* scip, /**< SCIP data structure */
2769  SCIP_CONS* cons /**< quadratic constraint */
2770  )
2771 {
2772  SCIP_CONSDATA* consdata;
2773  SCIP_BILINTERM* bilinterm;
2774  int i;
2775  int j;
2776  int* todelete;
2777  int ntodelete;
2778 
2779  assert(scip != NULL);
2780  assert(cons != NULL);
2781 
2782  consdata = SCIPconsGetData(cons);
2783 
2784  /* check if the bilinear terms are sorted */
2785  assert(consdataCheckBilinTermsSort(consdata));
2786 
2787  if( consdata->bilinmerged )
2788  return SCIP_OKAY;
2789 
2790  if( consdata->nbilinterms == 0 )
2791  {
2792  consdata->bilinmerged = TRUE;
2793  return SCIP_OKAY;
2794  }
2795 
2796  /* alloc memory for array of terms that need to be deleted finally */
2797  ntodelete = 0;
2798  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
2799 
2800  /* make sure bilinear terms are sorted */
2801  SCIP_CALL( consdataSortBilinTerms(scip, consdata) );
2802 
2803  i = 0;
2804  while( i < consdata->nbilinterms )
2805  {
2806  bilinterm = &consdata->bilinterms[i];
2807 
2808  /* sum up coefficients that correspond to same variables as term i */
2809  for( j = i+1; j < consdata->nbilinterms && bilinterm->var1 == consdata->bilinterms[j].var1 && bilinterm->var2 == consdata->bilinterms[j].var2; ++j )
2810  {
2811  bilinterm->coef += consdata->bilinterms[j].coef;
2812  todelete[ntodelete++] = j;
2813  }
2814 
2815  /* delete also entry at position i, if it became zero (or was zero before) */
2816  if( SCIPisZero(scip, bilinterm->coef) )
2817  {
2818  todelete[ntodelete++] = i;
2819  }
2820 
2821  /* continue with term after the current series */
2822  i = j;
2823  }
2824 
2825  /* delete bilinear terms */
2826  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
2827 
2828  SCIPfreeBufferArray(scip, &todelete);
2829 
2830  consdata->bilinmerged = TRUE;
2831 
2832  /* check if the bilinear terms are sorted */
2833  assert(consdataCheckBilinTermsSort(consdata));
2834 
2835  return SCIP_OKAY;
2836 }
2837 
2838 /** removes fixes (or aggregated) variables from a quadratic constraint */
2839 static
2841  SCIP* scip, /**< SCIP data structure */
2842  SCIP_CONS* cons /**< quadratic constraint */
2843  )
2844 {
2845  SCIP_CONSDATA* consdata;
2846  SCIP_BILINTERM* bilinterm;
2847  SCIP_Real coef;
2848  SCIP_Real offset;
2849  SCIP_VAR* var;
2850  SCIP_VAR* var2;
2851  int var2pos;
2852  int i;
2853  int j;
2854  int k;
2855 
2856  SCIP_Bool have_change;
2857 
2858  assert(scip != NULL);
2859  assert(cons != NULL);
2860 
2861  consdata = SCIPconsGetData(cons);
2862 
2863  have_change = FALSE;
2864  i = 0;
2865  while( i < consdata->nlinvars )
2866  {
2867  var = consdata->linvars[i];
2868 
2869  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2870  {
2871  ++i;
2872  continue;
2873  }
2874 
2875  have_change = TRUE;
2876 
2877  coef = consdata->lincoefs[i];
2878  offset = 0.0;
2879 
2880  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2881  {
2882  offset = coef * (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
2883  coef = 0.0;
2884  }
2885  else
2886  {
2887  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2888  }
2889 
2890  SCIPdebugMsg(scip, " linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]),
2891  coef, SCIPvarGetName(var), offset);
2892 
2893  /* delete previous variable (this will move another variable to position i) */
2894  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2895 
2896  /* put constant part into bounds */
2897  if( offset != 0.0 )
2898  {
2899  if( !SCIPisInfinity(scip, -consdata->lhs) )
2900  consdata->lhs -= offset;
2901  if( !SCIPisInfinity(scip, consdata->rhs) )
2902  consdata->rhs -= offset;
2903  }
2904 
2905  /* nothing left to do if variable had been fixed */
2906  if( coef == 0.0 )
2907  continue;
2908 
2909  /* if GetProbvar gave a linear variable, just add it
2910  * if it's a multilinear variable, add it's disaggregated variables */
2911  if( SCIPvarIsActive(var) )
2912  {
2913  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
2914  }
2915  else
2916  {
2917  int naggrs;
2918  SCIP_VAR** aggrvars;
2919  SCIP_Real* aggrscalars;
2920  SCIP_Real aggrconstant;
2921 
2922  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
2923 
2924  naggrs = SCIPvarGetMultaggrNVars(var);
2925  aggrvars = SCIPvarGetMultaggrVars(var);
2926  aggrscalars = SCIPvarGetMultaggrScalars(var);
2927  aggrconstant = SCIPvarGetMultaggrConstant(var);
2928 
2929  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
2930 
2931  for( j = 0; j < naggrs; ++j )
2932  {
2933  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
2934  }
2935 
2936  if( aggrconstant != 0.0 )
2937  {
2938  if( !SCIPisInfinity(scip, -consdata->lhs) )
2939  consdata->lhs -= coef * aggrconstant;
2940  if( !SCIPisInfinity(scip, consdata->rhs) )
2941  consdata->rhs -= coef * aggrconstant;
2942  }
2943  }
2944  }
2945 
2946  i = 0;
2947  while( i < consdata->nquadvars )
2948  {
2949  var = consdata->quadvarterms[i].var;
2950 
2951  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2952  {
2953  ++i;
2954  continue;
2955  }
2956 
2957  have_change = TRUE;
2958 
2959  coef = 1.0;
2960  offset = 0.0;
2961 
2962  if( !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2963  {
2964  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2965  }
2966  else
2967  {
2968  coef = 0.0;
2969  offset = (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
2970  }
2971 
2972  SCIPdebugMsg(scip, " quadratic variable <%s> with status %d is replaced by %g * <%s> + %g\n", SCIPvarGetName(consdata->quadvarterms[i].var),
2973  SCIPvarGetStatus(consdata->quadvarterms[i].var), coef, SCIPvarGetName(var), offset);
2974 
2975  /* handle fixed variable */
2976  if( coef == 0.0 )
2977  {
2978  /* if not fixed to 0.0, add to linear coefs of vars in bilinear terms, and deal with linear and square term as constant */
2979  if( offset != 0.0 )
2980  {
2981  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2982  {
2983  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
2984 
2985  var2 = bilinterm->var1 == consdata->quadvarterms[i].var ? bilinterm->var2 : bilinterm->var1;
2986  assert(var2 != consdata->quadvarterms[i].var);
2987 
2988  var2pos = 0;
2989  while( consdata->quadvarterms[var2pos].var != var2 )
2990  {
2991  ++var2pos;
2992  assert(var2pos < consdata->nquadvars);
2993  }
2994  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2995  }
2996 
2997  offset = consdata->quadvarterms[i].lincoef * offset + consdata->quadvarterms[i].sqrcoef * offset * offset;
2998  if( !SCIPisInfinity(scip, -consdata->lhs) )
2999  consdata->lhs -= offset;
3000  if( !SCIPisInfinity(scip, consdata->rhs) )
3001  consdata->rhs -= offset;
3002  }
3003 
3004  /* remove bilinear terms */
3005  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3006 
3007  /* delete quad. var term i */
3008  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3009 
3010  continue;
3011  }
3012 
3013  assert(var != NULL);
3014 
3015  /* if GetProbvar gave an active variable, replace the quad var term so that it uses the new variable */
3016  if( SCIPvarIsActive(var) )
3017  {
3018  /* replace x by coef*y+offset */
3019  SCIP_CALL( replaceQuadVarTermPos(scip, cons, i, var, coef, offset) );
3020 
3021  continue;
3022  }
3023  else
3024  {
3025  /* if GetProbVar gave a multi-aggregated variable, add new quad var terms and new bilinear terms
3026  * x is replaced by coef * (sum_i a_ix_i + b) + offset
3027  * lcoef * x + scoef * x^2 + bcoef * x * y ->
3028  * (b*coef + offset) * (lcoef + (b*coef + offset) * scoef)
3029  * + sum_i a_i*coef * (lcoef + 2 (b*coef + offset) * scoef) x_i
3030  * + sum_i (a_i*coef)^2 * scoef * x_i^2
3031  * + 2 sum_{i,j, i<j} (a_i a_j coef^2 scoef) x_i x_j
3032  * + bcoef * (b*coef + offset + coef * sum_i a_ix_i) y
3033  */
3034  int naggrs;
3035  SCIP_VAR** aggrvars; /* x_i */
3036  SCIP_Real* aggrscalars; /* a_i */
3037  SCIP_Real aggrconstant; /* b */
3038  int nquadtermsold;
3039 
3040  SCIP_Real lcoef;
3041  SCIP_Real scoef;
3042 
3043  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
3044 
3045  naggrs = SCIPvarGetMultaggrNVars(var);
3046  aggrvars = SCIPvarGetMultaggrVars(var);
3047  aggrscalars = SCIPvarGetMultaggrScalars(var);
3048  aggrconstant = SCIPvarGetMultaggrConstant(var);
3049 
3050  lcoef = consdata->quadvarterms[i].lincoef;
3051  scoef = consdata->quadvarterms[i].sqrcoef;
3052 
3053  nquadtermsold = consdata->nquadvars;
3054 
3055  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars + naggrs) );
3056 
3057  /* take care of constant part */
3058  if( aggrconstant != 0.0 || offset != 0.0 )
3059  {
3060  SCIP_Real constant;
3061  constant = (aggrconstant * coef + offset) * (lcoef + (aggrconstant * coef + offset) * scoef);
3062  if( !SCIPisInfinity(scip, -consdata->lhs) )
3063  consdata->lhs -= constant;
3064  if( !SCIPisInfinity(scip, consdata->rhs) )
3065  consdata->rhs -= constant;
3066  }
3067 
3068  /* add x_i's with linear and square coefficients */
3069  for( j = 0; j < naggrs; ++j )
3070  {
3071  SCIP_CALL( addQuadVarTerm(scip, cons, aggrvars[j],
3072  coef * aggrscalars[j] * (lcoef + 2.0 * scoef * (coef * aggrconstant + offset)),
3073  coef * coef * aggrscalars[j] * aggrscalars[j] * scoef) );
3074  }
3075 
3076  /* ensure space for bilinear terms */
3077  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nquadvars + (scoef != 0.0 ? (naggrs * (naggrs-1))/2 : 0) + consdata->quadvarterms[j].nadjbilin * naggrs) );
3078 
3079  /* add x_j*x_k's */
3080  if( scoef != 0.0 )
3081  {
3082  for( j = 0; j < naggrs; ++j )
3083  for( k = 0; k < j; ++k )
3084  {
3085  assert(aggrvars[j] != aggrvars[k]);
3086  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, nquadtermsold + k,
3087  2.0 * aggrscalars[j] * aggrscalars[k] * coef * coef * scoef) );
3088  }
3089  }
3090 
3091  /* add x_i*y's */
3092  for( k = 0; k < consdata->quadvarterms[i].nadjbilin; ++k )
3093  {
3094  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[k]];
3095  var2 = (bilinterm->var1 == consdata->quadvarterms[i].var) ? bilinterm->var2 : bilinterm->var1;
3096  assert(var2 != consdata->quadvarterms[i].var);
3097 
3098  /* this is not efficient, but we cannot sort the quadratic terms here, since we currently iterate over them */
3099  var2pos = 0;
3100  while( consdata->quadvarterms[var2pos].var != var2 )
3101  {
3102  ++var2pos;
3103  assert(var2pos < consdata->nquadvars);
3104  }
3105 
3106  for( j = 0; j < naggrs; ++j )
3107  {
3108  if( aggrvars[j] == var2 )
3109  { /* x_i == y, so we have a square term here */
3110  consdata->quadvarterms[var2pos].sqrcoef += bilinterm->coef * coef * aggrscalars[j];
3111  }
3112  else
3113  { /* x_i != y, so we need to add a bilinear term here */
3114  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, var2pos, bilinterm->coef * coef * aggrscalars[j]) );
3115  }
3116  }
3117 
3118  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * (aggrconstant * coef + offset);
3119  }
3120 
3121  /* remove bilinear terms */
3122  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3123 
3124  /* delete quad. var term i */
3125  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3126  }
3127  }
3128 
3129  consdata->isremovedfixings = TRUE;
3130 
3131  SCIPdebugMsg(scip, "removed fixations from <%s>\n -> ", SCIPconsGetName(cons));
3132  SCIPdebugPrintCons(scip, cons, NULL);
3133 
3134 #ifndef NDEBUG
3135  for( i = 0; i < consdata->nlinvars; ++i )
3136  assert(SCIPvarIsActive(consdata->linvars[i]));
3137 
3138  for( i = 0; i < consdata->nquadvars; ++i )
3139  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
3140 #endif
3141 
3142  if( !have_change )
3143  return SCIP_OKAY;
3144 
3145  /* some quadratic variable may have been replaced by an already existing linear variable
3146  * in this case, we want the linear variable to be removed, which happens in mergeAndCleanLinearVars
3147  */
3148  consdata->linvarsmerged = FALSE;
3149 
3150  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
3151  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
3152  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
3153 
3154 #ifndef NDEBUG
3155  for( i = 0; i < consdata->nbilinterms; ++i )
3156  {
3157  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
3158  assert(consdata->bilinterms[i].coef != 0.0);
3159  assert(SCIPvarCompare(consdata->bilinterms[i].var1, consdata->bilinterms[i].var2) < 0);
3160  }
3161 #endif
3162 
3163  return SCIP_OKAY;
3164 }
3165 
3166 /** create a nonlinear row representation of the constraint and stores them in consdata */
3167 static
3169  SCIP* scip, /**< SCIP data structure */
3170  SCIP_CONS* cons /**< quadratic constraint */
3171  )
3172 {
3173  SCIP_CONSDATA* consdata;
3174  int nquadvars; /* number of variables in quadratic terms */
3175  SCIP_VAR** quadvars; /* variables in quadratic terms */
3176  int nquadelems; /* number of quadratic elements (square and bilinear terms) */
3177  SCIP_QUADELEM* quadelems; /* quadratic elements (square and bilinear terms) */
3178  int nquadlinterms; /* number of linear terms using variables that are in quadratic terms */
3179  SCIP_VAR** quadlinvars; /* variables of linear terms using variables that are in quadratic terms */
3180  SCIP_Real* quadlincoefs; /* coefficients of linear terms using variables that are in quadratic terms */
3181  int i;
3182  int idx1;
3183  int idx2;
3184  int lincnt;
3185  int elcnt;
3186  SCIP_VAR* lastvar;
3187  int lastvaridx;
3188  SCIP_EXPRCURV curvature;
3189 
3190  assert(scip != NULL);
3191  assert(cons != NULL);
3192 
3193  consdata = SCIPconsGetData(cons);
3194  assert(consdata != NULL);
3195 
3196  if( consdata->nlrow != NULL )
3197  {
3198  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3199  }
3200 
3201  nquadvars = consdata->nquadvars;
3202  nquadelems = consdata->nbilinterms;
3203  nquadlinterms = 0;
3204  for( i = 0; i < nquadvars; ++i )
3205  {
3206  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3207  ++nquadelems;
3208  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3209  ++nquadlinterms;
3210  }
3211 
3212  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, nquadvars) );
3213  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
3214  SCIP_CALL( SCIPallocBufferArray(scip, &quadlinvars, nquadlinterms) );
3215  SCIP_CALL( SCIPallocBufferArray(scip, &quadlincoefs, nquadlinterms) );
3216 
3217  lincnt = 0;
3218  elcnt = 0;
3219  for( i = 0; i < nquadvars; ++i )
3220  {
3221  quadvars[i] = consdata->quadvarterms[i].var;
3222 
3223  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3224  {
3225  assert(elcnt < nquadelems);
3226  quadelems[elcnt].idx1 = i;
3227  quadelems[elcnt].idx2 = i;
3228  quadelems[elcnt].coef = consdata->quadvarterms[i].sqrcoef;
3229  ++elcnt;
3230  }
3231 
3232  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3233  {
3234  assert(lincnt < nquadlinterms);
3235  quadlinvars [lincnt] = consdata->quadvarterms[i].var;
3236  quadlincoefs[lincnt] = consdata->quadvarterms[i].lincoef;
3237  ++lincnt;
3238  }
3239  }
3240  assert(lincnt == nquadlinterms);
3241 
3242  /* bilinear terms are sorted first by first variable, then by second variable
3243  * 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 */
3244  lastvar = NULL;
3245  lastvaridx = -1;
3246  for( i = 0; i < consdata->nbilinterms; ++i )
3247  {
3248  if( lastvar == consdata->bilinterms[i].var1 )
3249  {
3250  assert(lastvaridx >= 0);
3251  assert(consdata->quadvarterms[lastvaridx].var == consdata->bilinterms[i].var1);
3252  }
3253  else
3254  {
3255  lastvar = consdata->bilinterms[i].var1;
3256  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, lastvar, &lastvaridx) );
3257  }
3258  idx1 = lastvaridx;
3259 
3260  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &idx2) );
3261 
3262  assert(elcnt < nquadelems);
3263  quadelems[elcnt].idx1 = MIN(idx1, idx2);
3264  quadelems[elcnt].idx2 = MAX(idx1, idx2);
3265  quadelems[elcnt].coef = consdata->bilinterms[i].coef;
3266  ++elcnt;
3267  }
3268  assert(elcnt == nquadelems);
3269 
3270  /* set curvature for the nonlinear row */
3271  if( consdata->isconcave && consdata->isconvex )
3272  {
3273  assert(consdata->nbilinterms == 0 && consdata->nquadvars == 0);
3274  curvature = SCIP_EXPRCURV_LINEAR;
3275  }
3276  else if( consdata->isconcave )
3277  curvature = SCIP_EXPRCURV_CONCAVE;
3278  else if( consdata->isconvex )
3279  curvature = SCIP_EXPRCURV_CONVEX;
3280  else
3281  curvature = SCIP_EXPRCURV_UNKNOWN;
3282 
3283  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3284  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
3285  nquadvars, quadvars, nquadelems, quadelems,
3286  NULL, consdata->lhs, consdata->rhs,
3287  curvature) );
3288 
3289  SCIP_CALL( SCIPaddLinearCoefsToNlRow(scip, consdata->nlrow, nquadlinterms, quadlinvars, quadlincoefs) );
3290 
3291  SCIPfreeBufferArray(scip, &quadlincoefs);
3292  SCIPfreeBufferArray(scip, &quadlinvars);
3293  SCIPfreeBufferArray(scip, &quadelems);
3294  SCIPfreeBufferArray(scip, &quadvars);
3295 
3296  return SCIP_OKAY;
3297 }
3298 
3299 /** solve constraint as presolving */
3300 static
3302  SCIP* scip, /**< SCIP data structure */
3303  SCIP_CONS* cons, /**< constraint */
3304  SCIP_RESULT* result, /**< to store result of solve: cutoff, success, or do-not-find */
3305  SCIP_Bool* redundant, /**< to store whether constraint is redundant now (should be deleted) */
3306  int* naggrvars /**< counter on number of variable aggregations */
3307  )
3308 {
3309  SCIP_CONSDATA* consdata;
3310 
3311  assert(scip != NULL);
3312  assert(cons != NULL);
3313  assert(result != NULL);
3314  assert(redundant != NULL);
3315 
3316  *result = SCIP_DIDNOTFIND;
3317  *redundant = FALSE;
3318 
3319  consdata = SCIPconsGetData(cons);
3320  assert(consdata != NULL);
3321 
3322  /* if constraint is an equality with two variables, at least one of them binary,
3323  * and linear after fixing the binary, then we can aggregate the variables */
3324  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && consdata->nlinvars == 0 && consdata->nquadvars == 2 &&
3325  ((SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ||
3326  (SCIPvarIsBinary(consdata->quadvarterms[1].var) && consdata->quadvarterms[0].sqrcoef == 0.0)) )
3327  {
3328  SCIP_Bool infeasible;
3329  SCIP_Bool aggregated;
3330  SCIP_Real a;
3331  SCIP_Real b;
3332  SCIP_Real c;
3333  SCIP_VAR* x;
3334  SCIP_VAR* y;
3335  int binvaridx;
3336 
3337  /* constraint is a*(x+x^2) + b*y + c*x*y = rhs, with x binary variable
3338  * x = 0 -> b*y == rhs
3339  * x = 1 -> (b+c)*y == rhs - a
3340  *
3341  * 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
3342  */
3343 
3344  binvaridx = (SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ? 0 : 1;
3345 
3346  x = consdata->quadvarterms[binvaridx].var;
3347  a = consdata->quadvarterms[binvaridx].sqrcoef + consdata->quadvarterms[binvaridx].lincoef;
3348 
3349  y = consdata->quadvarterms[1-binvaridx].var;
3350  b = consdata->quadvarterms[1-binvaridx].lincoef;
3351 
3352  assert(consdata->nbilinterms <= 1); /* should actually be 1, since constraint is otherwise linear */
3353  c = (consdata->nbilinterms == 1) ? consdata->bilinterms[0].coef : 0.0;
3354 
3355  if( !SCIPisZero(scip, b) && !SCIPisZero(scip, b+c) )
3356  {
3357  SCIPdebugMsg(scip, "<%s> = 0 -> %g*<%s> = %g and <%s> = 1 -> %g*<%s> = %g\n", SCIPvarGetName(x), b, SCIPvarGetName(y), consdata->rhs,
3358  SCIPvarGetName(x), b+c, SCIPvarGetName(y), consdata->rhs - a);
3359  SCIPdebugMsg(scip, "=> attempt aggregation <%s> = %g*<%s> + %g\n", SCIPvarGetName(y), (consdata->rhs-a)/(b+c) - consdata->rhs/b,
3360  SCIPvarGetName(x), consdata->rhs/b);
3361 
3362  SCIP_CALL( SCIPaggregateVars(scip, x, y, (consdata->rhs-a)/(b+c) - consdata->rhs/b, -1.0, -consdata->rhs/b, &infeasible, redundant, &aggregated) );
3363  if( infeasible )
3364  *result = SCIP_CUTOFF;
3365  else if( *redundant || aggregated )
3366  {
3367  /* aggregated (or were already aggregated), so constraint is now redundant */
3368  *result = SCIP_SUCCESS;
3369  *redundant = TRUE;
3370 
3371  if( aggregated )
3372  ++*naggrvars;
3373  }
3374  }
3375 
3376  /* @todo if b is 0 or b+c is 0, or lhs != rhs, then could replace by varbound constraint */
3377  }
3378 
3379  return SCIP_OKAY;
3380 }
3381 
3382 
3383 /** reformulates products of binary variables as AND constraint
3384  *
3385  * 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.
3386  */
3387 static
3389  SCIP* scip, /**< SCIP data structure */
3390  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3391  SCIP_CONS* cons, /**< constraint */
3392  int* naddconss /**< buffer where to add the number of AND constraints added */
3393  )
3394 {
3395  SCIP_CONSHDLRDATA* conshdlrdata;
3396  SCIP_CONSDATA* consdata;
3397  char name[SCIP_MAXSTRLEN];
3398  SCIP_VAR* vars[2];
3399  SCIP_VAR* auxvar;
3400  SCIP_CONS* andcons;
3401  int i;
3402  int ntodelete;
3403  int* todelete;
3404 
3405  assert(scip != NULL);
3406  assert(conshdlr != NULL);
3407  assert(cons != NULL);
3408  assert(naddconss != NULL);
3409 
3410  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3411  assert(conshdlrdata != NULL);
3412 
3413  /* if user does not like AND very much, then return */
3414  if( conshdlrdata->empathy4and < 2 )
3415  return SCIP_OKAY;
3416 
3417  consdata = SCIPconsGetData(cons);
3418  assert(consdata != NULL);
3419 
3420  if( consdata->nbilinterms == 0 )
3421  return SCIP_OKAY;
3422 
3423  /* get array to store indices of bilinear terms that shall be deleted */
3424  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
3425  ntodelete = 0;
3426 
3427  for( i = 0; i < consdata->nbilinterms; ++i )
3428  {
3429  vars[0] = consdata->bilinterms[i].var1;
3430  if( !SCIPvarIsBinary(vars[0]) )
3431  continue;
3432 
3433  vars[1] = consdata->bilinterms[i].var2;
3434  if( !SCIPvarIsBinary(vars[1]) )
3435  continue;
3436 
3437  /* create auxiliary variable */
3438  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]), SCIPconsGetName(cons));
3439  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
3440  SCIPvarIsInitial(vars[0]) || SCIPvarIsInitial(vars[1]), SCIPvarIsRemovable(vars[0]) && SCIPvarIsRemovable(vars[1]), NULL, NULL, NULL, NULL, NULL) );
3441  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3442 #ifdef SCIP_DEBUG_SOLUTION
3443  if( SCIPdebugIsMainscip(scip) )
3444  {
3445  SCIP_Real var0val;
3446  SCIP_Real var1val;
3447  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[0], &var0val) );
3448  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[1], &var1val) );
3449  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3450  }
3451 #endif
3452 
3453  /* create AND-constraint auxvar = x and y, need to be enforced as not redundant */
3454  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3455  SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, auxvar, 2, vars,
3456  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3457  SCIPconsIsSeparated(cons), TRUE, TRUE,
3460  SCIP_CALL( SCIPaddCons(scip, andcons) );
3461  SCIPdebugMsg(scip, "added AND constraint: ");
3462  SCIPdebugPrintCons(scip, andcons, NULL);
3463  SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
3464  ++*naddconss;
3465 
3466  /* add bilincoef * auxvar to linear terms */
3467  SCIP_CALL( addLinearCoef(scip, cons, auxvar, consdata->bilinterms[i].coef) );
3468  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3469 
3470  /* remember that we have to delete this bilinear term */
3471  assert(ntodelete < consdata->nbilinterms);
3472  todelete[ntodelete++] = i;
3473  }
3474 
3475  /* remove bilinear terms that have been replaced */
3476  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3477  SCIPfreeBufferArray(scip, &todelete);
3478 
3479  return SCIP_OKAY;
3480 }
3481 
3482 /** gets bounds of variable y if x takes a certain value; checks whether x = xval has implications on y */
3483 static
3485  SCIP* scip, /**< SCIP data structure */
3486  SCIP_VAR* x, /**< variable which implications to check */
3487  SCIP_Bool xval, /**< value of x to check for (TRUE for 1, FALSE for 0) */
3488  SCIP_VAR* y, /**< variable to check if bounds can be reduced */
3489  SCIP_INTERVAL* resultant /**< buffer to store bounds on y */
3490  )
3491 {
3492  SCIP_VAR** implvars;
3493  SCIP_BOUNDTYPE* impltypes;
3494  SCIP_Real* implbounds;
3495  int nimpls;
3496  int pos;
3497 
3498  assert(scip != NULL);
3499  assert(x != NULL);
3500  assert(y != NULL);
3501  assert(resultant != NULL);
3502 
3504 
3505  if( !SCIPvarIsBinary(x) || !SCIPvarIsActive(x) )
3506  return SCIP_OKAY;
3507 
3508  /* check in cliques for binary to binary implications */
3509  if( SCIPvarIsBinary(y) )
3510  {
3511  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 0.0));
3512  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 1.0));
3513 
3514  if( SCIPhaveVarsCommonClique(scip, x, xval, y, TRUE, FALSE) )
3515  {
3516  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 0.0));
3517  }
3518  else if( SCIPhaveVarsCommonClique(scip, x, xval, y, FALSE, FALSE) )
3519  {
3520  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 1.0));
3521  }
3522 
3523  return SCIP_OKAY;
3524  }
3525 
3526  /* analyze implications for x = xval */
3527  nimpls = SCIPvarGetNImpls(x, xval);
3528  if( nimpls == 0 )
3529  return SCIP_OKAY;
3530 
3531  implvars = SCIPvarGetImplVars (x, xval);
3532  impltypes = SCIPvarGetImplTypes (x, xval);
3533  implbounds = SCIPvarGetImplBounds(x, xval);
3534 
3535  assert(implvars != NULL);
3536  assert(impltypes != NULL);
3537  assert(implbounds != NULL);
3538 
3539  /* find implications */
3540  if( !SCIPsortedvecFindPtr((void**)implvars, SCIPvarComp, (void*)y, nimpls, &pos) )
3541  return SCIP_OKAY;
3542 
3543  /* if there are several implications on y, go to the first one */
3544  while( pos > 0 && implvars[pos-1] == y )
3545  --pos;
3546 
3547  /* update implied lower and upper bounds on y
3548  * but make sure that resultant will not be empty, due to tolerances
3549  */
3550  while( pos < nimpls && implvars[pos] == y )
3551  {
3552  if( impltypes[pos] == SCIP_BOUNDTYPE_LOWER )
3553  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, implbounds[pos]));
3554  else
3555  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, implbounds[pos]));
3556  ++pos;
3557  }
3558 
3559  assert(resultant->sup >= resultant->inf);
3560 
3561  return SCIP_OKAY;
3562 }
3563 
3564 /** Reformulates products of binary times bounded continuous variables as system of linear inequalities (plus auxiliary variable).
3565  *
3566  * For a product x*y, with y a binary variable and x a continous variable with finite bounds,
3567  * 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.
3568  *
3569  * 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.
3570  * For each product of linear term of length at most maxnrvar with y, an auxiliary z and linear inequalities are added.
3571  *
3572  * If y is a binary variable, the AND constraint \f$ z = x \wedge y \f$ may be added instead of linear constraints.
3573  */
3574 static
3576  SCIP* scip, /**< SCIP data structure */
3577  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3578  SCIP_CONS* cons, /**< constraint */
3579  int* naddconss /**< buffer where to add the number of auxiliary constraints added */
3580  )
3581 { /*lint --e{666} */
3582  SCIP_CONSHDLRDATA* conshdlrdata;
3583  SCIP_CONSDATA* consdata;
3584  SCIP_VAR** xvars;
3585  SCIP_Real* xcoef;
3586  SCIP_INTERVAL xbndszero;
3587  SCIP_INTERVAL xbndsone;
3588  SCIP_INTERVAL act0;
3589  SCIP_INTERVAL act1;
3590  int nxvars;
3591  SCIP_VAR* y;
3592  SCIP_VAR* bvar;
3593  char name[SCIP_MAXSTRLEN];
3594  int nbilinterms;
3595  SCIP_VAR* auxvar;
3596  SCIP_CONS* auxcons;
3597  int i;
3598  int j;
3599  int k;
3600  int bilinidx;
3601  SCIP_Real bilincoef;
3602  SCIP_Real mincoef;
3603  SCIP_Real maxcoef;
3604  int* todelete;
3605  int ntodelete;
3606  int maxnrvar;
3607  SCIP_Bool integral;
3608  SCIP_Longint gcd;
3609  SCIP_Bool auxvarinitial;
3610  SCIP_Bool auxvarremovable;
3611 
3612  assert(scip != NULL);
3613  assert(conshdlr != NULL);
3614  assert(cons != NULL);
3615  assert(naddconss != NULL);
3616 
3617  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3618  assert(conshdlrdata != NULL);
3619 
3620  maxnrvar = conshdlrdata->replacebinaryprodlength;
3621  if( maxnrvar == 0 )
3622  return SCIP_OKAY;
3623 
3624  consdata = SCIPconsGetData(cons);
3625  assert(consdata != NULL);
3626 
3627  xvars = NULL;
3628  xcoef = NULL;
3629  todelete = NULL;
3630  gcd = 0;
3631 
3632  for( i = 0; i < consdata->nquadvars; ++i )
3633  {
3634  y = consdata->quadvarterms[i].var;
3635  if( !SCIPvarIsBinary(y) )
3636  continue;
3637 
3638  nbilinterms = consdata->quadvarterms[i].nadjbilin;
3639  if( nbilinterms == 0 )
3640  continue;
3641 
3642  SCIP_CALL( SCIPreallocBufferArray(scip, &xvars, MIN(maxnrvar, nbilinterms)+2) ); /* add 2 for later use when creating linear constraints */
3643  SCIP_CALL( SCIPreallocBufferArray(scip, &xcoef, MIN(maxnrvar, nbilinterms)+2) );
3644 
3645  /* alloc array to store indices of bilinear terms that shall be deleted */
3646  SCIP_CALL( SCIPreallocBufferArray(scip, &todelete, nbilinterms) );
3647  ntodelete = 0;
3648 
3649  auxvarinitial = SCIPvarIsInitial(y);
3650  auxvarremovable = SCIPvarIsRemovable(y);
3651 
3652  /* 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)
3653  * and compute range of sum_i a_i*x_i for the cases y = 0 and y = 1
3654  * we may need several rounds of maxnrvar < nbilinterms
3655  */
3656  j = 0;
3657  do
3658  {
3659  nxvars = 0;
3660  SCIPintervalSet(&xbndszero, 0.0);
3661  SCIPintervalSet(&xbndsone, 0.0);
3662 
3663  mincoef = SCIPinfinity(scip);
3664  maxcoef = 0.0;
3665  integral = TRUE;
3666 
3667  /* collect at most maxnrvar variables for x term */
3668  for( ; j < nbilinterms && nxvars < maxnrvar; ++j )
3669  {
3670  bilinidx = consdata->quadvarterms[i].adjbilin[j];
3671  assert(bilinidx >= 0);
3672  assert(bilinidx < consdata->nbilinterms);
3673 
3674  bvar = consdata->bilinterms[bilinidx].var1;
3675  if( bvar == y )
3676  bvar = consdata->bilinterms[bilinidx].var2;
3677  assert(bvar != y);
3678 
3679  /* skip products with unbounded variables */
3680  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(bvar)) || SCIPisInfinity(scip, SCIPvarGetUbGlobal(bvar)) )
3681  {
3682  SCIPdebugMsg(scip, "skip reform of <%s><%s> due to unbounded second variable [%g,%g]\n",
3684  continue;
3685  }
3686 
3687  bilincoef = consdata->bilinterms[bilinidx].coef;
3688  assert(bilincoef != 0.0);
3689 
3690  /* get activity of bilincoef * x if y = 0 */
3691  SCIP_CALL( getImpliedBounds(scip, y, FALSE, bvar, &act0) );
3692  SCIPintervalMulScalar(SCIPinfinity(scip), &act0, act0, bilincoef);
3693 
3694  /* get activity of bilincoef * x if y = 1 */
3695  SCIP_CALL( getImpliedBounds(scip, y, TRUE, bvar, &act1) );
3696  SCIPintervalMulScalar(SCIPinfinity(scip), &act1, act1, bilincoef);
3697 
3698  /* skip products that give rise to very large coefficients (big big-M's) */
3699  if( SCIPfeastol(scip) * REALABS(act0.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act0.sup) >= conshdlrdata->binreformmaxcoef )
3700  {
3701  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 0.0\n",
3702  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act0), SCIPintervalGetSup(act0), SCIPvarGetName(y));
3703  continue;
3704  }
3705  if( SCIPfeastol(scip) * REALABS(act1.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act1.sup) >= conshdlrdata->binreformmaxcoef )
3706  {
3707  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 1.0\n",
3708  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act1), SCIPintervalGetSup(act1), SCIPvarGetName(y));
3709  continue;
3710  }
3711  if( !SCIPisZero(scip, MIN(REALABS(act0.inf), REALABS(act0.sup))) &&
3712  SCIPfeastol(scip) * MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)) >= conshdlrdata->binreformmaxcoef )
3713  {
3714  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3715  MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)), SCIPvarGetName(y));
3716  continue;
3717  }
3718  if( !SCIPisZero(scip, MIN(REALABS(act1.inf), REALABS(act1.sup))) &&
3719  SCIPfeastol(scip) * MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)) >= conshdlrdata->binreformmaxcoef )
3720  {
3721  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3722  MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)), SCIPvarGetName(y));
3723  continue;
3724  }
3725 
3726  /* add bvar to x term */
3727  xvars[nxvars] = bvar;
3728  xcoef[nxvars] = bilincoef;
3729  ++nxvars;
3730 
3731  /* update bounds on x term */
3732  SCIPintervalAdd(SCIPinfinity(scip), &xbndszero, xbndszero, act0);
3733  SCIPintervalAdd(SCIPinfinity(scip), &xbndsone, xbndsone, act1);
3734 
3735  if( REALABS(bilincoef) < mincoef )
3736  mincoef = ABS(bilincoef);
3737  if( REALABS(bilincoef) > maxcoef )
3738  maxcoef = ABS(bilincoef);
3739 
3740  /* update whether all coefficients will be integral and if so, compute their gcd */
3741  integral &= (SCIPvarGetType(bvar) < SCIP_VARTYPE_CONTINUOUS) && SCIPisIntegral(scip, bilincoef); /*lint !e514 */
3742  if( integral )
3743  {
3744  if( nxvars == 1 )
3745  gcd = (SCIP_Longint)SCIPround(scip, REALABS(bilincoef));
3746  else
3747  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)SCIPround(scip, REALABS(bilincoef)));
3748  }
3749 
3750  /* if bvar is initial, then also the auxiliary variable should be initial
3751  * if bvar is not removable, then also the auxiliary variable should not be removable
3752  */
3753  auxvarinitial |= SCIPvarIsInitial(bvar);
3754  auxvarremovable &= SCIPvarIsRemovable(bvar);
3755 
3756  /* remember that we have to remove this bilinear term later */
3757  assert(ntodelete < nbilinterms);
3758  todelete[ntodelete++] = bilinidx;
3759  }
3760 
3761  if( nxvars == 0 ) /* all (remaining) x_j seem to be unbounded */
3762  break;
3763 
3764  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndszero)));
3765  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndszero)));
3766  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndsone)));
3767  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndsone)));
3768 
3769 #ifdef SCIP_DEBUG
3770  if( SCIPintervalGetInf(xbndszero) != SCIPintervalGetInf(xbndsone) || /*lint !e777*/
3771  +SCIPintervalGetSup(xbndszero) != SCIPintervalGetSup(xbndsone) ) /*lint !e777*/
3772  {
3773  SCIPdebugMsg(scip, "got different bounds for y = 0: [%g, %g] and y = 1: [%g, %g]\n", xbndszero.inf, xbndszero.sup, xbndsone.inf, xbndsone.sup);
3774  }
3775 #endif
3776 
3777  if( nxvars == 1 && conshdlrdata->empathy4and >= 1 && SCIPvarIsBinary(xvars[0]) )
3778  {
3779  /* product of two binary variables, replace by auxvar and AND constraint */
3780  /* add auxiliary variable z */
3781  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3782  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT,
3783  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3784  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3785 
3786 #ifdef SCIP_DEBUG_SOLUTION
3787  if( SCIPdebugIsMainscip(scip) )
3788  {
3789  SCIP_Real var0val;
3790  SCIP_Real var1val;
3791  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[0], &var0val) );
3792  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &var1val) );
3793  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3794  }
3795 #endif
3796 
3797  /* add constraint z = x and y; need to be enforced, as it is not redundant w.r.t. existing constraints */
3798  xvars[1] = y;
3799  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3800  SCIP_CALL( SCIPcreateConsAnd(scip, &auxcons, name, auxvar, 2, xvars,
3801  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3802  SCIPconsIsSeparated(cons), TRUE, TRUE,
3805  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3806  SCIPdebugMsg(scip, "added AND constraint: ");
3807  SCIPdebugPrintCons(scip, auxcons, NULL);
3808  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3809  ++*naddconss;
3810 
3811  /* add linear term coef*auxvar */
3812  SCIP_CALL( addLinearCoef(scip, cons, auxvar, xcoef[0]) );
3813 
3814  /* forget about auxvar */
3815  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3816  }
3817  else
3818  {
3819  /* product of binary variable with more than one binary or with continuous variables or with binary and user
3820  * did not like AND -> replace by auxvar and linear constraints */
3821  SCIP_Real scale;
3822 
3823  /* scale auxiliary constraint by some nice value,
3824  * if all coefficients are integral, take a value that preserves integrality (-> gcd), so we can make the auxiliary variable impl. integer
3825  */
3826  if( integral )
3827  {
3828  scale = (SCIP_Real)gcd;
3829  assert(scale >= 1.0);
3830  }
3831  else if( nxvars == 1 )
3832  {
3833  /* scaling by the only coefficient gives auxiliary variable = x * y, which thus will be implicit integral provided y is not continuous */
3834  assert(mincoef == maxcoef); /*lint !e777 */
3835  scale = mincoef;
3836  integral = SCIPvarGetType(xvars[0]) < SCIP_VARTYPE_CONTINUOUS;
3837  }
3838  else
3839  {
3840  scale = 1.0;
3841  if( maxcoef < 0.5 )
3842  scale = maxcoef;
3843  if( mincoef > 2.0 )
3844  scale = mincoef;
3845  if( scale != 1.0 )
3846  scale = SCIPselectSimpleValue(scale / 2.0, 1.5 * scale, MAXDNOM);
3847  }
3848  assert(scale > 0.0);
3849  assert(!SCIPisInfinity(scip, scale));
3850 
3851  /* if x-term is always negative for y = 1, negate scale so we get a positive auxiliary variable; maybe this is better sometimes? */
3852  if( !SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3853  scale = -scale;
3854 
3855  SCIPdebugMsg(scip, "binary reformulation using scale %g, nxvars = %d, integral = %u\n", scale, nxvars, integral);
3856  if( scale != 1.0 )
3857  {
3858  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndszero, xbndszero, scale);
3859  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndsone, xbndsone, scale);
3860  for( k = 0; k < nxvars; ++k )
3861  xcoef[k] /= scale;
3862  }
3863 
3864  /* add auxiliary variable z */
3865  if( nxvars == 1 )
3866  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3867  else
3868  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_more_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3869  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, MIN(0., SCIPintervalGetInf(xbndsone)), MAX(0., SCIPintervalGetSup(xbndsone)),
3871  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3872  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3873 
3874  /* compute value of auxvar in debug solution */
3875 #ifdef SCIP_DEBUG_SOLUTION
3876  if( SCIPdebugIsMainscip(scip) )
3877  {
3878  SCIP_Real debugval;
3879  SCIP_Real varval;
3880 
3881  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &varval) );
3882  if( SCIPisZero(scip, varval) )
3883  {
3884  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, 0.0) );
3885  }
3886  else
3887  {
3888  assert(SCIPisEQ(scip, varval, 1.0));
3889 
3890  debugval = 0.0;
3891  for( k = 0; k < nxvars; ++k )
3892  {
3893  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[k], &varval) );
3894  debugval += xcoef[k] * varval;
3895  }
3896  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
3897  }
3898  }
3899 #endif
3900 
3901  /* add auxiliary constraints
3902  * it seems to be advantageous to make the varbound constraints initial and the linear constraints not initial
3903  * maybe because it is more likely that a binary variable takes value 0 instead of 1, and thus the varbound constraints
3904  * are more often active, compared to the linear constraints added below
3905  * also, the varbound constraints are more sparse than the linear cons
3906  */
3907  if( SCIPisNegative(scip, SCIPintervalGetInf(xbndsone)) )
3908  {
3909  /* add 0 <= z - xbndsone.inf * y constraint (as varbound constraint), need to be enforced as not redundant */
3910  if( nxvars == 1 )
3911  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3912  else
3913  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3914  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetInf(xbndsone), 0.0, SCIPinfinity(scip),
3915  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3916  SCIPconsIsSeparated(cons), TRUE, TRUE,
3919  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3920  SCIPdebugMsg(scip, "added varbound constraint: ");
3921  SCIPdebugPrintCons(scip, auxcons, NULL);
3922  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3923  ++*naddconss;
3924  }
3925  if( SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3926  {
3927  /* add z - xbndsone.sup * y <= 0 constraint (as varbound constraint), need to be enforced as not redundant */
3928  if( nxvars == 1 )
3929  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3930  else
3931  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3932  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetSup(xbndsone), -SCIPinfinity(scip), 0.0,
3933  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
3934  SCIPconsIsSeparated(cons), TRUE, TRUE,
3937  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3938  SCIPdebugMsg(scip, "added varbound constraint: ");
3939  SCIPdebugPrintCons(scip, auxcons, NULL);
3940  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3941  ++*naddconss;
3942  }
3943 
3944  /* add xbndszero.inf <= sum_i a_i*x_i + xbndszero.inf * y - z constraint, need to be enforced as not redundant */
3945  xvars[nxvars] = y;
3946  xvars[nxvars+1] = auxvar;
3947  xcoef[nxvars] = SCIPintervalGetInf(xbndszero);
3948  xcoef[nxvars+1] = -1;
3949 
3950  if( nxvars == 1 )
3951  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3952  else
3953  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3954  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, SCIPintervalGetInf(xbndszero), SCIPinfinity(scip),
3955  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3956  SCIPconsIsSeparated(cons), TRUE, TRUE,
3959  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3960  SCIPdebugMsg(scip, "added linear constraint: ");
3961  SCIPdebugPrintCons(scip, auxcons, NULL);
3962  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3963  ++*naddconss;
3964 
3965  /* add sum_i a_i*x_i + xbndszero.sup * y - z <= xbndszero.sup constraint, need to be enforced as not redundant */
3966  xcoef[nxvars] = SCIPintervalGetSup(xbndszero);
3967 
3968  if( nxvars == 1 )
3969  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3970  else
3971  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3972  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, -SCIPinfinity(scip), SCIPintervalGetSup(xbndszero),
3973  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3974  SCIPconsIsSeparated(cons), TRUE, TRUE,
3977  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3978  SCIPdebugMsg(scip, "added linear constraint: ");
3979  SCIPdebugPrintCons(scip, auxcons, NULL);
3980  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3981  ++*naddconss;
3982 
3983  /* add linear term scale*auxvar to this constraint */
3984  SCIP_CALL( addLinearCoef(scip, cons, auxvar, scale) );
3985 
3986  /* forget about auxvar */
3987  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3988  }
3989  }
3990  while( j < nbilinterms );
3991 
3992  /* remove bilinear terms that have been replaced */
3993  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3994  }
3995  SCIPdebugMsg(scip, "resulting quadratic constraint: ");
3996  SCIPdebugPrintCons(scip, cons, NULL);
3997 
3998  SCIPfreeBufferArrayNull(scip, &xvars);
3999  SCIPfreeBufferArrayNull(scip, &xcoef);
4000  SCIPfreeBufferArrayNull(scip, &todelete);
4001 
4002  return SCIP_OKAY;
4003 }
4004 
4005 /** tries to automatically convert a quadratic constraint (or a part of it) into a more specific and more specialized constraint */
4006 static
4008  SCIP* scip, /**< SCIP data structure */
4009  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4010  SCIP_CONS* cons, /**< source constraint to try to convert */
4011  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
4012  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
4013  int* naddconss, /**< buffer to increase with number of additional constraints created during upgrade */
4014  SCIP_PRESOLTIMING presoltiming /**< current presolving timing */
4015  )
4016 {
4017  SCIP_CONSHDLRDATA* conshdlrdata;
4018  SCIP_CONSDATA* consdata;
4019  SCIP_VAR* var;
4020  SCIP_Real lincoef;
4021  SCIP_Real quadcoef;
4022  SCIP_Real lb;
4023  SCIP_Real ub;
4024  int nbinlin;
4025  int nbinquad;
4026  int nintlin;
4027  int nintquad;
4028  int nimpllin;
4029  int nimplquad;
4030  int ncontlin;
4031  int ncontquad;
4032  SCIP_Bool integral;
4033  int i;
4034  int j;
4035  SCIP_CONS** upgdconss;
4036  int upgdconsssize;
4037  int nupgdconss_;
4038 
4039  assert(scip != NULL);
4040  assert(conshdlr != NULL);
4041  assert(cons != NULL);
4042  assert(!SCIPconsIsModifiable(cons));
4043  assert(upgraded != NULL);
4044  assert(nupgdconss != NULL);
4045  assert(naddconss != NULL);
4046 
4047  *upgraded = FALSE;
4048 
4049  nupgdconss_ = 0;
4050 
4051  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4052  assert(conshdlrdata != NULL);
4053 
4054  /* if there are no upgrade methods, we can also stop */
4055  if( conshdlrdata->nquadconsupgrades == 0 )
4056  return SCIP_OKAY;
4057 
4058  upgdconsssize = 2;
4059  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
4060 
4061  consdata = SCIPconsGetData(cons);
4062  assert(consdata != NULL);
4063 
4064  /* calculate some statistics on quadratic constraint */
4065  nbinlin = 0;
4066  nbinquad = 0;
4067  nintlin = 0;
4068  nintquad = 0;
4069  nimpllin = 0;
4070  nimplquad = 0;
4071  ncontlin = 0;
4072  ncontquad = 0;
4073  integral = TRUE;
4074  for( i = 0; i < consdata->nlinvars; ++i )
4075  {
4076  var = consdata->linvars[i];
4077  lincoef = consdata->lincoefs[i];
4078  lb = SCIPvarGetLbLocal(var);
4079  ub = SCIPvarGetUbLocal(var);
4080  assert(!SCIPisZero(scip, lincoef));
4081 
4082  switch( SCIPvarGetType(var) )
4083  {
4084  case SCIP_VARTYPE_BINARY:
4085  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4086  integral = integral && SCIPisIntegral(scip, lincoef);
4087  nbinlin++;
4088  break;
4089  case SCIP_VARTYPE_INTEGER:
4090  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4091  integral = integral && SCIPisIntegral(scip, lincoef);
4092  nintlin++;
4093  break;
4094  case SCIP_VARTYPE_IMPLINT:
4095  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4096  integral = integral && SCIPisIntegral(scip, lincoef);
4097  nimpllin++;
4098  break;
4100  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb);
4101  ncontlin++;
4102  break;
4103  default:
4104  SCIPerrorMessage("unknown variable type\n");
4105  return SCIP_INVALIDDATA;
4106  }
4107  }
4108 
4109  for( i = 0; i < consdata->nquadvars; ++i )
4110  {
4111  var = consdata->quadvarterms[i].var;
4112  lincoef = consdata->quadvarterms[i].lincoef;
4113  quadcoef = consdata->quadvarterms[i].sqrcoef;
4114  lb = SCIPvarGetLbLocal(var);
4115  ub = SCIPvarGetUbLocal(var);
4116 
4117  switch( SCIPvarGetType(var) )
4118  {
4119  case SCIP_VARTYPE_BINARY:
4120  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4121  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4122  nbinquad++;
4123  break;
4124  case SCIP_VARTYPE_INTEGER:
4125  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4126  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4127  nintquad++;
4128  break;
4129  case SCIP_VARTYPE_IMPLINT:
4130  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4131  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4132  nimplquad++;
4133  break;
4135  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb + quadcoef * lb * lb);
4136  ncontquad++;
4137  break;
4138  default:
4139  SCIPerrorMessage("unknown variable type\n");
4140  return SCIP_INVALIDDATA;
4141  }
4142  }
4143 
4144  if( integral )
4145  {
4146  for( i = 0; i < consdata->nbilinterms && integral; ++i )
4147  {
4148  if( SCIPvarGetType(consdata->bilinterms[i].var1) < SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->bilinterms[i].var2) < SCIP_VARTYPE_CONTINUOUS )
4149  integral = integral && SCIPisIntegral(scip, consdata->bilinterms[i].coef);
4150  else
4151  integral = FALSE;
4152  }
4153  }
4154 
4155  /* call the upgrading methods */
4156 
4157  SCIPdebugMsg(scip, "upgrading quadratic constraint <%s> (%d upgrade methods):\n",
4158  SCIPconsGetName(cons), conshdlrdata->nquadconsupgrades);
4159  SCIPdebugMsg(scip, " binlin=%d binquad=%d intlin=%d intquad=%d impllin=%d implquad=%d contlin=%d contquad=%d integral=%u\n",
4160  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral);
4161  SCIPdebugPrintCons(scip, cons, NULL);
4162 
4163  /* try all upgrading methods in priority order in case the upgrading step is enable */
4164  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
4165  {
4166  if( !conshdlrdata->quadconsupgrades[i]->active )
4167  continue;
4168 
4169  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4170  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4171  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4172 
4173  while( nupgdconss_ < 0 )
4174  {
4175  /* upgrade function requires more memory: resize upgdconss and call again */
4176  assert(-nupgdconss_ > upgdconsssize);
4177  upgdconsssize = -nupgdconss_;
4178  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
4179 
4180  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4181  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4182  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4183 
4184  assert(nupgdconss_ != 0);
4185  }
4186 
4187  if( nupgdconss_ > 0 )
4188  {
4189  /* got upgrade */
4190  SCIPdebugPrintCons(scip, cons, NULL);
4191  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
4192 
4193  /* add the upgraded constraints to the problem and forget them */
4194  for( j = 0; j < nupgdconss_; ++j )
4195  {
4196  SCIPdebugMsgPrint(scip, "\t");
4197  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
4198 
4199  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
4200  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
4201  }
4202 
4203  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
4204  *nupgdconss += 1;
4205  *naddconss += nupgdconss_ - 1;
4206  *upgraded = TRUE;
4207 
4208  /* delete upgraded constraint */
4209  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
4210  SCIP_CALL( SCIPdelCons(scip, cons) );
4211 
4212  break;
4213  }
4214  }
4215 
4216  SCIPfreeBufferArray(scip, &upgdconss);
4217 
4218  return SCIP_OKAY;
4219 }
4220 
4221 /** helper function for presolveDisaggregate */
4222 static
4224  SCIP* scip, /**< SCIP data structure */
4225  SCIP_CONSDATA* consdata, /**< constraint data */
4226  int quadvaridx, /**< index of quadratic variable to mark */
4227  SCIP_HASHMAP* var2component, /**< variables to components mapping */
4228  int componentnr /**< the component number to mark to */
4229  )
4230 {
4231  SCIP_QUADVARTERM* quadvarterm;
4232  SCIP_VAR* othervar;
4233  int othervaridx;
4234  int i;
4235 
4236  assert(consdata != NULL);
4237  assert(quadvaridx >= 0);
4238  assert(quadvaridx < consdata->nquadvars);
4239  assert(var2component != NULL);
4240  assert(componentnr >= 0);
4241 
4242  quadvarterm = &consdata->quadvarterms[quadvaridx];
4243 
4244  if( SCIPhashmapExists(var2component, quadvarterm->var) )
4245  {
4246  /* if we saw the variable before, then it should have the same component number */
4247  assert((int)(size_t)SCIPhashmapGetImage(var2component, quadvarterm->var) == componentnr);
4248  return SCIP_OKAY;
4249  }
4250 
4251  /* assign component number to variable */
4252  SCIP_CALL( SCIPhashmapInsert(var2component, quadvarterm->var, (void*)(size_t)componentnr) );
4253 
4254  /* assign same component number to all variables this variable is multiplied with */
4255  for( i = 0; i < quadvarterm->nadjbilin; ++i )
4256  {
4257  othervar = consdata->bilinterms[quadvarterm->adjbilin[i]].var1 == quadvarterm->var ?
4258  consdata->bilinterms[quadvarterm->adjbilin[i]].var2 : consdata->bilinterms[quadvarterm->adjbilin[i]].var1;
4259  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, othervar, &othervaridx) );
4260  assert(othervaridx >= 0);
4261  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, othervaridx, var2component, componentnr) );
4262  }
4263 
4264  return SCIP_OKAY;
4265 }
4266 
4267 /** for quadratic constraints that consists of a sum of quadratic terms, disaggregates the sum into a set of constraints by introducing auxiliary variables */
4268 static
4270  SCIP* scip, /**< SCIP data structure */
4271  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4272  SCIP_CONS* cons, /**< source constraint to try to convert */
4273  int* naddconss /**< pointer to counter of added constraints */
4274  )
4275 {
4276  SCIP_CONSDATA* consdata;
4277  SCIP_HASHMAP* var2component;
4278  int ncomponents;
4279  int i;
4280  int comp;
4281  SCIP_CONS** auxconss;
4282  SCIP_VAR** auxvars;
4283  SCIP_Real* auxcoefs;
4284  char name[SCIP_MAXSTRLEN];
4285 
4286  assert(scip != NULL);
4287  assert(conshdlr != NULL);
4288  assert(cons != NULL);
4289  assert(naddconss != NULL);
4290 
4291  consdata = SCIPconsGetData(cons);
4292  assert(consdata != NULL);
4293 
4294  /* make sure there are no quadratic variables without coefficients */
4295  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4296  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
4297 
4298  if( consdata->nquadvars <= 1 )
4299  return SCIP_OKAY;
4300 
4301  /* sort quadratic variable terms here, so we can later search in it without reordering the array */
4302  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4303 
4304  /* check how many quadratic terms with non-overlapping variables we have
4305  * in other words, the number of components in the sparsity graph of the quadratic term matrix */
4306  ncomponents = 0;
4307  SCIP_CALL( SCIPhashmapCreate(&var2component, SCIPblkmem(scip), consdata->nquadvars) );
4308  for( i = 0; i < consdata->nquadvars; ++i )
4309  {
4310  /* if variable was marked already, skip it */
4311  if( SCIPhashmapExists(var2component, (void*)consdata->quadvarterms[i].var) )
4312  continue;
4313 
4314  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, i, var2component, ncomponents) );
4315  ++ncomponents;
4316  }
4317  assert(ncomponents >= 1);
4318 
4319  /* if there is only one component, we cannot disaggregate
4320  * @todo we could still split the constraint into several while keeping the number of variables sharing several constraints as small as possible
4321  */
4322  if( ncomponents == 1 )
4323  {
4324  SCIPhashmapFree(&var2component);
4325  return SCIP_OKAY;
4326  }
4327 
4328  SCIP_CALL( SCIPallocBufferArray(scip, &auxconss, ncomponents) );
4329  SCIP_CALL( SCIPallocBufferArray(scip, &auxvars, ncomponents) );
4330  SCIP_CALL( SCIPallocBufferArray(scip, &auxcoefs, ncomponents) );
4331 
4332  /* create auxiliary variables and empty constraints for each component */
4333  for( comp = 0; comp < ncomponents; ++comp )
4334  {
4335  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp%d", SCIPconsGetName(cons), comp);
4336 
4337  SCIP_CALL( SCIPcreateVar(scip, &auxvars[comp], name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
4339 
4340  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &auxconss[comp], name, 0, NULL, NULL, 0, NULL, 0, NULL,
4341  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : 0.0),
4342  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : 0.0),
4345  SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons)) );
4346 
4347  auxcoefs[comp] = SCIPinfinity(scip);
4348  }
4349 
4350  /* add quadratic variables to each component constraint
4351  * delete adjacency information */
4352  for( i = 0; i < consdata->nquadvars; ++i )
4353  {
4354  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->quadvarterms[i].var);
4355  assert(comp >= 0);
4356  assert(comp < ncomponents);
4357 
4358  /* add variable term to corresponding constraint */
4359  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, auxconss[comp], consdata->quadvarterms[i].var, consdata->quadvarterms[i].lincoef, consdata->quadvarterms[i].sqrcoef) );
4360 
4361  /* reduce coefficient of aux variable */
4362  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) && ABS(consdata->quadvarterms[i].lincoef) < auxcoefs[comp] )
4363  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].lincoef);
4364  if( !SCIPisZero(scip, consdata->quadvarterms[i].sqrcoef) && ABS(consdata->quadvarterms[i].sqrcoef) < auxcoefs[comp] )
4365  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].sqrcoef);
4366 
4367  SCIPfreeBlockMemoryArray(scip, &consdata->quadvarterms[i].adjbilin, consdata->quadvarterms[i].adjbilinsize);
4368  consdata->quadvarterms[i].nadjbilin = 0;
4369  consdata->quadvarterms[i].adjbilinsize = 0;
4370  }
4371 
4372  /* add bilinear terms to each component constraint */
4373  for( i = 0; i < consdata->nbilinterms; ++i )
4374  {
4375  comp = (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var1);
4376  assert(comp == (int)(size_t) SCIPhashmapGetImage(var2component, consdata->bilinterms[i].var2));
4377  assert(!SCIPisZero(scip, consdata->bilinterms[i].coef));
4378 
4379  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, auxconss[comp],
4380  consdata->bilinterms[i].var1, consdata->bilinterms[i].var2, consdata->bilinterms[i].coef) );
4381 
4382  if( ABS(consdata->bilinterms[i].coef) < auxcoefs[comp] )
4383  auxcoefs[comp] = ABS(consdata->bilinterms[i].coef);
4384  }
4385 
4386  /* forget about bilinear terms in cons */
4387  SCIPfreeBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize);
4388  consdata->nbilinterms = 0;
4389  consdata->bilintermssize = 0;
4390 
4391  /* remove quadratic variable terms from cons */
4392  for( i = consdata->nquadvars - 1; i >= 0; --i )
4393  {
4394  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
4395  }
4396  assert(consdata->nquadvars == 0);
4397 
4398  /* add auxiliary variables to auxiliary constraints
4399  * add aux vars and constraints to SCIP
4400  * add aux vars to this constraint
4401  * @todo compute debug solution values and set for auxvars
4402  */
4403  SCIPdebugMsg(scip, "add %d constraints for disaggregation of quadratic constraint <%s>\n", ncomponents, SCIPconsGetName(cons));
4404  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + ncomponents) );
4405  for( comp = 0; comp < ncomponents; ++comp )
4406  {
4407  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, auxconss[comp], auxvars[comp], -auxcoefs[comp]) );
4408 
4409  SCIP_CALL( SCIPaddVar(scip, auxvars[comp]) );
4410 
4411  SCIP_CALL( SCIPaddCons(scip, auxconss[comp]) );
4412  SCIPdebugPrintCons(scip, auxconss[comp], NULL);
4413 
4414  SCIP_CALL( addLinearCoef(scip, cons, auxvars[comp], auxcoefs[comp]) );
4415 
4416  SCIP_CALL( SCIPreleaseCons(scip, &auxconss[comp]) );
4417  SCIP_CALL( SCIPreleaseVar(scip, &auxvars[comp]) );
4418  }
4419  *naddconss += ncomponents;
4420 
4421  SCIPdebugPrintCons(scip, cons, NULL);
4422 
4423  SCIPfreeBufferArray(scip, &auxconss);
4424  SCIPfreeBufferArray(scip, &auxvars);
4425  SCIPfreeBufferArray(scip, &auxcoefs);
4426  SCIPhashmapFree(&var2component);
4427 
4428  return SCIP_OKAY;
4429 }
4430 
4431 #ifdef CHECKIMPLINBILINEAR
4432 /** checks if there are bilinear terms x*y with a binary variable x and an implication x = {0,1} -> y = 0
4433  *
4434  * In this case, the bilinear term can be removed (x=0 case) or replaced by y (x=1 case).
4435  */
4436 static
4437 SCIP_RETCODE presolveApplyImplications(
4438  SCIP* scip, /**< SCIP data structure */
4439  SCIP_CONS* cons, /**< quadratic constraint */
4440  int* nbilinremoved /**< buffer to store number of removed bilinear terms */
4441  )
4442 {
4443  SCIP_CONSDATA* consdata;
4444  SCIP_VAR* x;
4445  SCIP_VAR* y;
4446  SCIP_INTERVAL implbnds;
4447  int i;
4448  int j;
4449  int k;
4450 
4451  assert(scip != NULL);
4452  assert(cons != NULL);
4453  assert(nbilinremoved != NULL);
4454 
4455  *nbilinremoved = 0;
4456 
4457  consdata = SCIPconsGetData(cons);
4458  assert(consdata != NULL);
4459 
4460  SCIPdebugMsg(scip, "apply implications in <%s>\n", SCIPconsGetName(cons));
4461 
4462  /* sort quadvarterms in case we need to search */
4463  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4464 
4465  for( i = 0; i < consdata->nquadvars; ++i )
4466  {
4467  x = consdata->quadvarterms[i].var;
4468  assert(x != NULL);
4469 
4470  if( consdata->quadvarterms[i].nadjbilin == 0 )
4471  continue;
4472 
4473  if( !SCIPvarIsBinary(x) )
4474  continue;
4475 
4476  if( !SCIPvarIsActive(x) )
4477  continue;
4478 
4479  if( SCIPvarGetNImpls(x, TRUE) == 0 && SCIPvarGetNImpls(x, FALSE) == 0 )
4480  continue;
4481 
4482  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4483  {
4484  k = consdata->quadvarterms[i].adjbilin[j];
4485  assert(k >= 0);
4486  assert(k < consdata->nbilinterms);
4487 
4488  if( consdata->bilinterms[k].coef == 0.0 )
4489  continue;
4490 
4491  y = consdata->bilinterms[k].var1 == x ? consdata->bilinterms[k].var2 : consdata->bilinterms[k].var1;
4492  assert(x != y);
4493 
4494  SCIP_CALL( getImpliedBounds(scip, x, TRUE, y, &implbnds) );
4495  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4496  {
4497  /* if x = 1 implies y = 0, then we can remove the bilinear term x*y, since it is always 0
4498  * we only set the coefficient to 0.0 here and mark the bilinterms as not merged */
4499  SCIPdebugMsg(scip, "remove bilinear term %g<%s><%s> from <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), SCIPconsGetName(cons));
4500  consdata->bilinterms[k].coef = 0.0;
4501  consdata->bilinmerged = FALSE;
4502  ++*nbilinremoved;
4503  continue;
4504  }
4505 
4506  SCIP_CALL( getImpliedBounds(scip, x, FALSE, y, &implbnds) );
4507  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4508  {
4509  /* if x = 0 implies y = 0, then we can replace the bilinear term x*y by y
4510  * we only move the coefficient to the linear coef of y here and mark the bilinterms as not merged */
4511  SCIPdebugMsg(scip, "replace bilinear term %g<%s><%s> by %g<%s> in <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), consdata->bilinterms[k].coef, SCIPvarGetName(y), SCIPconsGetName(cons));
4512  assert(consdata->quadvarssorted);
4513  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, cons, y, consdata->bilinterms[k].coef) );
4514  consdata->bilinterms[k].coef = 0.0;
4515  consdata->bilinmerged = FALSE;
4516  ++*nbilinremoved;
4517  }
4518  }
4519  }
4520 
4521  if( *nbilinremoved > 0 )
4522  {
4523  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4524 
4525  /* invalidate nonlinear row */
4526  if( consdata->nlrow != NULL )
4527  {
4528  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4529  }
4530 
4531  consdata->ispropagated = FALSE;
4532  consdata->ispresolved = FALSE;
4533  consdata->iscurvchecked = FALSE;
4534  }
4535 
4536  consdata->isimpladded = FALSE;
4537 
4538  return SCIP_OKAY;
4539 }
4540 #endif
4541 
4542 /** checks a quadratic constraint for convexity and/or concavity without checking multivariate functions */
4543 static
4544 void checkCurvatureEasy(
4545  SCIP* scip, /**< SCIP data structure */
4546  SCIP_CONS* cons, /**< quadratic constraint */
4547  SCIP_Bool* determined, /**< pointer to store whether the curvature could be determined */
4548  SCIP_Bool checkmultivariate /**< whether curvature will be checked later on for multivariate functions */
4549  )
4550 {
4551  SCIP_CONSDATA* consdata;
4552  int nquadvars;
4553 
4554  assert(scip != NULL);
4555  assert(cons != NULL);
4556  assert(determined != NULL);
4557 
4558  consdata = SCIPconsGetData(cons);
4559  assert(consdata != NULL);
4560 
4561  nquadvars = consdata->nquadvars;
4562  *determined = TRUE;
4563 
4564  if( consdata->iscurvchecked )
4565  return;
4566 
4567  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> without multivariate functions\n", SCIPconsGetName(cons));
4568 
4569  if( nquadvars == 1 )
4570  {
4571  assert(consdata->nbilinterms == 0);
4572  consdata->isconvex = !SCIPisNegative(scip, consdata->quadvarterms[0].sqrcoef);
4573  consdata->isconcave = !SCIPisPositive(scip, consdata->quadvarterms[0].sqrcoef);
4574  consdata->iscurvchecked = TRUE;
4575  }
4576  else if( nquadvars == 0 )
4577  {
4578  consdata->isconvex = TRUE;
4579  consdata->isconcave = TRUE;
4580  consdata->iscurvchecked = TRUE;
4581  }
4582  else if( consdata->nbilinterms == 0 )
4583  {
4584  int v;
4585 
4586  consdata->isconvex = TRUE;
4587  consdata->isconcave = TRUE;
4588 
4589  for( v = nquadvars - 1; v >= 0; --v )
4590  {
4591  consdata->isconvex = consdata->isconvex && !SCIPisNegative(scip, consdata->quadvarterms[v].sqrcoef);
4592  consdata->isconcave = consdata->isconcave && !SCIPisPositive(scip, consdata->quadvarterms[v].sqrcoef);
4593  }
4594 
4595  consdata->iscurvchecked = TRUE;
4596  }
4597  else if( !checkmultivariate )
4598  {
4599  consdata->isconvex = FALSE;
4600  consdata->isconcave = FALSE;
4601  consdata->iscurvchecked = TRUE;
4602  }
4603  else
4604  *determined = FALSE;
4605 }
4606 
4607 /** checks a quadratic constraint for convexity and/or concavity */
4608 static
4610  SCIP* scip, /**< SCIP data structure */
4611  SCIP_CONS* cons, /**< quadratic constraint */
4612  SCIP_Bool checkmultivariate /**< whether curvature should also be checked for multivariate functions */
4613  )
4614 {
4615  SCIP_CONSDATA* consdata;
4616  double* matrix;
4617  SCIP_HASHMAP* var2index;
4618  int i;
4619  int n;
4620  int nn;
4621  int row;
4622  int col;
4623  double* alleigval;
4624  SCIP_Bool determined;
4625 
4626  assert(scip != NULL);
4627  assert(cons != NULL);
4628 
4629  consdata = SCIPconsGetData(cons);
4630  assert(consdata != NULL);
4631 
4632  n = consdata->nquadvars;
4633 
4634  if( consdata->iscurvchecked )
4635  return SCIP_OKAY;
4636 
4637  /* easy checks for curvature detection */
4638  checkCurvatureEasy(scip, cons, &determined, checkmultivariate);
4639 
4640  /* if curvature was already detected stop */
4641  if( determined )
4642  {
4643  return SCIP_OKAY;
4644  }
4645 
4646  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> with multivariate functions\n", SCIPconsGetName(cons));
4647 
4648  if( n == 2 )
4649  {
4650  /* compute eigenvalues by hand */
4651  assert(consdata->nbilinterms == 1);
4652  consdata->isconvex =
4653  consdata->quadvarterms[0].sqrcoef >= 0 &&
4654  consdata->quadvarterms[1].sqrcoef >= 0 &&
4655  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4656  consdata->isconcave =
4657  consdata->quadvarterms[0].sqrcoef <= 0 &&
4658  consdata->quadvarterms[1].sqrcoef <= 0 &&
4659  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
4660 
4661  consdata->iscurvchecked = TRUE;
4662  return SCIP_OKAY;
4663  }
4664 
4665  /* do not check curvature if n is too large */
4666  nn = n * n;
4667  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
4668  {
4669  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "cons_quadratic - n is too large to check the curvature\n");
4670  consdata->isconvex = FALSE;
4671  consdata->isconcave = FALSE;
4672  consdata->iscurvchecked = TRUE;
4673  return SCIP_OKAY;
4674  }
4675 
4676  /* lower triangular of quadratic term matrix */
4677  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, nn) );
4678  BMSclearMemoryArray(matrix, nn);
4679 
4680  consdata->isconvex = TRUE;
4681  consdata->isconcave = TRUE;
4682 
4683  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
4684  for( i = 0; i < n; ++i )
4685  {
4686  if( consdata->quadvarterms[i].nadjbilin > 0 )
4687  {
4688  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
4689  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4690  }
4691  /* nonzero elements on diagonal tell a lot about convexity/concavity */
4692  if( SCIPisNegative(scip, consdata->quadvarterms[i].sqrcoef) )
4693  consdata->isconvex = FALSE;
4694  if( SCIPisPositive(scip, consdata->quadvarterms[i].sqrcoef) )
4695  consdata->isconcave = FALSE;
4696  }
4697 
4698  if( !consdata->isconvex && !consdata->isconcave )
4699  {
4700  SCIPfreeBufferArray(scip, &matrix);
4701  SCIPhashmapFree(&var2index);
4702  consdata->iscurvchecked = TRUE;
4703  return SCIP_OKAY;
4704  }
4705 
4707  {
4708  for( i = 0; i < consdata->nbilinterms; ++i )
4709  {
4710  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
4711  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
4712  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
4713  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
4714  if( row < col )
4715  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
4716  else
4717  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
4718  }
4719 
4720  SCIP_CALL( SCIPallocBufferArray(scip, &alleigval, n) );
4721  /* @todo Can we compute only min and max eigen value?
4722  * @todo Can we estimate the numerical error?
4723  * @todo Trying a cholesky factorization may be much faster.
4724  */
4725  if( LapackDsyev(FALSE, n, matrix, alleigval) != SCIP_OKAY )
4726  {
4727  SCIPwarningMessage(scip, "Failed to compute eigenvalues of quadratic coefficient matrix of constraint %s. Assuming matrix is indefinite.\n", SCIPconsGetName(cons));
4728  consdata->isconvex = FALSE;
4729  consdata->isconcave = FALSE;
4730  }
4731  else
4732  {
4733  /* deconvexification reformulates a stricly convex quadratic function in binaries such that it becomes not-strictly convex
4734  * by adding the -lambda*(x^2-x) terms for lambda the smallest eigenvalue of the matrix
4735  * 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
4736  */
4737 #ifdef DECONVEXIFY
4738  SCIP_Bool allbinary;
4739  printf("cons <%s>[%g,%g] spectrum = [%g,%g]\n", SCIPconsGetName(cons), consdata->lhs, consdata->rhs, alleigval[0], alleigval[n-1]);
4740 #endif
4741  consdata->isconvex &= !SCIPisNegative(scip, alleigval[0]); /*lint !e514*/
4742  consdata->isconcave &= !SCIPisPositive(scip, alleigval[n-1]); /*lint !e514*/
4743  consdata->iscurvchecked = TRUE;
4744 #ifdef DECONVEXIFY
4745  for( i = 0; i < consdata->nquadvars; ++i )
4746  if( !SCIPvarIsBinary(consdata->quadvarterms[i].var) )
4747  break;
4748  allbinary = i == consdata->nquadvars;
4749 
4750  if( !SCIPisInfinity(scip, consdata->rhs) && alleigval[0] > 0.1 && allbinary )
4751  {
4752  printf("deconvexify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[0]);
4753  for( i = 0; i < consdata->nquadvars; ++i )
4754  {
4755  consdata->quadvarterms[i].sqrcoef -= alleigval[0];
4756  consdata->quadvarterms[i].lincoef += alleigval[0];
4757  }
4758  }
4759 
4760  if( !SCIPisInfinity(scip, consdata->lhs) && alleigval[n-1] < -0.1 && allbinary )
4761  {
4762  printf("deconcavify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[n-1]);
4763  for( i = 0; i < consdata->nquadvars; ++i )
4764  {
4765  consdata->quadvarterms[i].sqrcoef -= alleigval[n-1];
4766  consdata->quadvarterms[i].lincoef += alleigval[n-1];
4767  }
4768  }
4769 #endif
4770  }
4771 
4772  SCIPfreeBufferArray(scip, &alleigval);
4773  }
4774  else
4775  {
4776  consdata->isconvex = FALSE;
4777  consdata->isconcave = FALSE;
4778  consdata->iscurvchecked = TRUE; /* set to TRUE since it does not help to repeat this procedure again and again (that will not bring Ipopt in) */
4779  }
4780 
4781  SCIPhashmapFree(&var2index);
4782  SCIPfreeBufferArray(scip, &matrix);
4783 
4784  return SCIP_OKAY;
4785 }
4786 
4787 /** check whether indefinite constraint function is factorable and store corresponding coefficients */
4788 static
4790  SCIP* scip, /**< SCIP data structure */
4791  SCIP_CONS* cons /**< constraint */
4792  )
4793 {
4794  SCIP_BILINTERM* bilinterm;
4795  SCIP_CONSDATA* consdata;
4796  SCIP_Real* a;
4797  SCIP_Real* eigvals;
4798  SCIP_Real sigma1;
4799  SCIP_Real sigma2;
4800  SCIP_Bool success;
4801  int n;
4802  int i;
4803  int idx1;
4804  int idx2;
4805  int posidx;
4806  int negidx;
4807 
4808  assert(scip != NULL);
4809  assert(cons != NULL);
4810 
4811  consdata = SCIPconsGetData(cons);
4812  assert(consdata != NULL);
4813  assert(consdata->factorleft == NULL);
4814  assert(consdata->factorright == NULL);
4815 
4816  /* we don't need this if there are no bilinear terms */
4817  if( consdata->nbilinterms == 0 )
4818  return SCIP_OKAY;
4819 
4820  /* write constraint as lhs <= linear + x'^T A x' <= rhs where x' = (x,1) and
4821  * A = ( Q b/2 )
4822  * ( b^T/2 0 )
4823  * compute an eigenvalue factorization of A and check if there are one positive and one negative eigenvalue
4824  * 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
4825  * thus, x'^T A x' = sigma1^2 (v1^T x')^2 - sigma2^2 (v2^T x')^2
4826  * = (sigma1 (v1^T x') - sigma2 (v2^T x')) * (sigma1 (v1^T x') + sigma2 (v2^T x'))
4827  * we then store sigma1 v1^T - sigma2 v2^T as left factor coef, and sigma1 v1^T + sigma2 v2^T as right factor coef
4828  */
4829 
4830  /* if we already know that there are only positive or only negative eigenvalues, then don't try */
4831  if( consdata->iscurvchecked && (consdata->isconvex || consdata->isconcave) )
4832  return SCIP_OKAY;
4833 
4834  n = consdata->nquadvars + 1;
4835 
4836  /* @todo handle case n=3 explicitly */
4837 
4838  /* skip too large matrices */
4839  if( n > 50 )
4840  return SCIP_OKAY;
4841 
4842  /* need routine to compute eigenvalues/eigenvectors */
4843  if( !SCIPisIpoptAvailableIpopt() )
4844  return SCIP_OKAY;
4845 
4846  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4847 
4848  SCIP_CALL( SCIPallocBufferArray(scip, &a, n*n) );
4849  BMSclearMemoryArray(a, n*n);
4850 
4851  /* set lower triangular entries of A corresponding to bilinear terms */
4852  for( i = 0; i < consdata->nbilinterms; ++i )
4853  {
4854  bilinterm = &consdata->bilinterms[i];
4855 
4856  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4857  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4858  assert(idx1 >= 0);
4859  assert(idx2 >= 0);
4860  assert(idx1 != idx2);
4861 
4862  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
4863  }
4864 
4865  /* set lower triangular entries of A corresponding to square and linear terms */
4866  for( i = 0; i < consdata->nquadvars; ++i )
4867  {
4868  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
4869  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
4870  }
4871 
4872  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, n) );
4873  if( LapackDsyev(TRUE, n, a, eigvals) != SCIP_OKAY )
4874  {
4875  SCIPdebugMsg(scip, "Failed to compute eigenvalues and eigenvectors of augmented quadratic form matrix for constraint <%s>.\n", SCIPconsGetName(cons));
4876  goto CLEANUP;
4877  }
4878 
4879  /* check if there is exactly one positive and one negative eigenvalue */
4880  posidx = -1;
4881  negidx = -1;
4882  for( i = 0; i < n; ++i )
4883  {
4884  if( SCIPisPositive(scip, eigvals[i]) )
4885  {
4886  if( posidx == -1 )
4887  posidx = i;
4888  else
4889  break;
4890  }
4891  else if( SCIPisNegative(scip, eigvals[i]) )
4892  {
4893  if( negidx == -1 )
4894  negidx = i;
4895  else
4896  break;
4897  }
4898  }
4899  if( i < n || posidx == -1 || negidx == -1 )
4900  {
4901  SCIPdebugMsg(scip, "Augmented quadratic form of constraint <%s> is not factorable.\n", SCIPconsGetName(cons));
4902  goto CLEANUP;
4903  }
4904  assert(SCIPisPositive(scip, eigvals[posidx]));
4905  assert(SCIPisNegative(scip, eigvals[negidx]));
4906 
4907  /* compute factorleft and factorright */
4908  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1) );
4909  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1) );
4910 
4911  /* eigenvectors are stored in a, inverse eigenvector matrix is transposed of a
4912  * it seems that v1 and v2 are at &a[posidx*n] and &a[negidx*n]
4913  */
4914  sigma1 = sqrt( eigvals[posidx]);
4915  sigma2 = sqrt(-eigvals[negidx]);
4916  for( i = 0; i < n; ++i )
4917  {
4918  consdata->factorleft[i] = sigma1 * a[posidx * n + i] - sigma2 * a[negidx * n + i];
4919  consdata->factorright[i] = sigma1 * a[posidx * n + i] + sigma2 * a[negidx * n + i];
4920  /* set almost-zero elements to zero */
4921  if( SCIPisZero(scip, consdata->factorleft[i]) )
4922  consdata->factorleft[i] = 0.0;
4923  if( SCIPisZero(scip, consdata->factorright[i]) )
4924  consdata->factorright[i] = 0.0;
4925  }
4926 
4927 #ifdef SCIP_DEBUG
4928  SCIPdebugMsg(scip, "constraint <%s> has factorable quadratic form: (%g", SCIPconsGetName(cons), consdata->factorleft[n-1]);
4929  for( i = 0; i < consdata->nquadvars; ++i )
4930  {
4931  if( consdata->factorleft[i] != 0.0 )
4932  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorleft[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4933  }
4934  SCIPdebugMsgPrint(scip, ") * (%g", consdata->factorright[n-1]);
4935  for( i = 0; i < consdata->nquadvars; ++i )
4936  {
4937  if( consdata->factorright[i] != 0.0 )
4938  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorright[i], SCIPvarGetName(consdata->quadvarterms[i].var));
4939  }
4940  SCIPdebugMsgPrint(scip, ")\n");
4941 #endif
4942 
4943  /* check whether factorleft * factorright^T is matrix of augmented quadratic form
4944  * we check here only the nonzero entries from the quadratic form
4945  */
4946  success = TRUE;
4947 
4948  /* check bilinear terms */
4949  for( i = 0; i < consdata->nbilinterms; ++i )
4950  {
4951  bilinterm = &consdata->bilinterms[i];
4952 
4953  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
4954  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
4955 
4956  if( !SCIPisRelEQ(scip, consdata->factorleft[idx1] * consdata->factorright[idx2] + consdata->factorleft[idx2] * consdata->factorright[idx1], bilinterm->coef) )
4957  {
4958  success = FALSE;
4959  break;
4960  }
4961  }
4962 
4963  /* set lower triangular entries of A corresponding to square and linear terms */
4964  for( i = 0; i < consdata->nquadvars; ++i )
4965  {
4966  if( !SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[i], consdata->quadvarterms[i].sqrcoef) )
4967  {
4968  success = FALSE;
4969  break;
4970  }
4971 
4972  if( !SCIPisRelEQ(scip, consdata->factorleft[n-1] * consdata->factorright[i] + consdata->factorleft[i] * consdata->factorright[n-1], consdata->quadvarterms[i].lincoef) )
4973  {
4974  success = FALSE;
4975  break;
4976  }
4977  }
4978 
4979  if( !success )
4980  {
4981  SCIPdebugMsg(scip, "Factorization not accurate enough. Dropping it.\n");
4982  SCIPfreeBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1);
4983  SCIPfreeBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1);
4984  }
4985 
4986  CLEANUP:
4987  SCIPfreeBufferArray(scip, &a);
4988  SCIPfreeBufferArray(scip, &eigvals);
4989 
4990  return SCIP_OKAY;
4991 }
4992 
4993 /** gets maximal absolute value in gradient of quadratic function */
4994 static
4996  SCIP* scip, /**< SCIP data structure */
4997  SCIP_CONS* cons, /**< constraint */
4998  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
4999  )
5000 {
5001  SCIP_CONSDATA* consdata;
5002  SCIP_Real maxelem;
5003  SCIP_Real g;
5004  int i, j, k;
5005  SCIP_VAR* var;
5006 
5007  assert(scip != NULL);
5008  assert(cons != NULL);
5009 
5010  consdata = SCIPconsGetData(cons);
5011  assert(consdata != NULL);
5012 
5013  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
5014  {
5015  maxelem = 0.0;
5016  for( i = 0; i < consdata->nlinvars; ++i )
5017  if( REALABS(consdata->lincoefs[i]) > maxelem )
5018  maxelem = REALABS(consdata->lincoefs[i]);
5019  }
5020  else
5021  maxelem = consdata->lincoefsmax;
5022 
5023  for( i = 0; i < consdata->nquadvars; ++i )
5024  {
5025  var = consdata->quadvarterms[i].var;
5026  assert(!SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)));
5027  assert(!SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)));
5028  g = consdata->quadvarterms[i].lincoef;
5029  g += 2.0 * consdata->quadvarterms[i].sqrcoef * SCIPgetSolVal(scip, sol, var);
5030  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
5031  {
5032  k = consdata->quadvarterms[i].adjbilin[j];
5033  if( consdata->bilinterms[k].var1 == var )
5034  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var2);
5035  else
5036  g += consdata->bilinterms[k].coef * SCIPgetSolVal(scip, sol, consdata->bilinterms[k].var1);
5037  }
5038  if( REALABS(g) > maxelem )
5039  maxelem = REALABS(g);
5040  }
5041 
5042  return maxelem;
5043 }
5044 
5045 /** computes activity and violation of a constraint
5046  *
5047  * If solution violates bounds by more than feastol, the violation is still computed, but *solviolbounds is set to TRUE
5048  */
5049 static
5051  SCIP* scip, /**< SCIP data structure */
5052  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5053  SCIP_CONS* cons, /**< constraint */
5054  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5055  SCIP_Bool* solviolbounds /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol */
5056  )
5057 { /*lint --e{666}*/
5058  SCIP_CONSHDLRDATA* conshdlrdata;
5059  SCIP_CONSDATA* consdata;
5060  SCIP_Real varval;
5061  SCIP_Real varval2;
5062  SCIP_VAR* var;
5063  SCIP_VAR* var2;
5064  int i;
5065  int j;
5066 
5067  assert(scip != NULL);
5068  assert(cons != NULL);
5069  assert(solviolbounds != NULL);
5070 
5071  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5072  assert(conshdlrdata != NULL);
5073 
5074  consdata = SCIPconsGetData(cons);
5075  assert(consdata != NULL);
5076 
5077  *solviolbounds = FALSE;
5078  consdata->activity = 0.0;
5079 
5080  /* @todo Take better care of variables at +/- infinity: e.g., run instance waste in debug mode with a short timelimit (30s). */
5081  for( i = 0; i < consdata->nlinvars; ++i )
5082  {
5083  var = consdata->linvars[i];
5084  varval = SCIPgetSolVal(scip, sol, var);
5085 
5086  if( SCIPisInfinity(scip, REALABS(varval)) )
5087  {
5088  consdata->activity = SCIPinfinity(scip);
5089  if( !SCIPisInfinity(scip, -consdata->lhs) )
5090  consdata->lhsviol = SCIPinfinity(scip);
5091  if( !SCIPisInfinity(scip, consdata->rhs) )
5092  consdata->rhsviol = SCIPinfinity(scip);
5093  return SCIP_OKAY;
5094  }
5095 
5096  consdata->activity += consdata->lincoefs[i] * varval;
5097  }
5098 
5099  for( j = 0; j < consdata->nquadvars; ++j )
5100  {
5101  var = consdata->quadvarterms[j].var;
5102  varval = SCIPgetSolVal(scip, sol, var);
5103  if( SCIPisInfinity(scip, REALABS(varval)) )
5104  {
5105  consdata->activity = SCIPinfinity(scip);
5106  if( !SCIPisInfinity(scip, -consdata->lhs) )
5107  consdata->lhsviol = SCIPinfinity(scip);
5108  if( !SCIPisInfinity(scip, consdata->rhs) )
5109  consdata->rhsviol = SCIPinfinity(scip);
5110  return SCIP_OKAY;
5111  }
5112 
5113  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5114  if( sol == NULL )
5115  {
5116  /* with non-initial columns, variables can shortly be a column variable before entering the LP and have value 0.0 in this case, which might violated the variable bounds */
5117  if( !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)) || !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)) )
5118  *solviolbounds = TRUE;
5119  else
5120  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5121  }
5122 
5123  consdata->activity += (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5124  }
5125 
5126  for( j = 0; j < consdata->nbilinterms; ++j )
5127  {
5128  var = consdata->bilinterms[j].var1;
5129  var2 = consdata->bilinterms[j].var2;
5130  varval = SCIPgetSolVal(scip, sol, var);
5131  varval2 = SCIPgetSolVal(scip, sol, var2);
5132 
5133  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5134  if( sol == NULL )
5135  {
5136  /* with non-initial columns, variables can shortly be a column variable before entering the LP and have value 0.0 in this case, which might violated the variable bounds */
5137  if( !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)) || !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)) )
5138  *solviolbounds = TRUE;
5139  else
5140  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5141 
5142  /* with non-initial columns, variables can shortly be a column variable before entering the LP and have value 0.0 in this case, which might violated the variable bounds */
5143  if( !SCIPisFeasGE(scip, varval2, SCIPvarGetLbLocal(var2)) || !SCIPisFeasLE(scip, varval2, SCIPvarGetUbLocal(var2)) )
5144  *solviolbounds = TRUE;
5145  else
5146  varval2 = MAX(SCIPvarGetLbLocal(var2), MIN(SCIPvarGetUbLocal(var2), varval2));
5147  }
5148 
5149  consdata->activity += consdata->bilinterms[j].coef * varval * varval2;
5150  }
5151 
5152  /* compute absolute violation left hand side */
5153  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
5154  consdata->lhsviol = consdata->lhs - consdata->activity;
5155  else
5156  consdata->lhsviol = 0.0;
5157 
5158  /* compute absolute violation right hand side */
5159  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
5160  consdata->rhsviol = consdata->activity - consdata->rhs;
5161  else
5162  consdata->rhsviol = 0.0;
5163 
5164  switch( conshdlrdata->scaling )
5165  {
5166  case 'o' :
5167  /* no scaling */
5168  break;
5169 
5170  case 'g' :
5171  /* scale by sup-norm of gradient in current point */
5172  if( consdata->lhsviol > 0.0 || consdata->rhsviol > 0.0 )
5173  {
5174  SCIP_Real norm;
5175  norm = getGradientMaxElement(scip, cons, sol);
5176  if( norm > 1.0 )
5177  {
5178  consdata->lhsviol /= norm;
5179  consdata->rhsviol /= norm;
5180  }
5181  }
5182  break;
5183 
5184  case 's' :
5185  /* scale by left/right hand side of constraint */
5186  if( consdata->lhsviol > 0.0 )
5187  consdata->lhsviol /= MAX(1.0, REALABS(consdata->lhs));
5188 
5189  if( consdata->rhsviol > 0.0 )
5190  consdata->rhsviol /= MAX(1.0, REALABS(consdata->rhs));
5191 
5192  break;
5193 
5194  default :
5195  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
5196  SCIPABORT();
5197  return SCIP_INVALIDDATA; /*lint !e527*/
5198  }
5199 
5200  return SCIP_OKAY;
5201 }
5202 
5203 /** computes violation of a set of constraints */
5204 static
5206  SCIP* scip, /**< SCIP data structure */
5207  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5208  SCIP_CONS** conss, /**< constraints */
5209  int nconss, /**< number of constraints */
5210  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5211  SCIP_Bool* solviolbounds, /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol in some constraint */
5212  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
5213  )
5214 {
5215  SCIP_CONSDATA* consdata;
5216  SCIP_Real viol;
5217  SCIP_Real maxviol;
5218  SCIP_Bool solviolbounds1;
5219  int c;
5220 
5221  assert(scip != NULL);
5222  assert(conss != NULL || nconss == 0);
5223  assert(solviolbounds != NULL);
5224  assert(maxviolcon != NULL);
5225 
5226  *solviolbounds = FALSE;
5227  *maxviolcon = NULL;
5228 
5229  maxviol = 0.0;
5230 
5231  for( c = 0; c < nconss; ++c )
5232  {
5233  assert(conss != NULL);
5234  assert(conss[c] != NULL);
5235 
5236  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol, &solviolbounds1) );
5237  *solviolbounds |= solviolbounds1;
5238 
5239  consdata = SCIPconsGetData(conss[c]);
5240  assert(consdata != NULL);
5241 
5242  viol = MAX(consdata->lhsviol, consdata->rhsviol);
5243  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
5244  {
5245  maxviol = viol;
5246  *maxviolcon = conss[c];
5247  }
5248  }
5249 
5250  return SCIP_OKAY;
5251 }
5252 
5253 /** tries to compute cut for multleft * <coefleft, x'> * multright <= rhs / (multright * <coefright, x'>) where x'=(x,1) */
5254 static
5256  SCIP* scip, /**< SCIP data structure */
5257  SCIP_CONS* cons, /**< constraint */
5258  SCIP_Real* ref, /**< reference solution where to generate the cut */
5259  SCIP_Real multleft, /**< multiplicator on lhs */
5260  SCIP_Real* coefleft, /**< coefficient for factor on lhs */
5261  SCIP_Real multright, /**< multiplicator on both sides */
5262  SCIP_Real* coefright, /**< coefficient for factor that goes to rhs */
5263  SCIP_Real rightminactivity, /**< minimal activity of <coefright, x> */
5264  SCIP_Real rightmaxactivity, /**< maximal activity of <coefright, x> */
5265  SCIP_Real rhs, /**< denominator on rhs */
5266  SCIP_Real* cutcoef, /**< array to store cut coefficients for quadratic variables */
5267  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5268  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5269  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5270  char* name /**< buffer to store name of cut */
5271  )
5272 {
5273  SCIP_CONSDATA* consdata;
5274  SCIP_Real constant;
5275  int i;
5276 
5277  assert(cutcoef != NULL);
5278  assert(rightminactivity * multright > 0.0);
5279  assert(rightmaxactivity * multright > 0.0);
5280  assert(multright == 1.0 || multright == -1.0);
5281 
5282  consdata = SCIPconsGetData(cons);
5283  assert(consdata != NULL);
5284 
5285  if( rhs > 0.0 )
5286  {
5287  /* if rhs > 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need secant:
5288  * 1 / multright*<coefright, x'> <= 1/minact + 1/maxact - 1/(minact * maxact) multright*<coefright, x'>
5289  * where [minact, maxact] = multright * [rightminactivity, rightmaxactivity]
5290  *
5291  * assuming multright is either -1 or 1, and substituting gives
5292  * multright/rightminactivity + multright/rightmaxactivity - multright/(rightminactivity * rightmaxactivity) *<coefright, x'>
5293  *
5294  * multiplying by rhs, gives the estimate
5295  * rhs / (multright * <coefright, x'>) <= rhs * multright * (1/rightminactivity + 1/rightmaxactivity - 1/(rightminactivity * rightmaxactivity) * <coefright, x'>)
5296  */
5297 
5298  /* cannot do if unbounded */
5299  if( SCIPisInfinity(scip, rightmaxactivity * multright) )
5300  {
5301  *success = FALSE;
5302  return;
5303  }
5304 
5305  assert(SCIPisFeasLE(scip, rightminactivity, rightmaxactivity));
5306 
5307  constant = multleft * multright * coefleft[consdata->nquadvars];
5308  constant -= rhs * multright * (1.0 / rightminactivity + 1.0 / rightmaxactivity);
5309  constant += rhs * multright * coefright[consdata->nquadvars] / (rightminactivity * rightmaxactivity);
5310 
5311  for( i = 0; i < consdata->nquadvars; ++i )
5312  {
5313  cutcoef[i] = multleft * multright * coefleft[i];
5314  cutcoef[i] += rhs * multright / (rightminactivity * rightmaxactivity) * coefright[i];
5315  }
5316 
5317  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_factorablesecant_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5318  }
5319  else
5320  {
5321  SCIP_Real refvalue;
5322 
5323  /* if rhs < 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need linearization:
5324  * rhs / (multright * <coefright, x'>)
5325  * <= rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'> - multright * <coefright, ref'>)
5326  * = 2*rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'>)
5327  *
5328  * where ref' = (ref, 1)
5329  */
5330 
5331  /* compute <coefright, ref'> */
5332  refvalue = coefright[consdata->nquadvars];
5333  for( i = 0; i < consdata->nquadvars; ++i )
5334  refvalue += coefright[i] * ref[i];
5335 
5336  /* should not happen, since we checked activity of <coefright,x> before, and assume ref within bounds */
5337  assert(!SCIPisZero(scip, refvalue));
5338 
5339  constant = multleft * multright * coefleft[consdata->nquadvars];
5340  constant -= 2.0 * rhs / (multright * refvalue);
5341  constant += rhs / (refvalue * refvalue) * multright * coefright[consdata->nquadvars];
5342 
5343  for( i = 0; i < consdata->nquadvars; ++i )
5344  {
5345  cutcoef[i] = multleft * multright * coefleft[i];
5346  cutcoef[i] += rhs / (refvalue * refvalue) * multright * coefright[i];
5347  }
5348 
5349  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_factorablelinearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
5350  }
5351 
5352  *cutrhs = -constant;
5353 
5354  /* @todo does not always need to be local */
5355  *islocal = TRUE;
5356  *success = TRUE;
5357 }
5358 
5359 /** tries to generate a cut if constraint quadratic function is factorable and there are no linear variables
5360  * (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
5361  */
5362 static
5364  SCIP* scip, /**< SCIP data structure */
5365  SCIP_CONS* cons, /**< constraint */
5366  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
5367  SCIP_Real* ref, /**< reference solution where to generate the cut */
5368  SCIP_Real* cutcoef, /**< array to store cut coefficients for quadratic variables */
5369  SCIP_Real* cutlhs, /**< buffer to store cut lhs */
5370  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
5371  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
5372  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
5373  char* name /**< buffer to store name of cut */
5374  )
5375 {
5376  SCIP_CONSDATA* consdata;
5377  SCIP_Real leftminactivity;
5378  SCIP_Real leftmaxactivity;
5379  SCIP_Real rightminactivity;
5380  SCIP_Real rightmaxactivity;
5381  SCIP_Real multleft;
5382  SCIP_Real multright;
5383  SCIP_Real rhs;
5384  int i;
5385 
5386  assert(scip != NULL);
5387  assert(cons != NULL);
5388  assert(ref != NULL);
5389  assert(cutcoef != NULL);
5390  assert(cutlhs != NULL);
5391  assert(cutrhs != NULL);
5392  assert(islocal != NULL);
5393  assert(success != NULL);
5394  assert(name != NULL);
5395 
5396  consdata = SCIPconsGetData(cons);
5397  assert(consdata != NULL);
5398  assert(consdata->nlinvars == 0);
5399  assert(consdata->factorleft != NULL);
5400  assert(consdata->factorright != NULL);
5401 
5402  *success = FALSE;
5403  *cutlhs = -SCIPinfinity(scip);
5404 
5405  leftminactivity = consdata->factorleft[consdata->nquadvars];
5406  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
5407  rightminactivity = consdata->factorright[consdata->nquadvars];
5408  rightmaxactivity = consdata->factorright[consdata->nquadvars];
5409  for( i = 0; i < consdata->nquadvars; ++i )
5410  {
5411  if( !SCIPisInfinity(scip, -leftminactivity) )
5412  {
5413  if( consdata->factorleft[i] > 0.0 )
5414  {
5415  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5416  leftminactivity = -SCIPinfinity(scip);
5417  else
5418  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5419  }
5420  else if( consdata->factorleft[i] < 0.0 )
5421  {
5422  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5423  leftminactivity = -SCIPinfinity(scip);
5424  else
5425  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5426  }
5427  }
5428  if( !SCIPisInfinity(scip, leftmaxactivity) )
5429  {
5430  if( consdata->factorleft[i] > 0.0 )
5431  {
5432  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5433  leftmaxactivity = SCIPinfinity(scip);
5434  else
5435  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5436  }
5437  else if( consdata->factorleft[i] < 0.0 )
5438  {
5439  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5440  leftmaxactivity = SCIPinfinity(scip);
5441  else
5442  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5443  }
5444  }
5445 
5446  if( !SCIPisInfinity(scip, -rightminactivity) )
5447  {
5448  if( consdata->factorright[i] > 0.0 )
5449  {
5450  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5451  rightminactivity = -SCIPinfinity(scip);
5452  else
5453  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5454  }
5455  else if( consdata->factorright[i] < 0.0 )
5456  {
5457  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5458  rightminactivity = -SCIPinfinity(scip);
5459  else
5460  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5461  }
5462  }
5463  if( !SCIPisInfinity(scip, rightmaxactivity) )
5464  {
5465  if( consdata->factorright[i] > 0.0 )
5466  {
5467  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
5468  rightmaxactivity = SCIPinfinity(scip);
5469  else
5470  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
5471  }
5472  else if( consdata->factorright[i] < 0.0 )
5473  {
5474  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
5475  rightmaxactivity = SCIPinfinity(scip);
5476  else
5477  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
5478  }
5479  }
5480  }
5481 
5482  /* write violated constraints as multleft * factorleft * factorright <= rhs */
5483  if( violside == SCIP_SIDETYPE_RIGHT )
5484  {
5485  rhs = consdata->rhs;
5486  multleft = 1.0;
5487  }
5488  else
5489  {
5490  rhs = -consdata->lhs;
5491  multleft = -1.0;
5492  }
5493 
5494  if( SCIPisZero(scip, rhs) )
5495  {
5496  /* @todo do something for rhs == 0.0? */
5497  return SCIP_OKAY;
5498  }
5499 
5500  if( !SCIPisFeasPositive(scip, leftminactivity) && !SCIPisFeasNegative(scip, leftmaxactivity) )
5501  {
5502  /* left factor has 0 within activity bounds, or is very close, at least */
5503  if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5504  {
5505  /* right factor also has 0 within activity bounds, or is very close, at least
5506  * -> cannot separate
5507  */
5508  return SCIP_OKAY;
5509  }
5510 
5511  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5512  * such that multright * factorright > 0.0
5513  */
5514  if( rightminactivity < 0.0 )
5515  multright = -1.0;
5516  else
5517  multright = 1.0;
5518 
5519  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5520  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5521  }
5522  else if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
5523  {
5524  /* left factor is bounded away from 0
5525  * right factor has 0 within activity bounds, or is very close, at least
5526  * -> so divide by left factor
5527  */
5528 
5529  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5530  * such that multright * factorleft > 0.0
5531  */
5532  if( leftminactivity < 0.0 )
5533  multright = -1.0;
5534  else
5535  multright = 1.0;
5536 
5537  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5538  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5539  }
5540  else if( SCIPisInfinity(scip, -leftminactivity) || SCIPisInfinity(scip, leftmaxactivity) ||
5541  (!SCIPisInfinity(scip, -rightminactivity) && !SCIPisInfinity(scip, rightmaxactivity) && rightmaxactivity - rightminactivity < leftmaxactivity - leftminactivity) )
5542  {
5543  /* both factors are bounded away from 0, but the right one has a smaller activity range, so divide by that one */
5544 
5545  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
5546  * such that multright * factorright > 0.0
5547  */
5548  if( rightminactivity < 0.0 )
5549  multright = -1.0;
5550  else
5551  multright = 1.0;
5552 
5553  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
5554  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5555  }
5556  else
5557  {
5558  /* both factors are bounded away from 0, but the left one has a smaller activity range, so divide by that one */
5559 
5560  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
5561  * such that multright * factorleft > 0.0
5562  */
5563  if( leftminactivity < 0.0 )
5564  multright = -1.0;
5565  else
5566  multright = 1.0;
5567 
5568  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
5569  generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, cutcoef, cutrhs, islocal, success, name);
5570  }
5571 
5572  return SCIP_OKAY;
5573 }
5574 
5575 /* finds intersections of a parametric line (x,y) = (x0,y0) + t [(x1,y1) - (x0,y0)] on curves x*y = wl and x*y = wu;
5576  * returns TRUE if unsuccessful and FALSE otherwise
5577  */
5578 static
5580  SCIP* scip,
5581  SCIP_Real x0,
5582  SCIP_Real y0_,
5583  SCIP_Real x1,
5584  SCIP_Real y1_,
5585  SCIP_Real wl,
5586  SCIP_Real wu,
5587  SCIP_Real* xl,
5588  SCIP_Real* yl,
5589  SCIP_Real* xu,
5590  SCIP_Real* yu
5591  )
5592 {
5593  SCIP_Real a;
5594  SCIP_Real b;
5595  SCIP_Real c;
5596  SCIP_Real tl;
5597  SCIP_Real tu;
5598 
5599  assert(wl == SCIP_INVALID || (xl != NULL && yl != NULL)); /*lint !e777 */
5600  assert(wu == SCIP_INVALID || (xu != NULL && yu != NULL)); /*lint !e777 */
5601 
5602  /* The parametric line is of the form
5603  *
5604  * x = x0 + t (x1-x0)
5605  * y = y0 + t (y1-y0)
5606  *
5607  * and for that to satisfy xy = wl and xy = wu we must have
5608  *
5609  * x0 y0 + t [x0 (y1-y0) + y0 (x1-x0)] + t^2 (x1-x0) (y1-y0) = wl
5610  * = wu
5611  *
5612  * or a t^2 + b t + c - wl = 0 for proper values of a,b,c.
5613  * a t^2 + b t + c - wu = 0
5614  *
5615  * Because of the way this procedure will be used, one of the two
5616  * solutions found we must always use the minimum nonnegative one
5617  */
5618 
5619  a = (x1 - x0) * (y1_ - y0_);
5620  c = x0 * y0_;
5621  b = x0 * y1_ + y0_ * x1 - 2.0 * c;
5622 
5623  tl = 0.0;
5624  tu = 0.0;
5625 
5626  if( !SCIPisZero(scip, (SCIP_Real)a) )
5627  {
5628  if( wl != SCIP_INVALID ) /*lint !e777 */
5629  {
5630  SCIP_Real tl1;
5631  SCIP_Real tl2;
5632  SCIP_Real denom;
5633  SCIP_Real q;
5634 
5635  if( b * b - 4.0 * a * (c - wl) < 0.0 )
5636  {
5637  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
5638  return TRUE;
5639  }
5640 
5641  denom = sqrt(b * b - 4.0 * a * (c - wl));
5642  q = -0.5 * (b + COPYSIGN(denom, b));
5643  tl1 = q / a;
5644  tl2 = (c - wl) / q;
5645 
5646  /* choose the smallest non-negative root */
5647  tl = (tl1 >= 0.0 && (tl2 < 0.0 || tl1 < tl2)) ? tl1 : tl2;
5648  }
5649 
5650  if( wu != SCIP_INVALID ) /*lint !e777 */
5651  {
5652  SCIP_Real tu1;
5653  SCIP_Real tu2;
5654  SCIP_Real denom;
5655  SCIP_Real q;
5656 
5657  if( b * b - 4.0 * a * (c - wu) < 0.0 )
5658  {
5659  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
5660  return TRUE;
5661  }
5662 
5663  denom = sqrt(b * b - 4.0 * a * (c - wu));
5664  q = -0.5 * (b + COPYSIGN(denom, b));
5665  tu1 = q / a;
5666  tu2 = (c - wu) / q;
5667 
5668  /* choose the smallest non-negative root */
5669  tu = (tu1 >= 0.0 && (tu2 < 0.0 || tu1 < tu2)) ? tu1 : tu2;
5670  }
5671  }
5672  else if( !SCIPisZero(scip, (SCIP_Real)b) )
5673  {
5674  if( wl != SCIP_INVALID ) /*lint !e777 */
5675  tl = (wl - c) / b;
5676  if( wu != SCIP_INVALID ) /*lint !e777 */
5677  tu = (wu - c) / b;
5678  }
5679  else
5680  {
5681  /* no or infinitely many solutions */
5682  return TRUE;
5683  }
5684 
5685  if( wl != SCIP_INVALID ) /*lint !e777 */
5686  {
5687  *xl = (SCIP_Real)(x0 + tl * (x1 - x0 ));
5688  *yl = (SCIP_Real)(y0_ + tl * (y1_ - y0_));
5689 
5690  if( !SCIPisRelEQ(scip, *xl * *yl, wl) )
5691  {
5692  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
5693  return TRUE;
5694  }
5695  }
5696 
5697  if( wu != SCIP_INVALID ) /*lint !e777 */
5698  {
5699  *xu = (SCIP_Real)(x0 + tu * (x1 - x0));
5700  *yu = (SCIP_Real)(y0_ + tu * (y1_ - y0_));
5701 
5702  if( !SCIPisRelEQ(scip, *xu * *yu, wu) )
5703  {
5704  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
5705  return TRUE;
5706  }
5707  }
5708 
5709  /* do not use the computed points if one of the components is infinite */
5710  if( (xu != NULL && SCIPisInfinity(scip, *xu)) || (xl != NULL && SCIPisInfinity(scip, -*xl)) ||
5711  (yu != NULL && SCIPisInfinity(scip, *yu)) || (yl != NULL && SCIPisInfinity(scip, -*yl)) )
5712  {
5713  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
5714  return TRUE;
5715  }
5716 
5717  return FALSE;
5718 }
5719 
5720 /** generate coefficients for a plane through points (x1, y1_, x1*y1) and (x2, y2, x2*y2)
5721  * such that intersecting it with one of them (the first if whichuse is FALSE, the second otherwise)
5722  * gives a tangent to the curve x*y = k
5723  *
5724  * Returns TRUE on error and FALSE on success.
5725  */
5726 static
5728  SCIP* scip,
5729  SCIP_Real x1,
5730  SCIP_Real y1_,
5731  SCIP_Real x2,
5732  SCIP_Real y2,
5733  SCIP_Bool whichuse,
5734  SCIP_Real* cx,
5735  SCIP_Real* cy,
5736  SCIP_Real* cw
5737  )
5738 {
5739  SCIP_Real xd;
5740  SCIP_Real yd;
5741  SCIP_Real xo;
5742  SCIP_Real yo;
5743 
5744  assert(cx != NULL);
5745  assert(cy != NULL);
5746  assert(cw != NULL);
5747 
5748  /* the x-y slope of this constraint must be tangent to a curve x*y = k at (xD,yD) */
5749  if( !whichuse )
5750  {
5751  xd = x1;
5752  xo = x2;
5753  yd = y1_;
5754  yo = y2;
5755  }
5756  else
5757  {
5758  xd = x2;
5759  xo = x1;
5760  yd = y2;
5761  yo = y1_;
5762  }
5763 
5764  *cx = yd;
5765  *cy = xd;
5766 
5767  /* lift it so that it touches the other curve */
5768 
5769  /* if the two points are on the same curve, then no cut */
5770  if( SCIPisZero(scip, xo * yo - xd * yd) )
5771  return TRUE;
5772 
5773  /* should ALWAYS be negative */
5774  *cw = (2.0 * xd * yd - (*cx * xo + *cy * yo)) / (xo * yo - xd * yd);
5775 
5776  return FALSE;
5777 }
5778 
5779 /** computes coefficients of a lifted-tangent inequality for x*y = w
5780  *
5781  * The code is an adaptation of the methods in exprMul-upperHull.cpp in Couenne/stable/0.4 rev773,
5782  * written by P. Belotti and licensed under Eclipse Public License.
5783  */
5784 static
5786  SCIP* scip, /**< SCIP data structure */
5787  SCIP_Real xl, /**< lower bound on x */
5788  SCIP_Real xu, /**< upper bound on x */
5789  SCIP_Real x0, /**< reference point for x */
5790  SCIP_Real yl, /**< lower bound on y */
5791  SCIP_Real yu, /**< upper bound on y */
5792  SCIP_Real y0_, /**< reference point for y */
5793  SCIP_Real wl, /**< lower bound on w */
5794  SCIP_Real wu, /**< upper bound on w */
5795  SCIP_Real w0, /**< reference point for w */
5796  SCIP_Real* cx, /**< buffer where to store cut coefficient for x */
5797  SCIP_Real* cy, /**< buffer where to store cut coefficient for y */
5798  SCIP_Real* cw, /**< buffer where to store cut coefficient for w */
5799  SCIP_Real* c0, /**< buffer where to store cut left-hand-side */
5800  SCIP_Bool* success /**< buffer where to indicate whether cut coefficients were computed */
5801  )
5802 {
5803  SCIP_Bool flipx;
5804  SCIP_Bool flipy;
5805  SCIP_Bool flipw;
5806  SCIP_Real tmp;
5807  SCIP_Real xlow;
5808  SCIP_Real ylow;
5809  SCIP_Real xupp;
5810  SCIP_Real yupp;
5811  SCIP_Real c0x;
5812  SCIP_Real c0y;
5813  SCIP_Real c0w;
5814 
5815  assert(scip != NULL);
5816  assert(cx != NULL);
5817  assert(cy != NULL);
5818  assert(cw != NULL);
5819  assert(c0 != NULL);
5820  assert(success != NULL);
5821 
5822  *success = FALSE;
5823  *cx = 0.0;
5824  *cy = 0.0;
5825  *cw = 0.0;
5826  *c0 = 0.0;
5827 
5828  SCIPdebugMsg(scip, "entering points:\n");
5829  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5830  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5831  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5832 
5833  /* generateCutLTI should have recognized these */
5834  assert(wl >= 0.0 || wu <= 0.0);
5835  assert(!SCIPisInfinity(scip, -wl));
5836  assert(!SCIPisInfinity(scip, wu));
5837 
5838  assert(SCIPisFeasGE(scip, x0, xl));
5839  assert(SCIPisFeasLE(scip, x0, xu));
5840  assert(SCIPisFeasGE(scip, y0_, yl));
5841  assert(SCIPisFeasLE(scip, y0_, yu));
5842 
5843  /* preliminary bound tightening */
5844  if( wl >= 0.0 )
5845  {
5846  if( xl >= 0.0 || yl >= 0.0 || SCIPisLT(scip, xl * yl, wl) )
5847  {
5848  xl = MAX(xl, 0.0);
5849  yl = MAX(yl, 0.0);
5850  }
5851  else if( xu <= 0.0 || yu <= 0.0 || SCIPisLT(scip, xu * yu, wl) )
5852  {
5853  xu = MIN(xu, 0.0);
5854  yu = MIN(yu, 0.0);
5855  }
5856  else
5857  {
5858  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yl and xu*yu are feasible
5859  * cannot generate cut for this
5860  */
5861  return;
5862  }
5863  }
5864  else
5865  {
5866  if( xl >= 0.0 || yu <= 0.0 || SCIPisGT(scip, xl * yu, wu) )
5867  {
5868  xl = MAX(xl, 0.0);
5869  yu = MIN(yu, 0.0);
5870  }
5871  else if( xu <= 0.0 || yl >= 0.0 || SCIPisGT(scip, xu * yl, wu))
5872  {
5873  xu = MIN(xu, 0.0);
5874  yl = MAX(yl, 0.0);
5875  }
5876  else
5877  {
5878  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yu and xu*yl are feasible
5879  * cannot generate cut for this
5880  */
5881  return;
5882  }
5883  }
5884 
5885  /* if x or y is fixed now or even infeasible, then do not think about a cut */
5886  if( SCIPisGE(scip, xl, xu) || SCIPisGE(scip, yl, yu) )
5887  return;
5888 
5889  /* reduce to positive orthant by flipping variables */
5890  if( xl < 0.0 )
5891  {
5892  flipx = TRUE;
5893  tmp = xu;
5894  xu = -xl;
5895  xl = -tmp;
5896  x0 = -x0;
5897  }
5898  else
5899  flipx = FALSE;
5900 
5901  if( yl < 0.0 )
5902  {
5903  flipy = TRUE;
5904  tmp = yu;
5905  yu = -yl;
5906  yl = -tmp;
5907  y0_ = -y0_;
5908  }
5909  else
5910  flipy = FALSE;
5911 
5912  if( flipx ^ flipy )
5913  {
5914  flipw = TRUE;
5915  tmp = wu;
5916  wu = -wl;
5917  wl = -tmp;
5918  w0 = -w0;
5919  }
5920  else
5921  flipw = FALSE;
5922 
5923  /* project refpoint into box not only for numerical reasons, but also due to preliminary bound tightening above */
5924  x0 = MIN(xu, MAX(x0, xl));
5925  y0_ = MIN(yu, MAX(y0_, yl));
5926  w0 = MIN(wu, MAX(w0, wl));
5927 
5928  SCIPdebugMsg(scip, "reduced points:\n");
5929  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
5930  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
5931  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
5932 
5933  if( SCIPisGE(scip, xl * yl, wl) && SCIPisLE(scip, xu * yu, wu) )
5934  {
5935  SCIPdebugMsg(scip, "box for x and y inside feasible region -> nothing to separate\n");
5936  return;
5937  }
5938  if( SCIPisGE(scip, x0 * y0_, w0) )
5939  {
5940  SCIPdebugMsg(scip, "point to separate not below curve -> cannot separate\n");
5941  return;
5942  }
5943 
5944  /* find intersections of halfline from origin
5945  * return if no proper point could be found
5946  */
5947  if( generateCutLTIfindIntersection(scip, 0.0, 0.0, x0, y0_, wl, wu, &xlow, &ylow, &xupp, &yupp) )
5948  return;
5949 
5950  SCIPdebugMsg(scip, "intersections:\n");
5951  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
5952  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
5953 
5954  /* Case 1: If both are outside of bounding box, either NW or SE, then McCormick is sufficient, so return */
5955  if( (xlow <= xl && yupp >= yu) || (ylow <= yl && xupp >= xu) )
5956  return;
5957 
5958  /* There will be at least one cut. Define coefficients and rhs ---will have to change them back if (flipX || flipY) */
5959  if( xlow >= xl && xupp <= xu && ylow >= yl && yupp <= yu )
5960  {
5961  /* Case 2: both are inside. Easy lifting... */
5962  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5963  return;
5964 
5965  c0x = *cx * xlow;
5966  c0y = *cy * ylow;
5967  c0w = *cw * wl;
5968  }
5969  else if( xlow >= xl && ylow >= yl && (xupp > xu || yupp > yu) )
5970  {
5971  /* Case 3a and 3b: through lower curve, but not upper. */
5972  if( yupp > yu )
5973  {
5974  /* upper intersect is North; place it within box */
5975  assert(!SCIPisInfinity(scip, yu));
5976  yupp = yu;
5977  xupp = wu / yu;
5978  }
5979  else
5980  {
5981  /* upper intersect is East; place it within box */
5982  assert(!SCIPisInfinity(scip, xu));
5983  xupp = xu;
5984  yupp = wu / xu;
5985  }
5986 
5987  /* find intersection on low curve on half line through new point and (x0,y0_) */
5988  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow, &ylow, NULL, NULL) )
5989  return;
5990 
5991  /* check whether McCormick is sufficient */
5992  if( xlow < xl || ylow < yl )
5993  return;
5994 
5995  /* lift inequality on lower point */
5996  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
5997  return;
5998 
5999  c0x = *cx * xlow;
6000  c0y = *cy * ylow;
6001  c0w = *cw * wl;
6002  }
6003  else if( xupp <= xu && yupp <= yu && (xlow < xl || ylow < yl) )
6004  {
6005  /* Case 4a and 4b: viceversa (lift for validity) */
6006  if( ylow < yl )
6007  {
6008  /* upper intersect is South; place it within box */
6009  assert(!SCIPisZero(scip, yl));
6010  ylow = yl;
6011  xlow = wl / yl;
6012  }
6013  else
6014  {
6015  /* upper intersect is West; place it within box */
6016  assert(!SCIPisZero(scip, xl));
6017  xlow = xl;
6018  ylow = wl / xl;
6019  }
6020 
6021  /* find intersection on low curve on half line through new point and (x0,y0) */
6022  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp, &yupp) )
6023  return;
6024 
6025  /* check whether McCormick is sufficient */
6026  if( xupp > xu || yupp > yu )
6027  return;
6028 
6029  /* lift inequality on UPPER point */
6030  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
6031  return;
6032 
6033  c0x = *cx * xupp;
6034  c0y = *cy * yupp;
6035  c0w = *cw * wu;
6036  }
6037  else if( (xlow < xl && xupp > xu) || (ylow < yl && yupp > yu) )
6038  {
6039  /* Case 5: both outside of bounding box, N and S or W and E. */
6040 #if 0
6041  SCIP_Real xlow2;
6042  SCIP_Real ylow2;
6043  SCIP_Real xupp2;
6044  SCIP_Real yupp2;
6045 #endif
6046 
6047  if( ylow < yl )
6048  {
6049  /* upper intersect is South; place it within box */
6050  assert(!SCIPisZero(scip, yl));
6051  assert(!SCIPisZero(scip, yu));
6052  ylow = yl;
6053  yupp = yu;
6054  xlow = wl / yl;
6055  xupp = wu / yu;
6056  }
6057  else
6058  {
6059  /* upper intersect is West; place it within box */
6060  assert(!SCIPisZero(scip, xl));
6061  assert(!SCIPisZero(scip, xu));
6062  xlow = xl;
6063  xupp = xu;
6064  ylow = wl / xl;
6065  yupp = wu / xu;
6066  }
6067 
6068  SCIPdebugMsg(scip, "New intersections:\n");
6069  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6070  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6071 
6072 #if 1
6073  /* Nothing to find. Just separate two inequalities at the same point, just using different support */
6074  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6075  {
6076  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
6077  return;
6078 
6079  c0x = *cx * xupp;
6080  c0y = *cy * yupp;
6081  c0w = *cw * wu;
6082  }
6083  else
6084  {
6085  c0x = *cx * xlow;
6086  c0y = *cy * ylow;
6087  c0w = *cw * wl;
6088  }
6089 
6090 #else
6091  /* find the intersection on the lower (upper) curve on the line through xLP and the upper (lower) point
6092  * this does not seem to work (cuts off solution at nous2), so it is disabled for now
6093  */
6094  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp2, &yupp2) ||
6095  generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp2, yupp2, FALSE, cx, cx, cw) )
6096  {
6097  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow2, &ylow2, NULL, NULL) ||
6098  generateCutLTIgenMulCoeff(scip, xlow2, ylow2, xupp, yupp, TRUE, cx, cy, cw) )
6099  return;
6100 
6101  c0x = *cx * xupp;
6102  c0y = *cy * yupp;
6103  c0w = *cw * wu;
6104  }
6105  else
6106  {
6107  c0x = *cx * xlow;
6108  c0y = *cy * ylow;
6109  c0w = *cw * wl;
6110  }
6111 #endif
6112  }
6113  else
6114  {
6115  SCIPdebugMsg(scip, "points are in a weird position:\n");
6116  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6117  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6118 
6119  return;
6120  }
6121 
6122  SCIPdebugMsg(scip, "cut w.r.t. reduced points: %gx-%g %+gy-%g %+gw-%g >= 0\n",
6123  *cx, c0x, *cy, c0y, *cw, c0w);
6124 
6125  /* re-transform back into original variables */
6126  if( flipx )
6127  *cx = -*cx;
6128  if( flipy )
6129  *cy = -*cy;
6130  if( flipw )
6131  *cw = -*cw;
6132 
6133  *c0 = c0x + c0y + c0w;
6134 
6135  *success = TRUE;
6136 }
6137 
6138 /** tries to generate a cut if constraint quadratic function is factorable and there are linear variables
6139  *
6140  * Computes what is called a lifted tangent inequality described in@n
6141  * Belotti, Miller, Namazifar, Lifted inequalities for bounded products of variables, SIAG/OPT Views-and-News 22:1, 2011
6142  */
6143 static
6145  SCIP* scip, /**< SCIP data structure */
6146  SCIP_CONS* cons, /**< constraint */
6147  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6148  SCIP_Real* ref, /**< reference solution where to generate the cut */
6149  SCIP_SOL* sol, /**< solution that shall be cutoff, NULL for LP solution */
6150  SCIP_Real** cutcoeflin, /**< buffer to store pointer to array with coefficients for linear variables */
6151  SCIP_Real* cutcoefquad, /**< array to store cut coefficients for quadratic variables */
6152  SCIP_Real* cutlhs, /**< buffer to store cut lhs */
6153  SCIP_Real* cutrhs, /**< buffer to store cut rhs */
6154  SCIP_Bool* islocal, /**< buffer to set to TRUE if local information was used */
6155  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6156  char* name /**< buffer to store name of cut */
6157  )
6158 {
6159  SCIP_CONSDATA* consdata;
6160  SCIP_Real leftminactivity;
6161  SCIP_Real leftmaxactivity;
6162  SCIP_Real leftrefactivity;
6163  SCIP_Real rightminactivity;
6164  SCIP_Real rightmaxactivity;
6165  SCIP_Real rightrefactivity;
6166  SCIP_Real rhsminactivity;
6167  SCIP_Real rhsmaxactivity;
6168  SCIP_Real rhsrefactivity;
6169  SCIP_Real coefleft;
6170  SCIP_Real coefright;
6171  SCIP_Real coefrhs;
6172  int i;
6173 
6174  assert(scip != NULL);
6175  assert(cons != NULL);
6176  assert(ref != NULL);
6177  assert(cutcoeflin != NULL);
6178  assert(cutcoefquad != NULL);
6179  assert(cutlhs != NULL);
6180  assert(cutrhs != NULL);
6181  assert(islocal != NULL);
6182  assert(success != NULL);
6183  assert(name != NULL);
6184  /* currently only separate LP solution or solutions given as SCIP_SOL, i.e., no cutgeneration during initlp */
6185  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
6186 
6187  consdata = SCIPconsGetData(cons);
6188  assert(consdata != NULL);
6189  assert(consdata->nlinvars > 0);
6190  assert(consdata->factorleft != NULL);
6191  assert(consdata->factorright != NULL);
6192 
6193  *success = FALSE;
6194  *cutlhs = -SCIPinfinity(scip); /* for compiler */
6195 
6196  /* write violated constraints as factorleft * factorright '==' rhs
6197  * where rhs are constraint sides - activity bound of linear part
6198  */
6199  rhsminactivity = consdata->lhs;
6200  rhsmaxactivity = consdata->rhs;
6201  rhsrefactivity = (violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
6202 
6203  for( i = 0; i < consdata->nlinvars; ++i )
6204  {
6205  if( !SCIPisInfinity(scip, -rhsminactivity) )
6206  {
6207  if( consdata->lincoefs[i] < 0.0 )
6208  {
6209  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6210  rhsminactivity = -SCIPinfinity(scip);
6211  else
6212  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6213  }
6214  else
6215  {
6216  assert(consdata->lincoefs[i] > 0.0);
6217  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6218  rhsminactivity = -SCIPinfinity(scip);
6219  else
6220  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6221  }
6222  }
6223  if( !SCIPisInfinity(scip, rhsmaxactivity) )
6224  {
6225  if( consdata->lincoefs[i] < 0.0 )
6226  {
6227  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
6228  rhsmaxactivity = SCIPinfinity(scip);
6229  else
6230  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
6231  }
6232  else
6233  {
6234  assert(consdata->lincoefs[i] > 0.0);
6235  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
6236  rhsmaxactivity = SCIPinfinity(scip);
6237  else
6238  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
6239  }
6240  }
6241  rhsrefactivity -= consdata->lincoefs[i] * SCIPgetSolVal(scip, sol, consdata->linvars[i]);
6242  }
6243 
6244  if( SCIPisInfinity(scip, -rhsminactivity) || SCIPisInfinity(scip, rhsmaxactivity) )
6245  {
6246  /* if right hand side is unbounded, then cannot do LTI */
6247  return SCIP_OKAY;
6248  }
6249 
6250  if( !SCIPisFeasPositive(scip, rhsminactivity) && !SCIPisFeasNegative(scip, rhsmaxactivity) )
6251  {
6252  /* if right hand side has 0 inside activity, then cannot do anything
6253  * if it has 0.0 as min or max activity, then a usual McCormick should be sufficient, too
6254  */
6255  return SCIP_OKAY;
6256  }
6257 
6258  leftminactivity = consdata->factorleft[consdata->nquadvars];
6259  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
6260  leftrefactivity = consdata->factorleft[consdata->nquadvars];
6261  rightminactivity = consdata->factorright[consdata->nquadvars];
6262  rightmaxactivity = consdata->factorright[consdata->nquadvars];
6263  rightrefactivity = consdata->factorright[consdata->nquadvars];
6264  for( i = 0; i < consdata->nquadvars; ++i )
6265  {
6266  if( !SCIPisInfinity(scip, -leftminactivity) )
6267  {
6268  if( consdata->factorleft[i] > 0.0 )
6269  {
6270  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6271  leftminactivity = -SCIPinfinity(scip);
6272  else
6273  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6274  }
6275  else if( consdata->factorleft[i] < 0.0 )
6276  {
6277  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6278  leftminactivity = -SCIPinfinity(scip);
6279  else
6280  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6281  }
6282  }
6283  if( !SCIPisInfinity(scip, leftmaxactivity) )
6284  {
6285  if( consdata->factorleft[i] > 0.0 )
6286  {
6287  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6288  leftmaxactivity = SCIPinfinity(scip);
6289  else
6290  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6291  }
6292  else if( consdata->factorleft[i] < 0.0 )
6293  {
6294  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6295  leftmaxactivity = SCIPinfinity(scip);
6296  else
6297  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6298  }
6299  }
6300  leftrefactivity += consdata->factorleft[i] * ref[i];
6301 
6302  if( !SCIPisInfinity(scip, -rightminactivity) )
6303  {
6304  if( consdata->factorright[i] > 0.0 )
6305  {
6306  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6307  rightminactivity = -SCIPinfinity(scip);
6308  else
6309  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6310  }
6311  else if( consdata->factorright[i] < 0.0 )
6312  {
6313  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6314  rightminactivity = -SCIPinfinity(scip);
6315  else
6316  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6317  }
6318  }
6319  if( !SCIPisInfinity(scip, rightmaxactivity) )
6320  {
6321  if( consdata->factorright[i] > 0.0 )
6322  {
6323  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6324  rightmaxactivity = SCIPinfinity(scip);
6325  else
6326  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6327  }
6328  else if( consdata->factorright[i] < 0.0 )
6329  {
6330  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6331  rightmaxactivity = SCIPinfinity(scip);
6332  else
6333  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6334  }
6335  }
6336  rightrefactivity += consdata->factorright[i] * ref[i];
6337  }
6338 
6339  /* if activities exceed "opposite" infinity, huge bounds seem to be involved, for which the below method is not prepared */
6340  if( SCIPisInfinity(scip, leftminactivity) || SCIPisInfinity(scip, -leftmaxactivity) ||
6341  SCIPisInfinity(scip, rightminactivity) || SCIPisInfinity(scip, -rightmaxactivity) )
6342  return SCIP_OKAY;
6343 
6344  /* if any of the factors is essentially fixed, give up and do usual method (numerically less sensitive, I hope) */
6345  if( SCIPisRelEQ(scip, leftminactivity, leftmaxactivity) || SCIPisRelEQ(scip, rightminactivity, rightmaxactivity) )
6346  return SCIP_OKAY;
6347 
6348  /* success can only be expected for separation of violated x*y <= w, assuming x>=0, y>=0
6349  * @todo we should check this early? */
6350 
6351  /* call Couenne magic */
6353  leftminactivity, leftmaxactivity, leftrefactivity,
6354  rightminactivity, rightmaxactivity, rightrefactivity,
6355  rhsminactivity, rhsmaxactivity, rhsrefactivity,
6356  &coefleft, &coefright, &coefrhs, cutlhs,
6357  success);
6358 
6359  if( !*success )
6360  return SCIP_OKAY;
6361 
6362  SCIPdebugMsg(scip, "LTI for x[%g,%g] * y[%g,%g] = w[%g,%g]: %gx %+gy %+gw >= %g; feas: %g\n",
6363  leftminactivity, leftmaxactivity, rightminactivity, rightmaxactivity, rhsminactivity, rhsmaxactivity,
6364  coefleft, coefright, coefrhs, *cutlhs,
6365  coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity - *cutlhs
6366  );
6367 
6368  if( coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity >= *cutlhs )
6369  {
6370  SCIPdebugMsg(scip, "does not cutoff point? :-(\n");
6371  *success = FALSE;
6372  return SCIP_OKAY;
6373  }
6374 
6375  /* setup cut coefs for
6376  * coefleft * leftfactor + coefright * rightfactor + coefrhs * w >= cutlhs, where conslhs - lincoefs <= w <= consrhs - lincoefs
6377  */
6378  for( i = 0; i < consdata->nquadvars; ++i )
6379  cutcoefquad[i] = coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i];
6380  assert(i == consdata->nquadvars);
6381  *cutlhs -= coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i];
6382 
6383  SCIP_CALL( SCIPallocBufferArray(scip, cutcoeflin, consdata->nlinvars) );
6384  for( i = 0; i < consdata->nlinvars; ++i )
6385  (*cutcoeflin)[i] = -coefrhs * consdata->lincoefs[i];
6386  if( coefrhs > 0.0 )
6387  {
6388  /* use coefrhs * w <= coefrhs * (consrhs - lincoefs) */
6389  assert(!SCIPisInfinity(scip, consdata->rhs));
6390  *cutlhs -= coefrhs * consdata->rhs;
6391  }
6392  else
6393  {
6394  /* use coefrhs * w <= coeflhs * (conslhs - lincoefs) */
6395  assert(!SCIPisInfinity(scip, -consdata->lhs));
6396  *cutlhs -= coefrhs * consdata->lhs;
6397  }
6398 
6399  *cutrhs = SCIPinfinity(scip);
6400  *islocal = TRUE;
6401 
6402  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_lti_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6403 
6404  *success = TRUE;
6405 
6406  return SCIP_OKAY;
6407 }
6408 
6409 /** computes cut coefficients by linearizing a quadratic function */
6410 static
6412  SCIP* scip, /**< SCIP data structure */
6413  SCIP_CONS* cons, /**< constraint */
6414  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6415  SCIP_Real* ref, /**< reference solution where to generate the cut */
6416  SCIP_Real* coef, /**< array to store cut coefficients w.r.t. quadratic variables */
6417  SCIP_Real* lhs, /**< buffer to store left-hand-side of cut */
6418  SCIP_Real* rhs, /**< buffer to store right-hand-side of cut */
6419  SCIP_Bool* islocal, /**< buffer to set to TRUE if local bounds were used */
6420  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6421  char* name /**< buffer to store name for cut */
6422  )
6423 {
6424  SCIP_CONSDATA* consdata;
6425  SCIP_BILINTERM* bilinterm;
6426  SCIP_Real constant;
6427  SCIP_VAR* var;
6428  int var2pos;
6429  int j;
6430  int k;
6431 
6432  assert(scip != NULL);
6433  assert(cons != NULL);
6434  assert(ref != NULL);
6435  assert(coef != NULL);
6436  assert(lhs != NULL);
6437  assert(rhs != NULL);
6438  assert(islocal != NULL);
6439  assert(success != NULL);
6440 
6441  consdata = SCIPconsGetData(cons);
6442  assert(consdata != NULL);
6443 
6444  constant = 0.0;
6445  BMSclearMemoryArray(coef, consdata->nquadvars);
6446  *success = TRUE;
6447 
6448  /* do first-order Taylor for each term */
6449  for( j = 0; j < consdata->nquadvars && *success; ++j )
6450  {
6451  /* initialize coefficients to linear coefficients of quadratic variables */
6452  coef[j] += consdata->quadvarterms[j].lincoef;
6453 
6454  /* add linearization of square term */
6455  var = consdata->quadvarterms[j].var;
6456  SCIPaddSquareLinearization(scip, consdata->quadvarterms[j].sqrcoef, ref[j],
6457  consdata->quadvarterms[j].nadjbilin == 0 && SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef[j], &constant, success);
6458 
6459  /* add linearization of bilinear terms that have var as first variable */
6460  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6461  {
6462  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6463  if( bilinterm->var1 != var )
6464  continue;
6465  assert(bilinterm->var2 != var);
6466  assert(consdata->sepabilinvar2pos != NULL);
6467 
6468  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6469  assert(var2pos >= 0);
6470  assert(var2pos < consdata->nquadvars);
6471  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6472 
6473  SCIPaddBilinLinearization(scip, bilinterm->coef, ref[j], ref[var2pos], &coef[j], &coef[var2pos], &constant, success);
6474  }
6475  }
6476 
6477  if( !*success )
6478  {
6479  SCIPdebugMsg(scip, "no success in linearization of <%s> in reference point\n", SCIPconsGetName(cons));
6480  return SCIP_OKAY;
6481  }
6482 
6483  if( violside == SCIP_SIDETYPE_LEFT )
6484  {
6485  *lhs = consdata->lhs - constant;
6486  *rhs = SCIPinfinity(scip);
6487  }
6488  else
6489  {
6490  *lhs = -SCIPinfinity(scip);
6491  *rhs = consdata->rhs - constant;
6492  }
6493 
6494  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_side%d_linearization_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6495 
6496  return SCIP_OKAY;
6497 }
6498 
6499 /** computes cut coefficients for a nonconvex quadratic function */
6500 static
6502  SCIP* scip, /**< SCIP data structure */
6503  SCIP_CONS* cons, /**< constraint */
6504  SCIP_SIDETYPE violside, /**< side for which to generate cut */
6505  SCIP_Real* ref, /**< reference solution where to generate the cut */
6506  SCIP_Real* coef, /**< array to store cut coefficients w.r.t. quadratic variables */
6507  SCIP_Real* lhs, /**< buffer to store left-hand-side of cut */
6508  SCIP_Real* rhs, /**< buffer to store right-hand-side of cut */
6509  SCIP_Bool* islocal, /**< buffer to set to TRUE if local bounds were used */
6510  SCIP_Bool* success, /**< buffer to indicate whether a cut was successfully computed */
6511  char* name /**< buffer to store name for cut */
6512  )
6513 {
6514  SCIP_CONSDATA* consdata;
6515  SCIP_BILINTERM* bilinterm;
6516  SCIP_Real constant;
6517  SCIP_Real sqrcoef;
6518  SCIP_VAR* var;
6519  int var2pos;
6520  int j;
6521  int k;
6522 
6523  assert(scip != NULL);
6524  assert(cons != NULL);
6525  assert(ref != NULL);
6526  assert(coef != NULL);
6527  assert(lhs != NULL);
6528  assert(rhs != NULL);
6529  assert(islocal != NULL);
6530  assert(success != NULL);
6531 
6532  consdata = SCIPconsGetData(cons);
6533  assert(consdata != NULL);
6534 
6535  *islocal = TRUE;
6536  constant = 0.0;
6537  BMSclearMemoryArray(coef, consdata->nquadvars);
6538  *success = TRUE;
6539 
6540  /* underestimate (secant, McCormick) or linearize each term separately */
6541  for( j = 0; j < consdata->nquadvars && *success; ++j )
6542  {
6543  /* initialize coefficients to linear coefficients of quadratic variables */
6544  coef[j] += consdata->quadvarterms[j].lincoef;
6545 
6546  var = consdata->quadvarterms[j].var;
6547 
6548  sqrcoef = consdata->quadvarterms[j].sqrcoef;
6549  if( sqrcoef != 0.0 )
6550  {
6551  if( (violside == SCIP_SIDETYPE_LEFT && sqrcoef <= 0.0) || (violside == SCIP_SIDETYPE_RIGHT && sqrcoef > 0.0) )
6552  {
6553  /* convex -> linearize */
6554  SCIPaddSquareLinearization(scip, sqrcoef, ref[j], SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef[j],
6555  &constant, success);
6556  }
6557  else
6558  {
6559  /* not convex -> secant approximation */
6560  SCIPaddSquareSecant(scip, sqrcoef, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j], &coef[j],
6561  &constant, success);
6562  }
6563  }
6564 
6565  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
6566  {
6567  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
6568  if( bilinterm->var1 != var )
6569  continue;
6570  assert(bilinterm->var2 != var);
6571  assert(consdata->sepabilinvar2pos != NULL);
6572 
6573  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
6574  assert(var2pos >= 0);
6575  assert(var2pos < consdata->nquadvars);
6576  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
6577 
6578  SCIPaddBilinMcCormick(scip, bilinterm->coef,
6579  SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j],
6580  SCIPvarGetLbLocal(bilinterm->var2), SCIPvarGetUbLocal(bilinterm->var2), ref[var2pos],
6581  violside == SCIP_SIDETYPE_LEFT, &coef[j], &coef[var2pos], &constant, success);
6582  }
6583  }
6584 
6585  if( !*success )
6586  {
6587  SCIPdebugMsg(scip, "no success to find estimator for nonconvex <%s>\n", SCIPconsGetName(cons));
6588  return SCIP_OKAY;
6589  }
6590 
6591  if( violside == SCIP_SIDETYPE_LEFT )
6592  {
6593  *lhs = consdata->lhs - constant;
6594  *rhs = SCIPinfinity(scip);
6595  }
6596  else
6597  {
6598  *lhs = -SCIPinfinity(scip);
6599  *rhs = consdata->rhs - constant;
6600  }
6601 
6602  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_side%d_estimation_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
6603 
6604  return SCIP_OKAY;
6605 }
6606 
6607 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a given reference point */
6608 static
6610  SCIP* scip, /**< SCIP data structure */
6611  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6612  SCIP_CONS* cons, /**< constraint */
6613  SCIP_Real* ref, /**< reference solution where to generate the cut */
6614  SCIP_SOL* sol, /**< point that we aim to separate, or NULL for LP solution */
6615  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6616  SCIP_ROW** row, /**< storage for cut */
6617  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
6618  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
6619  SCIP_Real minefficacy /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
6620  )
6621 {
6622  SCIP_CONSHDLRDATA* conshdlrdata;
6623  SCIP_CONSDATA* consdata;
6624  SCIP_Bool islocal;
6625  char cutname[SCIP_MAXSTRLEN];
6626  SCIP_Real* lincoefs;
6627  SCIP_Real* coef;
6628  SCIP_Real lhs;
6629  SCIP_Real rhs;
6630  SCIP_Bool success;
6631  SCIP_Real mincoef;
6632  SCIP_Real maxcoef;
6633  SCIP_Real lincoefsmax;
6634  SCIP_Real lincoefsmin;
6635  SCIP_Real viol;
6636  SCIP_Real rowefficacy;
6637  SCIP_VAR* var;
6638  int j;
6639 
6640  assert(scip != NULL);
6641  assert(conshdlr != NULL);
6642  assert(cons != NULL);
6643  assert(ref != NULL);
6644  assert(row != NULL);
6645 
6646  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6647  assert(conshdlrdata != NULL);
6648 
6649  consdata = SCIPconsGetData(cons);
6650  assert(consdata != NULL);
6651  assert(violside != SCIP_SIDETYPE_LEFT || !SCIPisInfinity(scip, -consdata->lhs));
6652  assert(violside != SCIP_SIDETYPE_RIGHT || !SCIPisInfinity(scip, consdata->rhs));
6653 
6654  *row = NULL;
6655  SCIP_CALL( SCIPallocBufferArray(scip, &coef, consdata->nquadvars) );
6656  lincoefs = consdata->lincoefs;
6657  lincoefsmax = consdata->lincoefsmax;
6658  lincoefsmin = consdata->lincoefsmin;
6659  islocal = SCIPconsIsLocal(cons);
6660  success = FALSE;
6661  lhs = -SCIPinfinity(scip);
6662  rhs = SCIPinfinity(scip);
6663  cutname[0] = '\0';
6664  rowefficacy = 0.0;
6665 
6666  /* if constraint function is factorable, then try to use factorable form to generate cut */
6667  if( consdata->factorleft != NULL )
6668  {
6669  if( consdata->nlinvars == 0 )
6670  {
6671  SCIP_CALL( generateCutFactorable(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6672  }
6673  else if( sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
6674  {
6675  int i;
6676 
6677  /* generateCutLTI needs reference values also for the linear variables, which we only have if sol is given or LP has been solved */
6678  SCIP_CALL( generateCutLTI(scip, cons, violside, ref, sol, &lincoefs, coef, &lhs, &rhs, &islocal, &success, cutname) );
6679 
6680  /* in case of LTI cuts, we have to recompute the min and max of lincoefs, since they may have been modified */
6681  for( i = 0; i < consdata->nlinvars; ++i )
6682  {
6683  if( REALABS(lincoefs[i]) > lincoefsmax )
6684  lincoefsmax = REALABS(lincoefs[i]);
6685  if( REALABS(lincoefs[i]) < lincoefsmin )
6686  lincoefsmin = REALABS(lincoefs[i]);
6687  }
6688  }
6689  }
6690 
6691  /* if constraint is not factorable or failed to generate cut, try default method */
6692  if( !success )
6693  {
6694  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
6695 
6696  if( (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave) || (violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex) )
6697  {
6698  SCIP_CALL( generateCutConvex(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6699  }
6700  else
6701  {
6702  SCIP_CALL( generateCutNonConvex(scip, cons, violside, ref, coef, &lhs, &rhs, &islocal, &success, cutname) );
6703  }
6704  }
6705 
6706  /* cut should be one-sided, if any found */
6707  assert(!success || SCIPisInfinity(scip, -lhs) || SCIPisInfinity(scip, rhs));
6708 
6709  /* check if range of cut coefficients is ok
6710  * compute cut activity and violation in sol
6711  */
6712  maxcoef = 0.0; /* only for compiler */
6713  viol = 0.0; /* only for compiler */
6714  if( success )
6715  {
6716  SCIP_Real constant;
6717  SCIP_Real abscoef;
6718  SCIP_Real roundcoef;
6719  int mincoefidx;
6720  SCIP_Real refactivity;
6721  SCIP_Real refactivitylinpart;
6722 
6723  /* compute activity of linear part in sol, if required
6724  * it is required if we need to check or return cut efficacy, for some debug output below, and some assert
6725  * round almost integral coefficients in integers, since this will happen when adding coefs to row (see comments below)
6726  */
6727  refactivitylinpart = 0.0;
6728 #if !defined(SCIP_DEBUG)
6729  if( !SCIPisInfinity(scip, -minefficacy) || efficacy != NULL )
6730 #endif
6731  for( j = 0; j < consdata->nlinvars; ++j )
6732  /* Loose variable have the best bound as LP solution value.
6733  * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
6734  * When this happens, their LP solution value changes to 0.0!
6735  * So when calculating the row activity, we treat loose variable as if they were already column variables.
6736  */
6737  if( SCIPvarGetStatus(consdata->linvars[j]) != SCIP_VARSTATUS_LOOSE )
6738  refactivitylinpart += (SCIPisIntegral(scip, lincoefs[j]) ? SCIPround(scip, lincoefs[j]) : lincoefs[j]) * SCIPgetSolVal(scip, sol, consdata->linvars[j]);
6739 
6740  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
6741 
6742  constant = 0.0;
6743  do
6744  {
6745  refactivity = refactivitylinpart;
6746  mincoefidx = -1;
6747  mincoef = lincoefsmin;
6748  maxcoef = lincoefsmax;
6749 
6750  for( j = 0; j < consdata->nquadvars; ++j )
6751  {
6752  /* coefficients smaller than epsilon are rounded to 0.0 when added to row
6753  * further, coefficients very close to integral values are rounded to integers when added to LP
6754  * both cases can be problematic if variable value is very large (bad numerics)
6755  * thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible)
6756  * i.e., estimate coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x)
6757  * if required bound of x is not finite, then do nothing
6758  */
6759  roundcoef = SCIPround(scip, coef[j]);
6760  if( SCIPisEQ(scip, coef[j], roundcoef) && coef[j] != roundcoef ) /*lint !e777*/
6761  {
6762  SCIP_Real xbnd;
6763 
6764  var = consdata->quadvarterms[j].var;
6765  if( !SCIPisInfinity(scip, rhs) )
6766  if( islocal )
6767  xbnd = coef[j] > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
6768  else
6769  xbnd = coef[j] > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
6770  else
6771  if( islocal )
6772  xbnd = coef[j] > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
6773  else
6774  xbnd = coef[j] > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
6775 
6776  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
6777  {
6778  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g and add constant %g\n",
6779  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef[j], roundcoef, (coef[j]-roundcoef) * xbnd);
6780  constant += (coef[j]-roundcoef) * xbnd;
6781  coef[j] = roundcoef;
6782  }
6783  }
6784 
6785  if( coef[j] == 0.0 )
6786  continue;
6787 
6788  /* As above: When calculating the row activity, we treat loose variable as if they were already column variables. */
6789  if( SCIPvarGetStatus(consdata->quadvarterms[j].var) != SCIP_VARSTATUS_LOOSE )
6790  refactivity += coef[j] * SCIPgetSolVal(scip, sol, consdata->quadvarterms[j].var);
6791 
6792  abscoef = REALABS(coef[j]);
6793  if( abscoef < mincoef )
6794  {
6795  mincoef = abscoef;
6796  mincoefidx = j;
6797  }
6798  if( abscoef > maxcoef )
6799  maxcoef = abscoef;
6800  }
6801 
6802  if( maxcoef < mincoef )
6803  {
6804  /* if all coefficients are zero, then mincoef and maxcoef are still at their initial values
6805  * thus, skip cut generation if its boring
6806  */
6807  assert(maxcoef == 0.0); /*lint !e777 */
6808  assert(mincoef == SCIPinfinity(scip)); /*lint !e777 */
6809 
6810  if( !SCIPisFeasPositive(scip, lhs) && !SCIPisFeasNegative(scip, rhs) )
6811  {
6812  SCIPdebugMsg(scip, "skip cut for constraint <%s> since all coefficients are zero and it's always satisfied\n", SCIPconsGetName(cons));
6813  success = FALSE;
6814  }
6815  else
6816  {
6817  /* cut will cutoff node */
6818  }
6819 
6820  break;
6821  }
6822 
6823  if( maxcoef / mincoef > conshdlrdata->cutmaxrange )
6824  {
6825  SCIPdebugMsg(scip, "cut coefficients for constraint <%s> have very large range: mincoef = %g maxcoef = %g\n", SCIPconsGetName(cons), mincoef, maxcoef);
6826  if( mincoefidx >= 0 )
6827  {
6828  var = consdata->quadvarterms[mincoefidx].var;
6829  /* try to eliminate coefficient with minimal absolute value by weakening cut and try again
6830  * since we use local bounds, we need to make the row local if they are different from their global counterpart
6831  */
6832  if( ((coef[mincoefidx] > 0.0 && !SCIPisInfinity(scip, rhs)) || (coef[mincoefidx] < 0.0 && !SCIPisInfinity(scip, -lhs))) &&
6833  !SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
6834  {
6835  SCIPdebugMsg(scip, "eliminate coefficient %g for <%s> [%g, %g]\n", coef[mincoefidx], SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6836  constant += coef[mincoefidx] * SCIPvarGetLbLocal(var);
6837  coef[mincoefidx] = 0.0;
6838  islocal |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
6839  continue;
6840  }
6841  else if( ((coef[mincoefidx] < 0.0 && !SCIPisInfinity(scip, rhs)) || (coef[mincoefidx] > 0.0 && !SCIPisInfinity(scip, -lhs))) &&
6842  !SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6843  {
6844  SCIPdebugMsg(scip, "eliminate coefficient %g for <%s> [%g, %g]\n", coef[mincoefidx], SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
6845  constant += coef[mincoefidx] * SCIPvarGetUbLocal(var);
6846  coef[mincoefidx] = 0.0;
6847  islocal |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
6848  continue;
6849  }
6850  }
6851 
6852  SCIPdebugMsg(scip, "skip cut\n");
6853  success = FALSE;
6854  }
6855  break;
6856  }
6857  while( TRUE ); /*lint !e506 */
6858 
6859  if( !SCIPisInfinity(scip, -lhs) )
6860  {
6861  lhs -= constant;
6862  viol = lhs - refactivity;
6863  }
6864  if( !SCIPisInfinity(scip, rhs) )
6865  {
6866  rhs -= constant;
6867  viol = refactivity - rhs;
6868  }
6869  }
6870 
6871  if( success && SCIPisInfinity(scip, REALABS(lhs)) && SCIPisInfinity(scip, REALABS(rhs)) )
6872  {
6873  SCIPdebugMsg(scip, "skip cut for constraint <%s> because both sides are not finite: lhs = %g, rhs = %g\n", SCIPconsGetName(cons), lhs, rhs);
6874  success = FALSE;
6875  }
6876 
6877  /* check if reference point violates cut sufficiently */
6878  if( success )
6879  {
6880  rowefficacy = viol;
6881  switch( conshdlrdata->scaling )
6882  {
6883  case 'o' :
6884  break;
6885 
6886  case 'g' :
6887  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
6888  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too also we
6889  * use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium scaling) */
6890  rowefficacy /= MAX(1.0, maxcoef);
6891  break;
6892 
6893  case 's' :
6894  {
6895  SCIP_Real abslhs = REALABS(lhs);
6896 
6897  if( !SCIPisInfinity(scip, abslhs) )
6898  rowefficacy /= MAX(1.0, abslhs);
6899  else
6900  {
6901  SCIP_Real absrhs = REALABS(rhs);
6902 
6903  rowefficacy /= MAX(1.0, absrhs);
6904  }
6905 
6906  break;
6907  }
6908 
6909  default:
6910  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
6911  SCIPABORT();
6912  return SCIP_INVALIDDATA; /*lint !e527*/
6913  }
6914  }
6915 
6916  if( success && !SCIPisInfinity(scip, -minefficacy) && rowefficacy < minefficacy ) /*lint !e644*/
6917  {
6918  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), rowefficacy, minefficacy);
6919  success = FALSE;
6920  }
6921 
6922  /* generate row */
6923  if( success )
6924  {
6925  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, lhs, rhs, islocal && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
6926 
6927  /* add coefficients from linear part */
6928  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nlinvars, consdata->linvars, lincoefs) );
6929 
6930  /* add coefficients from quadratic part */
6931  assert(consdata->sepaquadvars != NULL || consdata->nquadvars == 0);
6932  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nquadvars, consdata->sepaquadvars, coef) );
6933 
6934  SCIPdebugMsg(scip, "found cut <%s>, lhs=%g, rhs=%g, mincoef=%g, maxcoef=%g, range=%g, nnz=%d, violation=%g, efficacy=%g\n",
6935  SCIProwGetName(*row), lhs, rhs,
6936  mincoef, maxcoef, maxcoef/mincoef,
6937  SCIProwGetNNonz(*row), viol, rowefficacy); /*lint !e414 */
6938 
6939  if( efficacy != NULL )
6940  {
6941  *efficacy = rowefficacy;
6942 
6943  /* check that our computed efficacy is > feastol, iff efficacy computed by row is > feastol
6944  * computing efficacy w.r.t. the LP solution makes only sense if the LP was solved to optimality (see bug 612)
6945  *
6946  * disabled these asserts as they can fail due to numerical reasons (cancelation when substracting big numbers),
6947  * as the order in which we add up the activity for the single terms can be different than the one that lp.c uses
6948  */
6949  /*
6950  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
6951  assert((conshdlrdata->scaling != 'g') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol)/MAX(1.0,SCIPgetRowMaxCoef(scip, *row)))));
6952  assert((conshdlrdata->scaling != 's') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol)/MAX(1.0,MIN(REALABS(lhs),REALABS(rhs))))));
6953  assert((conshdlrdata->scaling != 'o') || (SCIPisFeasPositive(scip, rowefficacy) == SCIPisFeasPositive(scip, -SCIPgetRowSolFeasibility(scip, *row, sol))));
6954  */
6955  }
6956  }
6957 
6958  SCIPfreeBufferArray(scip, &coef);
6959 
6960  /* if coefficients for linear variables are different than those in constraint, then free array */
6961  if( lincoefs != consdata->lincoefs )
6962  {
6963  SCIPfreeBufferArray(scip, &lincoefs);
6964  }
6965 
6966  return SCIP_OKAY;
6967 }
6968 
6969 /** computes eigen decomposition of A, where \f$ f(x) = x^T A x + b^T x \f$.
6970  *
6971  * The eigen decomposition is given by A = P D P^T, where D is diagonal formed by the eigenvalues and P is orthonormal
6972  * whose columns are the eigenvectors; we also compute b^T * P, in case one needs the change of variables P^T x = y <=>
6973  * x = P y We store P^T in an array, specifically, in consdata->eigenvectors we store P^T row-wise, i.e., the first row
6974  * of P^T is stored in eigenvector[0..n-1], the second row is stored in eigenvectors[n..2n-1], etc; equivalently, the
6975  * first eigenvector is eigenvector[0..n-1], the second one is eigenvectors[n..2n-1], etc.
6976  *
6977  * @todo: - at the moment of writing, checkCurvature computes the eigenvalues (and vectors) for determining curvature
6978  * when it can't to it via other considerations. so one could try to merge both methods together.
6979  * - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A' so one
6980  * could do better in terms of memory and speed. For instance, when the matrix is diagonal, the eigenvectors
6981  * are the identity matrix and the eigenvalues are readily available from the constraint, so one could adapt
6982  * the functions that uses the eigenvectors in this particular case. One could also think about storing the
6983  * eigenvectors in a sparse fashion, though eigenvectors are seldom sparse.
6984  */
6985 static
6987  SCIP* scip, /**< SCIP data structure */
6988  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6989  SCIP_CONS* cons /**< constraint */
6990  )
6991 {
6992  SCIP_CONSDATA* consdata;
6993  int n;
6994  int nn;
6995  int row;
6996  int col;
6997  int i;
6998  int j;
6999  double* matrix;
7000  SCIP_HASHMAP* var2index;
7001 
7002  SCIPdebugMsg(scip, "computing ED for cons %s\n", SCIPconsGetName(cons));
7003 
7004  assert(scip != NULL);
7005  assert(conshdlr != NULL);
7006  assert(cons != NULL);
7007 
7008  consdata = SCIPconsGetData(cons);
7009  assert(consdata != NULL);
7010 
7011  /* function has to be convex with finite rhs or concave with finite lhs */
7012  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
7013  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7014 
7015  /* can't compute eigenvectors without IPOPT */
7016  if( !SCIPisIpoptAvailableIpopt() )
7017  {
7018  consdata->isedavailable = FALSE;
7019  return SCIP_OKAY;
7020  }
7021 
7022  /* @todo: - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A'
7023  * so one could do better in terms of memory and speed
7024  * - if n too big don't compute SVD
7025  */
7026  n = consdata->nquadvars;
7027 
7028  /* do not compute eigendecomposition if n is too large */
7029  nn = n * n;
7030  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
7031  {
7032  SCIPdebugMsg(scip, "n is too large to compute eigendecomposition\n");
7033  consdata->isedavailable = FALSE;
7034  return SCIP_OKAY;
7035  }
7036 
7037  /* we just need to pass the upper triangle of A since it is symmetric; build it here */
7038  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvectors, nn) );
7039  matrix = consdata->eigenvectors;
7040  BMSclearMemoryArray(matrix, nn);
7041 
7042  /* @todo if we are called in solving stage (or late from initsol), we can avoid the hashmap by using sepabilinvar2pos */
7043  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
7044 
7045  for( i = 0; i < n; ++i )
7046  {
7047  SCIP_CALL( SCIPhashmapInsert(var2index, consdata->quadvarterms[i].var, (void*)(size_t)i) );
7048  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
7049 #ifdef DEBUG_PROJ
7050  printf("inserting in position %d, value %g\n", i*n + i, consdata->quadvarterms[i].sqrcoef);
7051 #endif
7052  }
7053 
7054  for( i = 0; i < consdata->nbilinterms; ++i )
7055  {
7056  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
7057  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
7058  row = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var1);
7059  col = (int)(size_t)SCIPhashmapGetImage(var2index, consdata->bilinterms[i].var2);
7060  if( row < col )
7061  {
7062  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
7063 #ifdef DEBUG_PROJ
7064  printf("inserting in position %d, value %g\n", row*n + col, consdata->bilinterms[i].coef/2);
7065 #endif
7066  }
7067  else
7068  {
7069  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
7070 #ifdef DEBUG_PROJ
7071  printf("inserting in position %d, value %g\n", col*n + row, consdata->bilinterms[i].coef/2);
7072 #endif
7073  }
7074  }
7075 
7076 #ifdef DEBUG_PROJ
7077  printf("matrix built:\n");
7078  for( i = 0; i < n; i++ )
7079  {
7080  for( j = 0; j < n; j++ )
7081  printf("%g ", matrix[i*n + j]);
7082  printf("\n");
7083  }
7084 #endif
7085 
7086  /* compute eigenvalues and eigenvectors */
7087  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvalues, n) );
7088 
7089  if( LapackDsyev(TRUE, n, matrix, consdata->eigenvalues) != SCIP_OKAY )
7090  {
7091  SCIPdebugMsg(scip, "couldn't compute ED for cons %s\n", SCIPconsGetName(cons));
7092  consdata->isedavailable = FALSE;
7093  }
7094  else
7095  {
7096  consdata->isedavailable = TRUE;
7097 
7098  /* compute b^T*P */
7099  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &consdata->bp, n) );
7100  for( i = 0; i < n; i++ )
7101  for( j = 0; j < n; j++ )
7102  consdata->bp[i] += consdata->quadvarterms[j].lincoef * matrix[i*n + j];
7103 
7104 #ifdef DEBUG_PROJ
7105  printf("eigenvalues:\n");
7106  for( j = 0; j < n; j++ )
7107  printf("%g ", consdata->eigenvalues[j]);
7108 
7109  printf("\neigenvectors (P^T):\n");
7110  for( i = 0; i < n; i++ )
7111  {
7112  for( j = 0; j < n; j++ )
7113  printf("%g ", matrix[i*n + j]);
7114  printf("\n");
7115  }
7116 
7117  printf("b*P^T:\n");
7118  for( j = 0; j < n; j++ )
7119  printf("%g ", consdata->bp[j]);
7120  printf("svd computed successfully\n");
7121 #endif
7122  }
7123 
7124 
7125  SCIPhashmapFree(&var2index);
7126 
7127  return SCIP_OKAY;
7128 }
7129 
7130 /** computes an interior point for the quadratic part of the convex constraint
7131  *
7132  * There are different methods for computing the interior point
7133  * - 'a'ny: solves min 0, f(x) <= rhs, x in bounds
7134  * - 'm'ost interior: solves min f(x), x in bounds
7135  *
7136  * @todo: other methods for computing an interior point?
7137  */
7138 static
7140  SCIP* scip, /**< SCIP data structure */
7141  SCIP_CONS* cons, /**< constraint */
7142  char method, /**< method for computing interior point ('a' any point, 'm'ost interior) */
7143  SCIP_Bool* success /**< buffer to store if an interior point was found */
7144  )
7145 {
7146  SCIP_CONSDATA* consdata;
7147  SCIP_QUADELEM* nlrowquadelems;
7148  SCIP_NLPIPROBLEM* prob;
7149  SCIP_NLPI* nlpi;
7150  SCIP_Real* interiorpoint;
7151  SCIP_Real* lbs;
7152  SCIP_Real* ubs;
7153  SCIP_Real* lincoefs;
7154  SCIP_Real nlpiside;
7155  char probname[SCIP_MAXSTRLEN];
7156  int* lininds;
7157  int nlrownquadelems;
7158  int nquadvars;
7159  int i;
7160 
7161  assert(scip != NULL);
7162  assert(cons != NULL);
7163 
7164  assert(success != NULL);
7165  *success = FALSE;
7166 
7167  consdata = SCIPconsGetData(cons);
7168  assert(consdata != NULL);
7169 
7170  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
7171  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7172 
7173  /* need an NLP solver */
7174  if( SCIPgetNNlpis(scip) == 0 )
7175  return SCIP_OKAY;
7176 
7177  nlpi = NULL;
7178  prob = NULL;
7179  lbs = NULL;
7180  ubs = NULL;
7181  lincoefs = NULL;
7182  lininds = NULL;
7183 
7184 #ifdef SCIP_DEBUG_INT
7185  SCIPinfoMessage(scip, NULL, "Computing interior point for\n");
7186  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7187  SCIPinfoMessage(scip, NULL, ";\n");
7188 #endif
7189 
7190  /* in the convex case, we try to find an interior point of x^T A x + b^T x <= rhs - maximum activity linear part
7191  * in the concave case: lhs - minimum activity linear part <= x^T A x + b^T x; we compute activities ourselves,
7192  * since consdata->max(min)linactivity are only computed when lhs (rhs) is finite and this not always holds
7193  */
7194  if( consdata->isconvex )
7195  {
7196  /* compute maximum activity */
7197  nlpiside = 0;
7198  for( i = 0; i < consdata->nlinvars; ++i )
7199  {
7200  if( consdata->lincoefs[i] >= 0.0 )
7201  {
7202  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i]) ) )
7203  nlpiside = SCIPinfinity(scip);
7204  else
7205  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7206  }
7207  else
7208  {
7209  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i]) ) )
7210  nlpiside = SCIPinfinity(scip);
7211  else
7212  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7213  }
7214 
7215  if( SCIPisInfinity(scip, nlpiside) )
7216  {
7217  SCIPdebugMsg(scip, "maximum activity is infinity: there is no interior point for fun <= rhs - maxlinactivity!\n");
7218  return SCIP_OKAY;
7219  }
7220  }
7221 
7222  if( consdata->nlinvars == 0 )
7223  nlpiside = INTERIOR_EPS;
7224 
7225  nlpiside = consdata->rhs - nlpiside;
7226  }
7227  else
7228  {
7229  /* compute minimum activity */
7230  nlpiside = 0;
7231  for( i = 0; i < consdata->nlinvars; ++i )
7232  {
7233  if( consdata->lincoefs[i] >= 0.0 )
7234  {
7235  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
7236  nlpiside = -SCIPinfinity(scip);
7237  else
7238  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7239  }
7240  else
7241  {
7242  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
7243  nlpiside = -SCIPinfinity(scip);
7244  else
7245  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7246  }
7247 
7248  if( SCIPisInfinity(scip, -nlpiside) )
7249  {
7250  SCIPdebugMsg(scip, "minimum activity is -infinity: there is no interior point for fun >= lhs - minlinactivity!\n");
7251  return SCIP_OKAY;
7252  }
7253  }
7254 
7255  if( consdata->nlinvars == 0 )
7256  nlpiside = INTERIOR_EPS;
7257 
7258  nlpiside = consdata->lhs - nlpiside;
7259  }
7260 
7261  nquadvars = consdata->nquadvars;
7262 
7263  /* if we are looking for any interior point and the 0 is one, then use it */
7264  if( method == 'a' && ((consdata->isconvex && SCIPisGE(scip, nlpiside, 0.0))
7265  || (consdata->isconcave && SCIPisLE(scip, nlpiside, 0.0))) )
7266  {
7267  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
7268 
7269  *success = TRUE;
7270  goto TERMINATE;
7271  }
7272 
7273  /* build nlrow */
7274  if( consdata->nlrow == NULL )
7275  {
7276  SCIP_CALL( createNlRow(scip, cons) );
7277  assert(consdata->nlrow != NULL);
7278  }
7279 
7280  nlpi = SCIPgetNlpis(scip)[0];
7281  assert(nlpi != NULL);
7282 
7283  /* initializing the subproblem */
7284  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_subquad", SCIPgetProbName(scip));
7285  SCIP_CALL( SCIPnlpiCreateProblem(nlpi, &prob, probname) );
7286  assert(prob != NULL);
7287 
7288 #ifdef SCIP_DEBUG_INT
7290 #endif
7291  /* TODO: maybe one should set some generous iteration limit and/or a timelimit (remaining scip solve time)? */
7292 
7293  /* ask for memory to store data needed to create vars and linear coefficients */
7294  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nquadvars) );
7295  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nquadvars) );
7296  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nquadvars) );
7297  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nquadvars) );
7298 
7299  /* get bounds and linear coefficients */
7300  for( i = 0; i < nquadvars; i++ )
7301  {
7302  lbs[i] = SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
7303  ubs[i] = SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
7304 
7305  lincoefs[i] = consdata->quadvarterms[i].lincoef;
7306  lininds[i] = i;
7307  }
7308 
7309  /* add vars */
7310  SCIP_CALL( SCIPnlpiAddVars(nlpi, prob, nquadvars, lbs, ubs, NULL) );
7311 
7312  /* get nlrow info */
7313  nlrownquadelems = SCIPnlrowGetNQuadElems(consdata->nlrow);
7314  nlrowquadelems = SCIPnlrowGetQuadElems(consdata->nlrow);
7315 
7316 #ifndef NDEBUG
7317  {
7318  SCIP_VAR** nlrowquadvars;
7319 
7320  nlrowquadvars = SCIPnlrowGetQuadVars(consdata->nlrow);
7321  for( i = 0; i < nlrownquadelems; i++ )
7322  {
7323  assert(nlrowquadvars[nlrowquadelems[i].idx1] == consdata->quadvarterms[nlrowquadelems[i].idx1].var);
7324  assert(nlrowquadvars[nlrowquadelems[i].idx2] == consdata->quadvarterms[nlrowquadelems[i].idx2].var);
7325  }
7326  }
7327 #endif
7328 
7329  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
7330 
7331  switch( method )
7332  {
7333  case 'a':
7334  /* add constraint */
7335  if( consdata->isconvex )
7336  {
7337  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, NULL, &nlpiside, &nquadvars, &lininds, &lincoefs,
7338  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
7339  }
7340  else
7341  {
7342  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, &nlpiside, NULL, &nquadvars, &lininds, &lincoefs,
7343  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
7344  }
7345  break;
7346 
7347  case 'm':
7348  /* add objective */
7349  if( consdata->isconvex )
7350  {
7351  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
7352  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
7353  }
7354  else
7355  {
7356  /* NLPI assumes minimization: change signs */
7357  for( i = 0; i < nquadvars; i++ )
7358  lincoefs[i] *= -1;
7359 
7360  /* WARNING: this pointer is not ours, information should be restored! */
7361  for( i = 0; i < nlrownquadelems; i++ )
7362  nlrowquadelems->coef *= -1;
7363 
7364  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
7365  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
7366 
7367  /* WARNING: restore information! */
7368  for( i = 0; i < nlrownquadelems; i++ )
7369  nlrowquadelems->coef *= -1;
7370  }
7371  break;
7372 
7373  default:
7374  SCIPerrorMessage("undefined method for computing interior point: %c\n", method);
7375  return SCIP_INVALIDDATA;
7376  }
7377 
7378  /* solve NLP problem */
7379  SCIP_CALL( SCIPnlpiSolve(nlpi, prob) );
7380 
7381  /* check termination status */
7382  if( SCIPnlpiGetTermstat(nlpi, prob) != SCIP_NLPTERMSTAT_OKAY )
7383  {
7384  SCIPdebugMsg(scip, "cons <%s>: NLP Solver termination status not okay: %d\n",
7385  SCIPconsGetName(cons), SCIPnlpiGetTermstat(nlpi, prob));
7386  *success = FALSE;
7387  goto TERMINATE;
7388  }
7389 
7390  /* check solution status */
7391  switch( SCIPnlpiGetSolstat(nlpi, prob) )
7392  {
7396  /* fallthrough */
7397  SCIPdebugMsg(scip, "cons <%s>: found an interior point. solution status: %d, termination status: %d\n",
7398  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7399  break;
7400 
7403  /* fallthrough */
7404  /* TODO: we could still use the point, and let evaluateGauge decide whether the point is interior or not */
7405  SCIPdebugMsg(scip, "cons <%s>: failed to find an interior point. solution status: %d, termination status: %d\n",
7406  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7407  goto TERMINATE;
7408 
7411  default:
7412  /* fallthrough */
7413  SCIPerrorMessage("cons <%s>: undefined behaviour of NLP Solver. solution status: %d, termination status: %d\n",
7414  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7415  SCIPABORT();
7416  goto TERMINATE; /*lint !e527*/
7417  }
7418 
7419  /* fetch solution
7420  * note: nlpiGetSolution (at least for IPOPT) makes interiorpoint point to the internal solution stored in the
7421  * nlpi problem data structure; we need to copy it here because it will be destroyed once the problem is free'd
7422  */
7423  SCIP_CALL( SCIPnlpiGetSolution(nlpi, prob, &interiorpoint, NULL, NULL, NULL) );
7424 
7425  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
7426 
7427  for( i = 0; i < nquadvars; i++ )
7428  {
7429  if( SCIPisFeasZero(scip, interiorpoint[i]) )
7430  consdata->interiorpoint[i] = 0.0;
7431  else
7432  consdata->interiorpoint[i] = interiorpoint[i];
7433  }
7434 
7435  *success = TRUE;
7436 
7437 TERMINATE:
7438 
7439 #ifdef SCIP_DEBUG_INT
7440  printf("Computation of interior point for cons <%s>:\n", SCIPconsGetName(cons));
7441  printf(" - has %d linear variables\n", consdata->nlinvars);
7442  if( consdata->isconvex )
7443  {
7444  printf(" - is convex. rhs: %g maximum activity of linear variables: %g\n", consdata->rhs, consdata->rhs - nlpiside);
7445  printf(" - searched for point whose quadratic part is <= %g\n", nlpiside);
7446  }
7447  else
7448  {
7449  printf(" - is concave. lhs: %g minimum activity of linear variables: %g\n", consdata->lhs, consdata->lhs - nlpiside);
7450  printf(" - searched for point whose quadratic part is >= %g\n", nlpiside);
7451  }
7452 
7453  if( *success )
7454  {
7455  if( prob == NULL )
7456  {
7457  printf("Computation successful, 0 is interior point.\n");
7458  for( i = 0; i < nquadvars; i++ )
7459  {
7460  assert(consdata->interiorpoint[i] == 0.0);
7461  }
7462  }
7463  else
7464  {
7465  printf("Computation successful, NLP soltat: %d, termstat: %d\nPoint found:\n",
7466  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7467  for( i = 0; i < nquadvars; i++ )
7468  {
7469  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[i].var), consdata->interiorpoint[i]);
7470  }
7471  }
7472  }
7473  else
7474  {
7475  printf("Computation failed. NLP soltat: %d, termstat: %d\n",
7476  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
7477  printf("run with SCIP_DEBUG for more info\n");
7478  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7479  SCIPinfoMessage(scip, NULL, ";\n");
7480  /* FIXME: instance camshape100 says that there is no interior point (interior empty)
7481  * is there something intelligent that can be said?
7482  */
7483  }
7484 #endif
7485 
7486  /* free memory */
7487  SCIPfreeBufferArrayNull(scip, &lbs);
7488  SCIPfreeBufferArrayNull(scip, &ubs);
7489  SCIPfreeBufferArrayNull(scip, &lininds);
7490  SCIPfreeBufferArrayNull(scip, &lincoefs);
7491 
7492  if( prob != NULL )
7493  {
7494  SCIP_CALL( SCIPnlpiFreeProblem(nlpi, &prob) );
7495  }
7496 
7497  return SCIP_OKAY;
7498 }
7499 
7500 /** compute gauge function of the set \f$S - s_0\f$ where \f$ S = \{ x : f(x) \le c \}\f$ and \f$ s_0 \in \mathring S\f$.
7501  *
7502  * Here, \f$ f(x) \f$ is a purely quadratic (i.e, all \f$x\f$ variables appear in a bilinear or quadratic term).
7503  * Explicitly, \f$ f(x) = \pm x^T A x \pm b^T x \f$ depending whether \f$A\f$
7504  * is positive semidefinite (+) or negative semidefinite (-).
7505  * The constant \f$c\f$ is rhs - maximum activity of the purely linear part of the constraint
7506  * if \f$A \succeq 0\f$ and minimum activity - lhs if \f$A \preceq 0\f$.
7507  * This is computed only at INITSOL.
7508  *
7509  * The method does:
7510  * 1. compute interior point
7511  * 2. compute gauge function
7512  */
7513 static
7515  SCIP* scip, /**< SCIP data structure */
7516  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7517  SCIP_CONS* cons /**< constraint */
7518  )
7519 {
7520  SCIP_CONSHDLRDATA* conshdlrdata;
7521  SCIP_CONSDATA* consdata;
7522  SCIP_QUADVARTERM* quadvarterm;
7523  SCIP_BILINTERM* bilinterm;
7524  SCIP_Bool success;
7525  SCIP_Bool convex;
7526  int i;
7527  int j;
7528 
7529  assert(scip != NULL);
7530  assert(conshdlr != NULL);
7531  assert(cons != NULL);
7532 
7533  consdata = SCIPconsGetData(cons);
7534  assert(consdata != NULL);
7535 
7536  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7537  assert(conshdlrdata != NULL);
7538  assert(conshdlrdata->gaugecuts);
7539 
7540  /* function has to be convex with finite rhs or concave with finite lhs */
7541  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
7542  assert(convex || (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7543 
7544  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
7545 
7546  /* 1. */
7547  SCIP_CALL( computeInteriorPoint(scip, cons, conshdlrdata->interiorcomputation, &success) );
7548 
7549  /* if success, compute gaugecoefs (b_gauge) and gaugeconst (c_gauge) */
7550  if( !success )
7551  {
7552  SCIPdebugMsg(scip, "failed to compute gauge function\n");
7553  consdata->isgaugeavailable = FALSE;
7554  return SCIP_OKAY;
7555  }
7556 
7557  /* 2.
7558  * we are going to evaluate the function at interiorpoint; so, we need to compute interiorpoint^T A interiorpoint;
7559  * therefore, we need a mechanism that for a given variable, it returns its interior point value
7560  * fortunately, sepabilinvar2pos in consdata gives us all the information that we need
7561  */
7562 
7563  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->gaugecoefs), consdata->nquadvars) );
7564 
7565  /* compute value of quadratic part at interior point, build map and compute gaugeconst (c_gauge) */
7566  consdata->interiorpointval = 0;
7567  consdata->gaugeconst = 0;
7568  for( i = 0; i < consdata->nquadvars; i++ )
7569  {
7570  SCIP_Real val;
7571  SCIP_Real val2;
7572 
7573  val = consdata->interiorpoint[i];
7574  quadvarterm = &consdata->quadvarterms[i];
7575 
7576  consdata->interiorpointval += (quadvarterm->lincoef + quadvarterm->sqrcoef * val) * val;
7577  consdata->gaugeconst += quadvarterm->sqrcoef * val * val;
7578 
7579  for( j = 0; j < quadvarterm->nadjbilin; ++j )
7580  {
7581  int bilintermidx;
7582 
7583  bilintermidx = quadvarterm->adjbilin[j];
7584  bilinterm = &consdata->bilinterms[bilintermidx];
7585 
7586  if( bilinterm->var1 != quadvarterm->var )
7587  continue;
7588 
7589  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
7590  assert(consdata->sepabilinvar2pos != NULL); /* this should have been computed in INITSOL */
7591  assert(consdata->quadvarterms[consdata->sepabilinvar2pos[bilintermidx]].var == bilinterm->var2);
7592 
7593  val2 = consdata->interiorpoint[consdata->sepabilinvar2pos[bilintermidx]];
7594 
7595  consdata->interiorpointval += bilinterm->coef * val * val2;
7596  consdata->gaugeconst += bilinterm->coef * val * val2;
7597  }
7598  }
7599 
7600  /* compute gaugecoefs (b_gauge = b + 2 * A * interiorpoint) */
7601  for( i = 0; i < consdata->nquadvars; i++ )
7602  {
7603  quadvarterm = &consdata->quadvarterms[i];
7604  consdata->gaugecoefs[i] += quadvarterm->lincoef + 2.0 * quadvarterm->sqrcoef * consdata->interiorpoint[i];
7605 
7606  for( j = 0; j < quadvarterm->nadjbilin; j++ )
7607  {
7608  int varpos;
7609  int bilintermidx;
7610 
7611  bilintermidx = quadvarterm->adjbilin[j];
7612  bilinterm = &consdata->bilinterms[bilintermidx];
7613 
7614  if( bilinterm->var1 == quadvarterm->var )
7615  {
7616  varpos = consdata->sepabilinvar2pos[bilintermidx];
7617 
7618  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
7619  assert(consdata->quadvarterms[varpos].var == bilinterm->var2);
7620 
7621  consdata->gaugecoefs[i] += bilinterm->coef * consdata->interiorpoint[varpos];
7622  consdata->gaugecoefs[varpos] += bilinterm->coef * consdata->interiorpoint[i];
7623  }
7624  }
7625  }
7626 
7627 #ifdef SCIP_DEBUG_INT
7628  printf("quadratic part at interior point: %g\n", consdata->interiorpointval);
7629 
7630  for( j = 0; j < consdata->nquadvars; j++ )
7631  {
7632  printf("b_gauge[%s] = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), consdata->gaugecoefs[j]);
7633  }
7634  printf("c_gauge = %g\n", consdata->gaugeconst);
7635 #endif
7636 
7637  SCIPdebugMsg(scip, "gauge function computed successfully\n");
7638  consdata->isgaugeavailable = TRUE;
7639 
7640  return SCIP_OKAY;
7641 }
7642 
7643 /** evaluates gauge function of the set \f$S - s_0\f$ where \f$ S = \{ x : f(x) \le c \}\f$ and \f$ s_0 \in \mathring S\f$.
7644  *
7645  * \f$ S = \{ x : f(x) \le c \}\f$ at \f$sol - s_0\f$;
7646  * see computeGauge() for more details
7647  *
7648  * @todo Think about if user should tell that function is convex or ...
7649  */
7650 static
7652  SCIP* scip, /**< SCIP data structure */
7653  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7654  SCIP_CONS* cons, /**< constraint */
7655  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
7656  SCIP_Real* gaugeval, /**< buffer to store the value of the gauge function */
7657  SCIP_Bool* success /**< buffer to store if evaluation was successful */
7658  )
7659 {
7660  SCIP_CONSDATA* consdata;
7661  SCIP_Real side;
7662  SCIP_Real aterm;
7663  SCIP_Real bterm;
7664  SCIP_Real cterm;
7665  SCIP_Bool convex;
7666  int i;
7667 
7668  assert(scip != NULL);
7669  assert(conshdlr != NULL);
7670  assert(cons != NULL);
7671 
7672  consdata = SCIPconsGetData(cons);
7673  assert(consdata != NULL);
7674  assert(consdata->isgaugeavailable);
7675 
7676  *success = FALSE;
7677 
7678  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
7679 
7680  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
7681 
7682  /* evaluate gauge function at x0 = (refsol - interior point)
7683  *
7684  * compute aterm = side - function(interior point)
7685  */
7686  if( convex )
7687  {
7688  side = consdata->rhs;
7689  for( i = 0; i < consdata->nlinvars; i++ )
7690  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
7691 
7692  aterm = side - consdata->interiorpointval;
7693 
7694  /* it can happen that the interior point is not really interior, since we are not so strict at the moment of
7695  * computing the interior point, which makes sense in the case that the constraint is quadratic <= linear expr,
7696  * since we compute a point in quadratic <= min linear expr and it might be that this set consists of a single
7697  * point which will not be interior. furthermore, if this set is empty, we could just take any point and it could
7698  * happen that for some value of linear expr, the point is actually interior, but for many it could not be.
7699  * also, if min linear expr = -infinity, we might have computed an interior point using some finite value.
7700  * the point will not be an interior point, if and only if aterm is negative.
7701  */
7702 #ifdef SCIP_DEBUG_GAUGE
7703  if( SCIPisLE(scip, aterm, 0.0) )
7704  {
7705  printf("For current level, there is no interior point. ");
7706  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
7707  if( consdata->nlinvars == 1 )
7708  {
7709  SCIP_VAR* var;
7710 
7711  var = consdata->linvars[0];
7712  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
7713  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7714  }
7715  }
7716  else
7717  {
7718  printf("For current level, there is interior point. ");
7719  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
7720  }
7721 #endif
7722  if( !SCIPisPositive(scip, aterm) )
7723  {
7724  *gaugeval = -1.0;
7725  return SCIP_OKAY;
7726  }
7727  }
7728  else
7729  {
7730  side = consdata->lhs;
7731  for( i = 0; i < consdata->nlinvars; i++ )
7732  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
7733 
7734  aterm = side - consdata->interiorpointval;
7735 
7736 #ifdef SCIP_DEBUG_GAUGE
7737  if( SCIPisGE(scip, aterm, 0.0) )
7738  {
7739  printf("For current level, there is no interior point. ");
7740  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
7741  if( consdata->nlinvars == 1 )
7742  {
7743  SCIP_VAR* var;
7744 
7745  var = consdata->linvars[0];
7746  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
7747  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7748  }
7749  }
7750  else
7751  {
7752  printf("For current level, there is interior point. ");
7753  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
7754  }
7755 #endif
7756  if( !SCIPisNegative(scip, aterm) )
7757  {
7758  *gaugeval = -1.0;
7759  return SCIP_OKAY;
7760  }
7761  }
7762 
7763  /* compute bterm = b_gauge^T * refsol - f(interiorpoint) - c_gauge
7764  * compute cterm = f(refsol) - b_gauge^T * refsol + c_gauge */
7765  bterm = -consdata->interiorpointval - consdata->gaugeconst;
7766  cterm = consdata->gaugeconst;
7767  for( i = 0; i < consdata->nquadvars; i++ )
7768  {
7769  SCIP_Real val;
7770 
7771  val = SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var);
7772  bterm += consdata->gaugecoefs[i] * val;
7773  cterm -= consdata->gaugecoefs[i] * val;
7774  cterm += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val) * val;
7775  }
7776 
7777  for( i = 0; i < consdata->nbilinterms; i++ )
7778  {
7779  SCIP_VAR* var1;
7780  SCIP_VAR* var2;
7781 
7782  var1 = consdata->bilinterms[i].var1;
7783  var2 = consdata->bilinterms[i].var2;
7784  cterm += consdata->bilinterms[i].coef * SCIPgetSolVal(scip, refsol, var1) * SCIPgetSolVal(scip, refsol, var2);
7785  }
7786 
7787  /* now compute gauge */
7788  if( convex && cterm < 0.0 )
7789  {
7790  assert(SCIPisZero(scip, cterm));
7791  cterm = 0.0;
7792  }
7793  else if( !convex && cterm > 0.0 )
7794  {
7795  assert(SCIPisZero(scip, cterm));
7796  cterm = 0.0;
7797  }
7798  assert(bterm*bterm + 4*aterm*cterm >= 0);
7799 
7800  if( convex )
7801  {
7802  *gaugeval = bterm + sqrt(bterm*bterm + 4 * aterm * cterm);
7803  *gaugeval = *gaugeval / (2 * aterm);
7804  }
7805  else
7806  {
7807  *gaugeval = bterm - sqrt(bterm*bterm + 4 * aterm * cterm);
7808  *gaugeval = *gaugeval / (2 * aterm);
7809  }
7810  assert(!SCIPisNegative(scip, *gaugeval));
7811  *success = TRUE;
7812 
7813 #ifdef SCIP_DEBUG_GAUGE
7814  printf("Gauge's aterm = %g, bterm = %g, cterm = %g\n", aterm, bterm, cterm);
7815 #endif
7816  return SCIP_OKAY;
7817 }
7818 
7819 /** compute projection of refsol onto feasible region of cons; stores the projection in ref
7820  *
7821  * This method solves
7822  * \f[
7823  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x \le c \}
7824  * \f]
7825  * where \f$ \bar x \f$ is refsol.
7826  * Note that \f$ \bar x \f$ is not feasible, so the optimal solution actually satisfies
7827  * \f[
7828  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x = c \}
7829  * \f]
7830  * Using the eigendecomposition \f$ A = P D P^T \f$, the change of variables \f$ y = P^T x
7831  * \f$ and the optimality conditions, this reduces to finding \f$ \rho \f$ such that
7832  * \f[
7833  * y(\rho) = (I + \rho D)^{-1} (\bar y - \rho \bar b)
7834  * \f]
7835  * makes the constraint active. In the previous formula, \f$ \bar y = P^T \bar x\f$ and \f$ \bar b = P^T b \f$. If \f$
7836  * D \neq 0 \f$, the function
7837  * \f[
7838  * \varphi(\rho) := y(\rho)^T D y(\rho) + 2 \bar b^T y(\rho) - c
7839  * \f]
7840  * is strictly convex. So this method actually computes the unique 0 of this function using Newton's method.
7841  */
7842 static
7844  SCIP* scip, /**< SCIP data structure */
7845  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7846  SCIP_CONS* cons, /**< constraint */
7847  SCIP_SOL* refsol, /**< the given point to project, or NULL if LP solution should be used */
7848  SCIP_Real* ref /**< array to store reference point */
7849  )
7850 {
7851  SCIP_CONSDATA* consdata;
7852  SCIP_Real* pt; /* stores P^T */
7853  SCIP_Real* bp;
7854  SCIP_Real* D;
7855  SCIP_Real* y0_;
7856  SCIP_Real* yrho;
7857  SCIP_Real* yrhoprime;
7858  SCIP_Real c;
7859  SCIP_Real c1;
7860  SCIP_Real c2;
7861  SCIP_Real rho;
7862  SCIP_Real phirho;
7863  SCIP_Real phirhoprime;
7864  SCIP_Bool isconcave;
7865  int iter;
7866  int i;
7867  int j;
7868  int n;
7869 
7870  assert(scip != NULL);
7871  assert(conshdlr != NULL);
7872  assert(cons != NULL);
7873 
7874  consdata = SCIPconsGetData(cons);
7875  assert(consdata != NULL);
7876  assert(consdata->isedavailable);
7877 
7878  SCIPdebugMessage("computing projection\n");
7879 
7880  /* get the data we need */
7881  pt = consdata->eigenvectors;
7882  D = consdata->eigenvalues;
7883  n = consdata->nquadvars;
7884  bp = consdata->bp;
7885  c = consdata->rhs;
7886  c1 = 0;
7887  c2 = 0;
7888  for( i = 0; i < consdata->nlinvars; i++ )
7889  {
7890  c1 += consdata->lincoefs[i] * SCIPgetSolVal(scip, refsol, consdata->linvars[i]);
7891  c2 -= consdata->lincoefs[i] * consdata->lincoefs[i];
7892  }
7893  c2 /= 2.0;
7894 
7895  /* determine if convex or concave */
7896  isconcave = consdata->isconcave;
7897  assert((isconcave && !SCIPisInfinity(scip, -consdata->lhs)) || !SCIPisInfinity(scip, consdata->rhs));
7898 
7899  SCIP_CALL( SCIPallocClearBufferArray(scip, &y0_, n) );
7900  SCIP_CALL( SCIPallocBufferArray(scip, &yrho, n) );
7901  SCIP_CALL( SCIPallocBufferArray(scip, &yrhoprime, n) );
7902 
7903  /* change data if function is concave */
7904  if( isconcave )
7905  {
7906  c = -consdata->lhs;
7907  c1 = - c1;
7908  for( i = 0; i < n; i++ )
7909  {
7910  D[i] = -D[i];
7911  bp[i] = -bp[i];
7912  }
7913  }
7914 
7915  /* change coordinates: compute y(0) = x_0' * P */
7916  for( i = 0; i < n; i++ )
7917  for( j = 0; j < n; j++ )
7918  y0_[i] += SCIPgetSolVal(scip, refsol, consdata->quadvarterms[j].var) * pt[i*n + j];
7919 
7920 #ifdef DEBUG_PROJ
7921  /* debug output */
7922  printf("\nP^T:\n");
7923  for( i = 0; i < n; i++ )
7924  {
7925  for( j = 0; j < n; j++ )
7926  printf("%g ", pt[i*n + j]);
7927  printf("\n");
7928  }
7929  printf("x_0: ");
7930  for( i = 0; i < n; i++ )
7931  printf("%g ", SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var));
7932  printf("\n");
7933  printf("P^T x_0: ");
7934  for( i = 0; i < n; i++ )
7935  printf("%g ", y0_[i]);
7936  printf("\n");
7937  printf("P^T b: ");
7938  for( i = 0; i < n; i++ )
7939  printf("%g ", bp[i]);
7940  printf("\n");
7941  printf("<d,linvars> = %g\n", c1);
7942  printf("-norm(d)^2/2 = %g\n", c2);
7943 #endif
7944 
7945  /* perform newton's method: rho^+ = rho - phi(rho)/phi'(rho) */
7946  rho = 0.0;
7947  phirho = c;
7948  phirhoprime = 1.0;
7949  for( iter = 0; iter < 9; iter++ )
7950  {
7951  assert(phirhoprime != 0.0);
7952  rho = rho - (phirho - c)/ phirhoprime;
7953 
7954  /* compute phi(rho) and phi'(rho):
7955  * note that formulas were deduced for constraints of the form x' A x + 2 b x, so we use b/2 in the formulas:
7956  * c1 = <lin_coefs, sol_lin_vars>
7957  * c2 = - norm(lin_coefs)^2/2
7958  * y(rho) = (I + rho * D)^-1 * (y(0) - rho * bp/2)
7959  * y'(rho) = -(I + rho * D)^-2 * (D y(0) + bp/2)
7960  * phi(rho) = <y(rho), D * y(rho) + pb> + c1 + c2*rho
7961  * phi'(rho) = <y'(rho), 2 * D * y(rho) + pb> + c2
7962  */
7963  phirho = 0.0;
7964  phirhoprime = 0.0;
7965  for( i = 0; i < n; i++ )
7966  {
7967  assert(1.0 + rho * D[i] != 0.0);
7968  yrho[i] = (y0_[i] - rho * bp[i]/2.0) / (1.0 + rho * D[i]);
7969  yrhoprime[i] = -(D[i] * y0_[i] + bp[i]/2.0) / ( (1.0 + rho * D[i])*(1.0 + rho * D[i]) );
7970  phirho += yrho[i] * (yrho[i] * D[i] + bp[i]);
7971  phirhoprime += yrhoprime[i] * (2 * D[i] * yrho[i] + bp[i]);
7972  }
7973  phirho += c2 * rho + c1;
7974  phirhoprime += c2;
7975 #ifdef DEBUG_PROJ
7976  printf("iteration %d: rho = %g, phirho = %g, phirho' = %g\n", iter, rho, phirho, phirhoprime);
7977 #endif
7978  }
7979 
7980  /* come back to the original coordinates: new ref point is P*yrho */
7981  for( i = 0; i < n; i++ )
7982  {
7983  ref[i] = 0.0;
7984 
7985  for( j = 0; j < n; j++ )
7986  ref[i] += pt[j*n + i] * yrho[j];
7987  }
7988 
7989  /* change data back if function is concave */
7990  if( isconcave )
7991  {
7992  for( i = 0; i < n; i++ )
7993  {
7994  D[i] = -D[i];
7995  bp[i] = -bp[i];
7996  }
7997  }
7998 
7999 #ifdef SCIP_DISABLED_CODE
8000  /* project onto bounds; this is important for some cut generation methods such as generateCutLTI */
8001  for( j = 0; j < consdata->nquadvars; ++j )
8002  {
8003  SCIP_Real lb;
8004  SCIP_Real ub;
8005  SCIP_VAR* var;
8006 
8007  var = consdata->quadvarterms[j].var;
8008  lb = SCIPvarGetLbLocal(var);
8009  ub = SCIPvarGetUbLocal(var);
8010  /* do not like variables at infinity */
8011  assert(!SCIPisInfinity(scip, lb));
8012  assert(!SCIPisInfinity(scip, -ub));
8013 
8014  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8015  }
8016 #endif
8017 
8018 #ifdef DEBUG_PROJ
8019  printf("modified reference point by a projection:\n");
8020  for( j = 0; j < consdata->nquadvars; ++j )
8021  {
8022  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
8023  }
8024 #endif
8025 
8026  SCIPfreeBufferArray(scip, &y0_);
8027  SCIPfreeBufferArray(scip, &yrho);
8028  SCIPfreeBufferArray(scip, &yrhoprime);
8029 
8030  return SCIP_OKAY;
8031 }
8032 
8033 /** compute reference point suggested by gauge function */
8034 static
8036  SCIP* scip, /**< SCIP data structure */
8037  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8038  SCIP_CONS* cons, /**< constraint */
8039  SCIP_SOL* refsol, /**< reference point where to compute gauge, or NULL if LP solution should be used */
8040  SCIP_Real* ref, /**< array to store reference point */
8041  SCIP_Bool* success /**< buffer to store whether we succeeded computing reference point */
8042  )
8043 {
8044  SCIP_CONSDATA* consdata;
8045  SCIP_Real gaugeval;
8046  SCIP_Real intpoint;
8047  SCIP_Real lb;
8048  SCIP_Real ub;
8049  SCIP_VAR* var;
8050  int j;
8051 
8052  assert(scip != NULL);
8053  assert(conshdlr != NULL);
8054  assert(cons != NULL);
8055 
8056  consdata = SCIPconsGetData(cons);
8057  assert(consdata != NULL);
8058  assert(consdata->isgaugeavailable);
8059 
8060  SCIPdebugMsg(scip, "evaluating gauge\n");
8061  SCIP_CALL( evaluateGauge(scip, conshdlr, cons, refsol, &gaugeval, success) );
8062 
8063  if( !(*success) )
8064  {
8065 #ifdef SCIP_DEBUG_GAUGE
8066  printf("Couldn't evaluate gauge!\n");
8067 #endif
8068  return SCIP_OKAY;
8069  }
8070 
8071 #ifdef SCIP_DEBUG_GAUGE
8072  {
8073  SCIP_Real level;
8074 
8075  level = consdata->rhs;
8076  for( j = 0; j < consdata->nlinvars; j++ )
8077  level -= SCIPgetSolVal(scip, refsol, consdata->linvars[j]) * consdata->lincoefs[j];
8078 
8079  printf("Summary:\n");
8080  printf("For cons <%s>: gauge at level %g evaluated at (refsol - intpoint) is %.10f\n",
8081  SCIPconsGetName(cons), level, gaugeval);
8082  printf("refsol - intpoint:\n");
8083 
8084  for( j = 0; j < consdata->nquadvars; ++j )
8085  {
8086  SCIP_VAR* vvar;
8087  vvar = consdata->quadvarterms[j].var;
8088  printf("%s: % 20.15g - %g = %g\n", SCIPvarGetName(vvar), SCIPgetSolVal(scip, refsol, vvar),
8089  consdata->interiorpoint[j], SCIPgetSolVal(scip, refsol, vvar) - consdata->interiorpoint[j]);
8090  }
8091  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
8092  printf("refsol is in the closure of the region (gaugeval <= 1), don't modify reference point\n");
8093  }
8094 #endif
8095 
8096  /* scale gauge value so that final point is close to the boundary, but not on the boundary (weakens the cut) */
8097  gaugeval *= GAUGESCALE;
8098 
8099  /* if the point is not sufficiently violated, we don't modify it */
8100  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
8101  {
8102  *success = FALSE;
8103  return SCIP_OKAY;
8104  }
8105 
8106  /* set reference to (refsol - interior point)/gaugeval + interior point and project onto bounds this is important for
8107  * some cut generation methods such as generateCutLTI
8108  * @todo remove the projection onto the bounds; generateCutLTI shouldn't be called for convex constraints
8109  */
8110  for( j = 0; j < consdata->nquadvars; ++j )
8111  {
8112  var = consdata->quadvarterms[j].var;
8113  lb = SCIPvarGetLbLocal(var);
8114  ub = SCIPvarGetUbLocal(var);
8115  /* do not like variables at infinity */
8116  assert(!SCIPisInfinity(scip, lb));
8117  assert(!SCIPisInfinity(scip, -ub));
8118 
8119  intpoint = consdata->interiorpoint[j];
8120  ref[j] = (SCIPgetSolVal(scip, refsol, var) - intpoint) / gaugeval + intpoint;
8121  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8122  }
8123 
8124 #ifdef SCIP_DEBUG_GAUGE
8125  printf("successful application of guage: %g\n", gaugeval);
8126  printf("modified reference point:\n");
8127  for( j = 0; j < consdata->nquadvars; ++j )
8128  {
8129  printf("%s = % 20.15g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
8130  }
8131 #endif
8132 
8133  return SCIP_OKAY;
8134 }
8135 
8136 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a solution
8137  * @note mode indicates whether we should modify the point we want to cutoff (sol) via gauge or projection,
8138  * or if just normal linearization should be use, or the default way (whatever is specified via settings)
8139  */
8140 static
8142  SCIP* scip, /**< SCIP data structure */
8143  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8144  SCIP_CONS* cons, /**< constraint */
8145  SCIP_SOL* sol, /**< solution where to generate cut, or NULL if LP solution should be used */
8146  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
8147  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
8148  SCIP_ROW** row, /**< storage for cut */
8149  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
8150  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
8151  SCIP_Real minefficacy, /**< minimal required efficacy (violation scaled by maximal absolute coefficient) */
8152  char mode /**< mode of execution 'g'auge, 'p'rojection, 'l'inearization gradient, 'd'efault */
8153  )
8154 {
8155  SCIP_CONSHDLRDATA* conshdlrdata;
8156  SCIP_CONSDATA* consdata;
8157  SCIP_VAR* var;
8158  SCIP_Real lb;
8159  SCIP_Real ub;
8160  SCIP_Real* ref;
8161  SCIP_Bool success;
8162  int j;
8163 
8164  assert(scip != NULL);
8165  assert(conshdlr != NULL);
8166  assert(cons != NULL);
8167 
8168  consdata = SCIPconsGetData(cons);
8169  assert(consdata != NULL);
8170 
8171  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8172  assert(conshdlrdata != NULL);
8173 
8174  if( refsol == NULL )
8175  refsol = sol;
8176 
8177  /* get reference point */
8178  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
8179  success = FALSE;
8180 
8181  if( mode == 'd')
8182  {
8183  if( (consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
8184  (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
8185  {
8186  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
8187  {
8188  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
8189  }
8190  else if( conshdlrdata->projectedcuts && consdata->isedavailable )
8191  {
8192  SCIPdebugMessage("use the projection of refsol onto the region defined by the constraint as reference point\n");
8193  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
8194  success = TRUE;
8195  }
8196  }
8197 
8198  if( success )
8199  {
8200  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8201 
8202  /* if cut fails, try again without modifying reference point */
8203  if( *row == NULL || (efficacy != NULL && !SCIPisGT(scip, *efficacy, minefficacy)) || !SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
8204  {
8205  SCIPdebugMsg(scip, "%s cut fail, try without modifying\n", conshdlrdata->gaugecuts ? "gauge" : "projected");
8206  success = FALSE;
8207  }
8208  }
8209 
8210  /* note that this is not the same as calling this method with mode 'l', 'l' assume convex/concave function */
8211  if( !success )
8212  {
8213  for( j = 0; j < consdata->nquadvars; ++j )
8214  {
8215  var = consdata->quadvarterms[j].var;
8216  lb = SCIPvarGetLbLocal(var);
8217  ub = SCIPvarGetUbLocal(var);
8218  /* do not like variables at infinity */
8219  assert(!SCIPisInfinity(scip, lb));
8220  assert(!SCIPisInfinity(scip, -ub));
8221 
8222  ref[j] = SCIPgetSolVal(scip, refsol, var);
8223  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8224  }
8225 
8226  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8227  }
8228  }
8229  /* gauge cut */
8230  if( mode == 'g' )
8231  {
8232  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
8233  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
8234  {
8235  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
8236  }
8237  if( success )
8238  {
8239  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8240  }
8241  }
8242  /* projection cut */
8243  if( mode == 'p' )
8244  {
8245  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
8246  if( conshdlrdata->projectedcuts && consdata->isedavailable )
8247  {
8248  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
8249  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8250  }
8251  }
8252  /* gradient linearization cut at refsol */
8253  if( mode == 'l' )
8254  {
8255  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
8256  for( j = 0; j < consdata->nquadvars; ++j )
8257  {
8258  var = consdata->quadvarterms[j].var;
8259  lb = SCIPvarGetLbLocal(var);
8260  ub = SCIPvarGetUbLocal(var);
8261  /* do not like variables at infinity */
8262  assert(!SCIPisInfinity(scip, lb));
8263  assert(!SCIPisInfinity(scip, -ub));
8264 
8265  ref[j] = SCIPgetSolVal(scip, refsol, var);
8266  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8267  }
8268  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
8269  }
8270 
8271  SCIPfreeBufferArray(scip, &ref);
8272 
8273  return SCIP_OKAY;
8274 }
8275 
8276 /** tries to find a cut that intersects with an unbounded ray of the LP
8277  *
8278  * For convex functions, we do this by linearizing in the feasible solution of the LPI.
8279  * For nonconvex functions, we just call generateCutSol with the unbounded solution as reference point.
8280  */
8281 static
8283  SCIP* scip, /**< SCIP data structure */
8284  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8285  SCIP_CONS* cons, /**< constraint */
8286  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
8287  SCIP_ROW** row, /**< storage for cut */
8288  SCIP_Real* rowrayprod, /**< buffer to store product of ray with row coefficients, or NULL if not of interest */
8289  SCIP_Bool checkcurvmultivar /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
8290  )
8291 {
8292  SCIP_CONSDATA* consdata;
8293  SCIP_BILINTERM* bilinterm;
8294  SCIP_VAR* var;
8295  SCIP_Real* ref;
8296  SCIP_Real matrixrayprod;
8297  SCIP_Real linrayprod;
8298  SCIP_Real quadrayprod;
8299  SCIP_Real rayval;
8300  int i;
8301  int j;
8302 
8303  assert(scip != NULL);
8304  assert(conshdlr != NULL);
8305  assert(cons != NULL);
8306  assert(row != NULL);
8308 
8309  consdata = SCIPconsGetData(cons);
8310  assert(consdata != NULL);
8311 
8312  *row = NULL;
8313 
8314  if( !SCIPhasPrimalRay(scip) )
8315  {
8316  SCIPdebugMsg(scip, "do not have primal ray, thus cannot resolve unboundedness\n");
8317  return SCIP_OKAY;
8318  }
8319 
8320  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
8321  if( (!consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
8322  (!consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
8323  {
8324  /* if not convex, just call generateCut and hope it's getting something useful */
8325  SCIP_CALL( generateCutSol(scip, conshdlr, cons, NULL, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip), 'd') );
8326 
8327  /* compute product of cut coefficients with ray, if required */
8328  if( *row != NULL && rowrayprod != NULL )
8329  {
8330  *rowrayprod = 0.0;
8331  for( i = 0; i < SCIProwGetNNonz(*row); ++i )
8332  {
8333  assert(SCIProwGetCols(*row)[i] != NULL);
8334  var = SCIPcolGetVar(SCIProwGetCols(*row)[i]);
8335  assert(var != NULL);
8336 
8337  *rowrayprod += SCIProwGetVals(*row)[i] * SCIPgetPrimalRayVal(scip, var);
8338  }
8339  }
8340 
8341  return SCIP_OKAY;
8342  }
8343 
8344  /* we seek for a linearization of the quadratic function such that it intersects with the unbounded ray
8345  * that is, we need a reference point ref such that for the gradient g of xAx+bx in ref, we have
8346  * <g, ray> > 0.0 if rhs is finite and <g, ray> < 0.0 if lhs is finite
8347  * Since g = 2*A*ref + b, we have <g, ray> = <2*A*ref + b, ray> = <ref, 2*A*ray> + <b,ray>
8348  * 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)
8349  * <ref, 2*A*ray> + <b,ray> is sufficiently larger 0.0, we call generateCut for this point, otherwise, we scale up ref
8350  */
8351 
8352  quadrayprod = 0.0; /* <ref, 2*A*ray> */
8353  linrayprod = 0.0; /* <b, ray> */
8354  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
8355  for( i = 0; i < consdata->nquadvars; ++i )
8356  {
8357  var = consdata->quadvarterms[i].var;
8358  rayval = SCIPgetPrimalRayVal(scip, var);
8359 
8360  /* compute i-th entry of (2*A*ray) */
8361  matrixrayprod = 2.0 * consdata->quadvarterms[i].sqrcoef * rayval;
8362  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
8363  {
8364  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
8365  matrixrayprod += bilinterm->coef * SCIPgetPrimalRayVal(scip, bilinterm->var1 == var ? bilinterm->var2 : bilinterm->var1);
8366  }
8367 
8368  if( SCIPisPositive(scip, matrixrayprod) )
8369  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? 1.0 : -1.0);
8370  else if( SCIPisNegative(scip, matrixrayprod) )
8371  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? -1.0 : 1.0);
8372  else
8373  ref[i] = 0.0;
8374 
8375  quadrayprod += matrixrayprod * ref[i];
8376  linrayprod += consdata->quadvarterms[i].lincoef * rayval;
8377  }
8378  assert((violside == SCIP_SIDETYPE_RIGHT && quadrayprod >= 0.0) || (violside == SCIP_SIDETYPE_LEFT && quadrayprod <= 0.0));
8379 
8380  if( SCIPisZero(scip, quadrayprod) )
8381  {
8382  SCIPdebugMsg(scip, "ray is zero along cons <%s>\n", SCIPconsGetName(cons));
8383  SCIPfreeBufferArray(scip, &ref);
8384  return SCIP_OKAY;
8385  }
8386 
8387  /* add linear part to linrayprod */
8388  for( i = 0; i < consdata->nlinvars; ++i )
8389  linrayprod += consdata->lincoefs[i] * SCIPgetPrimalRayVal(scip, consdata->linvars[i]);
8390 
8391  SCIPdebugMsg(scip, "initially have <b,ray> = %g and <ref, 2*A*ref> = %g\n", linrayprod, quadrayprod);
8392 
8393  /* 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
8394  * if <b,ray> is zero, then we scale refpoint up if |<ref, 2*A*ray>| < 1.0
8395  */
8396  if( (!SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_RIGHT && quadrayprod < -2*linrayprod) ||
8397  ( !SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_LEFT && quadrayprod > -2*linrayprod) ||
8398  (SCIPisZero(scip, linrayprod) && REALABS(quadrayprod) < 1.0) )
8399  {
8400  SCIP_Real scale;
8401 
8402  if( !SCIPisZero(scip, linrayprod) )
8403  scale = 2*REALABS(linrayprod/quadrayprod); /*lint !e795 */
8404  else
8405  scale = 1.0/REALABS(quadrayprod);
8406 
8407  SCIPdebugMsg(scip, "scale refpoint by %g\n", scale);
8408  for( i = 0; i < consdata->nquadvars; ++i )
8409  ref[i] *= scale;
8410  quadrayprod *= scale;
8411  }
8412 
8413  if( rowrayprod != NULL )
8414  *rowrayprod = quadrayprod + linrayprod;
8415 
8416  SCIPdebugMsg(scip, "calling generateCut, expecting ray product %g\n", quadrayprod + linrayprod);
8417  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
8418 
8419  SCIPfreeBufferArray(scip, &ref);
8420 
8421  return SCIP_OKAY;
8422 }
8423 
8424 /** processes a cut for constraint cons, i.e., checks numerics and possibly adds cut to sepastore */
8425 static
8427  SCIP* scip, /**< SCIP data structure */
8428  SCIP_ROW** row, /**< cut to process */
8429  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
8430  SCIP_CONS* cons, /**< constraint */
8431  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8432  SCIP_Real efficacy, /**< efficacy of row in reference solution */
8433  SCIP_Real actminefficacy, /**< actual minimal efficacy (whatever that is) */
8434  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
8435  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 */
8436  SCIP_RESULT* result /**< result of separation */
8437  )
8438 {
8439  SCIP_CONSDATA* consdata;
8440  SCIP_CONSHDLRDATA* conshdlrdata;
8441 
8442  assert(scip != NULL);
8443  assert(row != NULL);
8444  assert(conshdlr != NULL);
8445  assert(result != NULL);
8446  assert(cons != NULL);
8447 
8448  /* no cut to process */
8449  if( *row == NULL )
8450  return SCIP_OKAY;
8451 
8452  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8453  assert(conshdlrdata != NULL);
8454 
8455  consdata = SCIPconsGetData(cons);
8456  assert(consdata != NULL);
8457 
8458  if( SCIPisGT(scip, efficacy, actminefficacy) && SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
8459  {
8460  SCIP_Bool infeasible;
8461 
8462  /* cut cuts off solution */
8463  SCIP_CALL( SCIPaddCut(scip, sol, *row, FALSE /* forcecut */, &infeasible) );
8464  if( infeasible )
8465  {
8466  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(cons));
8467  *result = SCIP_CUTOFF;
8468  }
8469  else
8470  {
8471  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy,
8472  SCIPconsGetName(cons), consdata->lhsviol+consdata->rhsviol);
8473  *result = SCIP_SEPARATED;
8474  }
8475  SCIP_CALL( SCIPresetConsAge(scip, cons) );
8476 
8477  /* mark row as not removable from LP for current node, if in enforcement */
8478  if( inenforcement && !conshdlrdata->enfocutsremovable )
8479  SCIPmarkRowNotRemovableLocal(scip, *row);
8480  }
8481  if( bestefficacy != NULL && efficacy > *bestefficacy )
8482  *bestefficacy = efficacy;
8483 
8484  SCIP_CALL( SCIPreleaseRow (scip, row) );
8485  return SCIP_OKAY;
8486 }
8487 /** tries to separate solution or LP solution by a linear cut
8488  *
8489  * assumes that constraint violations have been computed
8490  */
8491 static
8493  SCIP* scip, /**< SCIP data structure */
8494  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
8495  SCIP_CONS** conss, /**< constraints */
8496  int nconss, /**< number of constraints */
8497  int nusefulconss, /**< number of constraints that seem to be useful */
8498  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8499  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
8500  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
8501  SCIP_RESULT* result, /**< result of separation */
8502  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 */
8503  )
8504 {
8505  SCIP_CONSHDLRDATA* conshdlrdata;
8506  SCIP_CONSDATA* consdata;
8507  SCIP_Real efficacy;
8508  SCIP_Real actminefficacy;
8509  SCIP_SIDETYPE violside;
8510  int c;
8511  SCIP_ROW* row;
8512 
8513  assert(scip != NULL);
8514  assert(conshdlr != NULL);
8515  assert(conss != NULL || nconss == 0);
8516  assert(nusefulconss <= nconss);
8517  assert(result != NULL);
8518 
8519  *result = SCIP_FEASIBLE;
8520 
8521  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8522  assert(conshdlrdata != NULL);
8523 
8524  if( bestefficacy != NULL )
8525  *bestefficacy = 0.0;
8526 
8527  row = NULL;
8528  for( c = 0; c < nconss; ++c )
8529  {
8530  assert(conss != NULL);
8531  consdata = SCIPconsGetData(conss[c]);
8532  assert(consdata != NULL);
8533 
8534  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
8535  {
8536  /* we are not feasible anymore */
8537  if( *result == SCIP_FEASIBLE )
8538  *result = SCIP_DIDNOTFIND;
8539 
8540  violside = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT;
8541 
8542  /* actual minimal efficacy */
8543  actminefficacy = inenforcement && ((violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex ) || (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave))
8544  ? (SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip))
8545  : minefficacy;
8546 
8547  /* generate cut */
8548  if( sol == NULL && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
8549  {
8550  /* if the LP is unbounded, then we need a cut that cuts into the direction of a hopefully existing primal ray
8551  * 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
8552  * given a cut lhs <= <c,x> <= rhs, we check whether it imposes an upper bound on t and thus bounds the ray
8553  * 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>
8554  * similar, lhs > -infinity and <c,r> < 0 is good
8555  */
8556  SCIP_Real rayprod;
8557  SCIP_Real norm;
8558 
8559  rayprod = 0.0; /* for compiler */
8560  SCIP_CALL( generateCutUnboundedLP(scip, conshdlr, conss[c], violside, &row, &rayprod, conshdlrdata->checkcurvature) );
8561 
8562  if( row != NULL )
8563  {
8564  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) && SCIPisPositive(scip, rayprod) )
8565  efficacy = rayprod;
8566  else if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) && SCIPisNegative(scip, rayprod) )
8567  efficacy = -rayprod;
8568  else
8569  efficacy = 0.0;
8570 
8571  switch( conshdlrdata->scaling )
8572  {
8573  case 'o' :
8574  break;
8575 
8576  case 'g' :
8577  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding
8578  * cuts efficient which are only very slightly violated CPLEX does not seem to scale row
8579  * coefficients up too also we use infinity norm, since that seem to be the usual scaling strategy
8580  * in LP solvers (equilibrium scaling) */
8581  norm = SCIPgetRowMaxCoef(scip, row);
8582  efficacy /= MAX(1.0, norm);
8583  break;
8584 
8585  case 's' :
8586  {
8587  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
8588  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
8589  SCIP_Real minval = MIN(abslhs, absrhs);
8590 
8591  efficacy /= MAX(1.0, minval);
8592  break;
8593  }
8594 
8595  default:
8596  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
8597  SCIPABORT();
8598  return SCIP_INVALIDDATA; /*lint !e527*/
8599  }
8600 
8601  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], sol, efficacy, actminefficacy, inenforcement, bestefficacy, result) );
8602  }
8603  continue;
8604  }
8605  else
8606  {
8607  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], sol, NULL, violside, &row, &efficacy,
8608  conshdlrdata->checkcurvature, actminefficacy, 'd') );
8609  /* @todo If generation failed not because of low efficacy, then probably because of numerical issues */
8610  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], sol, efficacy, actminefficacy, inenforcement, bestefficacy, result) );
8611  }
8612  }
8613 
8614  if( *result == SCIP_CUTOFF )
8615  break;
8616 
8617  /* enforce only useful constraints
8618  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
8619  */
8620  if( c >= nusefulconss && *result == SCIP_SEPARATED )
8621  break;
8622  }
8623 
8624  return SCIP_OKAY;
8625 }
8626 
8627 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
8628  *
8629  * - 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.
8630  * - If separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only.
8631  * - If separatedlpsol is NULL, then cut is added to cutpool only.
8632  */
8633 static
8635  SCIP* scip, /**< SCIP data structure */
8636  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
8637  SCIP_CONS** conss, /**< constraints */
8638  int nconss, /**< number of constraints */
8639  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
8640  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP,
8641  * or NULL if adding to cutpool only */
8642  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
8643  )
8644 {
8645  SCIP_CONSHDLRDATA* conshdlrdata;
8646  SCIP_CONSDATA* consdata;
8647  SCIP_Bool addedtolp;
8648  SCIP_ROW* row;
8649  int c;
8650 
8651  assert(scip != NULL);
8652  assert(conshdlr != NULL);
8653  assert(conss != NULL || nconss == 0);
8654 
8655  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8656  assert(conshdlrdata != NULL);
8657 
8658  if( separatedlpsol != NULL )
8659  *separatedlpsol = FALSE;
8660 
8661  for( c = 0; c < nconss; ++c )
8662  {
8663  assert(conss[c] != NULL); /*lint !e613 */
8664 
8665  if( SCIPconsIsLocal(conss[c]) || !SCIPconsIsEnabled(conss[c]) ) /*lint !e613 */
8666  continue;
8667 
8668  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
8669 
8670  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
8671  assert(consdata != NULL);
8672 
8673  if( consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
8674  {
8675  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_RIGHT, &row, NULL,
8676  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
8677  }
8678  else if( consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
8679  {
8680  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_LEFT, &row, NULL,
8681  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
8682  }
8683  else
8684  continue;
8685 
8686  if( row == NULL )
8687  continue;
8688 
8689  addedtolp = FALSE;
8690 
8691  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
8692  if( separatedlpsol != NULL )
8693  {
8694  SCIP_Real efficacy;
8695  SCIP_Real norm;
8696 
8697  efficacy = -SCIPgetRowLPFeasibility(scip, row);
8698  switch( conshdlrdata->scaling )
8699  {
8700  case 'o' :
8701  break;
8702 
8703  case 'g' :
8704  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
8705  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too
8706  * also we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
8707  * scaling) */
8708  norm = SCIPgetRowMaxCoef(scip, row);
8709  efficacy /= MAX(1.0, norm);
8710  break;
8711 
8712  case 's' :
8713  {
8714  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
8715  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
8716  SCIP_Real minval = MIN(abslhs, absrhs);
8717 
8718  efficacy /= MAX(1.0, minval);
8719  break;
8720  }
8721 
8722  default:
8723  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
8724  SCIPABORT();
8725  return SCIP_INVALIDDATA; /*lint !e527*/
8726  }
8727 
8728  if( efficacy >= minefficacy )
8729  {
8730  SCIP_Bool infeasible;
8731 
8732  *separatedlpsol = TRUE;
8733  addedtolp = TRUE;
8734  SCIP_CALL( SCIPaddCut(scip, NULL, row, TRUE, &infeasible) );
8735  assert( ! infeasible );
8736  SCIPdebugMsg(scip, "added linearization cut <%s> to LP, efficacy = %g\n", SCIProwGetName(row), efficacy);
8737  }
8738  }
8739 
8740  if( !SCIProwIsLocal(row) && !addedtolp )
8741  {
8742  SCIP_CALL( SCIPaddPoolCut(scip, row) );
8743  SCIPdebugMsg(scip, "added linearization cut <%s> to cutpool\n", SCIProwGetName(row));
8744  }
8745 
8746  SCIP_CALL( SCIPreleaseRow(scip, &row) );
8747  }
8748 
8749  return SCIP_OKAY;
8750 }
8751 
8752 /** processes the event that a new primal solution has been found */
8753 static
8754 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
8756  SCIP_CONSHDLRDATA* conshdlrdata;
8757  SCIP_CONSHDLR* conshdlr;
8758  SCIP_CONS** conss;
8759  int nconss;
8760  SCIP_SOL* sol;
8761 
8762  assert(scip != NULL);
8763  assert(event != NULL);
8764  assert(eventdata != NULL);
8765  assert(eventhdlr != NULL);
8766 
8767  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
8768 
8769  conshdlr = (SCIP_CONSHDLR*)eventdata;
8770 
8771  nconss = SCIPconshdlrGetNConss(conshdlr);
8772 
8773  if( nconss == 0 )
8774  return SCIP_OKAY;
8775 
8776  sol = SCIPeventGetSol(event);
8777  assert(sol != NULL);
8778 
8779  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8780  assert(conshdlrdata != NULL);
8781 
8782  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
8783  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
8784  * or are from the tree, but postprocessed via proposeFeasibleSolution
8785  */
8786  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
8787  return SCIP_OKAY;
8788 
8789  conss = SCIPconshdlrGetConss(conshdlr);
8790  assert(conss != NULL);
8791 
8792  SCIPdebugMsg(scip, "caught new sol event %"SCIP_EVENTTYPE_FORMAT" from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
8793 
8794  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
8795 
8796  return SCIP_OKAY;
8797 }
8798 
8799 /** registers branching candidates according to convexification gap rule
8800  *
8801  * That is, computes for every nonconvex term the gap between the terms value in the LP solution and the value of the underestimator
8802  * as it would be (and maybe has been) constructed by the separation routines of this constraint handler. Then it registers all
8803  * variables occurring in each term with the computed gap. If variables appear in more than one term, they are registered several times.
8804  */
8805 static
8807  SCIP* scip, /**< SCIP data structure */
8808  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8809  SCIP_CONS** conss, /**< constraints to check */
8810  int nconss, /**< number of constraints to check */
8811  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8812  int* nnotify /**< counter for number of notifications performed */
8813  )
8814 {
8815  SCIP_CONSDATA* consdata;
8816  int c;
8817  int j;
8818  SCIP_Bool xbinary;
8819  SCIP_Bool ybinary;
8820  SCIP_Bool xunbounded;
8821  SCIP_Bool yunbounded;
8822  SCIP_VAR* x;
8823  SCIP_VAR* y;
8824  SCIP_Real xlb;
8825  SCIP_Real xub;
8826  SCIP_Real xval;
8827  SCIP_Real ylb;
8828  SCIP_Real yub;
8829  SCIP_Real yval;
8830  SCIP_Real gap;
8831  SCIP_Real coef_;
8832 
8833  assert(scip != NULL);
8834  assert(conshdlr != NULL);
8835  assert(conss != NULL || nconss == 0);
8836 
8837  *nnotify = 0;
8838  yval = SCIP_INVALID;
8839  xval = SCIP_INVALID;
8840 
8841  for( c = 0; c < nconss; ++c )
8842  {
8843  assert(conss != NULL);
8844  consdata = SCIPconsGetData(conss[c]);
8845  assert(consdata != NULL);
8846 
8847  if( !consdata->nquadvars )
8848  continue;
8849 
8850  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
8851  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
8852  continue;
8853  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
8854 
8855  /* square terms */
8856  for( j = 0; j < consdata->nquadvars; ++j )
8857  {
8858  x = consdata->quadvarterms[j].var;
8859  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef < 0) ||
8860  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef > 0) )
8861  {
8862  xlb = SCIPvarGetLbLocal(x);
8863  xub = SCIPvarGetUbLocal(x);
8864  if( SCIPisRelEQ(scip, xlb, xub) )
8865  {
8866  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
8867  continue;
8868  }
8869 
8870  xval = SCIPgetSolVal(scip, sol, x);
8871 
8872  /* if variable is at bounds, then no need to branch, since secant is exact there */
8873  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
8874  continue;
8875 
8876  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
8877  gap = SCIPinfinity(scip);
8878  else
8879  gap = (xval-xlb)*(xub-xval)/(1+2*ABS(xval));
8880  assert(!SCIPisFeasNegative(scip, gap));
8881  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(gap, 0.0), SCIP_INVALID) );
8882  ++*nnotify;
8883  }
8884  }
8885 
8886  /* bilinear terms */
8887  for( j = 0; j < consdata->nbilinterms; ++j )
8888  {
8889  /* if any of the variables if fixed, then it actually behaves like a linear term, so we don't need to branch on it */
8890  x = consdata->bilinterms[j].var1;
8891  xlb = SCIPvarGetLbLocal(x);
8892  xub = SCIPvarGetUbLocal(x);
8893  if( SCIPisRelEQ(scip, xlb, xub) )
8894  continue;
8895 
8896  y = consdata->bilinterms[j].var2;
8897  ylb = SCIPvarGetLbLocal(y);
8898  yub = SCIPvarGetUbLocal(y);
8899  if( SCIPisRelEQ(scip, ylb, yub) )
8900  continue;
8901 
8902  xunbounded = SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub);
8903  yunbounded = SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub);
8904 
8905  /* compute gap, if both variable are bounded */
8906  gap = SCIPinfinity(scip);
8907  if( !xunbounded && !yunbounded )
8908  {
8909  xval = SCIPgetSolVal(scip, sol, x);
8910  yval = SCIPgetSolVal(scip, sol, y);
8911 
8912  /* if both variables are at one of its bounds, then no need to branch, since McCormick is exact there */
8913  if( (SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub)) &&
8914  ( SCIPisLE(scip, yval, ylb) || SCIPisGE(scip, yval, yub)) )
8915  continue;
8916 
8917  xval = MAX(xlb, MIN(xval, xub));
8918  yval = MAX(ylb, MIN(yval, yub));
8919 
8920  coef_ = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? -consdata->bilinterms[j].coef : consdata->bilinterms[j].coef;
8921  if( coef_ > 0.0 )
8922  {
8923  if( (xub-xlb)*yval + (yub-ylb)*xval <= xub*yub - xlb*ylb )
8924  gap = (xval*yval - xlb*yval - ylb*xval + xlb*ylb) / (1+sqrt(xval*xval + yval*yval));
8925  else
8926  gap = (xval*yval - xval*yub - yval*xub + xub*yub) / (1+sqrt(xval*xval + yval*yval));
8927  }
8928  else
8929  { /* coef_ < 0 */
8930  if( (xub-xlb)*yval - (yub-ylb)*xval <= xub*ylb - xlb*yub )
8931  gap = -(xval*yval - xval*ylb - yval*xub + xub*ylb) / (1+sqrt(xval*xval + yval*yval));
8932  else
8933  gap = -(xval*yval - xval*yub - yval*xlb + xlb*yub) / (1+sqrt(xval*xval + yval*yval));
8934  }
8935 
8936  assert(!SCIPisNegative(scip, gap / MAX3(MAX(REALABS(xlb), REALABS(xub)), MAX(REALABS(ylb), REALABS(yub)), 1.0))); /*lint !e666*/
8937  if( gap < 0.0 )
8938  gap = 0.0;
8939  }
8940 
8941  /* if one of the variables is binary or integral with domain width 1, then branching on this makes the term linear, so prefer this */
8942  xbinary = SCIPvarIsBinary(x) || (SCIPvarIsIntegral(x) && xub - xlb < 1.5);
8943  ybinary = SCIPvarIsBinary(y) || (SCIPvarIsIntegral(y) && yub - ylb < 1.5);
8944  if( xbinary )
8945  {
8947  ++*nnotify;
8948  }
8949  if( ybinary )
8950  {
8952  ++*nnotify;
8953  }
8954  if( xbinary || ybinary )
8955  continue;
8956 
8957  /* if one of the variables is unbounded, then branch on it first */
8958  if( xunbounded )
8959  {
8961  ++*nnotify;
8962  }
8963  if( yunbounded )
8964  {
8966  ++*nnotify;
8967  }
8968  if( xunbounded || yunbounded )
8969  continue;
8970 
8971  /* if both variables are integral, prefer the one with the smaller domain, so variable gets fixed soon
8972  * does not seem to work well on tln instances, so disable for now and may look at it later again
8973  */
8974 #ifdef BRANCHTOLINEARITY
8975  if( SCIPvarIsIntegral(x) && SCIPvarIsIntegral(y) )
8976  {
8977  if( SCIPisLT(scip, xub-xlb, yub-ylb) )
8978  {
8980  ++*nnotify;
8981  continue;
8982  }
8983  if( SCIPisGT(scip, xub-xlb, yub-ylb) )
8984  {
8986  ++*nnotify;
8987  continue;
8988  }
8989  }
8990 #endif
8991 
8992  /* in the regular case, suggest those variables which are not at its bounds for branching
8993  * this is, because after branching both variables will be one the bounds, and McCormick will be exact then */
8994  if( !SCIPisLE(scip, xval, xlb) && !SCIPisGE(scip, xval, xub) )
8995  {
8997  ++*nnotify;
8998  }
8999  if( !SCIPisLE(scip, yval, ylb) && !SCIPisGE(scip, yval, yub) )
9000  {
9002  ++*nnotify;
9003  }
9004  }
9005  }
9006 
9007  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9008 
9009  return SCIP_OKAY;
9010 }
9011 
9012 /** registers branching candidates according to constraint violation rule
9013  *
9014  * That is, registers all variables appearing in nonconvex terms^1 with a score that is the violation of the constraint.
9015  * This is the same rule as is applied in cons_nonlinear and other nonlinear constraint handlers.
9016  *
9017  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
9018  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
9019  */
9020 static
9022  SCIP* scip, /**< SCIP data structure */
9023  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9024  SCIP_CONS** conss, /**< constraints to check */
9025  int nconss, /**< number of constraints to check */
9026  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9027  int* nnotify /**< counter for number of notifications performed */
9028  )
9029 {
9030  SCIP_CONSDATA* consdata;
9031  SCIP_QUADVARTERM* quadvarterm;
9032  int c;
9033  int j;
9034  SCIP_VAR* x;
9035  SCIP_Real xlb;
9036  SCIP_Real xub;
9037  SCIP_Real xval;
9038 
9039  assert(scip != NULL);
9040  assert(conshdlr != NULL);
9041  assert(conss != NULL || nconss == 0);
9042 
9043  *nnotify = 0;
9044 
9045  for( c = 0; c < nconss; ++c )
9046  {
9047  assert(conss != NULL);
9048  consdata = SCIPconsGetData(conss[c]);
9049  assert(consdata != NULL);
9050 
9051  if( !consdata->nquadvars )
9052  continue;
9053 
9054  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9055  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9056  continue;
9057  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9058 
9059  for( j = 0; j < consdata->nquadvars; ++j )
9060  {
9061  quadvarterm = &consdata->quadvarterms[j];
9062  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
9063  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
9064  quadvarterm->nadjbilin > 0 )
9065  {
9066  x = quadvarterm->var;
9067  xlb = SCIPvarGetLbLocal(x);
9068  xub = SCIPvarGetUbLocal(x);
9069 
9070  if( quadvarterm->nadjbilin == 0 )
9071  {
9072  xval = SCIPgetSolVal(scip, sol, x);
9073 
9074  /* if variable is at bounds and only in a nonconvex square term, then no need to branch, since secant is exact there */
9075  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
9076  continue;
9077  }
9078 
9079  if( SCIPisRelEQ(scip, xlb, xub) )
9080  {
9081  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9082  continue;
9083  }
9084 
9085  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
9086  ++*nnotify;
9087  }
9088  }
9089  }
9090 
9091  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9092 
9093  return SCIP_OKAY;
9094 }
9095 
9096 /** registers branching candidates according to centrality rule
9097  *
9098  * That is, registers all variables appearing in nonconvex terms^1 with a score that is given by the distance of the
9099  * variable value from its bounds. This rule should not make sense, as the distance to the bounds is also (often) considered
9100  * by the branching rule later on.
9101  *
9102  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
9103  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
9104  */
9105 static
9107  SCIP* scip, /**< SCIP data structure */
9108  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9109  SCIP_CONS** conss, /**< constraints to check */
9110  int nconss, /**< number of constraints to check */
9111  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9112  int* nnotify /**< counter for number of notifications performed */
9113  )
9114 {
9115  SCIP_CONSDATA* consdata;
9116  SCIP_QUADVARTERM* quadvarterm;
9117  int c;
9118  int j;
9119  SCIP_VAR* x;
9120  SCIP_Real xlb;
9121  SCIP_Real xub;
9122  SCIP_Real xval;
9123  SCIP_Real score;
9124 
9125  assert(scip != NULL);
9126  assert(conshdlr != NULL);
9127  assert(conss != NULL || nconss == 0);
9128 
9129  *nnotify = 0;
9130 
9131  for( c = 0; c < nconss; ++c )
9132  {
9133  assert(conss != NULL);
9134  consdata = SCIPconsGetData(conss[c]);
9135  assert(consdata != NULL);
9136 
9137  if( !consdata->nquadvars )
9138  continue;
9139 
9140  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9141  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9142  continue;
9143  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9144 
9145  for( j = 0; j < consdata->nquadvars; ++j )
9146  {
9147  quadvarterm = &consdata->quadvarterms[j];
9148  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
9149  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
9150  quadvarterm->nadjbilin > 0 )
9151  {
9152  x = quadvarterm->var;
9153  xlb = SCIPvarGetLbLocal(x);
9154  xub = SCIPvarGetUbLocal(x);
9155 
9156  if( SCIPisRelEQ(scip, xlb, xub) )
9157  {
9158  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9159  continue;
9160  }
9161 
9162  xval = SCIPgetSolVal(scip, sol, x);
9163  xval = MAX(xlb, MIN(xub, xval));
9164 
9165  /* compute relative difference of xval to each of its bounds
9166  * and scale such that if xval were in the middle, we get a score of 1
9167  * and if xval is on one its bounds, the score is 0
9168  */
9169  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
9170  {
9171  if( (!SCIPisInfinity(scip, -xlb) && SCIPisEQ(scip, xval, xlb)) || (!SCIPisInfinity(scip, xub) && SCIPisEQ(scip, xval, xub)) )
9172  score = 0.0;
9173  else
9174  score = 1.0;
9175  }
9176  else
9177  {
9178  score = 4.0 * (xval - xlb) * (xub - xval) / ((xub - xlb) * (xub - xlb));
9179  }
9180 
9181  SCIP_CALL( SCIPaddExternBranchCand(scip, x, score, SCIP_INVALID) );
9182  ++*nnotify;
9183  }
9184  }
9185  }
9186 
9187  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9188 
9189  return SCIP_OKAY;
9190 }
9191 
9192 /** registers branching candidates */
9193 static
9195  SCIP* scip, /**< SCIP data structure */
9196  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9197  SCIP_CONS** conss, /**< constraints to check */
9198  int nconss, /**< number of constraints to check */
9199  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9200  int* nnotify /**< counter for number of notifications performed */
9201  )
9202 {
9203  SCIP_CONSHDLRDATA* conshdlrdata;
9204 
9205  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9206  assert(conshdlrdata != NULL);
9207 
9208  switch( conshdlrdata->branchscoring )
9209  {
9210  case 'g' :
9211  SCIP_CALL( registerBranchingCandidatesGap(scip, conshdlr, conss, nconss, sol, nnotify) );
9212  break;
9213 
9214  case 'v' :
9215  SCIP_CALL( registerBranchingCandidatesViolation(scip, conshdlr, conss, nconss, sol, nnotify) );
9216  break;
9217 
9218  case 'c' :
9219  SCIP_CALL( registerBranchingCandidatesCentrality(scip, conshdlr, conss, nconss, sol, nnotify) );
9220  break;
9221 
9222  default :
9223  SCIPerrorMessage("invalid branchscoring selection");
9224  SCIPABORT();
9225  return SCIP_ERROR; /*lint !e527*/
9226  }
9227 
9228  return SCIP_OKAY;
9229 }
9230 
9231 
9232 /** registers a quadratic variable from a violated constraint as branching candidate that has a large absolute value in the (LP) relaxation */
9233 static
9235  SCIP* scip, /**< SCIP data structure */
9236  SCIP_CONS** conss, /**< constraints */
9237  int nconss, /**< number of constraints */
9238  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9239  SCIP_VAR** brvar /**< buffer to store branching variable */
9240  )
9241 {
9242  SCIP_CONSDATA* consdata;
9243  SCIP_Real val;
9244  SCIP_Real brvarval;
9245  int i;
9246  int c;
9247 
9248  assert(scip != NULL);
9249  assert(conss != NULL || nconss == 0);
9250 
9251  *brvar = NULL;
9252  brvarval = -1.0;
9253 
9254  for( c = 0; c < nconss; ++c )
9255  {
9256  assert(conss != NULL);
9257  consdata = SCIPconsGetData(conss[c]);
9258  assert(consdata != NULL);
9259 
9260  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
9261  continue;
9262 
9263  for( i = 0; i < consdata->nquadvars; ++i )
9264  {
9265  /* do not propose fixed variables */
9266  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
9267  continue;
9268  val = SCIPgetSolVal(scip, sol, consdata->quadvarterms[i].var);
9269  if( ABS(val) > brvarval )
9270  {
9271  brvarval = ABS(val);
9272  *brvar = consdata->quadvarterms[i].var;
9273  }
9274  }
9275  }
9276 
9277  if( *brvar != NULL )
9278  {
9279  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
9280  }
9281 
9282  return SCIP_OKAY;
9283 }
9284 
9285 /** replaces violated quadratic constraints where all quadratic variables are fixed by linear constraints */
9286 static
9288  SCIP* scip, /**< SCIP data structure */
9289  SCIP_CONS** conss, /**< constraints */
9290  int nconss, /**< number of constraints */
9291  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
9292  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
9293  SCIP_Bool* infeasible /**< whether we detected infeasibility */
9294  )
9295 {
9296  SCIP_CONS* cons;
9297  SCIP_CONSDATA* consdata;
9298  SCIP_RESULT checkresult;
9299  SCIP_Real constant;
9300  SCIP_Real val1;
9301  SCIP_Real val2;
9302  int i;
9303  int c;
9304 
9305  assert(scip != NULL);
9306  assert(conss != NULL || nconss == 0);
9307  assert(addedcons != NULL);
9308  assert(reduceddom != NULL);
9309  assert(infeasible != NULL);
9310 
9311  *addedcons = FALSE;
9312  *reduceddom = FALSE;
9313  *infeasible = FALSE;
9314 
9315  for( c = 0; c < nconss; ++c )
9316  {
9317  assert(conss != NULL);
9318  consdata = SCIPconsGetData(conss[c]);
9319  assert(consdata != NULL);
9320 
9321  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
9322  continue;
9323 
9324  constant = 0.0;
9325 
9326  for( i = 0; i < consdata->nquadvars; ++i )
9327  {
9328  /* variables should be fixed if constraint is violated */
9329  assert(SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
9330 
9331  val1 = (SCIPvarGetUbLocal(consdata->quadvarterms[i].var) + SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) / 2.0;
9332  constant += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val1) * val1;
9333  }
9334 
9335  for( i = 0; i < consdata->nbilinterms; ++i )
9336  {
9337  val1 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var1) + SCIPvarGetLbLocal(consdata->bilinterms[i].var1)) / 2.0;
9338  val2 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var2) + SCIPvarGetLbLocal(consdata->bilinterms[i].var2)) / 2.0;
9339  constant += consdata->bilinterms[i].coef * val1 * val2;
9340  }
9341 
9342  /* check if we have a bound change */
9343  if ( consdata->nlinvars == 1 )
9344  {
9345  SCIP_Bool tightened;
9346  SCIP_Real coef;
9347  SCIP_Real lhs;
9348  SCIP_Real rhs;
9349 
9350  coef = *consdata->lincoefs;
9351 
9352  /* compute lhs/rhs */
9353  if ( SCIPisInfinity(scip, -consdata->lhs) )
9354  lhs = -SCIPinfinity(scip);
9355  else
9356  lhs = consdata->lhs - constant;
9357 
9358  if ( SCIPisInfinity(scip, consdata->rhs) )
9359  rhs = SCIPinfinity(scip);
9360  else
9361  rhs = consdata->rhs - constant;
9362 
9363  SCIPdebugMsg(scip, "Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(*consdata->linvars), rhs);
9364 
9365  /* possibly correct lhs/rhs */
9366  assert( ! SCIPisZero(scip, coef) );
9367  if ( coef >= 0.0 )
9368  {
9369  if ( ! SCIPisInfinity(scip, -lhs) )
9370  lhs /= coef;
9371  if ( ! SCIPisInfinity(scip, rhs) )
9372  rhs /= coef;
9373  }
9374  else
9375  {
9376  SCIP_Real h;
9377  h = rhs;
9378  if ( ! SCIPisInfinity(scip, -lhs) )
9379  rhs = lhs/coef;
9380  else
9381  rhs = SCIPinfinity(scip);
9382 
9383  if ( ! SCIPisInfinity(scip, h) )
9384  lhs = h/coef;
9385  else
9386  lhs = -SCIPinfinity(scip);
9387  }
9388  SCIPdebugMsg(scip, "Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(*consdata->linvars), rhs);
9389 
9390  if( SCIPisInfinity(scip, -rhs) || SCIPisInfinity(scip, lhs) )
9391  {
9392  SCIPdebugMsg(scip, "node will marked as infeasible since lb/ub of %s is +/-infinity\n",
9393  SCIPvarGetName(consdata->linvars[0]));
9394 
9395  *infeasible = TRUE;
9396  return SCIP_OKAY;
9397  }
9398 
9399  if ( ! SCIPisInfinity(scip, -lhs) )
9400  {
9401  SCIP_CALL( SCIPtightenVarLb(scip, *consdata->linvars, lhs, TRUE, infeasible, &tightened) );
9402  if ( *infeasible )
9403  {
9404  SCIPdebugMsg(scip, "Lower bound leads to infeasibility.\n");
9405  return SCIP_OKAY;
9406  }
9407  if ( tightened )
9408  {
9409  SCIPdebugMsg(scip, "Lower boundx changed.\n");
9410  *reduceddom = TRUE;
9411  return SCIP_OKAY;
9412  }
9413  }
9414 
9415  if ( ! SCIPisInfinity(scip, rhs) )
9416  {
9417  SCIP_CALL( SCIPtightenVarUb(scip, *consdata->linvars, rhs, TRUE, infeasible, &tightened) );
9418  if ( *infeasible )
9419  {
9420  SCIPdebugMsg(scip, "Upper bound leads to infeasibility.\n");
9421  return SCIP_OKAY;
9422  }
9423  if ( tightened )
9424  {
9425  SCIPdebugMsg(scip, "Upper bound changed.\n");
9426  *reduceddom = TRUE;
9427  return SCIP_OKAY;
9428  }
9429  }
9430  }
9431  else
9432  {
9433  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
9434  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
9435  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : (consdata->lhs - constant)),
9436  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : (consdata->rhs - constant)),
9437  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
9438  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
9439  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
9440  SCIPconsIsStickingAtNode(conss[c])) );
9441 
9442  SCIPdebugMsg(scip, "replace quadratic constraint <%s> by linear constraint after all quadratic vars have been fixed\n", SCIPconsGetName(conss[c]) );
9443  SCIPdebugPrintCons(scip, cons, NULL);
9444 
9445  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
9446 
9447  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
9448  {
9449  SCIPdebugMsg(scip, "linear constraint is feasible and LP optimal, thus do not add\n");
9450  }
9451  else
9452  {
9453  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
9454  *addedcons = TRUE;
9455  }
9456  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
9457  }
9458  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
9459  }
9460 
9461  return SCIP_OKAY;
9462 }
9463 
9464 /** tightens a lower bound on a variable and checks the result */
9465 static
9467  SCIP* scip, /**< SCIP data structure */
9468  SCIP_CONS* cons, /**< constraint where we currently propagate */
9469  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9470  SCIP_VAR* var, /**< variable which domain we might reduce */
9471  SCIP_Real bnd, /**< new lower bound for variable */
9472  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
9473  int* nchgbds /**< counter to increase if a bound was tightened */
9474  )
9475 {
9476  SCIP_Bool infeas;
9477  SCIP_Bool tightened;
9478 
9479  assert(scip != NULL);
9480  assert(cons != NULL);
9481  assert(intervalinfty > 0.0);
9482  assert(bnd > -intervalinfty);
9483  assert(var != NULL);
9484  assert(result != NULL);
9485  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9486  assert(nchgbds != NULL);
9487 
9488  /* new bound is no improvement */
9489  if( SCIPisHugeValue(scip, -bnd) || SCIPisLE(scip, bnd, SCIPvarGetLbLocal(var)) )
9490  return SCIP_OKAY;
9491 
9492  if( SCIPisInfinity(scip, bnd) )
9493  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
9494  *result = SCIP_CUTOFF;
9495  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9496  return SCIP_OKAY;
9497  }
9498 
9499  /* new lower bound is very low (between -intervalinfty and -SCIPinfinity()) */
9500  if( SCIPisInfinity(scip, -bnd) )
9501  return SCIP_OKAY;
9502 
9503  bnd = SCIPadjustedVarLb(scip, var, bnd);
9504  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
9505  if( infeas )
9506  {
9507  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n",
9508  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
9509  *result = SCIP_CUTOFF;
9510  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9511  return SCIP_OKAY;
9512  }
9513  if( tightened )
9514  {
9515  SCIPdebugMsg(scip, "%s tightened lower bound of variable <%s> in constraint <%s> to %g\n",
9516  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
9517  ++*nchgbds;
9518  *result = SCIP_REDUCEDDOM;
9519  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9520  }
9521 
9522  return SCIP_OKAY;
9523 }
9524 
9525 /** tightens an upper bound on a variable and checks the result */
9526 static
9528  SCIP* scip, /**< SCIP data structure */
9529  SCIP_CONS* cons, /**< constraint where we currently propagate */
9530  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9531  SCIP_VAR* var, /**< variable which domain we might reduce */
9532  SCIP_Real bnd, /**< new upper bound for variable */
9533  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
9534  int* nchgbds /**< counter to increase if a bound was tightened */
9535  )
9536 {
9537  SCIP_Bool infeas;
9538  SCIP_Bool tightened;
9539 
9540  assert(scip != NULL);
9541  assert(cons != NULL);
9542  assert(intervalinfty > 0.0);
9543  assert(bnd < intervalinfty);
9544  assert(var != NULL);
9545  assert(result != NULL);
9546  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9547  assert(nchgbds != NULL);
9548 
9549  /* new bound is no improvement */
9550  if( SCIPisHugeValue(scip, bnd) || SCIPisGE(scip, bnd, SCIPvarGetUbLocal(var)) )
9551  return SCIP_OKAY;
9552 
9553  if( SCIPisInfinity(scip, -bnd) )
9554  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
9555  *result = SCIP_CUTOFF;
9556  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9557  return SCIP_OKAY;
9558  }
9559 
9560  /* new upper bound is very high (between SCIPinfinity() and intervalinfty) */
9561  if( SCIPisInfinity(scip, bnd) )
9562  return SCIP_OKAY;
9563 
9564  bnd = SCIPadjustedVarUb(scip, var, bnd);
9565  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
9566  if( infeas )
9567  {
9568  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n",
9569  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
9570  *result = SCIP_CUTOFF;
9571  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9572  return SCIP_OKAY;
9573  }
9574  if( tightened )
9575  {
9576  SCIPdebugMsg(scip, "%s tightened upper bound of variable <%s> in constraint <%s> to %g\n",
9577  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
9578  ++*nchgbds;
9579  *result = SCIP_REDUCEDDOM;
9580  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9581  }
9582 
9583  return SCIP_OKAY;
9584 }
9585 
9586 /** 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 */
9587 static
9589  SCIP* scip, /**< SCIP data structure */
9590  SCIP_CONS* cons, /**< constraint where we currently propagate */
9591  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9592  SCIP_VAR* var, /**< variable which bounds with might tighten */
9593  SCIP_Real a, /**< coefficient in square term */
9594  SCIP_INTERVAL b, /**< coefficient in linear term */
9595  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9596  SCIP_RESULT* result, /**< result of propagation */
9597  int* nchgbds /**< buffer where to add number of tightened bounds */
9598  )
9599 {
9600  SCIP_INTERVAL newrange;
9601 
9602  assert(scip != NULL);
9603  assert(cons != NULL);
9604  assert(var != NULL);
9605  assert(result != NULL);
9606  assert(nchgbds != NULL);
9607 
9608  /* compute solution of a*x^2 + b*x \in rhs */
9609  if( a == 0.0 && SCIPintervalGetInf(b) == 0.0 && SCIPintervalGetSup(b) == 0.0 )
9610  {
9611  /* relatively easy case: 0.0 \in rhs, thus check if infeasible or just redundant */
9612  if( SCIPintervalGetInf(rhs) > 0.0 || SCIPintervalGetSup(rhs) < 0.0 )
9613  {
9614  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9615  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9616  *result = SCIP_CUTOFF;
9617  }
9618  return SCIP_OKAY;
9619  }
9620  else if( SCIPvarGetLbLocal(var) >= 0.0 )
9621  {
9622  SCIP_INTERVAL a_;
9623 
9624  /* need only positive solutions */
9625  SCIPintervalSet(&a_, a);
9626  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &newrange, a_, b, rhs);
9627  }
9628  else if( SCIPvarGetUbLocal(var) <= 0.0 )
9629  {
9630  /* need only negative solutions */
9631  SCIP_INTERVAL a_;
9632  SCIP_INTERVAL tmp;
9633  SCIPintervalSet(&a_, a);
9635  SCIPintervalSolveUnivariateQuadExpressionPositive(intervalinfty, &tmp, a_, tmp, rhs);
9636  if( SCIPintervalIsEmpty(intervalinfty, tmp) )
9637  {
9638  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9639  *result = SCIP_CUTOFF;
9640  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9641  return SCIP_OKAY;
9642  }
9644  }
9645  else
9646  {
9647  /* need both positive and negative solution */
9648  SCIP_INTERVAL a_;
9649  SCIPintervalSet(&a_, a);
9650  SCIPintervalSolveUnivariateQuadExpression(intervalinfty, &newrange, a_, b, rhs);
9651  }
9652 
9653  /* SCIPdebugMsg(scip, "%g x^2 + [%g, %g] x in [%g, %g] -> [%g, %g]\n", a, b.inf, b.sup, rhs.inf, rhs.sup, newrange.inf, newrange.sup); */
9654 
9655  if( SCIPisInfinity(scip, SCIPintervalGetInf(newrange)) || SCIPisInfinity(scip, -SCIPintervalGetSup(newrange)) )
9656  {
9657  /* domain outside [-infty, +infty] -> declare node infeasible */
9658  SCIPdebugMsg(scip, "found <%s> infeasible because propagated domain of quadratic variable <%s> is outside of (-infty, +infty)\n",
9659  SCIPconsGetName(cons), SCIPvarGetName(var));
9660  *result = SCIP_CUTOFF;
9661  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9662  return SCIP_OKAY;
9663  }
9664 
9665  if( SCIPintervalIsEmpty(intervalinfty, newrange) )
9666  {
9667  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
9668  *result = SCIP_CUTOFF;
9669  return SCIP_OKAY;
9670  }
9671 
9672  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(newrange)) )
9673  {
9674  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, SCIPintervalGetInf(newrange), result, nchgbds) );
9675  if( *result == SCIP_CUTOFF )
9676  return SCIP_OKAY;
9677  }
9678 
9679  if( !SCIPisInfinity(scip, SCIPintervalGetSup(newrange)) )
9680  {
9681  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, SCIPintervalGetSup(newrange), result, nchgbds) );
9682  if( *result == SCIP_CUTOFF )
9683  return SCIP_OKAY;
9684  }
9685 
9686  return SCIP_OKAY;
9687 }
9688 
9689 /* The new version below computes potentially tighter bounds, but also always adds a small safety area since it is not implemented roundingsafe.
9690  * This may be a reason why it gives worse results on one of two instances.
9691  * Further, I have only very few instances where one can expect a difference.
9692  */
9693 #ifndef PROPBILINNEW
9694 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
9695  *
9696  * @note Domain reductions for y are not deduced.
9697  */
9698 static
9700  SCIP* scip, /**< SCIP data structure */
9701  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
9702  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9703  SCIP_VAR* x, /**< first variable */
9704  SCIP_Real xsqrcoef, /**< square coefficient of x */
9705  SCIP_Real xlincoef, /**< linear coefficient of x */
9706  SCIP_VAR* y, /**< second variable */
9707  SCIP_Real ysqrcoef, /**< square coefficient of y */
9708  SCIP_Real ylincoef, /**< linear coefficient of y */
9709  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
9710  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9711  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
9712  int* nchgbds /**< counter to increment if domain reductions are found */
9713  )
9714 {
9715  SCIP_INTERVAL myrhs;
9716  SCIP_INTERVAL varbnds;
9717  SCIP_INTERVAL lincoef;
9718 
9719  assert(scip != NULL);
9720  assert(cons != NULL);
9721  assert(x != NULL);
9722  assert(y != NULL);
9723  assert(x != y);
9724  assert(result != NULL);
9725  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9726  assert(nchgbds != NULL);
9727  assert(bilincoef != 0.0);
9728 
9729  if( SCIPintervalIsEntire(intervalinfty, rhs) )
9730  return SCIP_OKAY;
9731 
9732  /* try to find domain reductions for x */
9734 
9735  /* put ysqrcoef*y^2 + ylincoef * y into rhs */
9736  if( SCIPintervalGetSup(rhs) >= intervalinfty )
9737  {
9738  /* if rhs is unbounded by above, it is sufficient to get an upper bound on ysqrcoef*y^2 + ylincoef * y */
9739  SCIP_ROUNDMODE roundmode;
9740  SCIP_Real tmp;
9741 
9742  SCIPintervalSet(&lincoef, ylincoef);
9743  tmp = SCIPintervalQuadUpperBound(intervalinfty, ysqrcoef, lincoef, varbnds);
9744  roundmode = SCIPintervalGetRoundingMode();
9746  SCIPintervalSetBounds(&myrhs, SCIPintervalGetInf(rhs) - tmp, intervalinfty);
9747  SCIPintervalSetRoundingMode(roundmode);
9748  }
9749  else if( SCIPintervalGetInf(rhs) <= -intervalinfty )
9750  {
9751  /* if rhs is unbounded by below, it is sufficient to get a lower bound on ysqrcoef*y^2 + ylincoef * y */
9752  SCIP_ROUNDMODE roundmode;
9753  SCIP_Real tmp;
9754 
9755  SCIPintervalSet(&lincoef, -ylincoef);
9756  tmp = -SCIPintervalQuadUpperBound(intervalinfty, -ysqrcoef, lincoef, varbnds);
9757  roundmode = SCIPintervalGetRoundingMode();
9759  SCIPintervalSetBounds(&myrhs, -intervalinfty, SCIPintervalGetSup(rhs) - tmp);
9760  SCIPintervalSetRoundingMode(roundmode);
9761  }
9762  else
9763  {
9764  /* if rhs is bounded, we need both bounds on ysqrcoef*y^2 + ylincoef * y */
9765  SCIP_INTERVAL tmp;
9766 
9767  SCIPintervalSet(&lincoef, ylincoef);
9768  SCIPintervalQuad(intervalinfty, &tmp, ysqrcoef, lincoef, varbnds);
9769  SCIPintervalSub(intervalinfty, &myrhs, rhs, tmp);
9770  }
9771 
9772  /* create equation xsqrcoef * x^2 + (xlincoef + bilincoef * [ylb, yub]) * x \in myrhs */
9773  SCIPintervalMulScalar(intervalinfty, &lincoef, varbnds, bilincoef);
9774  SCIPintervalAddScalar(intervalinfty, &lincoef, lincoef, xlincoef);
9775 
9776  /* propagate bounds on x */
9777  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, x, xsqrcoef, lincoef, myrhs, result, nchgbds) );
9778 
9779  return SCIP_OKAY;
9780 }
9781 #else
9782 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
9783  *
9784  * @note Domain reductions for y are not deduced.
9785  */
9786 static
9788  SCIP* scip, /**< SCIP data structure */
9789  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
9790  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9791  SCIP_VAR* x, /**< first variable */
9792  SCIP_Real xsqrcoef, /**< square coefficient of x */
9793  SCIP_Real xlincoef, /**< linear coefficient of x */
9794  SCIP_VAR* y, /**< second variable */
9795  SCIP_Real ysqrcoef, /**< square coefficient of y */
9796  SCIP_Real ylincoef, /**< linear coefficient of y */
9797  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
9798  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
9799  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
9800  int* nchgbds /**< counter to increment if domain reductions are found */
9801  )
9802 {
9803  SCIP_INTERVAL xbnds;
9804  SCIP_INTERVAL ybnds;
9805 
9806  assert(scip != NULL);
9807  assert(cons != NULL);
9808  assert(x != NULL);
9809  assert(y != NULL);
9810  assert(x != y);
9811  assert(result != NULL);
9812  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
9813  assert(nchgbds != NULL);
9814  assert(bilincoef != 0.0);
9815 
9816  if( SCIPintervalIsEntire(intervalinfty, rhs) )
9817  return SCIP_OKAY;
9818 
9819  SCIPintervalSetBounds(&xbnds,
9820  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x))), /*lint !e666*/
9821  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)))); /*lint !e666*/
9822  SCIPintervalSetBounds(&ybnds,
9823  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))), /*lint !e666*/
9824  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))); /*lint !e666*/
9825 
9826  /* try to find domain reductions for x */
9827  SCIPintervalSolveBivariateQuadExpressionAllScalar(intervalinfty, &xbnds, xsqrcoef, ysqrcoef, bilincoef, xlincoef, ylincoef, rhs, xbnds, ybnds);
9828 
9829  if( SCIPintervalIsEmpty(intervalinfty, xbnds) )
9830  {
9831  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(x));
9832  *result = SCIP_CUTOFF;
9833  return SCIP_OKAY;
9834  }
9835 
9836  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(xbnds)) )
9837  {
9838  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, x, SCIPintervalGetInf(xbnds), result, nchgbds) );
9839  if( *result == SCIP_CUTOFF )
9840  return SCIP_OKAY;
9841  }
9842 
9843  if( !SCIPisInfinity(scip, SCIPintervalGetSup(xbnds)) )
9844  {
9845  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, x, SCIPintervalGetSup(xbnds), result, nchgbds) );
9846  if( *result == SCIP_CUTOFF )
9847  return SCIP_OKAY;
9848  }
9849 
9850  return SCIP_OKAY;
9851 }
9852 #endif
9853 
9854 /** computes the minimal and maximal activity for the quadratic part in a constraint data
9855  *
9856  * Only sums up terms that contribute finite values.
9857  * Gives the number of terms that contribute infinite values.
9858  * Only computes those activities where the corresponding side of the constraint is finite.
9859  */
9860 static
9862  SCIP* scip, /**< SCIP data structure */
9863  SCIP_CONSDATA* consdata, /**< constraint data */
9864  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
9865  SCIP_Real* minquadactivity, /**< minimal activity of quadratic variable terms where only terms with finite minimal activity contribute */
9866  SCIP_Real* maxquadactivity, /**< maximal activity of quadratic variable terms where only terms with finite maximal activity contribute */
9867  int* minactivityinf, /**< number of quadratic variables that contribute -infinity to minimal activity */
9868  int* maxactivityinf, /**< number of quadratic variables that contribute +infinity to maximal activity */
9869  SCIP_INTERVAL* quadactcontr /**< contribution of each quadratic variables to quadactivity */
9870  )
9871 { /*lint --e{666}*/
9872  SCIP_ROUNDMODE prevroundmode;
9873  int i;
9874  int j;
9875  int k;
9876  SCIP_INTERVAL tmp;
9877  SCIP_Real bnd;
9878  SCIP_INTERVAL xrng;
9879  SCIP_INTERVAL lincoef;
9880 
9881  assert(scip != NULL);
9882  assert(consdata != NULL);
9883  assert(minquadactivity != NULL);
9884  assert(maxquadactivity != NULL);
9885  assert(minactivityinf != NULL);
9886  assert(maxactivityinf != NULL);
9887  assert(quadactcontr != NULL);
9888 
9889  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
9890  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
9891  */
9892  *minquadactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
9893  *maxquadactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
9894 
9895  *minactivityinf = 0;
9896  *maxactivityinf = 0;
9897 
9898  if( consdata->nquadvars == 0 )
9899  {
9900  SCIPintervalSet(&consdata->quadactivitybounds, 0.0);
9901  return;
9902  }
9903 
9904  for( i = 0; i < consdata->nquadvars; ++i )
9905  {
9906  /* there should be no quadratic variables fixed at -/+ infinity due to our locks */
9907  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var)));
9908  assert(!SCIPisInfinity(scip, -SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
9909 
9910  SCIPintervalSetBounds(&quadactcontr[i], -intervalinfty, intervalinfty);
9911 
9912  SCIPintervalSetBounds(&xrng,
9913  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))),
9914  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))));
9915 
9916  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
9917  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
9918  {
9919  k = consdata->quadvarterms[i].adjbilin[j];
9920  if( consdata->bilinterms[k].var1 != consdata->quadvarterms[i].var )
9921  continue; /* handle this term later */
9922 
9923  SCIPintervalSetBounds(&tmp,
9924  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
9925  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
9926  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
9927  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
9928  }
9929 
9930  if( !SCIPisInfinity(scip, -consdata->lhs) )
9931  {
9932  /* compute maximal activity only if there is a finite left hand side */
9933  bnd = SCIPintervalQuadUpperBound(intervalinfty, consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
9934  if( SCIPisInfinity(scip, bnd) )
9935  {
9936  ++*maxactivityinf;
9937  }
9938  else if( SCIPisInfinity(scip, -bnd) )
9939  {
9940  /* if maximal activity is below value for -infinity, let's take -1e10 as upper bound on maximal activity
9941  * @todo Something better?
9942  */
9943  bnd = -sqrt(SCIPinfinity(scip));
9944  *maxquadactivity += bnd;
9945  quadactcontr[i].sup = bnd;
9946  }
9947  else
9948  {
9949  prevroundmode = SCIPintervalGetRoundingMode();
9951  *maxquadactivity += bnd;
9952  SCIPintervalSetRoundingMode(prevroundmode);
9953  quadactcontr[i].sup = bnd;
9954  }
9955  }
9956 
9957  if( !SCIPisInfinity(scip, consdata->rhs) )
9958  {
9959  /* compute minimal activity only if there is a finite right hand side */
9960  SCIPintervalSetBounds(&lincoef, -SCIPintervalGetSup(lincoef), -SCIPintervalGetInf(lincoef));
9961  bnd = -SCIPintervalQuadUpperBound(intervalinfty, -consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
9962 
9963  if( SCIPisInfinity(scip, -bnd) )
9964  {
9965  ++*minactivityinf;
9966  }
9967  else if( SCIPisInfinity(scip, bnd) )
9968  {
9969  /* if minimal activity is above value for infinity, let's take 1e10 as lower bound on minimal activity
9970  * @todo Something better?
9971  */
9972  bnd = sqrt(SCIPinfinity(scip));
9973  *minquadactivity += bnd;
9974  quadactcontr[i].inf = bnd;
9975  }
9976  else
9977  {
9978  prevroundmode = SCIPintervalGetRoundingMode();
9980  *minquadactivity += bnd;
9981  SCIPintervalSetRoundingMode(prevroundmode);
9982  quadactcontr[i].inf = bnd;
9983  }
9984  }
9985 
9986  }
9987 
9988  SCIPintervalSetBounds(&consdata->quadactivitybounds,
9989  (*minactivityinf > 0 ? -intervalinfty : *minquadactivity),
9990  (*maxactivityinf > 0 ? intervalinfty : *maxquadactivity));
9991  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
9992 }
9993 
9994 /** propagates bounds on a quadratic constraint */
9995 static
9997  SCIP* scip, /**< SCIP data structure */
9998  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9999  SCIP_CONS* cons, /**< constraint to process */
10000  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
10001  int* nchgbds, /**< buffer where to add the the number of changed bounds */
10002  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
10003  )
10004 { /*lint --e{666}*/
10005  SCIP_CONSDATA* consdata;
10006  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
10007  SCIP_INTERVAL consactivity; /* activity of linear plus quadratic part */
10008  SCIP_Real intervalinfty; /* infinity used for interval computation */
10009  SCIP_Real minquadactivity; /* lower bound on finite activities of quadratic part */
10010  SCIP_Real maxquadactivity; /* upper bound on finite activities of quadratic part */
10011  int quadminactinf; /* number of quadratic variables that contribute -infinity to minimal activity of quadratic term */
10012  int quadmaxactinf; /* number of quadratic variables that contribute +infinity to maximal activity of quadratic term */
10013  SCIP_INTERVAL* quadactcontr; /* contribution of each quadratic variable term to quadactivity */
10014 
10015  SCIP_VAR* var;
10016  SCIP_INTERVAL rhs; /* right hand side of quadratic equation */
10017  SCIP_INTERVAL tmp;
10018  SCIP_ROUNDMODE roundmode;
10019  SCIP_Real bnd;
10020  int i;
10021 
10022  assert(scip != NULL);
10023  assert(conshdlr != NULL);
10024  assert(cons != NULL);
10025  assert(result != NULL);
10026  assert(nchgbds != NULL);
10027  assert(redundant != NULL);
10028 
10029  consdata = SCIPconsGetData(cons);
10030  assert(consdata != NULL);
10031 
10032  *result = SCIP_DIDNOTRUN;
10033  *redundant = FALSE;
10034 
10035  *result = SCIP_DIDNOTFIND;
10036 
10037  intervalinfty = 1000 * SCIPinfinity(scip) * SCIPinfinity(scip);
10038 
10039  quadactcontr = NULL;
10040  quadminactinf = -1;
10041  quadmaxactinf = -1;
10042 
10043  SCIPdebugMsg(scip, "start domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
10044 
10045  /* make sure we have activity of linear term and that they are consistent */
10046  consdataUpdateLinearActivity(scip, consdata, intervalinfty);
10047  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10048  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10049  assert(consdata->minlinactivityinf >= 0);
10050  assert(consdata->maxlinactivityinf >= 0);
10051 
10052  /* sort quadratic variable terms, in case we need to search for terms occuring in bilinear terms later
10053  * we sort here already, since we rely on a constant variable order during this method
10054  */
10055  if( consdata->nbilinterms > 0 )
10056  {
10057  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
10058  }
10059 
10060  /* compute activity of quad term part, if not up to date
10061  * in that case, we also collect the contribution of each quad var term for later */
10062  if( SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds) )
10063  {
10064  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
10065  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
10066  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
10067  }
10068 
10069  SCIPdebugMsg(scip, "linear activity: [%g, %g] quadratic activity: [%g, %g]\n",
10070  (consdata->minlinactivityinf > 0 ? -SCIPinfinity(scip) : consdata->minlinactivity),
10071  (consdata->maxlinactivityinf > 0 ? SCIPinfinity(scip) : consdata->maxlinactivity),
10072  consdata->quadactivitybounds.inf, consdata->quadactivitybounds.sup);
10073 
10074  /* extend constraint bounds by epsilon to avoid some numerical difficulties */
10075  SCIPintervalSetBounds(&consbounds,
10076  -infty2infty(SCIPinfinity(scip), intervalinfty, -consdata->lhs+SCIPepsilon(scip)),
10077  +infty2infty(SCIPinfinity(scip), intervalinfty, consdata->rhs+SCIPepsilon(scip)));
10078 
10079  /* check redundancy and infeasibility */
10080  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity,
10081  consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity);
10082  SCIPintervalAdd(intervalinfty, &consactivity, consactivity, consdata->quadactivitybounds);
10083  if( SCIPintervalIsSubsetEQ(intervalinfty, consactivity, consbounds) )
10084  {
10085  SCIPdebugMsg(scip, "found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
10086  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
10087  *redundant = TRUE;
10088  goto CLEANUP;
10089  }
10090 
10091  /* was SCIPintervalAreDisjoint(consbounds, consactivity), but that would allow violations up to eps only
10092  * we need to decide feasibility w.r.t. feastol (but still want to propagate w.r.t. eps)
10093  */
10094  if( SCIPisFeasGT(scip, consbounds.inf, consactivity.sup) || SCIPisFeasLT(scip, consbounds.sup, consactivity.inf) )
10095  {
10096  SCIPdebugMsg(scip, "found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
10097  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
10098  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
10099  *result = SCIP_CUTOFF;
10100  goto CLEANUP;
10101  }
10102 
10103  /* propagate linear part \in rhs = consbounds - quadactivity (use the one from consdata, since that includes infinities) */
10104  SCIPintervalSub(intervalinfty, &rhs, consbounds, consdata->quadactivitybounds);
10105  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
10106  {
10107  SCIP_Real coef;
10108 
10109  for( i = 0; i < consdata->nlinvars; ++i )
10110  {
10111  coef = consdata->lincoefs[i];
10112  var = consdata->linvars[i];
10113 
10114  /* skip fixed variables
10115  * @todo is that a good or a bad idea?
10116  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
10117  */
10118  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10119  continue;
10120 
10121  /* due to large variable bounds and large coefficients, it might happen that the activity of the linear part
10122  * exceeds +/-SCIPinfinity() after updating the activities in consdataUpdateLinearActivity{Lb,Ub}Change; in
10123  * order to detect this case we need to check whether the value of consdata->{min,max}linactivity is infinite
10124  * (see #1433)
10125  */
10126  if( coef > 0.0 )
10127  {
10128  if( SCIPintervalGetSup(rhs) < intervalinfty )
10129  {
10130  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10131  /* try to tighten the upper bound on var x */
10132  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
10133  {
10134  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
10135  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
10136  roundmode = SCIPintervalGetRoundingMode();
10138  bnd = SCIPintervalGetSup(rhs);
10139  bnd -= consdata->minlinactivity;
10140  bnd += coef * SCIPvarGetLbLocal(var);
10141  bnd /= coef;
10142  SCIPintervalSetRoundingMode(roundmode);
10143  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10144  if( *result == SCIP_CUTOFF )
10145  break;
10146  }
10147  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
10148  {
10149  /* x was the variable that made the minimal linear activity equal -infinity, so
10150  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
10151  roundmode = SCIPintervalGetRoundingMode();
10153  bnd = SCIPintervalGetSup(rhs);
10154  bnd -= consdata->minlinactivity;
10155  bnd /= coef;
10156  SCIPintervalSetRoundingMode(roundmode);
10157  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10158  if( *result == SCIP_CUTOFF )
10159  break;
10160  }
10161  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
10162  }
10163 
10164  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10165  {
10166  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10167  /* try to tighten the lower bound on var x */
10168  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
10169  {
10170  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
10171  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
10172  roundmode = SCIPintervalGetRoundingMode();
10174  bnd = SCIPintervalGetInf(rhs);
10175  bnd -= consdata->maxlinactivity;
10176  bnd += coef * SCIPvarGetUbLocal(var);
10177  bnd /= coef;
10178  SCIPintervalSetRoundingMode(roundmode);
10179  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10180  if( *result == SCIP_CUTOFF )
10181  break;
10182  }
10183  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
10184  {
10185  /* x was the variable that made the maximal linear activity equal infinity, so
10186  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
10187  roundmode = SCIPintervalGetRoundingMode();
10189  bnd = SCIPintervalGetInf(rhs);
10190  bnd -= consdata->maxlinactivity;
10191  bnd /= coef;
10192  SCIPintervalSetRoundingMode(roundmode);
10193  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10194  if( *result == SCIP_CUTOFF )
10195  break;
10196  }
10197  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
10198  }
10199  }
10200  else
10201  {
10202  assert(coef < 0.0 );
10203  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10204  {
10205  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10206  /* try to tighten the upper bound on var x */
10207  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
10208  {
10209  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
10210  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
10211  roundmode = SCIPintervalGetRoundingMode();
10213  bnd = consdata->maxlinactivity;
10214  bnd += (-coef) * SCIPvarGetLbLocal(var);
10215  bnd -= SCIPintervalGetInf(rhs);
10216  bnd /= (-coef);
10217  SCIPintervalSetRoundingMode(roundmode);
10218  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10219  if( *result == SCIP_CUTOFF )
10220  break;
10221  }
10222  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
10223  {
10224  /* x was the variable that made the maximal linear activity equal infinity, so
10225  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
10226  roundmode = SCIPintervalGetRoundingMode();
10228  bnd = consdata->maxlinactivity;
10229  bnd -= SCIPintervalGetInf(rhs);
10230  bnd /= (-coef);
10231  SCIPintervalSetRoundingMode(roundmode);
10232  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10233  if( *result == SCIP_CUTOFF )
10234  break;
10235  }
10236  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
10237  }
10238 
10239  if( SCIPintervalGetSup(rhs) < intervalinfty )
10240  {
10241  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10242  /* try to tighten the lower bound on var x */
10243  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
10244  {
10245  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
10246  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
10247  roundmode = SCIPintervalGetRoundingMode();
10249  bnd = consdata->minlinactivity;
10250  bnd += (-coef) * SCIPvarGetUbLocal(var);
10251  bnd -= SCIPintervalGetSup(rhs);
10252  bnd /= (-coef);
10253  SCIPintervalSetRoundingMode(roundmode);
10254  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10255  if( *result == SCIP_CUTOFF )
10256  break;
10257  }
10258  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
10259  {
10260  /* x was the variable that made the maximal linear activity equal -infinity, so
10261  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
10262  roundmode = SCIPintervalGetRoundingMode();
10264  bnd = consdata->minlinactivity;
10265  bnd -= SCIPintervalGetSup(rhs);
10266  bnd /= (-coef);
10267  SCIPintervalSetRoundingMode(roundmode);
10268  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10269  if( *result == SCIP_CUTOFF )
10270  break;
10271  }
10272  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
10273  }
10274  }
10275  }
10276  if( *result == SCIP_CUTOFF )
10277  goto CLEANUP;
10278  }
10279 
10280  /* propagate quadratic part \in rhs = consbounds - linactivity */
10281  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10282  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10283  consdataUpdateLinearActivity(scip, consdata, intervalinfty); /* make sure, activities of linear part did not become invalid by above bound changes, if any */
10284  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
10285  SCIPintervalSetBounds(&tmp,
10286  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
10287  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity));
10288  SCIPintervalSub(intervalinfty, &rhs, consbounds, tmp);
10289  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
10290  {
10291  if( consdata->nquadvars == 1 )
10292  {
10293  /* quadratic part is just a*x^2+b*x -> a common case that we treat directly */
10294  SCIP_INTERVAL lincoef; /* linear coefficient of quadratic equation */
10295 
10296  assert(consdata->nbilinterms == 0);
10297 
10298  var = consdata->quadvarterms[0].var;
10299  SCIPintervalSet(&lincoef, consdata->quadvarterms[0].lincoef);
10300 
10301  /* propagate a*x^2 + b*x \in rhs */
10302  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[0].sqrcoef, lincoef, rhs, result, nchgbds) );
10303  }
10304  else if( consdata->nbilinterms == 1 && consdata->nquadvars == 2 )
10305  {
10306  /* quadratic part is just ax*x^2+bx*x + ay*y^2+by*y + c*xy -> a common case that we treat directly */
10307  assert(consdata->bilinterms[0].var1 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var1 == consdata->quadvarterms[1].var);
10308  assert(consdata->bilinterms[0].var2 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var2 == consdata->quadvarterms[1].var);
10309 
10310  /* 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 */
10311  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
10312  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
10313  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
10314  consdata->bilinterms[0].coef,
10315  rhs, result, nchgbds) );
10316  if( *result != SCIP_CUTOFF )
10317  {
10318  /* 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 */
10319  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
10320  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
10321  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
10322  consdata->bilinterms[0].coef,
10323  rhs, result, nchgbds) );
10324  }
10325  }
10326  else
10327  {
10328  /* general case */
10329 
10330  /* compute "advanced" information on quad var term activities, if not up-to-date */
10331  if( quadminactinf == -1 )
10332  {
10333  assert(quadactcontr == NULL);
10334  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
10335  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
10336  }
10337  assert(quadactcontr != NULL);
10338  assert(quadminactinf >= 0);
10339  assert(quadmaxactinf >= 0);
10340 
10341  /* if the quad activities are not hopelessly unbounded on useful sides, try to deduce domain reductions on quad vars */
10342  if( (SCIPintervalGetSup(rhs) < intervalinfty && quadminactinf <= 1) ||
10343  ( SCIPintervalGetInf(rhs) > -intervalinfty && quadmaxactinf <= 1) )
10344  {
10345  SCIP_INTERVAL lincoef;
10346  SCIP_INTERVAL rhs2;
10347  int j;
10348  int k;
10349 
10350  for( i = 0; i < consdata->nquadvars; ++i )
10351  {
10352  var = consdata->quadvarterms[i].var;
10353 
10354  /* skip fixed variables
10355  * @todo is that a good or a bad idea?
10356  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
10357  */
10358  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10359  continue;
10360 
10361  /* compute rhs2 such that we can propagate quadvarterm(x_i) \in rhs2 */
10362 
10363  /* setup rhs2.sup = rhs.sup - (quadactivity.inf - quadactcontr[i].inf), if everything were finite
10364  * if only quadactcontr[i].inf is infinite (i.e., the other i are all finite), we just get rhs2.sup = rhs.sup
10365  * otherwise we get rhs2.sup = infinity */
10366  if( SCIPintervalGetSup(rhs) < intervalinfty )
10367  {
10368  if( quadminactinf == 0 || (quadminactinf == 1 && SCIPintervalGetInf(quadactcontr[i]) <= -intervalinfty) )
10369  {
10370  roundmode = SCIPintervalGetRoundingMode();
10372  rhs2.sup = rhs.sup - minquadactivity; /*lint !e644*/
10373  /* if the residual quad min activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
10374  if( quadminactinf == 0 && SCIPintervalGetInf(quadactcontr[i]) != 0.0 )
10375  rhs2.sup += SCIPintervalGetInf(quadactcontr[i]);
10376  SCIPintervalSetRoundingMode(roundmode);
10377  }
10378  else
10379  {
10380  /* there are either >= 2 quad var terms contributing -infinity, or there is one which is not i */
10381  rhs2.sup = intervalinfty;
10382  }
10383  }
10384  else
10385  {
10386  rhs2.sup = intervalinfty;
10387  }
10388 
10389  /* setup rhs2.inf = rhs.inf - (quadactivity.sup - quadactcontr[i].sup), see also above */
10390  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10391  {
10392  if( quadmaxactinf == 0 || (quadmaxactinf == 1 && SCIPintervalGetSup(quadactcontr[i]) >= intervalinfty) )
10393  {
10394  roundmode = SCIPintervalGetRoundingMode();
10396  rhs2.inf = rhs.inf - maxquadactivity; /*lint !e644*/
10397  /* if the residual quad max activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
10398  if( quadmaxactinf == 0 && SCIPintervalGetSup(quadactcontr[i]) != 0.0 )
10399  rhs2.inf += SCIPintervalGetSup(quadactcontr[i]);
10400  SCIPintervalSetRoundingMode(roundmode);
10401  }
10402  else
10403  {
10404  /* there are either >= 2 quad var terms contributing infinity, or there is one which is not i */
10405  rhs2.inf = -intervalinfty;
10406  }
10407  }
10408  else
10409  {
10410  rhs2.inf = -intervalinfty;
10411  }
10412  assert(!SCIPintervalIsEmpty(intervalinfty, rhs2));
10413 
10414  /* if rhs2 is entire, then there is nothing we could propagate */
10415  if( SCIPintervalIsEntire(intervalinfty, rhs2) )
10416  continue;
10417 
10418  /* assemble linear coefficient for quad equation a*x^2 + b*x \in rhs2 */
10419  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
10420  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
10421  {
10422  k = consdata->quadvarterms[i].adjbilin[j];
10423 #if 1
10424  if( consdata->bilinterms[k].var1 == var )
10425  {
10426  /* bilinear term k contributes to the activity of quad var term i, so just add bounds to linear coef */
10427  SCIPintervalSetBounds(&tmp,
10428  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10429  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10430  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10431  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10432  }
10433  else
10434  {
10435  /* bilinear term k does not contribute to the activity of quad var term i
10436  * so bounds on term k are contained in rhs2
10437  * if they are finite, we try to remove them from rhs2 and update lincoef instead
10438  * 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
10439  * HOWEVER: when computing rhs2, we may not just have added the bounds for the bilinear term, but for the associated quadratic term
10440  * for this complete term, we used SCIPintervalQuad to compute the bounds
10441  * since we do not want to repeat a call to SCIPintervalQuad for that quadratic term with bilinear term k removed,
10442  * we only remove the bounds for the bilinear term k from rhs2 if the associated quadratic term consists only of this bilinear term,
10443  * i.e., the quadratic term corresponding to var1 should be only var1*var2, but have no square or linear coefs or other bilinear terms
10444  * (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)
10445  */
10446  SCIP_INTERVAL me;
10447  SCIP_INTERVAL bilinbounds;
10448  int otherpos;
10449 
10450  assert(consdata->bilinterms[k].var2 == var);
10451 
10452  assert(consdata->quadvarssorted);
10453  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[k].var1, &otherpos) );
10454  assert(otherpos >= 0);
10455  assert(consdata->quadvarterms[otherpos].var == consdata->bilinterms[k].var1);
10456 
10457  if( (consdata->quadvarterms[otherpos].sqrcoef != 0.0) || consdata->quadvarterms[otherpos].lincoef != 0.0 ||
10458  consdata->quadvarterms[otherpos].nadjbilin > 1 )
10459  continue;
10460 
10461  /* set tmp to bounds of other variable and multiply with bilin coef */
10462  SCIPintervalSetBounds(&tmp,
10463  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))),
10464  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))));
10465  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10466 
10467  /* set me to bounds of i'th variable */
10469  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10470  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10471 
10472  /* remove me*tmp from rhs2 */
10473 
10474  roundmode = SCIPintervalGetRoundingMode();
10475 
10476  if( rhs2.inf > -intervalinfty )
10477  {
10478  /* need upward rounding for SCIPintervalMulSup */
10480  SCIPintervalMulSup(intervalinfty, &bilinbounds, me, tmp);
10481  /* rhs2.inf += bilinbounds.sup, but we are in upward rounding */
10482  if( bilinbounds.sup < intervalinfty )
10483  rhs2.inf = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.inf) - bilinbounds.sup);
10484  }
10485 
10486  if( rhs2.sup < intervalinfty )
10487  {
10488  /* need downward rounding for SCIPintervalMulInf */
10490  SCIPintervalMulInf(intervalinfty, &bilinbounds, me, tmp);
10491  /* rhs2.sup += bilinbounds.inf, but we are in downward rounding */
10492  if( bilinbounds.inf > -intervalinfty )
10493  rhs2.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.sup) - bilinbounds.inf);
10494  }
10495 
10496  SCIPintervalSetRoundingMode(roundmode);
10497 
10498  /* add tmp to lincoef */
10499  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10500  }
10501 #else
10502  if( consdata->bilinterms[k].var1 != var )
10503  continue; /* this term does not contribute to the activity of quad var term i */
10504 
10505  SCIPintervalSetBounds(&tmp,
10506  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10507  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10508  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10509  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10510 #endif
10511  }
10512 
10513  /* deduce domain reductions for x_i */
10514  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[i].sqrcoef, lincoef, rhs2, result, nchgbds) );
10515  if( *result == SCIP_CUTOFF )
10516  goto CLEANUP;
10517  }
10518  }
10519  }
10520  }
10521 
10522  CLEANUP:
10523  SCIPfreeBufferArrayNull(scip, &quadactcontr);
10524 
10525  return SCIP_OKAY;
10526 }
10527 
10528 /** calls domain propagation for a set of constraints */
10529 static
10531  SCIP* scip, /**< SCIP data structure */
10532  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10533  SCIP_CONS** conss, /**< constraints to process */
10534  int nconss, /**< number of constraints */
10535  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
10536  int* nchgbds /**< buffer where to add the the number of changed bounds */
10537  )
10538 {
10539  SCIP_CONSHDLRDATA* conshdlrdata;
10540  SCIP_RESULT propresult;
10541  SCIP_Bool redundant;
10542  int c;
10543  int roundnr;
10544  SCIP_Bool success;
10545  int maxproprounds;
10546 
10547  assert(scip != NULL);
10548  assert(conshdlr != NULL);
10549  assert(conss != NULL || nconss == 0);
10550  assert(result != NULL);
10551  assert(nchgbds != NULL);
10552 
10554 
10555  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10556  assert(conshdlrdata != NULL);
10557 
10558  *result = SCIP_DIDNOTFIND;
10559  roundnr = 0;
10560  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
10561  maxproprounds = conshdlrdata->maxproproundspresolve;
10562  else
10563  maxproprounds = conshdlrdata->maxproprounds;
10564 
10565  do
10566  {
10567  success = FALSE;
10568  ++roundnr;
10569 
10570  SCIPdebugMsg(scip, "starting domain propagation round %d of %d for %d constraints\n", roundnr, maxproprounds, nconss);
10571 
10572  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
10573  {
10574  assert(conss != NULL);
10575  if( !SCIPconsIsEnabled(conss[c]) )
10576  continue;
10577 
10578  if( SCIPconsIsMarkedPropagate(conss[c]) )
10579  {
10580  /* unmark constraint for propagation */
10581  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[c]) );
10582 
10583  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
10584  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
10585  {
10586  *result = propresult;
10587  success = TRUE;
10588  }
10589  if( redundant )
10590  {
10591  SCIPdebugMsg(scip, "deleting constraint <%s> locally\n", SCIPconsGetName(conss[c]));
10592  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
10593  }
10594  }
10595  }
10596 
10597  }
10598  while( success && *result != SCIP_CUTOFF && roundnr < maxproprounds );
10599 
10600  return SCIP_OKAY;
10601 }
10602 
10603 /** checks for a linear variable that can be increase or decreased without harming feasibility */
10604 static
10606  SCIP* scip, /**< SCIP data structure */
10607  SCIP_CONSDATA* consdata /**< constraint data */
10608  )
10609 {
10610  int i;
10611  int poslock;
10612  int neglock;
10613 
10614  consdata->linvar_maydecrease = -1;
10615  consdata->linvar_mayincrease = -1;
10616 
10617  /* check for a linear variable that can be increase or decreased without harming feasibility */
10618  for( i = 0; i < consdata->nlinvars; ++i )
10619  {
10620  /* compute locks of i'th linear variable */
10621  assert(consdata->lincoefs[i] != 0.0);
10622  if( consdata->lincoefs[i] > 0.0 )
10623  {
10624  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
10625  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
10626  }
10627  else
10628  {
10629  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
10630  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
10631  }
10632 
10633  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - neglock == 0 )
10634  {
10635  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
10636  /* if we have already one candidate, then take the one where the loss in the objective function is less */
10637  if( (consdata->linvar_maydecrease < 0) ||
10638  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
10639  consdata->linvar_maydecrease = i;
10640  }
10641 
10642  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - poslock == 0 )
10643  {
10644  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
10645  /* if we have already one candidate, then take the one where the loss in the objective function is less */
10646  if( (consdata->linvar_mayincrease < 0) ||
10647  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
10648  consdata->linvar_mayincrease = i;
10649  }
10650  }
10651 
10652 #ifdef SCIP_DEBUG
10653  if( consdata->linvar_mayincrease >= 0 )
10654  {
10655  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
10656  }
10657  if( consdata->linvar_maydecrease >= 0 )
10658  {
10659  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
10660  }
10661 #endif
10662 }
10663 
10664 /** Given a solution where every quadratic constraint is either feasible or can be made feasible by
10665  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
10666  *
10667  * The method assumes that this is always possible and that not all constraints are feasible already.
10668  */
10669 static
10671  SCIP* scip, /**< SCIP data structure */
10672  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10673  SCIP_CONS** conss, /**< constraints to process */
10674  int nconss, /**< number of constraints */
10675  SCIP_SOL* sol, /**< solution to process */
10676  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
10677  )
10678 {
10679  SCIP_CONSHDLRDATA* conshdlrdata;
10680  SCIP_CONSDATA* consdata;
10681  char origscaling;
10682  SCIP_SOL* newsol;
10683  SCIP_VAR* var;
10684  int c;
10685  SCIP_Real viol;
10686  SCIP_Real delta;
10687  SCIP_Real gap;
10688  SCIP_Bool solviolbounds;
10689 
10690  assert(scip != NULL);
10691  assert(conshdlr != NULL);
10692  assert(conss != NULL || nconss == 0);
10693  assert(success != NULL);
10694 
10695  *success = FALSE;
10696 
10697  /* don't propose new solutions if not in presolve or solving */
10699  return SCIP_OKAY;
10700 
10701  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10702  assert(conshdlrdata != NULL);
10703 
10704  if( sol != NULL )
10705  {
10706  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
10707  }
10708  else
10709  {
10710  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
10711  }
10712  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
10713  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
10714  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
10715 
10716  origscaling = conshdlrdata->scaling;
10717  for( c = 0; c < nconss; ++c )
10718  {
10719  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
10720  assert(consdata != NULL);
10721 
10722  /* recompute violation of solution in case solution has changed
10723  * get absolution violation and sign
10724  * @todo avoid doing it this way
10725  */
10726  conshdlrdata->scaling = 'o';
10727  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
10728  {
10729  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
10730  assert(!solviolbounds);
10731  viol = consdata->lhs - consdata->activity;
10732  }
10733  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10734  {
10735  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
10736  assert(!solviolbounds);
10737  viol = consdata->rhs - consdata->activity;
10738  }
10739  else
10740  continue; /* constraint is satisfied */
10741 
10742  assert(viol != 0.0);
10743  if( consdata->linvar_mayincrease >= 0 &&
10744  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
10745  {
10746  /* have variable where increasing makes the constraint less violated */
10747  var = consdata->linvars[consdata->linvar_mayincrease];
10748  /* compute how much we would like to increase var */
10749  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
10750  assert(delta > 0.0);
10751  /* if var has an upper bound, may need to reduce delta */
10752  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
10753  {
10754  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
10755  delta = MIN(MAX(0.0, gap), delta);
10756  }
10757  if( SCIPisPositive(scip, delta) )
10758  {
10759  /* if variable is integral, round delta up so that it will still have an integer value */
10760  if( SCIPvarIsIntegral(var) )
10761  delta = SCIPceil(scip, delta);
10762 
10763  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
10764  SCIPdebugMsg(scip, "increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
10765 
10766  /* adjust constraint violation, if satisfied go on to next constraint */
10767  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
10768  if( SCIPisZero(scip, viol) )
10769  continue;
10770  }
10771  }
10772 
10773  assert(viol != 0.0);
10774  if( consdata->linvar_maydecrease >= 0 &&
10775  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
10776  {
10777  /* have variable where decreasing makes constraint less violated */
10778  var = consdata->linvars[consdata->linvar_maydecrease];
10779  /* compute how much we would like to decrease var */
10780  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
10781  assert(delta < 0.0);
10782  /* if var has a lower bound, may need to reduce delta */
10783  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
10784  {
10785  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
10786  delta = MAX(MIN(0.0, gap), delta);
10787  }
10788  if( SCIPisNegative(scip, delta) )
10789  {
10790  /* if variable is integral, round delta down so that it will still have an integer value */
10791  if( SCIPvarIsIntegral(var) )
10792  delta = SCIPfloor(scip, delta);
10793  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
10794  SCIPdebugMsg(scip, "increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
10795 
10796  /* adjust constraint violation, if satisfied go on to next constraint */
10797  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
10798  if( SCIPisZero(scip, viol) )
10799  continue;
10800  }
10801  }
10802 
10803  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
10804  break;
10805  }
10806  conshdlrdata->scaling = origscaling;
10807 
10808  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
10809  * then pass it to the trysol heuristic
10810  */
10811  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
10812  {
10813  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
10814 
10815  assert(conshdlrdata->trysolheur != NULL);
10816  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
10817 
10818  *success = TRUE;
10819  }
10820 
10821  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
10822 
10823  return SCIP_OKAY;
10824 }
10825 
10826 /** helper function to enforce constraints */
10827 static
10829  SCIP* scip, /**< SCIP data structure */
10830  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10831  SCIP_CONS** conss, /**< constraints to process */
10832  int nconss, /**< number of constraints */
10833  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
10834  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
10835  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
10836  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
10837  )
10838 {
10839  SCIP_CONSHDLRDATA* conshdlrdata;
10840  SCIP_CONSDATA* consdata;
10841  SCIP_CONS* maxviolcon;
10842  SCIP_Real maxviol;
10843  SCIP_RESULT propresult;
10844  SCIP_RESULT separateresult;
10845  int nchgbds;
10846  int nnotify;
10847  SCIP_Real sepaefficacy;
10848  SCIP_Real minefficacy;
10849  SCIP_Real leastpossibleefficacy;
10850  SCIP_Bool solviolbounds;
10851 
10852  assert(scip != NULL);
10853  assert(conshdlr != NULL);
10854  assert(conss != NULL || nconss == 0);
10855  assert(nconss >= 0);
10856  assert(nusefulconss >= 0);
10857  assert(result != NULL);
10858 
10859  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10860  assert(conshdlrdata != NULL);
10861 
10862  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &solviolbounds, &maxviolcon) );
10863 
10864  if( maxviolcon == NULL )
10865  {
10866  *result = SCIP_FEASIBLE;
10867  return SCIP_OKAY;
10868  }
10869 
10870  *result = SCIP_INFEASIBLE;
10871 
10872  if( solviolbounds )
10873  {
10874  /* if LP solution violates variable bounds, then this should be because a row was added that
10875  * introduced this variable newly to the LP, in which case it gets value 0.0; the row should
10876  * have been added to resolve an infeasibility, so solinfeasible should be TRUE
10877  * see also issue #627
10878  */
10879  assert(solinfeasible);
10880  return SCIP_OKAY;
10881  }
10882 
10883  consdata = SCIPconsGetData(maxviolcon);
10884  assert(consdata != NULL);
10885  maxviol = consdata->lhsviol + consdata->rhsviol;
10886  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
10887 
10888  SCIPdebugMsg(scip, "enforcement with max violation %g in cons <%s> for %s solution\n", maxviol, SCIPconsGetName(maxviolcon),
10889  sol == NULL ? "LP" : "relaxation");
10890 
10891  /* if we are above the 100'th enforcement round for this node, something is strange
10892  * (maybe the LP / relaxator does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
10893  * 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
10894  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
10895  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
10896  * we only increment nenforounds until 101 to avoid an overflow
10897  */
10898  if( conshdlrdata->lastenfonode == SCIPgetCurrentNode(scip) )
10899  {
10900  if( conshdlrdata->nenforounds > 100 )
10901  {
10902  if( SCIPisStopped(scip) )
10903  {
10904  SCIP_NODE* child;
10905 
10906  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
10907  *result = SCIP_BRANCHED;
10908 
10909  return SCIP_OKAY;
10910  }
10911  }
10912 
10913  ++conshdlrdata->nenforounds;
10914 
10915  /* cut off the current subtree, if a limit on the enforcement rounds should be applied. At this point, feasible
10916  * solutions might get cut off; the enfolplimit parameter should therefore only be set if SCIP is used as a
10917  * heuristic solver and when the returned result (infeasible, optimal, the gap) can be ignored
10918  */
10919  if( conshdlrdata->enfolplimit != -1 && conshdlrdata->nenforounds > conshdlrdata->enfolplimit )
10920  {
10922  "cut off subtree because enforcement limit was reached; this might lead to incorrect results\n");
10923  *result = SCIP_CUTOFF;
10924  return SCIP_OKAY;
10925  }
10926  }
10927  else
10928  {
10929  conshdlrdata->lastenfonode = SCIPgetCurrentNode(scip);
10930  conshdlrdata->nenforounds = 0;
10931  }
10932 
10933  /* run domain propagation */
10934  nchgbds = 0;
10935  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
10936  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
10937  {
10938  SCIPdebugMsg(scip, "propagation succeeded (%s)\n", propresult == SCIP_CUTOFF ? "cutoff" : "reduceddom");
10939  *result = propresult;
10940  return SCIP_OKAY;
10941  }
10942 
10943  /* we would like a cut that is efficient enough that it is not redundant in the LP (>feastol)
10944  * however, if the maximal violation is very small, also the best cut efficacy cannot be large
10945  * thus, in the latter case, we are also happy if the efficacy is at least, say, 75% of the maximal violation
10946  * but in any case we need an efficacy that is at least feastol
10947  */
10948  minefficacy = MIN(0.75*maxviol, conshdlrdata->mincutefficacyenfofac * SCIPfeastol(scip)); /*lint !e666 */
10949  minefficacy = MAX(minefficacy, SCIPfeastol(scip)); /*lint !e666 */
10950  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, minefficacy, TRUE, &separateresult, &sepaefficacy) );
10951  if( separateresult == SCIP_CUTOFF )
10952  {
10953  SCIPdebugMsg(scip, "separation found cutoff\n");
10954  *result = SCIP_CUTOFF;
10955  return SCIP_OKAY;
10956  }
10957  if( separateresult == SCIP_SEPARATED )
10958  {
10959  SCIPdebugMsg(scip, "separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, minefficacy);
10960  *result = SCIP_SEPARATED;
10961  return SCIP_OKAY;
10962  }
10963 
10964  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
10965  * -> collect variables for branching
10966  */
10967 
10968  SCIPdebugMsg(scip, "separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, minefficacy, maxviol);
10969 
10970  /* find branching candidates */
10971  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, sol, &nnotify) );
10972 
10973  /* if sepastore can decrease feasibility tolerance, we can add cuts with efficacy in [eps, feastol] */
10974  leastpossibleefficacy = SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip);
10975  if( nnotify == 0 && !solinfeasible && minefficacy > leastpossibleefficacy )
10976  {
10977  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
10978  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, leastpossibleefficacy, TRUE, &separateresult, &sepaefficacy) );
10979  if( separateresult == SCIP_CUTOFF )
10980  {
10981  SCIPdebugMsg(scip, "separation found cutoff\n");
10982  *result = SCIP_CUTOFF;
10983  return SCIP_OKAY;
10984  }
10985  if( separateresult == SCIP_SEPARATED )
10986  {
10987  SCIPdebugMsg(scip, "separation fallback succeeded, efficacy = %g\n", sepaefficacy);
10988  *result = SCIP_SEPARATED;
10989  return SCIP_OKAY;
10990  }
10991  }
10992 
10993  if( nnotify == 0 && !solinfeasible )
10994  {
10995  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
10996  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
10997  */
10998  SCIP_VAR* brvar = NULL;
10999  SCIP_CALL( registerLargeRelaxValueVariableForBranching(scip, conss, nconss, sol, &brvar) );
11000  if( brvar == NULL )
11001  {
11002  /* fallback 3: all quadratic variables seem to be fixed -> replace by linear constraint */
11003  SCIP_Bool addedcons;
11004  SCIP_Bool reduceddom;
11005  SCIP_Bool infeasible;
11006 
11007  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
11008  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
11009  * when it enforces the new constraints again and nothing resolves the infeasiblity that we declare here thus,
11010  * we only add them if considered violated, and otherwise claim the solution is feasible (but print a
11011  * warning) */
11012  if ( infeasible )
11013  *result = SCIP_CUTOFF;
11014  else if ( addedcons )
11015  *result = SCIP_CONSADDED;
11016  else if ( reduceddom )
11017  *result = SCIP_REDUCEDDOM;
11018  else
11019  {
11020  *result = SCIP_FEASIBLE;
11021  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
11022  assert(!SCIPisInfinity(scip, maxviol));
11023  }
11024  return SCIP_OKAY;
11025  }
11026  else
11027  {
11028  SCIPdebugMsg(scip, "Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
11029  SCIPvarGetName(brvar), SCIPgetSolVal(scip, sol, brvar));
11030  nnotify = 1;
11031  }
11032  }
11033 
11034  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
11035  return SCIP_OKAY;
11036 }
11037 
11038 /** tries to upgrade a nonlinear constraint into a quadratic constraint */
11039 static
11040 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
11042  SCIP_EXPRGRAPH* exprgraph;
11043  SCIP_EXPRGRAPHNODE* node;
11044  int i;
11045 
11046  assert(nupgdconss != NULL);
11047  assert(upgdconss != NULL);
11048 
11049  *nupgdconss = 0;
11050 
11051  node = SCIPgetExprgraphNodeNonlinear(scip, cons);
11052 
11053  /* no interest in linear constraints */
11054  if( node == NULL )
11055  return SCIP_OKAY;
11056 
11057  /* if a quadratic expression has been simplified, then all children of the node should be variables */
11059  return SCIP_OKAY;
11060 
11061  switch( SCIPexprgraphGetNodeOperator(node) )
11062  {
11063  case SCIP_EXPR_VARIDX:
11064  case SCIP_EXPR_CONST:
11065  case SCIP_EXPR_PLUS:
11066  case SCIP_EXPR_MINUS:
11067  case SCIP_EXPR_SUM:
11068  case SCIP_EXPR_LINEAR:
11069  /* these should not appear as exprgraphnodes after constraint presolving */
11070  return SCIP_OKAY;
11071 
11072  case SCIP_EXPR_DIV:
11073  case SCIP_EXPR_SQRT:
11074  case SCIP_EXPR_REALPOWER:
11075  case SCIP_EXPR_INTPOWER:
11076  case SCIP_EXPR_SIGNPOWER:
11077  case SCIP_EXPR_EXP:
11078  case SCIP_EXPR_LOG:
11079  case SCIP_EXPR_SIN:
11080  case SCIP_EXPR_COS:
11081  case SCIP_EXPR_TAN:
11082  /* case SCIP_EXPR_ERF: */
11083  /* case SCIP_EXPR_ERFI: */
11084  case SCIP_EXPR_MIN:
11085  case SCIP_EXPR_MAX:
11086  case SCIP_EXPR_ABS:
11087  case SCIP_EXPR_SIGN:
11088  case SCIP_EXPR_PRODUCT:
11089  case SCIP_EXPR_POLYNOMIAL:
11090  case SCIP_EXPR_USER:
11091  /* these do not look like an quadratic expression (assuming the expression graph simplifier did run) */
11092  return SCIP_OKAY;
11093 
11094  case SCIP_EXPR_MUL:
11095  case SCIP_EXPR_SQUARE:
11096  case SCIP_EXPR_QUADRATIC:
11097  /* these mean that we have something quadratic */
11098  break;
11099 
11100  case SCIP_EXPR_PARAM:
11101  case SCIP_EXPR_LAST:
11102  default:
11103  SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
11104  return SCIP_OKAY;
11105  }
11106 
11107  /* setup a quadratic constraint */
11108 
11109  if( upgdconsssize < 1 )
11110  {
11111  /* request larger upgdconss array */
11112  *nupgdconss = -1;
11113  return SCIP_OKAY;
11114  }
11115 
11116  *nupgdconss = 1;
11117  SCIP_CALL( SCIPcreateConsQuadratic(scip, &upgdconss[0], SCIPconsGetName(cons),
11119  0, NULL, 0, NULL,
11120  SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
11124  assert(!SCIPconsIsStickingAtNode(cons));
11125 
11126  exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
11127 
11128  /* add variables from expression tree as "quadratic" variables to quadratic constraint */
11129  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
11130  {
11131  assert(SCIPexprgraphGetNodeChildren(node)[i] != NULL);
11132  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, upgdconss[0], (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[i]), 0.0, 0.0) );
11133  }
11134 
11135  switch( SCIPexprgraphGetNodeOperator(node) )
11136  {
11137  case SCIP_EXPR_MUL:
11138  /* expression is product of two variables, so add bilinear term to constraint */
11139  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
11140 
11141  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
11144  1.0) );
11145 
11146  break;
11147 
11148  case SCIP_EXPR_SQUARE:
11149  /* expression is square of a variable, so change square coefficient of quadratic variable */
11150  assert(SCIPexprgraphGetNodeNChildren(node) == 1);
11151 
11152  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
11154  1.0) );
11155 
11156  break;
11157 
11158  case SCIP_EXPR_QUADRATIC:
11159  {
11160  /* expression is quadratic */
11161  SCIP_QUADELEM* quadelems;
11162  int nquadelems;
11163  SCIP_Real* lincoefs;
11164 
11166  nquadelems = SCIPexprgraphGetNodeQuadraticNQuadElements(node);
11168 
11170 
11171  if( lincoefs != NULL )
11172  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
11173  if( lincoefs[i] != 0.0 )
11174  {
11175  /* linear term */
11176  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, upgdconss[0],
11178  lincoefs[i]) );
11179  }
11180 
11181  for( i = 0; i < nquadelems; ++i )
11182  {
11183  assert(quadelems[i].idx1 < SCIPexprgraphGetNodeNChildren(node));
11184  assert(quadelems[i].idx2 < SCIPexprgraphGetNodeNChildren(node));
11185 
11186  if( quadelems[i].idx1 == quadelems[i].idx2 )
11187  {
11188  /* square term */
11189  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
11190  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
11191  quadelems[i].coef) );
11192  }
11193  else
11194  {
11195  /* bilinear term */
11196  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
11197  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
11198  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx2]),
11199  quadelems[i].coef) );
11200  }
11201  }
11202 
11203  break;
11204  }
11205 
11206  default:
11207  SCIPerrorMessage("you should not be here\n");
11208  return SCIP_ERROR;
11209  } /*lint !e788 */
11210 
11211  return SCIP_OKAY;
11212 }
11213 
11214 /*
11215  * Callback methods of constraint handler
11216  */
11217 
11218 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
11219 static
11220 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
11221 { /*lint --e{715}*/
11222  assert(scip != NULL);
11223  assert(conshdlr != NULL);
11224  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
11225 
11226  /* call inclusion method of constraint handler */
11228 
11229  *valid = TRUE;
11230 
11231  return SCIP_OKAY;
11232 }
11233 
11234 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
11235 static
11236 SCIP_DECL_CONSFREE(consFreeQuadratic)
11238  SCIP_CONSHDLRDATA* conshdlrdata;
11239  int i;
11240 
11241  assert(scip != NULL);
11242  assert(conshdlr != NULL);
11243 
11244  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11245  assert(conshdlrdata != NULL);
11246 
11247  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
11248  {
11249  assert(conshdlrdata->quadconsupgrades[i] != NULL);
11250  SCIPfreeBlockMemory(scip, &conshdlrdata->quadconsupgrades[i]); /*lint !e866*/
11251  }
11252  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize);
11253 
11254  SCIPfreeBlockMemory(scip, &conshdlrdata);
11255 
11256  return SCIP_OKAY;
11257 }
11258 
11259 /** initialization method of constraint handler (called after problem was transformed) */
11260 static
11261 SCIP_DECL_CONSINIT(consInitQuadratic)
11262 { /*lint --e{715} */
11263  SCIP_CONSHDLRDATA* conshdlrdata;
11264 
11265  assert(scip != NULL);
11266  assert(conshdlr != NULL);
11267 
11268  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11269  assert(conshdlrdata != NULL);
11270 
11271  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11272  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11273 
11274  return SCIP_OKAY;
11275 }
11276 
11277 
11278 /** deinitialization method of constraint handler (called before transformed problem is freed) */
11279 static
11280 SCIP_DECL_CONSEXIT(consExitQuadratic)
11281 { /*lint --e{715} */
11282  SCIP_CONSHDLRDATA* conshdlrdata;
11283 
11284  assert(scip != NULL);
11285  assert(conshdlr != NULL);
11286 
11287  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11288  assert(conshdlrdata != NULL);
11289 
11290  conshdlrdata->subnlpheur = NULL;
11291  conshdlrdata->trysolheur = NULL;
11292 
11293  return SCIP_OKAY;
11294 }
11295 
11296 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
11297 #if 0
11298 static
11299 SCIP_DECL_CONSINITPRE(consInitpreQuadratic)
11300 { /*lint --e{715}*/
11301  SCIP_CONSHDLRDATA* conshdlrdata;
11302  SCIP_CONSDATA* consdata;
11303  int c;
11304 
11305  assert(scip != NULL);
11306  assert(conshdlr != NULL);
11307  assert(conss != NULL || nconss == 0);
11308 
11309  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11310  assert(conshdlrdata != NULL);
11311 
11312  return SCIP_OKAY;
11313 }
11314 #endif
11315 
11316 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11317 static
11318 SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
11319 { /*lint --e{715}*/
11320  SCIP_CONSDATA* consdata;
11321  int c;
11322 #ifndef NDEBUG
11323  int i;
11324 #endif
11325 
11326  assert(scip != NULL);
11327  assert(conshdlr != NULL);
11328  assert(conss != NULL || nconss == 0);
11329 
11330  for( c = 0; c < nconss; ++c )
11331  {
11332  assert(conss != NULL);
11333  consdata = SCIPconsGetData(conss[c]);
11334  assert(consdata != NULL);
11335 
11336  if( !consdata->isremovedfixings )
11337  {
11338  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
11339  }
11340 
11341  /* make sure we do not have duplicate bilinear terms, quad var terms, or linear vars */
11342  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
11343  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
11344  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
11345 
11346  assert(consdata->isremovedfixings);
11347  assert(consdata->linvarsmerged);
11348  assert(consdata->quadvarsmerged);
11349  assert(consdata->bilinmerged);
11350 
11351 #ifndef NDEBUG
11352  for( i = 0; i < consdata->nlinvars; ++i )
11353  assert(SCIPvarIsActive(consdata->linvars[i]));
11354 
11355  for( i = 0; i < consdata->nquadvars; ++i )
11356  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
11357 #endif
11358 
11359  /* tell SCIP that we have something nonlinear */
11360  if( SCIPconsIsAdded(conss[c]) && consdata->nquadvars > 0 )
11361  SCIPenableNLP(scip);
11362  }
11363 
11364  return SCIP_OKAY;
11365 }
11366 
11367 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin)
11368  *
11369  * @note Also called from consEnableQuadratic during solving stage.
11370  */
11371 static
11372 SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
11374  SCIP_CONSHDLRDATA* conshdlrdata;
11375  SCIP_CONSDATA* consdata;
11376  int c;
11377  int i;
11378 
11379  assert(scip != NULL);
11380  assert(conshdlr != NULL);
11381  assert(conss != NULL || nconss == 0);
11382 
11383  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11384  assert(conshdlrdata != NULL);
11385 
11386  for( c = 0; c < nconss; ++c )
11387  {
11388  assert(conss != NULL);
11389  consdata = SCIPconsGetData(conss[c]);
11390  assert(consdata != NULL);
11391 
11392  /* check for a linear variable that can be increase or decreased without harming feasibility */
11393  consdataFindUnlockedLinearVar(scip, consdata);
11394 
11395  /* setup lincoefsmin, lincoefsmax */
11396  consdata->lincoefsmin = SCIPinfinity(scip);
11397  consdata->lincoefsmax = 0.0;
11398  for( i = 0; i < consdata->nlinvars; ++i )
11399  {
11400  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666 */
11401  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666 */
11402  }
11403 
11404  /* add nlrow representation to NLP, if NLP had been constructed */
11405  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
11406  {
11407  if( consdata->nlrow == NULL )
11408  {
11409  /* compute curvature for the quadratic constraint if not done yet */
11410  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) );
11411 
11412  SCIP_CALL( createNlRow(scip, conss[c]) );
11413  assert(consdata->nlrow != NULL);
11414  }
11415  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
11416  }
11417 
11418  /* setup sepaquadvars and sepabilinvar2pos */
11419  assert(consdata->sepaquadvars == NULL);
11420  assert(consdata->sepabilinvar2pos == NULL);
11421  if( consdata->nquadvars > 0 )
11422  {
11423  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepaquadvars, consdata->nquadvars) );
11424  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms) );
11425 
11426  /* make sure, quadratic variable terms are sorted */
11427  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
11428 
11429  for( i = 0; i < consdata->nquadvars; ++i )
11430  consdata->sepaquadvars[i] = consdata->quadvarterms[i].var;
11431 
11432  for( i = 0; i < consdata->nbilinterms; ++i )
11433  {
11434  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &consdata->sepabilinvar2pos[i]) );
11435  }
11436  }
11437 
11438  if( conshdlrdata->checkfactorable )
11439  {
11440  /* check if constraint function is factorable, i.e., can be written as product of two linear functions */
11441  SCIP_CALL( checkFactorable(scip, conss[c]) );
11442  }
11443 
11444  /* compute gauge function using interior points per constraint, only when there are quadratic variables */
11445  if( conshdlrdata->gaugecuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
11446  {
11447  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11448  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
11449  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
11450  {
11451  SCIP_CALL( computeGauge(scip, conshdlr, conss[c]) );
11452  }
11453  }
11454 
11455  /* compute eigendecomposition for convex quadratics */
11456  if( conshdlrdata->projectedcuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
11457  {
11458  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11459  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
11460  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
11461  {
11462  SCIP_CALL( computeED(scip, conshdlr, conss[c]) );
11463  }
11464  }
11465 
11466  /* mark constraint for propagation */
11467  SCIP_CALL( SCIPmarkConsPropagate(scip, conss[c]) );
11468  consdata->ispropagated = FALSE;
11469  }
11470 
11471  if( SCIPgetStage(scip) != SCIP_STAGE_INITSOLVE )
11472  {
11473  /* if called from consEnableQuadratic, then don't do below */
11474  return SCIP_OKAY;
11475  }
11476 
11477  conshdlrdata->newsoleventfilterpos = -1;
11478  if( nconss != 0 && conshdlrdata->linearizeheursol )
11479  {
11480  SCIP_EVENTHDLR* eventhdlr;
11481 
11482  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
11483  assert(eventhdlr != NULL);
11484 
11485  /* @todo Should we catch every new solution or only new *best* solutions */
11486  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11487  }
11488 
11489  if( nconss != 0 && !SCIPisIpoptAvailableIpopt() && !SCIPisInRestart(scip) )
11490  {
11491  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");
11492  }
11493 
11494  /* reset flags and counters */
11495  conshdlrdata->sepanlp = FALSE;
11496  conshdlrdata->lastenfonode = NULL;
11497  conshdlrdata->nenforounds = 0;
11498 
11499  return SCIP_OKAY;
11500 }
11501 
11502 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed)
11503  *
11504  * @note Also called from consDisableQuadratic during solving stage.
11505  */
11506 static
11507 SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
11508 { /*lint --e{715}*/
11509  SCIP_CONSHDLRDATA* conshdlrdata;
11510  SCIP_CONSDATA* consdata;
11511  int c;
11512 
11513  assert(scip != NULL);
11514  assert(conshdlr != NULL);
11515  assert(conss != NULL || nconss == 0);
11516 
11517  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11518  assert(conshdlrdata != NULL);
11519 
11520  for( c = 0; c < nconss; ++c )
11521  {
11522  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
11523  assert(consdata != NULL);
11524 
11525  /* free nonlinear row representation */
11526  if( consdata->nlrow != NULL )
11527  {
11528  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
11529  }
11530 
11531  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepaquadvars != NULL || consdata->nquadvars == 0); /*lint !e613 */
11532  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepabilinvar2pos != NULL || consdata->nquadvars == 0); /*lint !e613 */
11533  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepaquadvars, consdata->nquadvars);
11534  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms);
11535 
11536  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorleft, consdata->nquadvars + 1);
11537  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorright, consdata->nquadvars + 1);
11538 
11539  SCIPfreeBlockMemoryArrayNull(scip, &consdata->interiorpoint, consdata->nquadvars);
11540  SCIPfreeBlockMemoryArrayNull(scip, &consdata->gaugecoefs, consdata->nquadvars);
11541  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvalues, consdata->nquadvars);
11542  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvectors, (int)(consdata->nquadvars*consdata->nquadvars));
11543  SCIPfreeBlockMemoryArrayNull(scip, &consdata->bp, consdata->nquadvars);
11544  }
11545 
11546  if( SCIPgetStage(scip) != SCIP_STAGE_EXITSOLVE )
11547  {
11548  /* if called from consDisableQuadratic, then don't do below */
11549  return SCIP_OKAY;
11550  }
11551 
11552  if( conshdlrdata->newsoleventfilterpos >= 0 )
11553  {
11554  SCIP_EVENTHDLR* eventhdlr;
11555 
11556  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
11557  assert(eventhdlr != NULL);
11558 
11559  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11560  conshdlrdata->newsoleventfilterpos = -1;
11561  }
11562 
11563  return SCIP_OKAY;
11564 }
11565 
11566 /** frees specific constraint data */
11567 static
11568 SCIP_DECL_CONSDELETE(consDeleteQuadratic)
11570  assert(scip != NULL);
11571  assert(conshdlr != NULL);
11572  assert(cons != NULL);
11573  assert(consdata != NULL);
11574  assert(SCIPconsGetData(cons) == *consdata);
11575 
11576  SCIP_CALL( consdataFree(scip, consdata) );
11577 
11578  assert(*consdata == NULL);
11579 
11580  return SCIP_OKAY;
11581 }
11582 
11583 /** transforms constraint data into data belonging to the transformed problem */
11584 static
11585 SCIP_DECL_CONSTRANS(consTransQuadratic)
11586 {
11587  SCIP_CONSDATA* sourcedata;
11588  SCIP_CONSDATA* targetdata;
11589  int i;
11590 
11591  sourcedata = SCIPconsGetData(sourcecons);
11592  assert(sourcedata != NULL);
11593 
11594  SCIP_CALL( consdataCreate(scip, &targetdata,
11595  sourcedata->lhs, sourcedata->rhs,
11596  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
11597  sourcedata->nquadvars, sourcedata->quadvarterms,
11598  sourcedata->nbilinterms, sourcedata->bilinterms,
11599  FALSE) );
11600 
11601  for( i = 0; i < targetdata->nlinvars; ++i )
11602  {
11603  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
11604  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
11605  }
11606 
11607  for( i = 0; i < targetdata->nquadvars; ++i )
11608  {
11609  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->quadvarterms[i].var, &targetdata->quadvarterms[i].var) );
11610  SCIP_CALL( SCIPcaptureVar(scip, targetdata->quadvarterms[i].var) );
11611  }
11612 
11613  for( i = 0; i < targetdata->nbilinterms; ++i )
11614  {
11615  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var1, &targetdata->bilinterms[i].var1) );
11616  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var2, &targetdata->bilinterms[i].var2) );
11617 
11618  if( SCIPvarCompare(targetdata->bilinterms[i].var1, targetdata->bilinterms[i].var2) > 0 )
11619  {
11620  SCIP_VAR* tmp;
11621  tmp = targetdata->bilinterms[i].var2;
11622  targetdata->bilinterms[i].var2 = targetdata->bilinterms[i].var1;
11623  targetdata->bilinterms[i].var1 = tmp;
11624  }
11625  }
11626 
11627  /* create target constraint */
11628  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
11629  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11630  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
11631  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
11632  SCIPconsIsStickingAtNode(sourcecons)) );
11633 
11634  SCIPdebugMsg(scip, "created transformed quadratic constraint ");
11635  SCIPdebugPrintCons(scip, *targetcons, NULL);
11636 
11637  return SCIP_OKAY;
11638 }
11639 
11640 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11641 static
11642 SCIP_DECL_CONSINITLP(consInitlpQuadratic)
11644  SCIP_CONSHDLRDATA* conshdlrdata;
11645  SCIP_CONSDATA* consdata;
11646  SCIP_VAR* var;
11647  SCIP_ROW* row;
11648  SCIP_Real* x;
11649  int c;
11650  int i;
11651 
11652  assert(scip != NULL);
11653  assert(conshdlr != NULL);
11654  assert(conss != NULL || nconss == 0);
11655 
11656  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11657  assert(conshdlrdata != NULL);
11658 
11659  *infeasible = FALSE;
11660 
11661  for( c = 0; c < nconss && !(*infeasible); ++c )
11662  {
11663  assert(conss[c] != NULL); /*lint !e613 */
11664 
11665  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11666 
11667  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
11668  assert(consdata != NULL);
11669 
11670  row = NULL;
11671 
11672  if( consdata->nquadvars == 0 )
11673  {
11674  /* if we are actually linear, add the constraint as row to the LP */
11675  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
11676  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613 */
11677  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
11678  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, infeasible) );
11679  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11680  continue;
11681  }
11682 
11683  /* alloc memory for reference point */
11684  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nquadvars) );
11685 
11686  /* for convex parts, add linearizations in 5 points */
11687  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
11688  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
11689  {
11690  SCIP_Real lb;
11691  SCIP_Real ub;
11692  SCIP_Real lambda;
11693  int k;
11694 
11695  for( k = 0; k < 5; ++k )
11696  {
11697  lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
11698  for( i = 0; i < consdata->nquadvars; ++i )
11699  {
11700  var = consdata->quadvarterms[i].var;
11701  lb = SCIPvarGetLbGlobal(var);
11702  ub = SCIPvarGetUbGlobal(var);
11703 
11704  if( ub > -INITLPMAXVARVAL )
11705  lb = MAX(lb, -INITLPMAXVARVAL);
11706  if( lb < INITLPMAXVARVAL )
11707  ub = MIN(ub, INITLPMAXVARVAL);
11708 
11709  /* make bounds finite */
11710  if( SCIPisInfinity(scip, -lb) )
11711  lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
11712  if( SCIPisInfinity(scip, ub) )
11713  ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
11714 
11716  x[i] = lambda * ub + (1.0 - lambda) * lb;
11717  else
11718  x[i] = lambda * lb + (1.0 - lambda) * ub;
11719  }
11720 
11721  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, consdata->isconvex ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT, &row, NULL,
11722  FALSE, -SCIPinfinity(scip)) ); /*lint !e613 */
11723  if( row != NULL )
11724  {
11725  SCIPdebugMsg(scip, "initlp adds row <%s> for lambda = %g of conss <%s>\n", SCIProwGetName(row), lambda, SCIPconsGetName(conss[c])); /*lint !e613 */
11726  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11727 
11728  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, infeasible) );
11729  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11730  }
11731  }
11732  }
11733 
11734  /* for concave parts, add underestimator w.r.t. at most 2 reference points */
11735  if( !(*infeasible) && ((! consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs))
11736  || (! consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs))) )
11737  {
11738  SCIP_Bool unbounded;
11739  SCIP_Bool possquare;
11740  SCIP_Bool negsquare;
11741  SCIP_Real lb;
11742  SCIP_Real ub;
11743  SCIP_Real lambda;
11744  int k;
11745 
11746  unbounded = FALSE; /* whether there are unbounded variables */
11747  possquare = FALSE; /* whether there is a positive square term */
11748  negsquare = FALSE; /* whether there is a negative square term */
11749  for( k = 0; k < 2; ++k )
11750  {
11751  /* Set reference point to 0 projected on bounds for unbounded variables or in between lower and upper bound
11752  * for bounded variables in the first round, we set it closer to the best bound for one part of the
11753  * variables, in the second closer to the best bound for the other part of the variables.
11754  * Additionally, we use slightly different weights for each variable.
11755  * The reason for the latter is, that for a bilinear term with bounded variables, there are always two linear underestimators
11756  * if the same weight is used for both variables of a product, then rounding and luck decides which underestimator is chosen
11757  * of course, the possible number of cuts is something in the order of 2^nquadvars, and we choose two of them here.
11758  */
11759  for( i = 0; i < consdata->nquadvars; ++i )
11760  {
11761  var = consdata->quadvarterms[i].var;
11762  lb = SCIPvarGetLbGlobal(var);
11763  ub = SCIPvarGetUbGlobal(var);
11764 
11765  if( SCIPisInfinity(scip, -lb) )
11766  {
11767  if( SCIPisInfinity(scip, ub) )
11768  x[i] = 0.0;
11769  else
11770  x[i] = MIN(0.0, ub);
11771  unbounded = TRUE;
11772  }
11773  else
11774  {
11775  if( SCIPisInfinity(scip, ub) )
11776  {
11777  x[i] = MAX(0.0, lb);
11778  unbounded = TRUE;
11779  }
11780  else
11781  {
11782  lambda = 0.4 + 0.2 * ((i+k)%2) + 0.01 * i / (double)consdata->nquadvars;
11783  x[i] = lambda * SCIPvarGetBestBoundLocal(var) + (1.0-lambda) * SCIPvarGetWorstBoundLocal(var);
11784  }
11785  }
11786 
11787  possquare |= consdata->quadvarterms[i].sqrcoef > 0.0; /*lint !e514 */
11788  negsquare |= consdata->quadvarterms[i].sqrcoef < 0.0; /*lint !e514 */
11789  }
11790 
11791  if( !consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
11792  {
11793  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_RIGHT, &row, NULL,
11794  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
11795  if( row != NULL )
11796  {
11797  SCIPdebugMsg(scip, "initlp adds row <%s> for rhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
11798  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11799 
11800  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, infeasible) );
11801  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11802  }
11803  }
11804  if( !(*infeasible) && !consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
11805  {
11806  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_LEFT, &row, NULL,
11807  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
11808  if( row != NULL )
11809  {
11810  SCIPdebugMsg(scip, "initlp adds row <%s> for lhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
11811  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
11812 
11813  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, infeasible) );
11814  SCIP_CALL( SCIPreleaseRow (scip, &row) );
11815  }
11816  }
11817 
11818  /* if there are unbounded variables, then there is typically only at most one possible underestimator, so don't try another round
11819  * 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 */
11820  if( unbounded ||
11821  (consdata->nbilinterms == 0 && (!possquare || SCIPisInfinity(scip, consdata->rhs))) ||
11822  (consdata->nbilinterms == 0 && (!negsquare || SCIPisInfinity(scip, -consdata->lhs))) )
11823  break;
11824  }
11825  }
11826 
11827  SCIPfreeBufferArray(scip, &x);
11828  }
11829 
11830  return SCIP_OKAY;
11831 }
11832 
11833 /** separation method of constraint handler for LP solutions */
11834 static
11835 SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
11836 {
11837  SCIP_CONSHDLRDATA* conshdlrdata;
11838  SCIP_Bool solviolbounds;
11839  SCIP_CONS* maxviolcon;
11840 
11841  assert(scip != NULL);
11842  assert(conshdlr != NULL);
11843  assert(conss != NULL || nconss == 0);
11844  assert(result != NULL);
11845 
11846  *result = SCIP_DIDNOTFIND;
11847 
11848  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11849  assert(conshdlrdata != NULL);
11850 
11851  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
11852 
11853  /* don't try to separate solutions that violate variable bounds */
11854  if( solviolbounds )
11855  return SCIP_OKAY;
11856 
11857  /* if nothing violated, then nothing to separate */
11858  if( maxviolcon == NULL )
11859  return SCIP_OKAY;
11860 
11861  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
11862  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
11863  */
11864  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
11865  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) ||
11866  (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
11867  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
11868  {
11869  SCIP_CONSDATA* consdata;
11870  SCIP_NLPSOLSTAT solstat;
11871  SCIP_Bool solvednlp;
11872  int c;
11873 
11874  solstat = SCIPgetNLPSolstat(scip);
11875  solvednlp = FALSE;
11876  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
11877  {
11878  /* NLP is not solved yet, so we might want to do this
11879  * but first check whether there is a violated constraint side which corresponds to a convex function
11880  */
11881  for( c = 0; c < nconss; ++c )
11882  {
11883  assert(conss[c] != NULL); /*lint !e613 */
11884 
11885  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
11886  assert(consdata != NULL);
11887 
11888  /* skip feasible constraints */
11889  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11890  continue;
11891 
11892  /* make sure curvature has been checked */
11893  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
11894 
11895  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->isconvex) ||
11896  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->isconcave) )
11897  break;
11898  }
11899 
11900  if( c < nconss )
11901  {
11902  /* try to solve NLP and update solstat */
11903 
11904  /* ensure linear conss are in NLP */
11905  if( conshdlrdata->subnlpheur != NULL )
11906  {
11907  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
11908  }
11909 
11910  /* set LP solution as starting values, if available */
11912  {
11914  }
11915 
11916  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
11917  SCIP_CALL( SCIPsolveNLP(scip) );
11918 
11919  solstat = SCIPgetNLPSolstat(scip);
11920  SCIPdebugMsg(scip, "solved NLP relax, solution status: %d\n", solstat);
11921 
11922  solvednlp = TRUE;
11923  }
11924  }
11925 
11926  conshdlrdata->sepanlp = TRUE;
11927 
11928  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
11929  {
11930  SCIPdebugMsg(scip, "NLP relaxation is globally infeasible, thus can cutoff node\n");
11931  *result = SCIP_CUTOFF;
11932  return SCIP_OKAY;
11933  }
11934 
11935  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
11936  {
11937  /* if we have feasible NLP solution, generate linearization cuts there */
11938  SCIP_Bool lpsolseparated;
11939  SCIP_SOL* nlpsol;
11940 
11941  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
11942  assert(nlpsol != NULL);
11943 
11944  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
11945  if( solvednlp && conshdlrdata->trysolheur != NULL )
11946  {
11947  int nfracvars;
11948 
11949  nfracvars = 0;
11950  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
11951  {
11952  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
11953  }
11954 
11955  if( nfracvars == 0 )
11956  {
11957  SCIPdebugMsg(scip, "pass solution with obj. value %g to trysol\n", SCIPgetSolOrigObj(scip, nlpsol));
11958  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
11959  }
11960  }
11961 
11962  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, conshdlrdata->mincutefficacysepa) );
11963 
11964  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
11965 
11966  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
11967  if( lpsolseparated )
11968  {
11969  SCIPdebugMsg(scip, "linearization cuts separate LP solution\n");
11970  *result = SCIP_SEPARATED;
11971 
11972  return SCIP_OKAY;
11973  }
11974  }
11975  }
11976  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
11977  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
11978  */
11979 
11980  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
11981 
11982  return SCIP_OKAY;
11983 }
11984 
11985 /** separation method of constraint handler for arbitrary primal solutions */
11986 static
11987 SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
11989  SCIP_CONSHDLRDATA* conshdlrdata;
11990  SCIP_Bool solviolbounds;
11991  SCIP_CONS* maxviolcon;
11992 
11993  assert(scip != NULL);
11994  assert(conshdlr != NULL);
11995  assert(conss != NULL || nconss == 0);
11996  assert(sol != NULL);
11997  assert(result != NULL);
11998 
11999  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12000  assert(conshdlrdata != NULL);
12001 
12002  *result = SCIP_DIDNOTFIND;
12003 
12004  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &solviolbounds, &maxviolcon) );
12005 
12006  /* don't separate solution that are outside variable bounds */
12007  if( solviolbounds )
12008  return SCIP_OKAY;
12009 
12010  /* if nothing violated, then nothing to separate */
12011  if( maxviolcon == NULL )
12012  return SCIP_OKAY;
12013 
12014  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
12015 
12016  return SCIP_OKAY;
12017 }
12018 
12019 /** constraint enforcing method of constraint handler for LP solutions */
12020 static
12021 SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
12022 { /*lint --e{715}*/
12023  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12024 
12025  return SCIP_OKAY;
12026 }
12027 
12028 /** constraint enforcing method of constraint handler for relaxation solutions */
12029 static
12030 SCIP_DECL_CONSENFORELAX(consEnforelaxQuadratic)
12031 { /*lint --e{715}*/
12032  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12033 
12034  return SCIP_OKAY;
12035 }
12036 
12037 /** constraint enforcing method of constraint handler for pseudo solutions */
12038 static
12039 SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
12040 { /*lint --e{715}*/
12041  SCIP_Bool solviolbounds;
12042  SCIP_CONS* maxviolcon;
12043  SCIP_CONSDATA* consdata;
12044  SCIP_RESULT propresult;
12045  SCIP_VAR* var;
12046  int c;
12047  int i;
12048  int nchgbds;
12049  int nnotify;
12050 
12051  assert(scip != NULL);
12052  assert(conss != NULL || nconss == 0);
12053 
12054  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
12055 
12056  /* pseudo solutions should be within bounds by definition */
12057  assert(!solviolbounds);
12058 
12059  if( maxviolcon == NULL )
12060  {
12061  *result = SCIP_FEASIBLE;
12062  return SCIP_OKAY;
12063  }
12064 
12065  *result = SCIP_INFEASIBLE;
12066 
12067  SCIPdebugMsg(scip, "enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcon));
12068 
12069  /* run domain propagation */
12070  nchgbds = 0;
12071  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
12072  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
12073  {
12074  *result = propresult;
12075  return SCIP_OKAY;
12076  }
12077 
12078  /* we are not feasible and we cannot proof that the whole node is infeasible
12079  * -> collect all variables in violated constraints for branching
12080  */
12081  nnotify = 0;
12082  for( c = 0; c < nconss; ++c )
12083  {
12084  assert(conss != NULL);
12085  consdata = SCIPconsGetData(conss[c]);
12086  assert(consdata != NULL);
12087 
12088  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12089  continue;
12090 
12091  for( i = 0; i < consdata->nlinvars; ++i )
12092  {
12093  var = consdata->linvars[i];
12094  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
12095  {
12096  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
12097  ++nnotify;
12098  }
12099  }
12100 
12101  for( i = 0; i < consdata->nquadvars; ++i )
12102  {
12103  var = consdata->quadvarterms[i].var;
12104  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
12105  {
12106  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
12107  ++nnotify;
12108  }
12109  }
12110  }
12111 
12112  if( nnotify == 0 )
12113  {
12114  SCIPdebugMsg(scip, "All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
12115  *result = SCIP_SOLVELP;
12116  }
12117 
12118  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
12119  return SCIP_OKAY;
12120 }
12121 
12122 /** domain propagation method of constraint handler */
12123 static
12124 SCIP_DECL_CONSPROP(consPropQuadratic)
12126  int nchgbds;
12127 
12128  assert(scip != NULL);
12129  assert(conshdlr != NULL);
12130  assert(conss != NULL || nconss == 0);
12131  assert(result != NULL);
12132 
12133  nchgbds = 0;
12134  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nmarkedconss, result, &nchgbds) );
12135 
12136  return SCIP_OKAY;
12137 } /*lint !e715 */
12138 
12139 /** presolving method of constraint handler */
12140 static
12141 SCIP_DECL_CONSPRESOL(consPresolQuadratic)
12142 { /*lint --e{715,788}*/
12143  SCIP_CONSHDLRDATA* conshdlrdata;
12144  SCIP_CONSDATA* consdata;
12145  SCIP_RESULT solveresult;
12146  SCIP_Bool redundant;
12147  SCIP_Bool havechange;
12148  SCIP_Bool doreformulations;
12149  int c;
12150  int i;
12151 
12152  assert(scip != NULL);
12153  assert(conshdlr != NULL);
12154  assert(conss != NULL || nconss == 0);
12155  assert(result != NULL);
12156 
12157  *result = SCIP_DIDNOTFIND;
12158 
12159  /* if other presolvers did not find enough changes for another presolving round,
12160  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
12161  * otherwise, we wait with these
12162  * @todo first do all usual presolving steps, then check SCIPisPresolveFinished(scip), and if true then do reformulations (and usual steps again)
12163  */
12164  doreformulations = nrounds > 0 && ((presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 || SCIPisPresolveFinished(scip));
12165  SCIPdebugMsg(scip, "presolving will %swait with reformulation\n", doreformulations ? "not " : "");
12166 
12167  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12168  assert(conshdlrdata != NULL);
12169 
12170  for( c = 0; c < nconss; ++c )
12171  {
12172  assert(conss != NULL);
12173  consdata = SCIPconsGetData(conss[c]);
12174  assert(consdata != NULL);
12175 
12176  SCIPdebugMsg(scip, "process constraint <%s>\n", SCIPconsGetName(conss[c]));
12177  SCIPdebugPrintCons(scip, conss[c], NULL);
12178 
12179  if( !consdata->initialmerge )
12180  {
12181  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12182  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12183  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12184  consdata->initialmerge = TRUE;
12185  }
12186 
12187  havechange = FALSE;
12188 #ifdef CHECKIMPLINBILINEAR
12189  if( consdata->isimpladded && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
12190  {
12191  int nbilinremoved;
12192  SCIP_CALL( presolveApplyImplications(scip, conss[c], &nbilinremoved) );
12193  if( nbilinremoved > 0 )
12194  {
12195  *nchgcoefs += nbilinremoved;
12196  havechange = TRUE;
12197  *result = SCIP_SUCCESS;
12198  }
12199  assert(!consdata->isimpladded);
12200  }
12201 #endif
12202  /* 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
12203  * we want to do this before (multi)aggregated variables are replaced, since that may change structure, e.g., introduce bilinear terms
12204  */
12205  if( !consdata->ispresolved || !consdata->ispropagated || nnewchgvartypes > 0 )
12206  {
12207  SCIP_Bool upgraded;
12208 
12209  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
12210  if( upgraded )
12211  {
12212  *result = SCIP_SUCCESS;
12213  continue;
12214  }
12215  }
12216 
12217  if( !consdata->isremovedfixings )
12218  {
12219  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
12220  assert(consdata->isremovedfixings);
12221  havechange = TRUE;
12222  }
12223 
12224  /* try to "solve" the constraint, e.g., reduce to a variable aggregation */
12225  SCIP_CALL( presolveSolve(scip, conss[c], &solveresult, &redundant, naggrvars) );
12226  if( solveresult == SCIP_CUTOFF )
12227  {
12228  SCIPdebugMsg(scip, "solving constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
12229  *result = SCIP_CUTOFF;
12230  return SCIP_OKAY;
12231  }
12232  if( redundant )
12233  {
12234  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12235  ++*ndelconss;
12236  *result = SCIP_SUCCESS;
12237  break;
12238  }
12239  if( solveresult == SCIP_SUCCESS )
12240  {
12241  *result = SCIP_SUCCESS;
12242  havechange = TRUE;
12243  }
12244 
12245  /* @todo divide constraint by gcd of coefficients if all are integral */
12246 
12247  if( doreformulations )
12248  {
12249  int naddconss_old;
12250 
12251  naddconss_old = *naddconss;
12252 
12253  SCIP_CALL( presolveTryAddAND(scip, conshdlr, conss[c], naddconss) );
12254  assert(*naddconss >= naddconss_old);
12255 
12256  if( *naddconss == naddconss_old )
12257  {
12258  /* user not so empathic about AND, or we don't have products of two binaries, so try this more general reformulation */
12259  SCIP_CALL( presolveTryAddLinearReform(scip, conshdlr, conss[c], naddconss) );
12260  assert(*naddconss >= naddconss_old);
12261  }
12262 
12263  if( conshdlrdata->disaggregate )
12264  {
12265  /* try disaggregation, if enabled */
12266  SCIP_CALL( presolveDisaggregate(scip, conshdlr, conss[c], naddconss) );
12267  }
12268 
12269  if( *naddconss > naddconss_old )
12270  {
12271  /* if something happened, report success and cleanup constraint */
12272  *result = SCIP_SUCCESS;
12273  havechange = TRUE;
12274  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12275  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12276  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12277  }
12278  }
12279 
12280  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
12281  {
12282  /* all variables fixed or removed, constraint function is 0.0 now */
12283  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
12284  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
12285  { /* left hand side positive or right hand side negative */
12286  SCIPdebugMsg(scip, "constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
12287  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12288  ++*ndelconss;
12289  *result = SCIP_CUTOFF;
12290  return SCIP_OKAY;
12291  }
12292 
12293  /* left and right hand side are consistent */
12294  SCIPdebugMsg(scip, "constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
12295  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12296  ++*ndelconss;
12297  *result = SCIP_SUCCESS;
12298  continue;
12299  }
12300 
12301  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 && !consdata->ispropagated )
12302  {
12303  /* try domain propagation if there were bound changes or constraint has changed (in which case, processVarEvents may have set ispropagated to false) */
12304  SCIP_RESULT propresult;
12305  int roundnr;
12306 
12307  roundnr = 0;
12308  do
12309  {
12310  ++roundnr;
12311 
12312  SCIPdebugMsg(scip, "starting domain propagation round %d of %d\n", roundnr, conshdlrdata->maxproproundspresolve);
12313 
12314  if( !consdata->ispropagated )
12315  {
12316  consdata->ispropagated = TRUE;
12317 
12318  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
12319 
12320  if( propresult == SCIP_CUTOFF )
12321  {
12322  SCIPdebugMsg(scip, "propagation on constraint <%s> says problem is infeasible in presolve\n",
12323  SCIPconsGetName(conss[c]));
12324  *result = SCIP_CUTOFF;
12325  return SCIP_OKAY;
12326  }
12327 
12328  /* delete constraint if found redundant by bound tightening */
12329  if( redundant )
12330  {
12331  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
12332  ++*ndelconss;
12333  *result = SCIP_SUCCESS;
12334  break;
12335  }
12336 
12337  if( propresult == SCIP_REDUCEDDOM )
12338  {
12339  *result = SCIP_SUCCESS;
12340  havechange = TRUE;
12341  }
12342  }
12343  }
12344  while( !consdata->ispropagated && roundnr < conshdlrdata->maxproproundspresolve );
12345 
12346  if( redundant )
12347  continue;
12348  }
12349 
12350  /* check if we have a single linear continuous variable that we can make implicit integer */
12351  if( (nnewchgvartypes != 0 || havechange || !consdata->ispresolved)
12352  && (SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->lhs)) )
12353  {
12354  int ncontvar;
12355  SCIP_VAR* candidate;
12356  SCIP_Bool fail;
12357 
12358  fail = FALSE;
12359  candidate = NULL;
12360  ncontvar = 0;
12361 
12362  for( i = 0; !fail && i < consdata->nlinvars; ++i )
12363  {
12364  if( !SCIPisIntegral(scip, consdata->lincoefs[i]) )
12365  {
12366  fail = TRUE;
12367  }
12368  else if( SCIPvarGetType(consdata->linvars[i]) == SCIP_VARTYPE_CONTINUOUS )
12369  {
12370  if( ncontvar > 0 ) /* now at 2nd continuous variable */
12371  fail = TRUE;
12372  else if( SCIPisEQ(scip, ABS(consdata->lincoefs[i]), 1.0) )
12373  candidate = consdata->linvars[i];
12374  ++ncontvar;
12375  }
12376  }
12377  for( i = 0; !fail && i < consdata->nquadvars; ++i )
12378  fail = SCIPvarGetType(consdata->quadvarterms[i].var) == SCIP_VARTYPE_CONTINUOUS ||
12379  !SCIPisIntegral(scip, consdata->quadvarterms[i].lincoef) ||
12380  !SCIPisIntegral(scip, consdata->quadvarterms[i].sqrcoef);
12381  for( i = 0; !fail && i < consdata->nbilinterms; ++i )
12382  fail = !SCIPisIntegral(scip, consdata->bilinterms[i].coef);
12383 
12384  if( !fail && candidate != NULL )
12385  {
12386  SCIP_Bool infeasible;
12387 
12388  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n", SCIPvarGetName(candidate), SCIPconsGetName(conss[c]));
12389 
12390  SCIP_CALL( SCIPchgVarType(scip, candidate, SCIP_VARTYPE_IMPLINT, &infeasible) );
12391  if( infeasible )
12392  {
12393  SCIPdebugMsg(scip, "infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(candidate));
12394  *result = SCIP_CUTOFF;
12395 
12396  return SCIP_OKAY;
12397  }
12398 
12399  ++(*nchgvartypes);
12400  *result = SCIP_SUCCESS;
12401  havechange = TRUE;
12402  }
12403  }
12404 
12405  /* call upgrade methods again if constraint has been changed */
12406  if( havechange )
12407  {
12408  SCIP_Bool upgraded;
12409 
12410  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
12411  if( upgraded )
12412  {
12413  *result = SCIP_SUCCESS;
12414  continue;
12415  }
12416  }
12417 
12418  /* fix quadratic variables with proper square coefficients contained in a single quadratic constraint to their
12419  * upper or lower bounds
12420  */
12421  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && conshdlrdata->checkquadvarlocks != 'd'
12422  && SCIPisPresolveFinished(scip) )
12423  {
12424  SCIP_CONS* cons;
12425  SCIP_VAR* vars[2];
12426  SCIP_BOUNDTYPE boundtypes[2];
12427  SCIP_Real bounds[2];
12428  char name[SCIP_MAXSTRLEN];
12429 
12430  /* merge variables in order to get correct locks for quadratic variables */
12431  if( !consdata->initialmerge )
12432  {
12433  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12434  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12435  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12436  consdata->initialmerge = TRUE;
12437  }
12438 
12439  for( i = 0; i < consdata->nquadvars; ++i )
12440  {
12441  if( hasQuadvarHpProperty(scip, consdata, i) )
12442  {
12443  SCIP_VAR* var;
12444 
12445  var = consdata->quadvarterms[i].var;
12446  assert(var != NULL);
12447 
12448  /* try to change the variable type to binary */
12449  if( conshdlrdata->checkquadvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
12450  {
12451  SCIP_Bool infeasible;
12452 
12453  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
12454  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
12455 
12456  if( infeasible )
12457  {
12458  SCIPdebugMsg(scip, "detect infeasibility after changing variable <%s> to binary type\n", SCIPvarGetName(var));
12459  *result = SCIP_CUTOFF;
12460  return SCIP_OKAY;
12461  }
12462  }
12463  /* add bound disjunction constraint if bounds of variable are finite */
12464  else if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
12465  {
12466  vars[0] = var;
12467  vars[1] = var;
12468  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
12469  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
12470  bounds[0] = SCIPvarGetUbGlobal(var);
12471  bounds[1] = SCIPvarGetLbGlobal(var);
12472 
12473  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
12474 
12475  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
12476  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
12477  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
12478 
12479  SCIP_CALL( SCIPaddCons(scip, cons) );
12480  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
12481  }
12482 
12483  *result = SCIP_SUCCESS;
12484  }
12485  }
12486  }
12487 
12488  consdata->ispresolved = TRUE;
12489  }
12490 
12491  return SCIP_OKAY;
12492 }
12493 
12494 /** variable rounding lock method of constraint handler */
12495 static
12496 SCIP_DECL_CONSLOCK(consLockQuadratic)
12497 { /*lint --e{715}*/
12498  SCIP_CONSDATA* consdata;
12499  SCIP_Bool haslb;
12500  SCIP_Bool hasub;
12501  int i;
12502 
12503  assert(scip != NULL);
12504  assert(cons != NULL);
12505 
12506  consdata = SCIPconsGetData(cons);
12507  assert(consdata != NULL);
12508 
12509  haslb = !SCIPisInfinity(scip, -consdata->lhs);
12510  hasub = !SCIPisInfinity(scip, consdata->rhs);
12511 
12512  for( i = 0; i < consdata->nlinvars; ++i )
12513  {
12514  if( consdata->lincoefs[i] > 0 )
12515  {
12516  if( haslb )
12517  {
12518  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
12519  }
12520  if( hasub )
12521  {
12522  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
12523  }
12524  }
12525  else
12526  {
12527  if( haslb )
12528  {
12529  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
12530  }
12531  if( hasub )
12532  {
12533  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
12534  }
12535  }
12536  }
12537 
12538  for( i = 0; i < consdata->nquadvars; ++i )
12539  {
12540  /* @todo try to be more clever, but variable locks that depend on the bounds of other variables are not trival to maintain */
12541  SCIP_CALL( SCIPaddVarLocks(scip, consdata->quadvarterms[i].var, nlockspos+nlocksneg, nlockspos+nlocksneg) );
12542  }
12543 
12544  return SCIP_OKAY;
12545 }
12546 
12547 /** constraint enabling notification method of constraint handler */
12548 static
12549 SCIP_DECL_CONSENABLE(consEnableQuadratic)
12551  SCIP_CONSHDLRDATA* conshdlrdata;
12552 
12553  assert(scip != NULL);
12554  assert(conshdlr != NULL);
12555  assert(cons != NULL);
12556  assert(SCIPconsIsTransformed(cons));
12557  assert(SCIPconsIsActive(cons));
12558 
12559  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12560  assert(conshdlrdata != NULL);
12561 
12562  SCIPdebugMsg(scip, "enable cons <%s>\n", SCIPconsGetName(cons));
12563 
12564  if( SCIPgetStage(scip) >= SCIP_STAGE_EXITPRESOLVE )
12565  {
12566  /* merge duplicate bilinear terms, move quad terms that are linear to linear vars */
12567  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
12568  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
12569  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
12570  }
12571 
12572  /* catch variable events */
12573  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12574 
12575  /* initialize solving data */
12576  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
12577  {
12578  SCIP_CALL( consInitsolQuadratic(scip, conshdlr, &cons, 1) );
12579  }
12580 
12581  return SCIP_OKAY;
12582 }
12583 
12584 /** constraint disabling notification method of constraint handler */
12585 static
12586 SCIP_DECL_CONSDISABLE(consDisableQuadratic)
12587 { /*lint --e{715}*/
12588  SCIP_CONSHDLRDATA* conshdlrdata;
12589 
12590  assert(scip != NULL);
12591  assert(conshdlr != NULL);
12592  assert(cons != NULL);
12593  assert(SCIPconsIsTransformed(cons));
12594 
12595  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12596  assert(conshdlrdata != NULL);
12597 
12598  SCIPdebugMsg(scip, "disable cons <%s>\n", SCIPconsGetName(cons));
12599 
12600  /* free solving data */
12601  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
12602  {
12603  SCIP_CALL( consExitsolQuadratic(scip, conshdlr, &cons, 1, FALSE) );
12604  }
12605 
12606  /* drop variable events */
12607  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
12608 
12609  return SCIP_OKAY;
12610 }
12611 
12612 /** constraint display method of constraint handler */
12613 static
12614 SCIP_DECL_CONSPRINT(consPrintQuadratic)
12615 { /*lint --e{715}*/
12616  SCIP_CONSDATA* consdata;
12617 
12618  assert(scip != NULL);
12619  assert(cons != NULL);
12620 
12621  consdata = SCIPconsGetData(cons);
12622  assert(consdata != NULL);
12623 
12624  /* print left hand side for ranged rows */
12625  if( !SCIPisInfinity(scip, -consdata->lhs)
12626  && !SCIPisInfinity(scip, consdata->rhs)
12627  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12628  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
12629 
12630  /* print coefficients and variables */
12631  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
12632  {
12633  SCIPinfoMessage(scip, file, "0 ");
12634  }
12635  else
12636  {
12637  SCIP_VAR*** monomialvars;
12638  SCIP_Real** monomialexps;
12639  SCIP_Real* monomialcoefs;
12640  int* monomialnvars;
12641  int nmonomials;
12642  int monomialssize;
12643  int j;
12644 
12645  monomialssize = consdata->nlinvars + 2 * consdata->nquadvars + consdata->nbilinterms;
12646  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, monomialssize) );
12647  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps, monomialssize) );
12648  SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, monomialssize) );
12649  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, monomialssize) );
12650 
12651  nmonomials = 0;
12652  for( j = 0; j < consdata->nlinvars; ++j )
12653  {
12654  assert(nmonomials < monomialssize);
12655 
12656  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
12657 
12658  monomialvars[nmonomials][0] = consdata->linvars[j];
12659  monomialexps[nmonomials] = NULL;
12660  monomialcoefs[nmonomials] = consdata->lincoefs[j];
12661  monomialnvars[nmonomials] = 1;
12662  ++nmonomials;
12663  }
12664 
12665  for( j = 0; j < consdata->nquadvars; ++j )
12666  {
12667  if( consdata->quadvarterms[j].lincoef != 0.0 )
12668  {
12669  assert(nmonomials < monomialssize);
12670 
12671  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
12672 
12673  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
12674  monomialexps[nmonomials] = NULL;
12675  monomialcoefs[nmonomials] = consdata->quadvarterms[j].lincoef;
12676  monomialnvars[nmonomials] = 1;
12677  ++nmonomials;
12678  }
12679 
12680  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
12681  {
12682  assert(nmonomials < monomialssize);
12683 
12684  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
12685  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps[nmonomials], 1) ); /*lint !e866 */
12686 
12687  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
12688  monomialexps[nmonomials][0] = 2.0;
12689  monomialcoefs[nmonomials] = consdata->quadvarterms[j].sqrcoef;
12690  monomialnvars[nmonomials] = 1;
12691  ++nmonomials;
12692  }
12693  }
12694 
12695  for( j = 0; j < consdata->nbilinterms; ++j )
12696  {
12697  assert(nmonomials < monomialssize);
12698 
12699  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 2) ); /*lint !e866 */
12700 
12701  monomialvars[nmonomials][0] = consdata->bilinterms[j].var1;
12702  monomialvars[nmonomials][1] = consdata->bilinterms[j].var2;
12703  monomialexps[nmonomials] = NULL;
12704  monomialcoefs[nmonomials] = consdata->bilinterms[j].coef;
12705  monomialnvars[nmonomials] = 2;
12706  ++nmonomials;
12707  }
12708 
12709  SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, monomialexps, monomialcoefs, monomialnvars, nmonomials, TRUE) );
12710 
12711  for( j = 0; j < nmonomials; ++j )
12712  {
12713  SCIPfreeBufferArray(scip, &monomialvars[j]);
12714  SCIPfreeBufferArrayNull(scip, &monomialexps[j]);
12715  }
12716 
12717  SCIPfreeBufferArray(scip, &monomialvars);
12718  SCIPfreeBufferArray(scip, &monomialexps);
12719  SCIPfreeBufferArray(scip, &monomialcoefs);
12720  SCIPfreeBufferArray(scip, &monomialnvars);
12721  }
12722 
12723  /* print right hand side */
12724  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
12725  {
12726  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
12727  }
12728  else if( !SCIPisInfinity(scip, consdata->rhs) )
12729  {
12730  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
12731  }
12732  else if( !SCIPisInfinity(scip, -consdata->lhs) )
12733  {
12734  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
12735  }
12736  else
12737  {
12738  /* should be ignored by parser */
12739  SCIPinfoMessage(scip, file, " [free]");
12740  }
12741 
12742  return SCIP_OKAY;
12743 }
12744 
12745 /** feasibility check method of constraint handler for integral solutions */
12746 static
12747 SCIP_DECL_CONSCHECK(consCheckQuadratic)
12748 { /*lint --e{715}*/
12749  SCIP_CONSHDLRDATA* conshdlrdata;
12750  SCIP_CONSDATA* consdata;
12751  SCIP_Real maxviol;
12752  int c;
12753  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
12754  SCIP_Bool solviolbounds;
12755 
12756  assert(scip != NULL);
12757  assert(conss != NULL || nconss == 0);
12758  assert(result != NULL);
12759 
12760  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12761  assert(conshdlrdata != NULL);
12762 
12763  *result = SCIP_FEASIBLE;
12764 
12765  maxviol = 0.0;
12766  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
12768  for( c = 0; c < nconss; ++c )
12769  {
12770  assert(conss != NULL);
12771  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol, &solviolbounds) );
12772  assert(!solviolbounds); /* see also issue #627 */
12773 
12774  consdata = SCIPconsGetData(conss[c]);
12775  assert(consdata != NULL);
12776 
12777  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12778  {
12779  *result = SCIP_INFEASIBLE;
12780  if( printreason )
12781  {
12782  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
12783  SCIPinfoMessage(scip, NULL, ";\n");
12784  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
12785  {
12786  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
12787  }
12788  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12789  {
12790  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
12791  }
12792  }
12793  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
12794  return SCIP_OKAY;
12795  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
12796  maxviol = consdata->lhsviol + consdata->rhsviol;
12797 
12798  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
12799  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
12800  maypropfeasible = FALSE;
12801 
12802  if( maypropfeasible )
12803  {
12804  /* update information on linear variables that may be in- or decreased, if initsolve has not done so yet */
12806  consdataFindUnlockedLinearVar(scip, consdata);
12807 
12808  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
12809  {
12810  /* check if there is a variable which may help to get the left hand side satisfied
12811  * if there is no such var, then we cannot get feasible */
12812  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
12813  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
12814  maypropfeasible = FALSE;
12815  }
12816  else
12817  {
12818  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
12819  /* check if there is a variable which may help to get the right hand side satisfied
12820  * if there is no such var, then we cannot get feasible */
12821  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
12822  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
12823  maypropfeasible = FALSE;
12824  }
12825  }
12826  }
12827  }
12828 
12829  if( *result == SCIP_INFEASIBLE && maypropfeasible )
12830  {
12831  SCIP_Bool success;
12832 
12833  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
12834 
12835  /* do not pass solution to NLP heuristic if we made it feasible this way */
12836  if( success )
12837  return SCIP_OKAY;
12838  }
12839 
12840  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL )
12841  {
12842  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
12843  }
12844 
12845  return SCIP_OKAY;
12846 }
12847 
12848 /** constraint copying method of constraint handler */
12849 static
12850 SCIP_DECL_CONSCOPY(consCopyQuadratic)
12852  SCIP_CONSDATA* consdata;
12853  SCIP_CONSDATA* targetconsdata;
12854  SCIP_VAR** linvars;
12855  SCIP_QUADVARTERM* quadvarterms;
12856  SCIP_BILINTERM* bilinterms;
12857  int i;
12858  int j;
12859  int k;
12860 
12861  assert(scip != NULL);
12862  assert(cons != NULL);
12863  assert(sourcescip != NULL);
12864  assert(sourceconshdlr != NULL);
12865  assert(sourcecons != NULL);
12866  assert(varmap != NULL);
12867  assert(valid != NULL);
12868 
12869  consdata = SCIPconsGetData(sourcecons);
12870  assert(consdata != NULL);
12871 
12872  linvars = NULL;
12873  quadvarterms = NULL;
12874  bilinterms = NULL;
12875 
12876  *valid = TRUE;
12877 
12878  if( consdata->nlinvars != 0 )
12879  {
12880  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
12881  for( i = 0; i < consdata->nlinvars; ++i )
12882  {
12883  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
12884  assert(!(*valid) || linvars[i] != NULL);
12885 
12886  /* we do not copy, if a variable is missing */
12887  if( !(*valid) )
12888  goto TERMINATE;
12889  }
12890  }
12891 
12892  if( consdata->nbilinterms != 0 )
12893  {
12894  SCIP_CALL( SCIPallocBufferArray(sourcescip, &bilinterms, consdata->nbilinterms) );
12895  }
12896 
12897  if( consdata->nquadvars != 0 )
12898  {
12899  SCIP_CALL( SCIPallocBufferArray(sourcescip, &quadvarterms, consdata->nquadvars) );
12900  for( i = 0; i < consdata->nquadvars; ++i )
12901  {
12902  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->quadvarterms[i].var, &quadvarterms[i].var, varmap, consmap, global, valid) );
12903  assert(!(*valid) || quadvarterms[i].var != NULL);
12904 
12905  /* we do not copy, if a variable is missing */
12906  if( !(*valid) )
12907  goto TERMINATE;
12908 
12909  quadvarterms[i].lincoef = consdata->quadvarterms[i].lincoef;
12910  quadvarterms[i].sqrcoef = consdata->quadvarterms[i].sqrcoef;
12911  quadvarterms[i].eventdata = NULL;
12912  quadvarterms[i].nadjbilin = consdata->quadvarterms[i].nadjbilin;
12913  quadvarterms[i].adjbilin = consdata->quadvarterms[i].adjbilin;
12914 
12915  assert(consdata->nbilinterms != 0 || consdata->quadvarterms[i].nadjbilin == 0);
12916 
12917  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
12918  {
12919  assert(bilinterms != NULL);
12920 
12921  k = consdata->quadvarterms[i].adjbilin[j];
12922  assert(consdata->bilinterms[k].var1 != NULL);
12923  assert(consdata->bilinterms[k].var2 != NULL);
12924  if( consdata->bilinterms[k].var1 == consdata->quadvarterms[i].var )
12925  {
12926  assert(consdata->bilinterms[k].var2 != consdata->quadvarterms[i].var);
12927  bilinterms[k].var1 = quadvarterms[i].var;
12928  }
12929  else
12930  {
12931  assert(consdata->bilinterms[k].var2 == consdata->quadvarterms[i].var);
12932  bilinterms[k].var2 = quadvarterms[i].var;
12933  }
12934  bilinterms[k].coef = consdata->bilinterms[k].coef;
12935  }
12936  }
12937  }
12938 
12939  assert(stickingatnode == FALSE);
12940  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name ? name : SCIPconsGetName(sourcecons),
12941  consdata->nlinvars, linvars, consdata->lincoefs,
12942  consdata->nquadvars, quadvarterms,
12943  consdata->nbilinterms, bilinterms,
12944  consdata->lhs, consdata->rhs,
12945  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12946 
12947  /* copy information on curvature */
12948  targetconsdata = SCIPconsGetData(*cons);
12949  targetconsdata->isconvex = consdata->isconvex;
12950  targetconsdata->isconcave = consdata->isconcave;
12951  targetconsdata->iscurvchecked = consdata->iscurvchecked;
12952 
12953  TERMINATE:
12954  SCIPfreeBufferArrayNull(sourcescip, &quadvarterms);
12955  SCIPfreeBufferArrayNull(sourcescip, &bilinterms);
12956  SCIPfreeBufferArrayNull(sourcescip, &linvars);
12957 
12958  return SCIP_OKAY;
12959 }
12960 
12961 /** constraint parsing method of constraint handler */
12962 static
12963 SCIP_DECL_CONSPARSE(consParseQuadratic)
12964 { /*lint --e{715}*/
12965  SCIP_VAR*** monomialvars;
12966  SCIP_Real** monomialexps;
12967  SCIP_Real* monomialcoefs;
12968  char* endptr;
12969  int* monomialnvars;
12970  int nmonomials;
12971 
12972  SCIP_Real lhs;
12973  SCIP_Real rhs;
12974 
12975  assert(scip != NULL);
12976  assert(success != NULL);
12977  assert(str != NULL);
12978  assert(name != NULL);
12979  assert(cons != NULL);
12980 
12981  /* set left and right hand side to their default values */
12982  lhs = -SCIPinfinity(scip);
12983  rhs = SCIPinfinity(scip);
12984 
12985  (*success) = FALSE;
12986 
12987  /* return of string empty */
12988  if( !*str )
12989  return SCIP_OKAY;
12990 
12991  /* ignore whitespace */
12992  while( isspace((unsigned char)*str) )
12993  ++str;
12994 
12995  /* check for left hand side */
12996  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
12997  {
12998  /* there is a number coming, maybe it is a left-hand-side */
12999  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13000  {
13001  SCIPerrorMessage("error parsing number from <%s>\n", str);
13002  return SCIP_OKAY;
13003  }
13004 
13005  /* ignore whitespace */
13006  while( isspace((unsigned char)*endptr) )
13007  ++endptr;
13008 
13009  if( endptr[0] != '<' || endptr[1] != '=' )
13010  {
13011  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
13012  lhs = -SCIPinfinity(scip);
13013  }
13014  else
13015  {
13016  /* it was indeed a left-hand-side, so continue parsing after it */
13017  str = endptr + 2;
13018 
13019  /* ignore whitespace */
13020  while( isspace((unsigned char)*str) )
13021  ++str;
13022  }
13023  }
13024 
13025  SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, &endptr, success) );
13026 
13027  if( *success )
13028  {
13029  /* check for right hand side */
13030  str = endptr;
13031 
13032  /* ignore whitespace */
13033  while( isspace((unsigned char)*str) )
13034  ++str;
13035 
13036  if( *str && str[0] == '<' && str[1] == '=' )
13037  {
13038  /* we seem to get a right-hand-side */
13039  str += 2;
13040 
13041  if( !SCIPstrToRealValue(str, &rhs, &endptr) )
13042  {
13043  SCIPerrorMessage("error parsing right-hand-side from %s\n", str);
13044  *success = FALSE;
13045  }
13046  }
13047  else if( *str && str[0] == '>' && str[1] == '=' )
13048  {
13049  /* we seem to get a left-hand-side */
13050  str += 2;
13051 
13052  /* we should not have a left-hand-side already */
13053  assert(SCIPisInfinity(scip, -lhs));
13054 
13055  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13056  {
13057  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
13058  *success = FALSE;
13059  }
13060  }
13061  else if( *str && str[0] == '=' && str[1] == '=' )
13062  {
13063  /* we seem to get a left- and right-hand-side */
13064  str += 2;
13065 
13066  /* we should not have a left-hand-side already */
13067  assert(SCIPisInfinity(scip, -lhs));
13068 
13069  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13070  {
13071  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
13072  *success = FALSE;
13073  }
13074  else
13075  {
13076  rhs = lhs;
13077  }
13078  }
13079  }
13080 
13081  if( *success )
13082  {
13083  int i;
13084 
13085  /* setup constraint */
13086  assert(stickingatnode == FALSE);
13087  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL,
13088  0, NULL, NULL, NULL, lhs, rhs,
13089  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
13090 
13091  for( i = 0; i < nmonomials; ++i )
13092  {
13093  if( monomialnvars[i] == 0 )
13094  {
13095  /* constant monomial */
13096  SCIPaddConstantQuadratic(scip, *cons, monomialcoefs[i]);
13097  }
13098  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 1.0 )
13099  {
13100  /* linear monomial */
13101  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, *cons, monomialvars[i][0], monomialcoefs[i]) );
13102  }
13103  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 2.0 )
13104  {
13105  /* square monomial */
13106  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, monomialvars[i][0], 0.0, monomialcoefs[i]) );
13107  }
13108  else if( monomialnvars[i] == 2 && monomialexps[i][0] == 1.0 && monomialexps[i][1] == 1.0 )
13109  {
13110  /* bilinear term */
13111  SCIP_VAR* var1;
13112  SCIP_VAR* var2;
13113  int pos;
13114 
13115  var1 = monomialvars[i][0];
13116  var2 = monomialvars[i][1];
13117  if( var1 == var2 )
13118  {
13119  /* actually a square term */
13120  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, monomialcoefs[i]) );
13121  }
13122  else
13123  {
13124  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var1, &pos) );
13125  if( pos == -1 )
13126  {
13127  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, 0.0) );
13128  }
13129 
13130  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var2, &pos) );
13131  if( pos == -1 )
13132  {
13133  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var2, 0.0, 0.0) );
13134  }
13135  }
13136 
13137  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, *cons, var1, var2, monomialcoefs[i]) );
13138  }
13139  else
13140  {
13141  SCIPerrorMessage("polynomial in quadratic constraint does not have degree at most 2\n");
13142  *success = FALSE;
13143  SCIP_CALL( SCIPreleaseCons(scip, cons) );
13144  break;
13145  }
13146  }
13147  }
13148 
13149  SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
13150 
13151  return SCIP_OKAY;
13152 }
13153 
13154 /** constraint method of constraint handler which returns the variables (if possible) */
13155 static
13156 SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
13157 { /*lint --e{715}*/
13158  SCIP_CONSDATA* consdata;
13159 
13160  assert(cons != NULL);
13161  assert(success != NULL);
13162 
13163  consdata = SCIPconsGetData(cons);
13164  assert(consdata != NULL);
13165 
13166  if( varssize < consdata->nlinvars + consdata->nquadvars )
13167  (*success) = FALSE;
13168  else
13169  {
13170  int i;
13171 
13172  assert(vars != NULL);
13173 
13174  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
13175 
13176  for( i = 0; i < consdata->nquadvars; ++i )
13177  vars[consdata->nlinvars+i] = consdata->quadvarterms[i].var;
13178 
13179  (*success) = TRUE;
13180  }
13181 
13182  return SCIP_OKAY;
13183 }
13184 
13185 /** constraint method of constraint handler which returns the number of variables (if possible) */
13186 static
13187 SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
13188 { /*lint --e{715}*/
13189  SCIP_CONSDATA* consdata;
13190 
13191  assert(cons != NULL);
13192  assert(success != NULL);
13193 
13194  consdata = SCIPconsGetData(cons);
13195  assert(consdata != NULL);
13196 
13197  (*nvars) = consdata->nlinvars + consdata->nquadvars;
13198  (*success) = TRUE;
13199 
13200  return SCIP_OKAY;
13201 }
13202 
13203 
13204 /*
13205  * constraint specific interface methods
13206  */
13207 
13208 /** creates the handler for quadratic constraints and includes it in SCIP */
13210  SCIP* scip /**< SCIP data structure */
13211  )
13212 {
13213  SCIP_CONSHDLRDATA* conshdlrdata;
13214  SCIP_CONSHDLR* conshdlr;
13215 
13216  /* create quadratic constraint handler data */
13217  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
13218  BMSclearMemory(conshdlrdata);
13219 
13220  /* include constraint handler */
13223  consEnfolpQuadratic, consEnfopsQuadratic, consCheckQuadratic, consLockQuadratic,
13224  conshdlrdata) );
13225  assert(conshdlr != NULL);
13226 
13227 
13228  /* set non-fundamental callbacks via specific setter functions */
13229  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyQuadratic, consCopyQuadratic) );
13230  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteQuadratic) );
13231  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableQuadratic) );
13232  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableQuadratic) );
13233  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitQuadratic) );
13234  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreQuadratic) );
13235  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolQuadratic) );
13236  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeQuadratic) );
13237  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsQuadratic) );
13238  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsQuadratic) );
13239  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitQuadratic) );
13240  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolQuadratic) );
13241  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpQuadratic) );
13242  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseQuadratic) );
13243  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolQuadratic, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
13244  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintQuadratic) );
13245  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropQuadratic, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
13247  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpQuadratic, consSepasolQuadratic, CONSHDLR_SEPAFREQ,
13249  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransQuadratic) );
13250  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxQuadratic) );
13251 
13252  /* add quadratic constraint handler parameters */
13253  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/replacebinaryprod",
13254  "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)",
13255  &conshdlrdata->replacebinaryprodlength, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
13256 
13257  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/empathy4and",
13258  "empathy level for using the AND constraint handler: 0 always avoid using AND; 1 use AND sometimes; 2 use AND as often as possible",
13259  &conshdlrdata->empathy4and, FALSE, 0, 0, 2, NULL, NULL) );
13260 
13261  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreforminitial",
13262  "whether to make non-varbound linear constraints added due to replacing products with binary variables initial",
13263  &conshdlrdata->binreforminitial, TRUE, FALSE, NULL, NULL) );
13264 
13265  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/binreformmaxcoef",
13266  "limit (as factor on 1/feastol) on coefficients and coef. range in linear constraints created when replacing products with binary variables",
13267  &conshdlrdata->binreformmaxcoef, TRUE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
13268 
13269  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacysepa",
13270  "minimal efficacy for a cut to be added to the LP during separation; overwrites separating/efficacy",
13271  &conshdlrdata->mincutefficacysepa, TRUE, 0.0001, 0.0, SCIPinfinity(scip), NULL, NULL) );
13272 
13273  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacyenfofac",
13274  "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)",
13275  &conshdlrdata->mincutefficacyenfofac, TRUE, 2.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
13276 
13277  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/scaling",
13278  "whether scaling of infeasibility is 'o'ff, by sup-norm of function 'g'radient, or by left/right hand 's'ide",
13279  &conshdlrdata->scaling, TRUE, 'o', "ogs", NULL, NULL) );
13280 
13281  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
13282  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
13283  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
13284 
13285  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
13286  "whether linearizations of convex quadratic constraints should be added to cutpool in a solution found by some heuristic",
13287  &conshdlrdata->linearizeheursol, TRUE, TRUE, NULL, NULL) );
13288 
13289  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkcurvature",
13290  "whether multivariate quadratic functions should be checked for convexity/concavity",
13291  &conshdlrdata->checkcurvature, FALSE, TRUE, NULL, NULL) );
13292 
13293  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkfactorable",
13294  "whether constraint functions should be checked to be factorable",
13295  &conshdlrdata->checkfactorable, TRUE, TRUE, NULL, NULL) );
13296 
13297  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkquadvarlocks",
13298  "whether quadratic variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction)",
13299  &conshdlrdata->checkquadvarlocks, TRUE, 't', "bdt", NULL, NULL) );
13300 
13301  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
13302  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
13303  &conshdlrdata->linfeasshift, TRUE, TRUE, NULL, NULL) );
13304 
13305  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/disaggregate",
13306  "whether to disaggregate quadratic parts that decompose into a sum of non-overlapping quadratic terms",
13307  &conshdlrdata->disaggregate, TRUE, FALSE, NULL, NULL) );
13308 
13309  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
13310  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve",
13311  &conshdlrdata->maxproprounds, TRUE, 1, 0, INT_MAX, NULL, NULL) );
13312 
13313  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproproundspresolve",
13314  "limit on number of propagation rounds for a single constraint within one round of SCIP presolve",
13315  &conshdlrdata->maxproproundspresolve, TRUE, 10, 0, INT_MAX, NULL, NULL) );
13316 
13317  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/enfolplimit",
13318  "maximum number of enforcement rounds before declaring the LP relaxation infeasible (-1: no limit); WARNING: changing this parameter might lead to incorrect results!",
13319  &conshdlrdata->enfolplimit, TRUE, -1, -1, INT_MAX, NULL, NULL) );
13320 
13321  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
13322  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
13323  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
13324 
13325  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
13326  "are cuts added during enforcement removable from the LP in the same node?",
13327  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
13328 
13329  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/gaugecuts",
13330  "should convex quadratics generated strong cuts via gauge function?",
13331  &conshdlrdata->gaugecuts, FALSE, TRUE, NULL, NULL) );
13332 
13333  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/interiorcomputation",
13334  "how the interior point for gauge cuts should be computed: 'a'ny point per constraint, 'm'ost interior per constraint",
13335  &conshdlrdata->interiorcomputation, TRUE, 'a', "am", NULL, NULL) );
13336 
13337  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/projectedcuts",
13338  "should convex quadratics generated strong cuts via projections?",
13339  &conshdlrdata->projectedcuts, FALSE, FALSE, NULL, NULL) );
13340 
13341  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchscoring",
13342  "which score to give branching candidates: convexification 'g'ap, constraint 'v'iolation, 'c'entrality of variable value in domain",
13343  &conshdlrdata->branchscoring, TRUE, 'g', "cgv", NULL, NULL) );
13344 
13345  conshdlrdata->eventhdlr = NULL;
13346  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr),CONSHDLR_NAME"_boundchange", "signals a bound change to a quadratic constraint",
13347  processVarEvent, NULL) );
13348  assert(conshdlrdata->eventhdlr != NULL);
13349 
13350  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
13351  processNewSolutionEvent, NULL) );
13352 
13353  /* include the quadratic constraint upgrade in the nonlinear constraint handler */
13355 
13356  return SCIP_OKAY;
13357 }
13358 
13359 /** includes a quadratic constraint update method into the quadratic constraint handler */
13361  SCIP* scip, /**< SCIP data structure */
13362  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
13363  int priority, /**< priority of upgrading method */
13364  SCIP_Bool active, /**< should the upgrading method be active by default? */
13365  const char* conshdlrname /**< name of the constraint handler */
13366  )
13367 {
13368  SCIP_CONSHDLR* conshdlr;
13369  SCIP_CONSHDLRDATA* conshdlrdata;
13370  SCIP_QUADCONSUPGRADE* quadconsupgrade;
13371  char paramname[SCIP_MAXSTRLEN];
13372  char paramdesc[SCIP_MAXSTRLEN];
13373  int i;
13374 
13375  assert(quadconsupgd != NULL);
13376  assert(conshdlrname != NULL );
13377 
13378  /* find the quadratic constraint handler */
13379  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13380  if( conshdlr == NULL )
13381  {
13382  SCIPerrorMessage("quadratic constraint handler not found\n");
13383  return SCIP_PLUGINNOTFOUND;
13384  }
13385 
13386  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13387  assert(conshdlrdata != NULL);
13388 
13389  if( !conshdlrdataHasUpgrade(scip, conshdlrdata, quadconsupgd, conshdlrname) )
13390  {
13391  /* create a quadratic constraint upgrade data object */
13392  SCIP_CALL( SCIPallocBlockMemory(scip, &quadconsupgrade) );
13393  quadconsupgrade->quadconsupgd = quadconsupgd;
13394  quadconsupgrade->priority = priority;
13395  quadconsupgrade->active = active;
13396 
13397  /* insert quadratic constraint upgrade method into constraint handler data */
13398  assert(conshdlrdata->nquadconsupgrades <= conshdlrdata->quadconsupgradessize);
13399  if( conshdlrdata->nquadconsupgrades+1 > conshdlrdata->quadconsupgradessize )
13400  {
13401  int newsize;
13402 
13403  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nquadconsupgrades+1);
13404  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize, newsize) );
13405  conshdlrdata->quadconsupgradessize = newsize;
13406  }
13407  assert(conshdlrdata->nquadconsupgrades+1 <= conshdlrdata->quadconsupgradessize);
13408 
13409  for( i = conshdlrdata->nquadconsupgrades; i > 0 && conshdlrdata->quadconsupgrades[i-1]->priority < quadconsupgrade->priority; --i )
13410  conshdlrdata->quadconsupgrades[i] = conshdlrdata->quadconsupgrades[i-1];
13411  assert(0 <= i && i <= conshdlrdata->nquadconsupgrades);
13412  conshdlrdata->quadconsupgrades[i] = quadconsupgrade;
13413  conshdlrdata->nquadconsupgrades++;
13414 
13415  /* adds parameter to turn on and off the upgrading step */
13416  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
13417  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable quadratic upgrading for constraint handler <%s>", conshdlrname);
13419  paramname, paramdesc,
13420  &quadconsupgrade->active, FALSE, active, NULL, NULL) );
13421  }
13422 
13423  return SCIP_OKAY;
13424 }
13425 
13426 /** Creates and captures a quadratic constraint.
13427  *
13428  * The constraint should be given in the form
13429  * \f[
13430  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
13431  * \f]
13432  * where \f$x_i = y_j = z_k\f$ is possible.
13433  *
13434  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13435  */
13437  SCIP* scip, /**< SCIP data structure */
13438  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13439  const char* name, /**< name of constraint */
13440  int nlinvars, /**< number of linear terms (n) */
13441  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13442  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13443  int nquadterms, /**< number of quadratic terms (m) */
13444  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
13445  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
13446  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
13447  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
13448  SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
13449  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
13450  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
13451  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
13452  * Usually set to TRUE. */
13453  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
13454  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13455  SCIP_Bool check, /**< should the constraint be checked for feasibility?
13456  * TRUE for model constraints, FALSE for additional, redundant constraints. */
13457  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
13458  * Usually set to TRUE. */
13459  SCIP_Bool local, /**< is constraint only valid locally?
13460  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
13461  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
13462  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
13463  * adds coefficients to this constraint. */
13464  SCIP_Bool dynamic, /**< is constraint subject to aging?
13465  * Usually set to FALSE. Set to TRUE for own cuts which
13466  * are separated as constraints. */
13467  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
13468  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
13469  )
13470 {
13471  SCIP_CONSHDLR* conshdlr;
13472  SCIP_CONSDATA* consdata;
13473  SCIP_HASHMAP* quadvaridxs;
13474  SCIP_Real sqrcoef;
13475  int i;
13476  int var1pos;
13477  int var2pos;
13478 
13479  int nbilinterms;
13480 
13481  assert(linvars != NULL || nlinvars == 0);
13482  assert(lincoefs != NULL || nlinvars == 0);
13483  assert(quadvars1 != NULL || nquadterms == 0);
13484  assert(quadvars2 != NULL || nquadterms == 0);
13485  assert(quadcoefs != NULL || nquadterms == 0);
13486 
13487  assert(modifiable == FALSE); /* we do not support column generation */
13488 
13489  /* find the quadratic constraint handler */
13490  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13491  if( conshdlr == NULL )
13492  {
13493  SCIPerrorMessage("quadratic constraint handler not found\n");
13494  return SCIP_PLUGINNOTFOUND;
13495  }
13496 
13497  /* create constraint data and constraint */
13498  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
13499 
13500  consdata->lhs = lhs;
13501  consdata->rhs = rhs;
13502 
13503  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13504  local, modifiable, dynamic, removable, FALSE) );
13505 
13506  /* add quadratic variables and remember their indices */
13507  SCIP_CALL( SCIPhashmapCreate(&quadvaridxs, SCIPblkmem(scip), nquadterms) );
13508  nbilinterms = 0;
13509  for( i = 0; i < nquadterms; ++i )
13510  {
13511  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
13512  continue;
13513 
13514  /* if it is actually a square term, remember it's coefficient */
13515  /* cppcheck-suppress nullPointer */
13516  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
13517  sqrcoef = quadcoefs[i]; /*lint !e613 */
13518  else
13519  sqrcoef = 0.0;
13520 
13521  /* add quadvars1[i], if not in there already */
13522  if( !SCIPhashmapExists(quadvaridxs, quadvars1[i]) ) /*lint !e613*/
13523  {
13524  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars1[i], 0.0, sqrcoef) ); /*lint !e613*/
13525  assert(consdata->nquadvars >= 0);
13526  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars1[i]); /*lint !e613*/
13527 
13528  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars1[i], (void*)(size_t)(consdata->nquadvars-1)) ); /*lint !e613*/
13529  }
13530  else if( !SCIPisZero(scip, sqrcoef) )
13531  {
13532  /* if it's there already, but we got a square coefficient, add it to the previous one */
13533  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]); /*lint !e613*/
13534  assert(consdata->quadvarterms[var1pos].var == quadvars1[i]); /*lint !e613*/
13535  consdata->quadvarterms[var1pos].sqrcoef += sqrcoef;
13536  }
13537 
13538  /* cppcheck-suppress nullPointer */
13539  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
13540  continue;
13541 
13542  /* add quadvars2[i], if not in there already */
13543  if( !SCIPhashmapExists(quadvaridxs, quadvars2[i]) ) /*lint !e613*/
13544  {
13545  assert(sqrcoef == 0.0);
13546  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars2[i], 0.0, 0.0) ); /*lint !e613*/
13547  assert(consdata->nquadvars >= 0);
13548  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars2[i]); /*lint !e613*/
13549 
13550  SCIP_CALL( SCIPhashmapInsert(quadvaridxs, quadvars2[i], (void*)(size_t)(consdata->nquadvars-1)) ); /*lint !e613*/
13551  }
13552 
13553  ++nbilinterms;
13554  }
13555 
13556  /* add bilinear terms, if we saw any */
13557  if( nbilinterms > 0 )
13558  {
13559  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, nbilinterms) );
13560  for( i = 0; i < nquadterms; ++i )
13561  {
13562  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
13563  continue;
13564 
13565  /* square terms have been taken care of already */
13566  if( quadvars1[i] == quadvars2[i] ) /*lint !e613 */
13567  continue;
13568 
13569  assert(SCIPhashmapExists(quadvaridxs, quadvars1[i])); /*lint !e613*/
13570  assert(SCIPhashmapExists(quadvaridxs, quadvars2[i])); /*lint !e613*/
13571 
13572  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars1[i]); /*lint !e613*/
13573  var2pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, quadvars2[i]); /*lint !e613*/
13574 
13575  SCIP_CALL( addBilinearTerm(scip, *cons, var1pos, var2pos, quadcoefs[i]) ); /*lint !e613*/
13576  }
13577  }
13578 
13579  /* add linear variables */
13580  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
13581  for( i = 0; i < nlinvars; ++i )
13582  {
13583  if( SCIPisZero(scip, lincoefs[i]) ) /*lint !e613*/
13584  continue;
13585 
13586  /* if it's a linear coefficient for a quadratic variable, add it there, otherwise add as linear variable */
13587  if( SCIPhashmapExists(quadvaridxs, linvars[i]) ) /*lint !e613*/
13588  {
13589  var1pos = (int) (size_t) SCIPhashmapGetImage(quadvaridxs, linvars[i]); /*lint !e613*/
13590  assert(consdata->quadvarterms[var1pos].var == linvars[i]); /*lint !e613*/
13591  consdata->quadvarterms[var1pos].lincoef += lincoefs[i]; /*lint !e613*/
13592  }
13593  else
13594  {
13595  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) ); /*lint !e613*/
13596  }
13597  }
13598 
13599  SCIPhashmapFree(&quadvaridxs);
13600 
13601  SCIPdebugMsg(scip, "created quadratic constraint ");
13602  SCIPdebugPrintCons(scip, *cons, NULL);
13603 
13604  return SCIP_OKAY;
13605 }
13606 
13607 /** creates and captures a quadratic constraint with all its
13608  * flags set to their default values.
13609  *
13610  * The constraint should be given in the form
13611  * \f[
13612  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
13613  * \f]
13614  * where \f$x_i = y_j = z_k\f$ is possible.
13615  *
13616  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13617  */
13619  SCIP* scip, /**< SCIP data structure */
13620  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13621  const char* name, /**< name of constraint */
13622  int nlinvars, /**< number of linear terms (n) */
13623  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13624  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13625  int nquadterms, /**< number of quadratic terms (m) */
13626  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
13627  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
13628  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
13629  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
13630  SCIP_Real rhs /**< right hand side of quadratic equation (u) */
13631  )
13632 {
13633  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, nlinvars, linvars, lincoefs,
13634  nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
13635  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
13636 
13637  return SCIP_OKAY;
13638 }
13639 
13640 /** Creates and captures a quadratic constraint.
13641  *
13642  * The constraint should be given in the form
13643  * \f[
13644  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m (a_j y_j^2 + b_j y_j) + \sum_{k=1}^p c_k v_k w_k \leq u.
13645  * \f]
13646  *
13647  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13648  */
13650  SCIP* scip, /**< SCIP data structure */
13651  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13652  const char* name, /**< name of constraint */
13653  int nlinvars, /**< number of linear terms (n) */
13654  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13655  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13656  int nquadvarterms, /**< number of quadratic terms (m) */
13657  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
13658  int nbilinterms, /**< number of bilinear terms (p) */
13659  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
13660  SCIP_Real lhs, /**< constraint left hand side (ell) */
13661  SCIP_Real rhs, /**< constraint right hand side (u) */
13662  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
13663  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
13664  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
13665  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
13666  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
13667  SCIP_Bool local, /**< is constraint only valid locally? */
13668  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
13669  SCIP_Bool dynamic, /**< is constraint dynamic? */
13670  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
13671  )
13672 {
13673  SCIP_CONSHDLR* conshdlr;
13674  SCIP_CONSDATA* consdata;
13675 
13676  assert(modifiable == FALSE); /* we do not support column generation */
13677  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
13678  assert(nquadvarterms == 0 || quadvarterms != NULL);
13679  assert(nbilinterms == 0 || bilinterms != NULL);
13680 
13681  /* find the quadratic constraint handler */
13682  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
13683  if( conshdlr == NULL )
13684  {
13685  SCIPerrorMessage("quadratic constraint handler not found\n");
13686  return SCIP_PLUGINNOTFOUND;
13687  }
13688 
13689  /* create constraint data */
13690  SCIP_CALL( consdataCreate(scip, &consdata, lhs, rhs,
13691  nlinvars, linvars, lincoefs, nquadvarterms, quadvarterms, nbilinterms, bilinterms,
13692  TRUE) );
13693 
13694  /* create constraint */
13695  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
13696  local, modifiable, dynamic, removable, FALSE) );
13697 
13698  return SCIP_OKAY;
13699 }
13700 
13701 /** creates and captures a quadratic constraint in its most basic version, i.e.,
13702  * all constraint flags are set to their default values.
13703  *
13704  * The constraint should be given in the form
13705  * \f[
13706  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m (a_j y_j^2 + b_j y_j) + \sum_{k=1}^p c_k v_k w_k \leq u.
13707  * \f]
13708  *
13709  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
13710  */
13712  SCIP* scip, /**< SCIP data structure */
13713  SCIP_CONS** cons, /**< pointer to hold the created constraint */
13714  const char* name, /**< name of constraint */
13715  int nlinvars, /**< number of linear terms (n) */
13716  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
13717  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
13718  int nquadvarterms, /**< number of quadratic terms (m) */
13719  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
13720  int nbilinterms, /**< number of bilinear terms (p) */
13721  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
13722  SCIP_Real lhs, /**< constraint left hand side (ell) */
13723  SCIP_Real rhs /**< constraint right hand side (u) */
13724  )
13725 {
13726  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name, nlinvars, linvars, lincoefs,
13727  nquadvarterms, quadvarterms, nbilinterms, bilinterms, lhs, rhs,
13728  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
13729 
13730  return SCIP_OKAY;
13731 }
13732 
13733 
13734 /** Adds a constant to the constraint function, that is, subtracts a constant from both sides */
13736  SCIP* scip, /**< SCIP data structure */
13737  SCIP_CONS* cons, /**< constraint */
13738  SCIP_Real constant /**< constant to subtract from both sides */
13739  )
13740 {
13741  SCIP_CONSDATA* consdata;
13742 
13743  assert(scip != NULL);
13744  assert(cons != NULL);
13745  assert(!SCIPisInfinity(scip, REALABS(constant)));
13746 
13747  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13748  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13749  {
13750  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13751  SCIPABORT();
13752  }
13753 
13754  consdata = SCIPconsGetData(cons);
13755  assert(consdata != NULL);
13756  assert(consdata->lhs <= consdata->rhs);
13757 
13758  if( !SCIPisInfinity(scip, -consdata->lhs) )
13759  consdata->lhs -= constant;
13760  if( !SCIPisInfinity(scip, consdata->rhs) )
13761  consdata->rhs -= constant;
13762 
13763  if( consdata->lhs > consdata->rhs )
13764  {
13765  assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
13766  consdata->lhs = consdata->rhs;
13767  }
13768 }
13769 
13770 /** Adds a linear variable with coefficient to a quadratic constraint. */
13772  SCIP* scip, /**< SCIP data structure */
13773  SCIP_CONS* cons, /**< constraint */
13774  SCIP_VAR* var, /**< variable */
13775  SCIP_Real coef /**< coefficient of variable */
13776  )
13777 {
13778  assert(scip != NULL);
13779  assert(cons != NULL);
13780  assert(var != NULL);
13781  assert(!SCIPisInfinity(scip, REALABS(coef)));
13782 
13783  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13784  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13785  {
13786  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13787  return SCIP_INVALIDCALL;
13788  }
13789 
13790  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
13791 
13792  return SCIP_OKAY;
13793 }
13794 
13795 /** Adds a quadratic variable with linear and square coefficient to a quadratic constraint. */
13797  SCIP* scip, /**< SCIP data structure */
13798  SCIP_CONS* cons, /**< constraint */
13799  SCIP_VAR* var, /**< variable */
13800  SCIP_Real lincoef, /**< linear coefficient of variable */
13801  SCIP_Real sqrcoef /**< square coefficient of variable */
13802  )
13803 {
13804  assert(scip != NULL);
13805  assert(cons != NULL);
13806  assert(var != NULL);
13807  assert(!SCIPisInfinity(scip, REALABS(lincoef)));
13808  assert(!SCIPisInfinity(scip, REALABS(sqrcoef)));
13809 
13810  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13811  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13812  {
13813  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13814  return SCIP_INVALIDCALL;
13815  }
13816 
13817  SCIP_CALL( addQuadVarTerm(scip, cons, var, lincoef, sqrcoef) );
13818 
13819  return SCIP_OKAY;
13820 }
13821 
13822 /** Adds a linear coefficient for a quadratic variable.
13823  *
13824  * Variable will be added with square coefficient 0.0 if not existing yet.
13825  */
13827  SCIP* scip, /**< SCIP data structure */
13828  SCIP_CONS* cons, /**< constraint */
13829  SCIP_VAR* var, /**< variable */
13830  SCIP_Real coef /**< value to add to linear coefficient of variable */
13831  )
13832 {
13833  SCIP_CONSDATA* consdata;
13834  int pos;
13835 
13836  assert(scip != NULL);
13837  assert(cons != NULL);
13838  assert(var != NULL);
13839  assert(!SCIPisInfinity(scip, REALABS(coef)));
13840 
13841  if( SCIPisZero(scip, coef) )
13842  return SCIP_OKAY;
13843 
13844  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13845  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13846  {
13847  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13848  return SCIP_INVALIDCALL;
13849  }
13850 
13851  consdata = SCIPconsGetData(cons);
13852  assert(consdata != NULL);
13853 
13854  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
13855  if( pos < 0 )
13856  {
13857  SCIP_CALL( addQuadVarTerm(scip, cons, var, coef, 0.0) );
13858  return SCIP_OKAY;
13859  }
13860  assert(pos < consdata->nquadvars);
13861  assert(consdata->quadvarterms[pos].var == var);
13862 
13863  consdata->quadvarterms[pos].lincoef += coef;
13864 
13865  /* update flags and invalid activities */
13866  consdata->ispropagated = FALSE;
13867  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].lincoef);
13868 
13869  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
13870  consdata->activity = SCIP_INVALID;
13871 
13872  return SCIP_OKAY;
13873 }
13874 
13875 /** Adds a square coefficient for a quadratic variable.
13876  *
13877  * Variable will be added with linear coefficient 0.0 if not existing yet.
13878  */
13880  SCIP* scip, /**< SCIP data structure */
13881  SCIP_CONS* cons, /**< constraint */
13882  SCIP_VAR* var, /**< variable */
13883  SCIP_Real coef /**< value to add to square coefficient of variable */
13884  )
13885 {
13886  SCIP_CONSDATA* consdata;
13887  int pos;
13888 
13889  assert(scip != NULL);
13890  assert(cons != NULL);
13891  assert(var != NULL);
13892  assert(!SCIPisInfinity(scip, REALABS(coef)));
13893 
13894  if( SCIPisZero(scip, coef) )
13895  return SCIP_OKAY;
13896 
13897  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13898  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13899  {
13900  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13901  return SCIP_INVALIDCALL;
13902  }
13903 
13904  consdata = SCIPconsGetData(cons);
13905  assert(consdata != NULL);
13906 
13907  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
13908  if( pos < 0 )
13909  {
13910  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
13911  return SCIP_OKAY;
13912  }
13913  assert(pos < consdata->nquadvars);
13914  assert(consdata->quadvarterms[pos].var == var);
13915 
13916  consdata->quadvarterms[pos].sqrcoef += coef;
13917 
13918  /* update flags and invalid activities */
13919  consdata->isconvex = FALSE;
13920  consdata->isconcave = FALSE;
13921  consdata->iscurvchecked = FALSE;
13922  consdata->ispropagated = FALSE;
13923  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].sqrcoef);
13924 
13925  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
13926  consdata->activity = SCIP_INVALID;
13927 
13928  return SCIP_OKAY;
13929 }
13930 
13931 /** Adds a bilinear term to a quadratic constraint.
13932  *
13933  * Variables will be added with linear and square coefficient 0.0 if not existing yet.
13934  * If variables are equal, only the square coefficient of the variable is updated.
13935  */
13937  SCIP* scip, /**< SCIP data structure */
13938  SCIP_CONS* cons, /**< constraint */
13939  SCIP_VAR* var1, /**< first variable */
13940  SCIP_VAR* var2, /**< second variable */
13941  SCIP_Real coef /**< coefficient of bilinear term */
13942  )
13943 {
13944  SCIP_CONSDATA* consdata;
13945  int var1pos;
13946  int var2pos;
13947 
13948  assert(scip != NULL);
13949  assert(cons != NULL);
13950  assert(var1 != NULL);
13951  assert(var2 != NULL);
13952  assert(!SCIPisInfinity(scip, REALABS(coef)));
13953 
13954  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
13955  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
13956  {
13957  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
13958  return SCIP_INVALIDCALL;
13959  }
13960 
13961  if( var1 == var2 )
13962  {
13963  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, cons, var1, coef) );
13964  return SCIP_OKAY;
13965  }
13966 
13967  consdata = SCIPconsGetData(cons);
13968  assert(consdata != NULL);
13969 
13970  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
13971  if( var1pos < 0 )
13972  {
13973  SCIP_CALL( addQuadVarTerm(scip, cons, var1, 0.0, 0.0) );
13974  var1pos = consdata->nquadvars-1;
13975  }
13976 
13977  if( !consdata->quadvarssorted )
13978  {
13979  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
13980  /* sorting may change the position of var1 */
13981  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
13982  assert(var1pos >= 0);
13983  }
13984 
13985  assert(consdata->quadvarssorted);
13986  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var2, &var2pos) );
13987  if( var2pos < 0 )
13988  {
13989  SCIP_CALL( addQuadVarTerm(scip, cons, var2, 0.0, 0.0) );
13990  var2pos = consdata->nquadvars-1;
13991  }
13992 
13993  assert(consdata->quadvarterms[var1pos].var == var1);
13994  assert(consdata->quadvarterms[var2pos].var == var2);
13995 
13996  SCIP_CALL( addBilinearTerm(scip, cons, var1pos, var2pos, coef) );
13997 
13998  return SCIP_OKAY;
13999 }
14000 
14001 /** Gets the quadratic constraint as a nonlinear row representation. */
14003  SCIP* scip, /**< SCIP data structure */
14004  SCIP_CONS* cons, /**< constraint */
14005  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
14006  )
14007 {
14008  SCIP_CONSDATA* consdata;
14009 
14010  assert(cons != NULL);
14011  assert(nlrow != NULL);
14012 
14013  consdata = SCIPconsGetData(cons);
14014  assert(consdata != NULL);
14015 
14016  if( consdata->nlrow == NULL )
14017  {
14018  SCIP_CALL( createNlRow(scip, cons) );
14019  }
14020  assert(consdata->nlrow != NULL);
14021  *nlrow = consdata->nlrow;
14022 
14023  return SCIP_OKAY;
14024 }
14025 
14026 /** Gets the number of variables in the linear term of a quadratic constraint. */
14028  SCIP* scip, /**< SCIP data structure */
14029  SCIP_CONS* cons /**< constraint */
14030  )
14031 {
14032  assert(cons != NULL);
14033  assert(SCIPconsGetData(cons) != NULL);
14034 
14035  return SCIPconsGetData(cons)->nlinvars;
14036 }
14037 
14038 /** Gets the variables in the linear part of a quadratic constraint.
14039  * Length is given by SCIPgetNLinearVarsQuadratic.
14040  */
14042  SCIP* scip, /**< SCIP data structure */
14043  SCIP_CONS* cons /**< constraint */
14044  )
14045 {
14046  assert(cons != NULL);
14047  assert(SCIPconsGetData(cons) != NULL);
14048 
14049  return SCIPconsGetData(cons)->linvars;
14050 }
14051 
14052 /** Gets the coefficients in the linear part of a quadratic constraint.
14053  * Length is given by SCIPgetNLinearVarsQuadratic.
14054  */
14056  SCIP* scip, /**< SCIP data structure */
14057  SCIP_CONS* cons /**< constraint */
14058  )
14059 {
14060  assert(cons != NULL);
14061  assert(SCIPconsGetData(cons) != NULL);
14062 
14063  return SCIPconsGetData(cons)->lincoefs;
14064 }
14065 
14066 /** Gets the number of quadratic variable terms of a quadratic constraint.
14067  */
14069  SCIP* scip, /**< SCIP data structure */
14070  SCIP_CONS* cons /**< constraint */
14071  )
14072 {
14073  assert(cons != NULL);
14074  assert(SCIPconsGetData(cons) != NULL);
14075 
14076  return SCIPconsGetData(cons)->nquadvars;
14077 }
14078 
14079 /** Gets the quadratic variable terms of a quadratic constraint.
14080  * Length is given by SCIPgetNQuadVarTermsQuadratic.
14081  */
14083  SCIP* scip, /**< SCIP data structure */
14084  SCIP_CONS* cons /**< constraint */
14085  )
14086 {
14087  assert(cons != NULL);
14088  assert(SCIPconsGetData(cons) != NULL);
14089 
14090  return SCIPconsGetData(cons)->quadvarterms;
14091 }
14092 
14093 /** Ensures that quadratic variable terms are sorted. */
14095  SCIP* scip, /**< SCIP data structure */
14096  SCIP_CONS* cons /**< constraint */
14097  )
14098 {
14099  assert(cons != NULL);
14100  assert(SCIPconsGetData(cons) != NULL);
14101 
14103 
14104  return SCIP_OKAY;
14105 }
14106 
14107 /** Finds the position of a quadratic variable term for a given variable.
14108  *
14109  * @note If the quadratic variable terms have not been sorted before, then a search may reorder the current order of the terms.
14110  */
14112  SCIP* scip, /**< SCIP data structure */
14113  SCIP_CONS* cons, /**< constraint */
14114  SCIP_VAR* var, /**< variable to search for */
14115  int* pos /**< buffer to store position of quadvarterm for var, or -1 if not found */
14116  )
14117 {
14118  assert(cons != NULL);
14119  assert(SCIPconsGetData(cons) != NULL);
14120  assert(var != NULL);
14121  assert(pos != NULL);
14122 
14123  SCIP_CALL( consdataFindQuadVarTerm(scip, SCIPconsGetData(cons), var, pos) );
14124 
14125  return SCIP_OKAY;
14126 }
14127 
14128 /** Gets the number of bilinear terms of a quadratic constraint. */
14130  SCIP* scip, /**< SCIP data structure */
14131  SCIP_CONS* cons /**< constraint */
14132  )
14133 {
14134  assert(cons != NULL);
14135  assert(SCIPconsGetData(cons) != NULL);
14136 
14137  return SCIPconsGetData(cons)->nbilinterms;
14138 }
14139 
14140 /** Gets the bilinear terms of a quadratic constraint.
14141  * Length is given by SCIPgetNBilinTermQuadratic.
14142  */
14144  SCIP* scip, /**< SCIP data structure */
14145  SCIP_CONS* cons /**< constraint */
14146  )
14147 {
14148  assert(cons != NULL);
14149  assert(SCIPconsGetData(cons) != NULL);
14150 
14151  return SCIPconsGetData(cons)->bilinterms;
14152 }
14153 
14154 /** Gets the left hand side of a quadratic constraint. */
14156  SCIP* scip, /**< SCIP data structure */
14157  SCIP_CONS* cons /**< constraint */
14158  )
14159 {
14160  assert(cons != NULL);
14161  assert(SCIPconsGetData(cons) != NULL);
14162 
14163  return SCIPconsGetData(cons)->lhs;
14164 }
14165 
14166 /** Gets the right hand side of a quadratic constraint. */
14168  SCIP* scip, /**< SCIP data structure */
14169  SCIP_CONS* cons /**< constraint */
14170  )
14171 {
14172  assert(cons != NULL);
14173  assert(SCIPconsGetData(cons) != NULL);
14174 
14175  return SCIPconsGetData(cons)->rhs;
14176 }
14177 
14178 /** get index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
14180  SCIP* scip, /**< SCIP data structure */
14181  SCIP_CONS* cons /**< constraint */
14182  )
14183 {
14184  SCIP_CONSDATA* consdata;
14185 
14186  assert(cons != NULL);
14187 
14188  consdata = SCIPconsGetData(cons);
14189  assert(consdata != NULL);
14190 
14191  /* check for a linear variable that can be increase or decreased without harming feasibility */
14192  consdataFindUnlockedLinearVar(scip, consdata);
14193 
14194  return consdata->linvar_maydecrease;
14195 }
14196 
14197 /** get index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
14199  SCIP* scip, /**< SCIP data structure */
14200  SCIP_CONS* cons /**< constraint */
14201  )
14202 {
14203  SCIP_CONSDATA* consdata;
14204 
14205  assert(cons != NULL);
14206 
14207  consdata = SCIPconsGetData(cons);
14208  assert(consdata != NULL);
14209 
14210  /* check for a linear variable that can be increase or decreased without harming feasibility */
14211  consdataFindUnlockedLinearVar(scip, consdata);
14212 
14213  return consdata->linvar_mayincrease;
14214 }
14215 
14216 /** Check the quadratic function of a quadratic constraint for its semi-definiteness, if not done yet. */
14218  SCIP* scip, /**< SCIP data structure */
14219  SCIP_CONS* cons /**< constraint */
14220  )
14221 {
14222  assert(cons != NULL);
14223 
14224  SCIP_CALL( checkCurvature(scip, cons, TRUE) );
14225 
14226  return SCIP_OKAY;
14227 }
14228 
14229 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) convex. */
14231  SCIP* scip, /**< SCIP data structure */
14232  SCIP_CONS* cons /**< constraint */
14233  )
14234 {
14235  SCIP_Bool determined;
14236 
14237  assert(cons != NULL);
14238  assert(SCIPconsGetData(cons) != NULL);
14239 
14240  checkCurvatureEasy(scip, cons, &determined, FALSE);
14241  assert(determined);
14242 
14243  return (SCIPconsGetData(cons)->isconvex);
14244 }
14245 
14246 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) concave. */
14248  SCIP* scip, /**< SCIP data structure */
14249  SCIP_CONS* cons /**< constraint */
14250  )
14251 {
14252  SCIP_Bool determined;
14253 
14254  assert(cons != NULL);
14255  assert(SCIPconsGetData(cons) != NULL);
14256 
14257  checkCurvatureEasy(scip, cons, &determined, FALSE);
14258  assert(determined);
14259 
14260  return (SCIPconsGetData(cons)->isconcave);
14261 }
14262 
14263 /** Computes the violation of a constraint by a solution */
14265  SCIP* scip, /**< SCIP data structure */
14266  SCIP_CONS* cons, /**< constraint */
14267  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
14268  SCIP_Real* violation /**< pointer to store violation of constraint */
14269  )
14270 {
14271  SCIP_CONSHDLR* conshdlr;
14272  SCIP_CONSDATA* consdata;
14273  SCIP_Bool solviolbounds;
14274 
14275  assert(scip != NULL);
14276  assert(cons != NULL);
14277  assert(violation != NULL);
14278 
14279  conshdlr = SCIPconsGetHdlr(cons);
14280  assert(conshdlr != NULL);
14281 
14282  SCIP_CALL( computeViolation(scip, conshdlr, cons, sol, &solviolbounds) );
14283  /* we don't care here whether the solution violated variable bounds */
14284 
14285  consdata = SCIPconsGetData(cons);
14286  assert(consdata != NULL);
14287 
14288  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
14289 
14290  return SCIP_OKAY;
14291 }
14292 
14293 /** Indicates whether the quadratic constraint is local w.r.t. the current local bounds.
14294  *
14295  * That is, checks whether each variable with a square term is fixed and for each bilinear term at least one variable is fixed.
14296  */
14298  SCIP* scip, /**< SCIP data structure */
14299  SCIP_CONS* cons /**< constraint */
14300  )
14301 {
14302  SCIP_CONSDATA* consdata;
14303  SCIP_VAR* var1;
14304  SCIP_VAR* var2;
14305  int i;
14306 
14307  assert(scip != NULL);
14308  assert(cons != NULL);
14309 
14310  consdata = SCIPconsGetData(cons);
14311  assert(consdata != NULL);
14312 
14313  /* check all square terms */
14314  for( i = 0; i < consdata->nquadvars; ++i )
14315  {
14316  if( consdata->quadvarterms[i].sqrcoef == 0.0 )
14317  continue;
14318 
14319  var1 = consdata->quadvarterms[i].var;
14320  assert(var1 != NULL);
14321 
14322  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) )
14323  return FALSE;
14324  }
14325 
14326  for( i = 0; i < consdata->nbilinterms; ++i )
14327  {
14328  var1 = consdata->bilinterms[i].var1;
14329  var2 = consdata->bilinterms[i].var2;
14330 
14331  assert(var1 != NULL);
14332  assert(var2 != NULL);
14333 
14334  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) &&
14335  ! SCIPisRelEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
14336  return FALSE;
14337  }
14338 
14339  return TRUE;
14340 }
14341 
14342 /** Adds the constraint to an NLPI problem. */
14344  SCIP* scip, /**< SCIP data structure */
14345  SCIP_CONS* cons, /**< constraint */
14346  SCIP_NLPI* nlpi, /**< interface to NLP solver */
14347  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
14348  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
14349  SCIP_Bool names /**< whether to pass constraint names to NLPI */
14350  )
14351 {
14352  SCIP_CONSDATA* consdata;
14353  int nlininds;
14354  int* lininds;
14355  SCIP_Real* linvals;
14356  int nquadelems;
14357  SCIP_QUADELEM* quadelems;
14358  SCIP_VAR* othervar;
14359  const char* name;
14360  int j;
14361  int l;
14362  int lincnt;
14363  int quadcnt;
14364  int idx1;
14365  int idx2;
14366 
14367  assert(scip != NULL);
14368  assert(cons != NULL);
14369  assert(nlpi != NULL);
14370  assert(nlpiprob != NULL);
14371  assert(scipvar2nlpivar != NULL);
14372 
14373  consdata = SCIPconsGetData(cons);
14374  assert(consdata != NULL);
14375 
14376  /* count nonzeros in quadratic part */
14377  nlininds = consdata->nlinvars;
14378  nquadelems = consdata->nbilinterms;
14379  for( j = 0; j < consdata->nquadvars; ++j )
14380  {
14381  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
14382  ++nquadelems;
14383  if( consdata->quadvarterms[j].lincoef != 0.0 )
14384  ++nlininds;
14385  }
14386 
14387  /* setup linear part */
14388  lininds = NULL;
14389  linvals = NULL;
14390  lincnt = 0;
14391  if( nlininds > 0 )
14392  {
14393  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
14394  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
14395 
14396  for( j = 0; j < consdata->nlinvars; ++j )
14397  {
14398  linvals[j] = consdata->lincoefs[j];
14399  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->linvars[j]));
14400  lininds[j] = (int) (size_t) SCIPhashmapGetImage(scipvar2nlpivar, consdata->linvars[j]);
14401  }
14402 
14403  lincnt = consdata->nlinvars;
14404  }
14405 
14406  /* setup quadratic part */
14407  quadelems = NULL;
14408  if( nquadelems > 0 )
14409  {
14410  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
14411  }
14412  quadcnt = 0;
14413 
14414  for( j = 0; j < consdata->nquadvars; ++j )
14415  {
14416  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->quadvarterms[j].var));
14417  idx1 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, consdata->quadvarterms[j].var);
14418  if( consdata->quadvarterms[j].lincoef != 0.0 )
14419  {
14420  assert(lininds != NULL);
14421  assert(linvals != NULL);
14422  lininds[lincnt] = idx1;
14423  linvals[lincnt] = consdata->quadvarterms[j].lincoef;
14424  ++lincnt;
14425  }
14426 
14427  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
14428  {
14429  assert(quadcnt < nquadelems);
14430  assert(quadelems != NULL);
14431  quadelems[quadcnt].idx1 = idx1;
14432  quadelems[quadcnt].idx2 = idx1;
14433  quadelems[quadcnt].coef = consdata->quadvarterms[j].sqrcoef;
14434  ++quadcnt;
14435  }
14436 
14437  for( l = 0; l < consdata->quadvarterms[j].nadjbilin; ++l )
14438  {
14439  othervar = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].var2;
14440  /* if othervar is on position 2, then we process this bilinear term later (or it was processed already) */
14441  if( othervar == consdata->quadvarterms[j].var )
14442  continue;
14443 
14444  assert(quadcnt < nquadelems);
14445  assert(quadelems != NULL);
14446  assert(SCIPhashmapExists(scipvar2nlpivar, othervar));
14447  idx2 = (int)(size_t)SCIPhashmapGetImage(scipvar2nlpivar, othervar);
14448  quadelems[quadcnt].idx1 = MIN(idx1, idx2);
14449  quadelems[quadcnt].idx2 = MAX(idx1, idx2);
14450  quadelems[quadcnt].coef = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].coef;
14451  ++quadcnt;
14452  }
14453  }
14454 
14455  assert(quadcnt == nquadelems);
14456  assert(lincnt == nlininds);
14457 
14458  name = names ? SCIPconsGetName(cons) : NULL;
14459 
14460  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
14461  &consdata->lhs, &consdata->rhs,
14462  &nlininds, &lininds, &linvals ,
14463  &nquadelems, &quadelems,
14464  NULL, NULL, &name) );
14465 
14466  SCIPfreeBufferArrayNull(scip, &quadelems);
14467  SCIPfreeBufferArrayNull(scip, &lininds);
14468  SCIPfreeBufferArrayNull(scip, &linvals);
14469 
14470  return SCIP_OKAY;
14471 }
14472 
14473 
14474 /** sets the left hand side of a quadratic constraint
14475  *
14476  * @note This method may only be called during problem creation stage for an original constraint.
14477  */
14479  SCIP* scip, /**< SCIP data structure */
14480  SCIP_CONS* cons, /**< constraint data */
14481  SCIP_Real lhs /**< new left hand side */
14482  )
14483 {
14484  SCIP_CONSDATA* consdata;
14485 
14486  assert(scip != NULL);
14487  assert(cons != NULL);
14488  assert(!SCIPisInfinity(scip, lhs));
14489 
14490  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14491  {
14492  SCIPerrorMessage("constraint is not quadratic\n");
14493  return SCIP_INVALIDDATA;
14494  }
14495 
14496  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
14497  {
14498  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
14499  return SCIP_INVALIDDATA;
14500  }
14501 
14502  consdata = SCIPconsGetData(cons);
14503  assert(consdata != NULL);
14504  assert(!SCIPisInfinity(scip, consdata->lhs));
14505 
14506  /* adjust value to not be smaller than -inf */
14507  if( SCIPisInfinity(scip, -lhs) )
14508  lhs = -SCIPinfinity(scip);
14509 
14510  /* check for lhs <= rhs */
14511  if( !SCIPisLE(scip, lhs, consdata->rhs) )
14512  return SCIP_INVALIDDATA;
14513 
14514  consdata->lhs = lhs;
14515 
14516  return SCIP_OKAY;
14517 }
14518 
14519 /** sets the right hand side of a quadratic constraint
14520  *
14521  * @note This method may only be called during problem creation stage for an original constraint.
14522  */
14524  SCIP* scip, /**< SCIP data structure */
14525  SCIP_CONS* cons, /**< constraint data */
14526  SCIP_Real rhs /**< new right hand side */
14527  )
14528 {
14529  SCIP_CONSDATA* consdata;
14530 
14531  assert(scip != NULL);
14532  assert(cons != NULL);
14533  assert(!SCIPisInfinity(scip, -rhs));
14534 
14535  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14536  {
14537  SCIPerrorMessage("constraint is not quadratic\n");
14538  return SCIP_INVALIDDATA;
14539  }
14540 
14541  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
14542  {
14543  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
14544  return SCIP_INVALIDDATA;
14545  }
14546 
14547  consdata = SCIPconsGetData(cons);
14548  assert(consdata != NULL);
14549  assert(!SCIPisInfinity(scip, -consdata->rhs));
14550 
14551  /* adjust value to not be greater than inf */
14552  if( SCIPisInfinity(scip, rhs) )
14553  rhs = SCIPinfinity(scip);
14554 
14555  /* check for lhs <= rhs */
14556  if( !SCIPisLE(scip, consdata->lhs, rhs) )
14557  return SCIP_INVALIDDATA;
14558 
14559  consdata->rhs = rhs;
14560 
14561  return SCIP_OKAY;
14562 }
14563 
14564 /** gets the feasibility of the quadratic constraint in the given solution */
14566  SCIP* scip, /**< SCIP data structure */
14567  SCIP_CONS* cons, /**< constraint data */
14568  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
14569  SCIP_Real* feasibility /**< pointer to store the feasibility */
14570  )
14571 {
14572  SCIP_CONSDATA* consdata;
14573  SCIP_Bool solviolbounds;
14574 
14575  assert(scip != NULL);
14576  assert(cons != NULL);
14577  assert(feasibility != NULL);
14578 
14579  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14580  {
14581  SCIPerrorMessage("constraint is not quadratic\n");
14582  SCIPABORT();
14583  }
14584 
14585  SCIP_CALL( computeViolation(scip, SCIPconsGetHdlr(cons), cons, sol, &solviolbounds) );
14586 
14587  consdata = SCIPconsGetData(cons);
14588  assert(consdata != NULL);
14589 
14590  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
14591  *feasibility = SCIPinfinity(scip);
14592  else if( SCIPisInfinity(scip, -consdata->lhs) )
14593  *feasibility = (consdata->rhs - consdata->activity);
14594  else if( SCIPisInfinity(scip, consdata->rhs) )
14595  *feasibility = (consdata->activity - consdata->lhs);
14596  else
14597  {
14598  assert(!SCIPisInfinity(scip, -consdata->rhs));
14599  assert(!SCIPisInfinity(scip, consdata->lhs));
14600  *feasibility = MIN( consdata->rhs - consdata->activity, consdata->activity - consdata->lhs );
14601  }
14602 
14603  return SCIP_OKAY;
14604 }
14605 
14606 /** gets the activity of the quadratic constraint in the given solution */
14608  SCIP* scip, /**< SCIP data structure */
14609  SCIP_CONS* cons, /**< constraint data */
14610  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
14611  SCIP_Real* activity /**< pointer to store the activity */
14612  )
14613 {
14614  SCIP_CONSDATA* consdata;
14615  SCIP_Bool solviolbounds;
14616 
14617  assert(scip != NULL);
14618  assert(cons != NULL);
14619  assert(activity != NULL);
14620 
14621  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14622  {
14623  SCIPerrorMessage("constraint is not quadratic\n");
14624  SCIPABORT();
14625  }
14626 
14627  SCIP_CALL( computeViolation(scip, SCIPconsGetHdlr(cons), cons, sol, &solviolbounds) );
14628 
14629  consdata = SCIPconsGetData(cons);
14630  assert(consdata != NULL);
14631 
14632  *activity = consdata->activity;
14633 
14634  return SCIP_OKAY;
14635 }
14636 
14637 /** changes the linear coefficient value for a given quadratic variable in a quadratic constraint data; if not
14638  * available, it adds it
14639  *
14640  * @note this is only allowed for original constraints and variables in problem creation stage
14641  */
14643  SCIP* scip, /**< SCIP data structure */
14644  SCIP_CONS* cons, /**< constraint data */
14645  SCIP_VAR* var, /**< quadratic variable */
14646  SCIP_Real coef /**< new coefficient */
14647  )
14648 {
14649  SCIP_CONSDATA* consdata;
14650  SCIP_Bool found;
14651  int i;
14652 
14653  assert(scip != NULL);
14654  assert(cons != NULL);
14655  assert(var != NULL);
14656 
14657  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14658  {
14659  SCIPerrorMessage("constraint is not quadratic\n");
14660  return SCIP_INVALIDDATA;
14661  }
14662 
14663  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
14664  {
14665  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
14666  return SCIP_INVALIDDATA;
14667  }
14668 
14669  consdata = SCIPconsGetData(cons);
14670  assert(consdata != NULL);
14671 
14672  /* check all quadratic variables */
14673  found = FALSE;
14674  for( i = 0; i < consdata->nquadvars; ++i )
14675  {
14676  if( var == consdata->quadvarterms[i].var )
14677  {
14678  if( found || SCIPisZero(scip, coef) )
14679  {
14680  consdata->quadvarterms[i].lincoef = 0.0;
14681 
14682  /* remember to merge quadratic variable terms */
14683  consdata->quadvarsmerged = FALSE;
14684  }
14685  else
14686  consdata->quadvarterms[i].lincoef = coef;
14687 
14688  found = TRUE;
14689  }
14690  }
14691 
14692  /* check all linear variables */
14693  i = 0;
14694  while( i < consdata->nlinvars )
14695  {
14696  if( var == consdata->linvars[i] )
14697  {
14698  if( found || SCIPisZero(scip, coef) )
14699  {
14700  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
14701 
14702  /* decrease i by one since otherwise we would skip the coefficient which has been switched to position i */
14703  i--;
14704  }
14705  else
14706  {
14707  SCIP_CALL( chgLinearCoefPos(scip, cons, i, coef) );
14708  }
14709 
14710  found = TRUE;
14711  }
14712  i++;
14713  }
14714 
14715  /* add linear term if necessary */
14716  if( !found && !SCIPisZero(scip, coef) )
14717  {
14718  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
14719  }
14720 
14721  consdata->ispropagated = FALSE;
14722  consdata->ispresolved = FALSE;
14723 
14724  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14725  consdata->activity = SCIP_INVALID;
14726 
14727  return SCIP_OKAY;
14728 }
14729 
14730 /** changes the square coefficient value for a given quadratic variable in a quadratic constraint data; if not
14731  * available, it adds it
14732  *
14733  * @note this is only allowed for original constraints and variables in problem creation stage
14734  */
14736  SCIP* scip, /**< SCIP data structure */
14737  SCIP_CONS* cons, /**< constraint data */
14738  SCIP_VAR* var, /**< quadratic variable */
14739  SCIP_Real coef /**< new coefficient */
14740  )
14741 {
14742  SCIP_CONSDATA* consdata;
14743  SCIP_Bool found;
14744  int i;
14745 
14746  assert(scip != NULL);
14747  assert(cons != NULL);
14748  assert(var != NULL);
14749  assert(!SCIPisInfinity(scip, REALABS(coef)));
14750 
14751  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14752  {
14753  SCIPerrorMessage("constraint is not quadratic\n");
14754  return SCIP_INVALIDDATA;
14755  }
14756 
14757  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
14758  {
14759  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
14760  return SCIP_INVALIDDATA;
14761  }
14762 
14763  consdata = SCIPconsGetData(cons);
14764  assert(consdata != NULL);
14765 
14766  /* find the quadratic variable and change its quadratic coefficient */
14767  found = FALSE;
14768  for( i = 0; i < consdata->nquadvars; ++i )
14769  {
14770  if( var == consdata->quadvarterms[i].var )
14771  {
14772  consdata->quadvarterms[i].sqrcoef = (found || SCIPisZero(scip, coef)) ? 0.0 : coef;
14773  found = TRUE;
14774  }
14775  }
14776 
14777  /* add bilinear term if necessary */
14778  if( !found && !SCIPisZero(scip, coef) )
14779  {
14780  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
14781  }
14782 
14783  /* update flags and invalidate activities */
14784  consdata->isconvex = FALSE;
14785  consdata->isconcave = FALSE;
14786  consdata->iscurvchecked = FALSE;
14787  consdata->ispropagated = FALSE;
14788  consdata->ispresolved = FALSE;
14789 
14790  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14791  consdata->activity = SCIP_INVALID;
14792 
14793  /* remember to merge quadratic variable terms */
14794  consdata->quadvarsmerged = FALSE;
14795 
14796  return SCIP_OKAY;
14797 }
14798 
14799 /** changes the bilinear coefficient value for a given quadratic variable in a quadratic constraint data; if not
14800  * available, it adds it
14801  *
14802  * @note this is only allowed for original constraints and variables in problem creation stage
14803  */
14805  SCIP* scip, /**< SCIP data structure */
14806  SCIP_CONS* cons, /**< constraint */
14807  SCIP_VAR* var1, /**< first variable */
14808  SCIP_VAR* var2, /**< second variable */
14809  SCIP_Real coef /**< coefficient of bilinear term */
14810  )
14811 {
14812  SCIP_CONSDATA* consdata;
14813  SCIP_Bool found;
14814  int i;
14815 
14816  assert(scip != NULL);
14817  assert(cons != NULL);
14818  assert(var1 != NULL);
14819  assert(var2 != NULL);
14820  assert(!SCIPisInfinity(scip, REALABS(coef)));
14821 
14822  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
14823  {
14824  SCIPerrorMessage("constraint is not quadratic\n");
14825  return SCIP_INVALIDDATA;
14826  }
14827 
14828  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var1) || !SCIPvarIsOriginal(var2) )
14829  {
14830  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
14831  return SCIP_INVALIDDATA;
14832  }
14833 
14834  if( var1 == var2 )
14835  {
14836  SCIP_CALL( SCIPchgSquareCoefQuadratic(scip, cons, var1, coef) );
14837  return SCIP_OKAY;
14838  }
14839 
14840  consdata = SCIPconsGetData(cons);
14841  assert(consdata != NULL);
14842 
14843  /* search array of bilinear terms */
14844  found = FALSE;
14845  for( i = 0; i < consdata->nbilinterms; ++i )
14846  {
14847  if( (consdata->bilinterms[i].var1 == var1 && consdata->bilinterms[i].var2 == var2) ||
14848  (consdata->bilinterms[i].var1 == var2 && consdata->bilinterms[i].var2 == var1) )
14849  {
14850  if( found || SCIPisZero(scip, coef) )
14851  {
14852  consdata->bilinterms[i].coef = 0.0;
14853 
14854  /* remember to merge bilinear terms */
14855  consdata->bilinmerged = FALSE;
14856  }
14857  else
14858  consdata->bilinterms[i].coef = coef;
14859  found = TRUE;
14860  }
14861  }
14862 
14863  /* add bilinear term if necessary */
14864  if( !found )
14865  {
14866  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, cons, var1, var2, coef) );
14867  }
14868 
14869  /* update flags and invalidate activities */
14870  consdata->isconvex = FALSE;
14871  consdata->isconcave = FALSE;
14872  consdata->iscurvchecked = FALSE;
14873  consdata->ispropagated = FALSE;
14874  consdata->ispresolved = FALSE;
14875 
14876  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14877  consdata->activity = SCIP_INVALID;
14878 
14879  return SCIP_OKAY;
14880 }
SCIP_RETCODE SCIPaddLinearCoefsToNlRow(SCIP *scip, SCIP_NLROW *nlrow, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:32016
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21909
SCIP_RETCODE SCIPchgSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPincludeConshdlrQuadratic(SCIP *scip)
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int SCIPgetNIntVars(SCIP *scip)
Definition: scip.c:11721
SCIP_RETCODE SCIPchgBilinCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
static SCIP_Bool conshdlrdataHasUpgrade(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), const char *conshdlrname)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:46151
SCIP_Bool SCIPisIpoptAvailableIpopt(void)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:21898
static SCIP_RETCODE mergeAndCleanLinearVars(SCIP *scip, SCIP_CONS *cons)
static SCIP_Bool generateCutLTIgenMulCoeff(SCIP *scip, SCIP_Real x1, SCIP_Real y1_, SCIP_Real x2, SCIP_Real y2, SCIP_Bool whichuse, SCIP_Real *cx, SCIP_Real *cy, SCIP_Real *cw)
SCIP_Real SCIPvarGetWorstBoundLocal(SCIP_VAR *var)
Definition: var.c:17265
void SCIPintervalMulSup(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_Real lhs, SCIP_Real rhs, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Bool capturevars)
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:6228
static SCIP_RETCODE propagateBoundsQuadVar(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real a, SCIP_INTERVAL b, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
SCIP_EXPRGRAPH * SCIPgetExprgraphNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
static SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
SCIP_RETCODE SCIPincludeNonlinconsUpgrade(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)), SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)), int priority, SCIP_Bool active, const char *conshdlrname)
static void consdataMoveLinearVar(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:45274
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:7978
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21892
static SCIP_RETCODE consdataSortBilinTerms(SCIP *scip, SCIP_CONSDATA *consdata)
primal heuristic that tries a given solution
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip.c:30835
SCIP_RETCODE SCIPaddQuadVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22118
SCIP_VAR * var2
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip.c:40453
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:814
#define MAXDNOM
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
#define GAUGESCALE
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8140
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:16958
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip.c:37964
static SCIP_RETCODE separatePoint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Real *bestefficacy)
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:6251
#define CONSHDLR_PRESOLTIMING
static SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
void SCIPaddConstantQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real constant)
static SCIP_RETCODE consdataEnsureQuadVarTermsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46099
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 SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46462
SCIP_RETCODE SCIPaddSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE propagateBoundsBilinearTerm(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *x, SCIP_Real xsqrcoef, SCIP_Real xlincoef, SCIP_VAR *y, SCIP_Real ysqrcoef, SCIP_Real ylincoef, SCIP_Real bilincoef, SCIP_INTERVAL rhs, SCIP_RESULT *result, int *nchgbds)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:40275
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:6541
SCIP_RETCODE SCIPchgRhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12866
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip.h:21927
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17166
SCIP_RETCODE SCIPincludeQuadconsUpgrade(SCIP *scip, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:6481
static SCIP_DECL_SORTINDCOMP(quadVarTermComp)
#define SCIP_MAXSTRLEN
Definition: def.h:215
static SCIP_RETCODE replaceQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_VAR *var, SCIP_Real coef, SCIP_Real offset)
#define SCIP_DECL_CONSINITPRE(x)
Definition: type_cons.h:114
#define CONSHDLR_DELAYPROP
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16753
SCIP_VAR * var1
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip.c:5973
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21896
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:27962
static SCIP_RETCODE getImpliedBounds(SCIP *scip, SCIP_VAR *x, SCIP_Bool xval, SCIP_VAR *y, SCIP_INTERVAL *resultant)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12481
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:45601
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:16946
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16232
#define CONSHDLR_PROPFREQ
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:45876
#define INTERIOR_EPS
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17222
static SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45803
internal methods for NLPI solver interfaces
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:8250
SCIP_RETCODE SCIPnlpiCreateProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem, const char *name)
Definition: nlpi.c:211
static SCIP_RETCODE catchVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:8526
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip.c:31218
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:16370
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)
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip.c:18575
static void consdataUpdateLinearActivityUbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
static SCIP_RETCODE dropLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:18384
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16732
static SCIP_RETCODE addQuadVarTerm(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:46175
SCIP_Real SCIPvarGetBestBoundLocal(SCIP_VAR *var)
Definition: var.c:17252
static SCIP_DECL_CONSENABLE(consEnableQuadratic)
static SCIP_RETCODE generateCut(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Real *ref, SCIP_SOL *sol, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *efficacy, SCIP_Bool checkcurvmultivar, SCIP_Real minefficacy)
static void consdataUpdateLinearActivityLbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46138
static SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
SCIP_Real SCIPgetRelaxFeastolFactor(SCIP *scip)
Definition: scip.c:34449
#define CONSHDLR_MAXPREROUNDS
SCIP_RETCODE SCIPchgLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
static SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4485
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16311
#define FALSE
Definition: def.h:64
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip.c:21580
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2765
static SCIP_Real getGradientMaxElement(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol)
#define INITLPMAXVARVAL
static SCIP_RETCODE evaluateGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *gaugeval, SCIP_Bool *success)
static SCIP_RETCODE presolveSolve(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result, SCIP_Bool *redundant, int *naggrvars)
SCIP_RETCODE SCIPnlpiAddConstraints(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nconss, const SCIP_Real *lhss, const SCIP_Real *rhss, const int *nlininds, int *const *lininds, SCIP_Real *const *linvals, const int *nquadelems, SCIP_QUADELEM *const *quadelems, int *const *exprvaridxs, SCIP_EXPRTREE *const *exprtrees, const char **names)
Definition: nlpi.c:268
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip.c:3533
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:5831
SCIP_Real * SCIPgetLinearCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:45816
#define CONSHDLR_SEPAPRIORITY
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:9340
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:45888
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28192
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPsolveNLP(SCIP *scip)
Definition: scip.c:31195
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:21255
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8160
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
static void consdataFindUnlockedLinearVar(SCIP *scip, SCIP_CONSDATA *consdata)
static void checkCurvatureEasy(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *determined, SCIP_Bool checkmultivariate)
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
SCIP_Real SCIPgetRhsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8190
SCIP_RETCODE SCIPcreateConsBasicQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Real lhs, SCIP_Real rhs)
static GRAPHNODE ** active
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22234
static SCIP_RETCODE removeBilinearTermsPos(SCIP *scip, SCIP_CONS *cons, int nterms, int *termposs)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:21907
void SCIPaddBilinLinearization(SCIP *scip, SCIP_Real bilincoef, SCIP_Real refpointx, SCIP_Real refpointy, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:33011
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip.c:5885
SCIP_Real SCIPselectSimpleValue(SCIP_Real lb, SCIP_Real ub, SCIP_Longint maxdnom)
Definition: misc.c:8482
static SCIP_RETCODE presolveTryAddAND(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip.c:8656
Constraint handler for AND constraints, .
SCIP_RETCODE SCIPnlpiGetSolution(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_Real **primalvalues, SCIP_Real **consdualvalues, SCIP_Real **varlbdualvalues, SCIP_Real **varubdualvalues)
Definition: nlpi.c:535
SCIP_RETCODE SCIPwriteVarsPolynomial(SCIP *scip, FILE *file, SCIP_VAR ***monomialvars, SCIP_Real **monomialexps, SCIP_Real *monomialcoefs, int *monomialnvars, int nmonomials, SCIP_Bool type)
Definition: scip.c:17527
static SCIP_RETCODE mergeAndCleanBilinearTerms(SCIP *scip, SCIP_CONS *cons)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2903
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45751
static SCIP_RETCODE chgLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_Real newcoef)
static SCIP_RETCODE propagateBoundsCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_RESULT *result, int *nchgbds, SCIP_Bool *redundant)
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:37047
static SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:21937
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip.c:21548
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16763
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:21890
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
static SCIP_RETCODE dropQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIP_RETCODE SCIPcreateConsBasicQuadratic(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8150
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:108
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:6274
static SCIP_RETCODE registerBranchingCandidatesViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1260
#define SCIPdebugMsgPrint
Definition: scip.h:452
#define SCIPdebugMsg
Definition: scip.h:451
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4202
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:6458
SCIP_Real SCIPgetLhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:7942
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1336
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:11811
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:27146
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:45246
static SCIP_RETCODE lockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30491
SCIP_RETCODE SCIPaddLinearVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
SCIP_RETCODE SCIPcreateConsQuadratic(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
static SCIP_RETCODE unlockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
int SCIPgetNQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8180
int SCIPnlrowGetNQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3322
SCIP_RETCODE SCIPcreateConsVarbound(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *var, SCIP_VAR *vbdvar, SCIP_Real vbdcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:104
const char * SCIPgetProbName(SCIP *scip)
Definition: scip.c:10724
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2997
static SCIP_RETCODE registerBranchingCandidatesGap(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPnlpiSolve(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:495
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:236
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12926
static SCIP_RETCODE consdataSortQuadVarTerms(SCIP *scip, SCIP_CONSDATA *consdata)
#define CONSHDLR_EAGERFREQ
SCIP_RETCODE SCIPnlpiAddVars(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nvars, const SCIP_Real *lbs, const SCIP_Real *ubs, const char **varnames)
Definition: nlpi.c:250
SCIP_RETCODE SCIPchgVarType(SCIP *scip, SCIP_VAR *var, SCIP_VARTYPE vartype, SCIP_Bool *infeasible)
Definition: scip.c:25045
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17176
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip.c:6094
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:21904
SCIP_Bool SCIPisConcaveQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real coef
Definition: type_expr.h:102
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:127
SCIP_Real inf
Definition: intervalarith.h:39
SCIP_RETCODE SCIPchgLhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real lhs)
static SCIP_RETCODE checkCurvature(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkmultivariate)
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1162
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip.c:37295
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip.c:1047
SCIP_Bool SCIPconsIsLocked(SCIP_CONS *cons)
Definition: cons.c:8220
SCIP_VAR ** SCIPnlrowGetQuadVars(SCIP_NLROW *nlrow)
Definition: nlp.c:3285
static SCIP_RETCODE presolveTryAddLinearReform(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
static 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)
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30455
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5997
SCIP_RETCODE SCIPaddLinearConsToNlpHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_Bool addcombconss, SCIP_Bool addcontconss)
Definition: heur_subnlp.c:2383
static SCIP_DECL_CONSEXIT(consExitQuadratic)
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1181
struct SCIP_QuadVarEventData SCIP_QUADVAREVENTDATA
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
void SCIPaddBilinMcCormick(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:33058
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip.c:8140
SCIP_RETCODE SCIPfindQuadVarTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, int *pos)
static void propagateBoundsGetQuadActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty, SCIP_Real *minquadactivity, SCIP_Real *maxquadactivity, int *minactivityinf, int *maxactivityinf, SCIP_INTERVAL *quadactcontr)
static SCIP_RETCODE addLinearizationCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *ref, SCIP_Bool *separatedlpsol, SCIP_Real minefficacy)
SCIP_RETCODE SCIPcreateConsAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_and.c:4948
#define SCIPerrorMessage
Definition: pub_message.h:45
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4113
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12410
interval arithmetics for provable bounds
static SCIP_RETCODE removeFixedVariables(SCIP *scip, SCIP_CONS *cons)
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45764
SCIP_RETCODE SCIPaddConsLocal(SCIP *scip, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip.c:13030
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip.c:31086
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:69
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:13111
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
static SCIP_DECL_CONSDELETE(consDeleteQuadratic)
static SCIP_DECL_CONSPARSE(consParseQuadratic)
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:16420
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip.c:31901
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss, SCIP_PRESOLTIMING presoltiming)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:18929
static SCIP_RETCODE catchQuadVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int quadvarpos)
SCIP_Real * SCIPgetCoefsLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIPInterval sqrt(const SCIPInterval &x)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:21938
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:45519
int SCIPgetLinvarMayDecreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcheckCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_RESULT *result)
Definition: scip.c:28252
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21383
static SCIP_DECL_CONSCHECK(consCheckQuadratic)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7881
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8100
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:71
static SCIP_DECL_CONSPRESOL(consPresolQuadratic)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16552
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:6022
static SCIP_DECL_CONSTRANS(consTransQuadratic)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2798
constraint handler for quadratic constraints
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4133
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)
#define CONSHDLR_CHECKPRIORITY
#define NULL
Definition: lpi_spx1.cpp:137
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28164
static SCIP_RETCODE registerBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2382
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38137
int SCIPgetNNlpis(SCIP *scip)
Definition: scip.c:9444
#define REALABS(x)
Definition: def.h:159
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31163
SCIP_RETCODE SCIPgetNlRowQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip.c:36704
SCIP_QUADELEM * SCIPnlrowGetQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3332
#define SCIP_CALL(x)
Definition: def.h:306
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:63
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
static SCIP_RETCODE disaggregate(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, int *naddconss, int *ndelconss, SCIP_Bool *success)
Definition: cons_soc.c:2928
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46125
#define CONSHDLR_ENFOPRIORITY
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:16970
SCIP_Real sup
Definition: intervalarith.h:40
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46112
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16321
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1353
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8120
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:265
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:33869
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
SCIP_BILINTERM * SCIPgetBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:106
SCIP_RETCODE LapackDsyev(SCIP_Bool computeeigenvectors, int N, SCIP_Real *a, SCIP_Real *w)
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:16257
SCIP_NLPSOLSTAT SCIPnlpiGetSolstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:509
SCIP_RETCODE SCIPnlpiSetObjective(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, int nlins, const int *lininds, const SCIP_Real *linvals, int nquadelems, const SCIP_QUADELEM *quadelems, const int *exprvaridxs, const SCIP_EXPRTREE *exprtree, const SCIP_Real constant)
Definition: nlpi.c:300
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:105
SCIP_Bool SCIPhasPrimalRay(SCIP *scip)
Definition: scip.c:40124
void SCIPaddSquareSecant(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real lb, SCIP_Real ub, SCIP_Real refpoint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:32961
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4515
static SCIP_RETCODE consdataEnsureAdjBilinSize(SCIP *scip, SCIP_QUADVARTERM *quadvarterm, int num)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
Definition: scip.c:45839
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_Real SCIPgetRhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13029
SCIP_RETCODE SCIPgetViolationQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
SCIP_Bool SCIPvarIsOriginal(SCIP_VAR *var)
Definition: var.c:16681
SCIP_RETCODE SCIPaddBilinTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
SCIP_RETCODE SCIPnlpiFreeProblem(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **problem)
Definition: nlpi.c:224
Ipopt NLP interface.
static SCIP_RETCODE computeInteriorPoint(SCIP *scip, SCIP_CONS *cons, char method, SCIP_Bool *success)
static SCIP_RETCODE propagateBoundsTightenVarUb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:21925
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:16267
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17476
#define CONSHDLR_NEEDSCONS
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:982
static SCIP_DECL_CONSINITLP(consInitlpQuadratic)
#define SCIP_Bool
Definition: def.h:61
static SCIP_DECL_CONSFREE(consFreeQuadratic)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:40207
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:28854
static SCIP_RETCODE presolveDisaggregate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14524
#define CONSHDLR_DELAYSEPA
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
static SCIP_RETCODE registerBranchingCandidatesCentrality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:959
static SCIP_RETCODE computeGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
static const char * paramname[]
Definition: lpi_msk.c:4268
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:30022
SCIP_Real SCIPgetLhsNonlinear(SCIP *scip, SCIP_CONS *cons)
#define NONLINCONSUPGD_PRIORITY
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:42094
SCIP_RETCODE SCIPnlpiSetIntPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, int ival)
Definition: nlpi.c:633
constraint handler for nonlinear constraints
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17444
void SCIPintervalSolveBivariateQuadExpressionAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:28652
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3217
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:9411
SCIP_NLPTERMSTAT SCIPnlpiGetTermstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:521
static SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
static SCIP_RETCODE replaceByLinearConstraints(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *addedcons, SCIP_Bool *reduceddom, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:33964
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7901
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11249
methods for debugging
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip.c:6389
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:40241
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:37631
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8080
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8050
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17014
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:40321
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:17237
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:36399
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:89
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21309
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38090
#define infty2infty(infty1, infty2, val)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:6435
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:65
Constraint handler for linear constraints in their most general form, .
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *solviolbounds, SCIP_CONS **maxviolcon)
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip.c:33851
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:16934
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:45827
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17490
#define CONSHDLR_NAME
#define BMSclearMemory(ptr)
Definition: memory.h:84
static SCIP_Bool consdataCheckBilinTermsSort(SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip.c:6366
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12958
int SCIPgetNBinVars(SCIP *scip)
Definition: scip.c:11676
SCIP_Bool SCIPisLinearLocalQuadratic(SCIP *scip, SCIP_CONS *cons)
static void generateCutLTIcomputeCoefs(SCIP *scip, SCIP_Real xl, SCIP_Real xu, SCIP_Real x0, SCIP_Real yl, SCIP_Real yu, SCIP_Real y0_, SCIP_Real wl, SCIP_Real wu, SCIP_Real w0, SCIP_Real *cx, SCIP_Real *cy, SCIP_Real *cw, SCIP_Real *c0, SCIP_Bool *success)
static SCIP_DECL_CONSENFORELAX(consEnforelaxQuadratic)
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:35033
static SCIP_Bool generateCutLTIfindIntersection(SCIP *scip, SCIP_Real x0, SCIP_Real y0_, SCIP_Real x1, SCIP_Real y1_, SCIP_Real wl, SCIP_Real wu, SCIP_Real *xl, SCIP_Real *yl, SCIP_Real *xu, SCIP_Real *yu)
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13041
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11631
SCIP_RETCODE SCIPcheckCurvatureQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7173
void SCIPenableNLP(SCIP *scip)
Definition: scip.c:30820
static SCIP_RETCODE registerLargeRelaxValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_VAR **brvar)
SCIP_QUADVAREVENTDATA * eventdata
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17461
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:6166
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:93
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:30160
int SCIPgetLinvarMayIncreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE addBilinearTerm(SCIP *scip, SCIP_CONS *cons, int var1pos, int var2pos, SCIP_Real coef)
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:37075
static void consdataMoveQuadVarTerm(SCIP_CONSDATA *consdata, int oldpos, int newpos)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3162
static SCIP_RETCODE processCut(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real efficacy, SCIP_Real actminefficacy, SCIP_Bool inenforcement, SCIP_Real *bestefficacy, SCIP_RESULT *result)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:4653
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45790
static SCIP_RETCODE consdataCreateEmpty(SCIP *scip, SCIP_CONSDATA **consdata)
static SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:45900
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:4286
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16081
int SCIPgetNLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
void SCIPfreeParseVarsPolynomialData(SCIP *scip, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int nmonomials)
Definition: scip.c:18294
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:1911
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:11311
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7911
#define CONSHDLR_DESC
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:6046
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:6070
static SCIP_RETCODE dropVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons)
static SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:135
static SCIP_DECL_CONSCOPY(consCopyQuadratic)
static SCIP_DECL_CONSINIT(consInitQuadratic)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:27323
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingModeUpwards(void)
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)
static SCIP_RETCODE computeReferencePointProjection(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *ref)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:6190
NLP local search primal heuristic using sub-SCIPs.
static SCIP_RETCODE generateCutSol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_SOL *refsol, SCIP_SIDETYPE violside, SCIP_ROW **row, SCIP_Real *efficacy, SCIP_Bool checkcurvmultivar, SCIP_Real minefficacy, char mode)
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30579
SCIP_RETCODE SCIPgetFeasibilityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *feasibility)
SCIP_RETCODE SCIPsortQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1138
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:46163
SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
Definition: scip.c:31338
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16671
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:25250
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:18350
#define SCIP_Real
Definition: def.h:135
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8130
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:30314
SCIP_RETCODE SCIPaddToNlpiProblemQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *nlpiprob, SCIP_HASHMAP *scipvar2nlpivar, SCIP_Bool names)
SCIP_VAR ** SCIPgetLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1138
#define MIN(x, y)
Definition: memory.c:75
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:6504
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Bool SCIPhaveVarsCommonClique(SCIP *scip, SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: scip.c:24529
static SCIP_RETCODE computeReferencePointGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *ref, SCIP_Bool *success)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8070
static SCIP_RETCODE checkFactorable(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12876
#define SCIP_INVALID
Definition: def.h:155
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8060
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:30762
void SCIPsortInt(int *intarray, int len)
static SCIP_RETCODE propagateBoundsTightenVarLb(SCIP *scip, SCIP_CONS *cons, SCIP_Real intervalinfty, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
SCIP_RETCODE SCIPcreateConsQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
static SCIP_RETCODE delLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
#define SCIP_Longint
Definition: def.h:120
static SCIP_RETCODE consdataEnsureBilinSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
SCIP_RETCODE SCIPaddQuadVarLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_BOUNDTYPE SCIPvarGetBestBoundType(SCIP_VAR *var)
Definition: var.c:17278
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:37836
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:264
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16717
static SCIP_DECL_CONSLOCK(consLockQuadratic)
SCIP_RETCODE SCIPcreateConsBounddisjunction(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_BOUNDTYPE *boundtypes, SCIP_Real *bounds, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPparseVarsPolynomial(SCIP *scip, const char *str, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int *nmonomials, char **endptr, SCIP_Bool *success)
Definition: scip.c:17942
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
void SCIPintervalMulInf(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:45864
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45777
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
static SCIP_DECL_EVENTEXEC(processVarEvent)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17232
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:21910
static SCIP_RETCODE addLinearCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16694
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2417
SCIP_Bool SCIPconsIsMarkedPropagate(SCIP_CONS *cons)
Definition: cons.c:8090
#define CONSHDLR_PROP_TIMING
#define SCIP_DECL_QUADCONSUPGD(x)
static SCIP_DECL_CONSPROP(consPropQuadratic)
SCIP_NLPI ** SCIPgetNlpis(SCIP *scip)
Definition: scip.c:9431
static SCIP_RETCODE delQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
Definition: scip.c:42472
static SCIP_DECL_CONSPRINT(consPrintQuadratic)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2846
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45998
static SCIP_RETCODE presolveDisaggregateMarkComponent(SCIP *scip, SCIP_CONSDATA *consdata, int quadvaridx, SCIP_HASHMAP *var2component, int componentnr)
#define CONSHDLR_SEPAFREQ
static SCIP_RETCODE computeED(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
SCIP_QUADVARTERM * SCIPgetQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_VAR **quadvars, int nquadelems, SCIP_QUADELEM *quadelems, SCIP_EXPRTREE *expression, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip.c:31793
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:13065
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *solviolbounds)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:45949
constraint handler for bound disjunction constraints
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:6118
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:41363
#define SCIPABORT()
Definition: def.h:278
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
Definition: scip.c:45961
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16743
static SCIP_RETCODE consdataFindQuadVarTerm(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_VAR *var, int *pos)
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
SCIP_Longint SCIPcalcGreComDiv(SCIP_Longint val1, SCIP_Longint val2)
Definition: misc.c:7945
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:38007
static SCIP_RETCODE mergeAndCleanQuadVarTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisInRestart(SCIP *scip)
Definition: scip.c:17200
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1223
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4258
static SCIP_RETCODE consdataEnsureLinearVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
void SCIPintervalSetRoundingModeDownwards(void)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:45937
SCIP_Bool SCIPisConvexQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetPrimalRayVal(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:40142
static SCIP_DECL_CONSDISABLE(consDisableQuadratic)
SCIP_RETCODE SCIPgetActivityQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *activity)
static SCIP_Bool hasQuadvarHpProperty(SCIP *scip, SCIP_CONSDATA *consdata, int idx)
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4176
void SCIPintervalSolveUnivariateQuadExpressionPositive(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16839
void SCIPaddSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
Definition: scip.c:32893
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:21929
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:134
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5931
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:13053