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-2019 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 visit 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 #define SCIP_PRIVATE_ROWPREP
35 
36 #include "blockmemshell/memory.h"
37 #include <ctype.h>
38 #include "nlpi/nlpi.h"
39 #include "nlpi/nlpi_ipopt.h"
40 #include "nlpi/pub_expr.h"
41 #include "nlpi/type_expr.h"
42 #include "scip/cons_and.h"
44 #include "scip/cons_linear.h"
45 #include "scip/cons_nonlinear.h"
46 #include "scip/cons_quadratic.h"
47 #include "scip/cons_varbound.h"
48 #include "scip/debug.h"
49 #include "scip/heur_subnlp.h"
50 #include "scip/heur_trysol.h"
51 #include "scip/intervalarith.h"
52 #include "scip/pub_cons.h"
53 #include "scip/pub_event.h"
54 #include "scip/pub_heur.h"
55 #include "scip/pub_lp.h"
56 #include "scip/pub_message.h"
57 #include "scip/pub_misc.h"
58 #include "scip/pub_misc_sort.h"
59 #include "scip/pub_nlp.h"
60 #include "scip/pub_sol.h"
61 #include "scip/pub_tree.h"
62 #include "scip/pub_var.h"
63 #include "scip/scip_branch.h"
64 #include "scip/scip_cons.h"
65 #include "scip/scip_copy.h"
66 #include "scip/scip_cut.h"
67 #include "scip/scip_event.h"
68 #include "scip/scip_general.h"
69 #include "scip/scip_heur.h"
70 #include "scip/scip_lp.h"
71 #include "scip/scip_mem.h"
72 #include "scip/scip_message.h"
73 #include "scip/scip_nlp.h"
74 #include "scip/scip_nonlinear.h"
75 #include "scip/scip_numerics.h"
76 #include "scip/scip_param.h"
77 #include "scip/scip_prob.h"
78 #include "scip/scip_probing.h"
79 #include "scip/scip_sepa.h"
80 #include "scip/scip_sol.h"
81 #include "scip/scip_solve.h"
82 #include "scip/scip_solvingstats.h"
83 #include "scip/scip_tree.h"
84 #include "scip/scip_var.h"
85 #include <string.h>
86 
87 /* constraint handler properties */
88 #define CONSHDLR_NAME "quadratic"
89 #define CONSHDLR_DESC "quadratic constraints of the form lhs <= b' x + x' A x <= rhs"
90 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
91 #define CONSHDLR_ENFOPRIORITY -50 /**< priority of the constraint handler for constraint enforcing */
92 #define CONSHDLR_CHECKPRIORITY -4000000 /**< priority of the constraint handler for checking feasibility */
93 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
94 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
95 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
96  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
97 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
98 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
99 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
100 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
102 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
103 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
105 #define MAXDNOM 10000LL /**< maximal denominator for simple rational fixed values */
106 #define NONLINCONSUPGD_PRIORITY 40000 /**< priority of upgrading nonlinear constraints */
107 #define INITLPMAXVARVAL 1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
109 /* Activating this define enables reformulation of bilinear terms x*y with implications from x to y into linear terms.
110  * 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,
111  * then the implication may not be enforced in a solution.
112  * This issue need to be fixed before this feature can be enabled.
113  */
114 /* #define CHECKIMPLINBILINEAR */
115 
116 /* enable new propagation for bivariate quadratic terms */
117 #define PROPBILINNEW
119 /* epsilon for differentiating between a boundary and interior point */
120 #define INTERIOR_EPS 1e-1
122 /* scaling factor for gauge function */
123 #define GAUGESCALE 0.99999
125 #define ROWPREP_SCALEUP_VIOLNONZERO (10.0*SCIPepsilon(scip)) /**< minimal violation for considering up-scaling of rowprep (we want to avoid upscaling very small violations) */
126 #define ROWPREP_SCALEUP_MINVIOLFACTOR 2.0 /**< scale up will target a violation of ~MINVIOLFACTOR*minviol, where minviol is given by caller */
127 #define ROWPREP_SCALEUP_MAXMINCOEF (1.0 / SCIPfeastol(scip)) /**< scale up only if min. coef is below this number (before scaling) */
128 #define ROWPREP_SCALEUP_MAXMAXCOEF SCIPgetHugeValue(scip) /**< scale up only if max. coef will not exceed this number by scaling */
129 #define ROWPREP_SCALEUP_MAXSIDE SCIPgetHugeValue(scip) /**< scale up only if side will not exceed this number by scaling */
130 #define ROWPREP_SCALEDOWN_MINMAXCOEF (1.0 / SCIPfeastol(scip)) /**< scale down if max. coef is at least this number (before scaling) */
131 #define ROWPREP_SCALEDOWN_MINCOEF SCIPfeastol(scip) /**< scale down only if min. coef does not drop below this number by scaling */
133 /*
134  * Data structures
135  */
136 
137 /** eventdata for variable bound change events in quadratic constraints */
138 struct SCIP_QuadVarEventData
139 {
140  SCIP_CONS* cons; /**< the constraint */
141  int varidx; /**< the index of the variable which bound change is caught, positive for linear variables, negative for quadratic variables */
142  int filterpos; /**< position of eventdata in SCIP's event filter */
143 };
144 
145 /** Data of a quadratic constraint. */
146 struct SCIP_ConsData
147 {
148  SCIP_Real lhs; /**< left hand side of constraint */
149  SCIP_Real rhs; /**< right hand side of constraint */
150 
151  int nlinvars; /**< number of linear variables */
152  int linvarssize; /**< length of linear variable arrays */
153  SCIP_VAR** linvars; /**< linear variables */
154  SCIP_Real* lincoefs; /**< coefficients of linear variables */
155  SCIP_QUADVAREVENTDATA** lineventdata; /**< eventdata for bound change of linear variable */
156 
157  int nquadvars; /**< number of variables in quadratic terms */
158  int quadvarssize; /**< length of quadratic variable terms arrays */
159  SCIP_QUADVARTERM* quadvarterms; /**< array with quadratic variable terms */
160 
161  int nbilinterms; /**< number of bilinear terms */
162  int bilintermssize; /**< length of bilinear term arrays */
163  SCIP_BILINTERM* bilinterms; /**< bilinear terms array */
164  int* bilintermsidx; /**< unique index of each bilinear term xy in the bilinestimators array of the constraint handler data */
165 
166  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
167 
168  unsigned int linvarssorted:1; /**< are the linear variables already sorted? */
169  unsigned int linvarsmerged:1; /**< are equal linear variables already merged? */
170  unsigned int quadvarssorted:1; /**< are the quadratic variables already sorted? */
171  unsigned int quadvarsmerged:1; /**< are equal quadratic variables already merged? */
172  unsigned int bilinsorted:1; /**< are the bilinear terms already sorted? */
173  unsigned int bilinmerged:1; /**< are equal bilinear terms (and bilinear terms with zero coefficient) already merged? */
174 
175  unsigned int isconvex:1; /**< is quadratic function is convex ? */
176  unsigned int isconcave:1; /**< is quadratic function is concave ? */
177  unsigned int iscurvchecked:1; /**< is quadratic function checked on convexity or concavity ? */
178  unsigned int isremovedfixings:1; /**< did we removed fixed/aggr/multiaggr variables ? */
179  unsigned int ispropagated:1; /**< was the constraint propagated with respect to the current bounds ? */
180  unsigned int ispresolved:1; /**< did we checked for possibilities of upgrading or implicit integer variables ? */
181  unsigned int initialmerge:1; /**< did we perform an initial merge and clean in presolving yet ? */
182 #ifdef CHECKIMPLINBILINEAR
183  unsigned int isimpladded:1; /**< has there been an implication added for a binary variable in a bilinear term? */
184 #endif
185  unsigned int isgaugeavailable:1; /**< is the gauge function computed? */
186  unsigned int isedavailable:1; /**< is the eigen decomposition of A available? */
187 
188  SCIP_Real minlinactivity; /**< sum of minimal activities of all linear terms with finite minimal activity */
189  SCIP_Real maxlinactivity; /**< sum of maximal activities of all linear terms with finite maximal activity */
190  int minlinactivityinf; /**< number of linear terms with infinite minimal activity */
191  int maxlinactivityinf; /**< number of linear terms with infinity maximal activity */
192  SCIP_INTERVAL quadactivitybounds; /**< bounds on the activity of the quadratic term, if up to date, otherwise empty interval */
193  SCIP_Real activity; /**< activity of quadratic function w.r.t. current solution */
194  SCIP_Real lhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
195  SCIP_Real rhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
196 
197  int linvar_maydecrease; /**< index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
198  int linvar_mayincrease; /**< index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
199 
200  SCIP_VAR** sepaquadvars; /**< variables corresponding to quadvarterms to use in separation, only available in solving stage */
201  int* sepabilinvar2pos; /**< position of second variable in bilinear terms to use in separation, only available in solving stage */
202  SCIP_Real lincoefsmin; /**< minimal absolute value of coefficients in linear part, only available in solving stage */
203  SCIP_Real lincoefsmax; /**< maximal absolute value of coefficients in linear part, only available in solving stage */
204 
205  SCIP_Real* factorleft; /**< coefficients of left factor if constraint function is factorable */
206  SCIP_Real* factorright; /**< coefficients of right factor if constraint function is factorable */
207 
208  SCIP_Real* gaugecoefs; /**< coefficients of the gauge function */
209  SCIP_Real gaugeconst; /**< constant of the gauge function */
210  SCIP_Real* interiorpoint; /**< interior point of the region defined by the convex function */
211  SCIP_Real interiorpointval; /**< function value at interior point */
212 
213  SCIP_Real* eigenvalues; /**< eigenvalues of A */
214  SCIP_Real* eigenvectors; /**< orthonormal eigenvectors of A; if A = P D P^T, then eigenvectors is P^T */
215  SCIP_Real* bp; /**< stores b * P where b are the linear coefficients of the quadratic vars */
216  SCIP_Real maxnonconvexity; /**< nonconvexity measure: estimate on largest absolute value of nonconvex eigenvalues */
217 
218  SCIP_Bool isdisaggregated; /**< has the constraint already been disaggregated? if might happen that more disaggreation would be potentially
219  possible, but we reached the maximum number of sparsity components during presolveDisaggregate() */
220 };
221 
222 /** quadratic constraint update method */
224 {
225  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)); /**< method to call for upgrading quadratic constraint */
226  int priority; /**< priority of upgrading method */
227  SCIP_Bool active; /**< is upgrading enabled */
228 };
229 typedef struct SCIP_QuadConsUpgrade SCIP_QUADCONSUPGRADE; /**< quadratic constraint update method */
231 /** structure to store everything needed for using linear inequalities to improve upon the McCormick relaxation */
232 struct BilinearEstimator
233 {
234  SCIP_VAR* x; /**< first variable */
235  SCIP_VAR* y; /**< second variable */
236  SCIP_Real inequnderest[6]; /**< at most two inequalities that can be used to underestimate xy; stored as (xcoef,ycoef,constant) with xcoef x <= ycoef y + constant */
237  SCIP_Real ineqoverest[6]; /**< at most two inequalities that can be used to overestimate xy; stored as (xcoef,ycoef,constant) with xcoef x <= ycoef y + constant */
238  SCIP_Real maxnonconvexity; /**< estimate on largest absolute value of nonconvex eigenvalues of all quadratic constraint containing xy */
239  int ninequnderest; /**< total number of inequalities for underestimating xy */
240  int nineqoverest; /**< total number of inequalities for overestimating xy */
241  int nunderest; /**< number of constraints that require to underestimate xy */
242  int noverest; /**< number of constraints that require to overestimate xy */
244  SCIP_Real lastimprfac; /**< last achieved improvement factor */
245 };
246 typedef struct BilinearEstimator BILINESTIMATOR;
248 /** constraint handler data */
249 struct SCIP_ConshdlrData
250 {
251  int replacebinaryprodlength; /**< length of linear term which when multiplied with a binary variable is replaced by an auxiliary variable and an equivalent linear formulation */
252  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 */
253  SCIP_Bool binreforminitial; /**< whether to make constraints added due to replacing products with binary variables initial */
254  SCIP_Bool binreformbinaryonly;/**< whether to consider only binary variables when reformulating products with binary variables */
255  SCIP_Real binreformmaxcoef; /**< factor on 1/feastol to limit coefficients and coef range in linear constraints created by binary reformulation */
256  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
257  SCIP_Bool linearizeheursol; /**< whether linearizations of convex quadratic constraints should be added to cutpool when some heuristics finds a new solution */
258  SCIP_Bool checkcurvature; /**< whether functions should be checked for convexity/concavity */
259  SCIP_Bool checkfactorable; /**< whether functions should be checked to be factorable */
260  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) */
261  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
262  int maxdisaggrsize; /**< maximum number of components when disaggregating a quadratic constraint (<= 1: off) */
263  char disaggrmergemethod; /**< method on merging blocks in disaggregation */
264  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve */
265  int maxproproundspresolve; /**< limit on number of propagation rounds for a single constraint within one presolving round */
266  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
267  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
268  SCIP_Bool gaugecuts; /**< should convex quadratics generated strong cuts via gauge function? */
269  SCIP_Bool projectedcuts; /**< should convex quadratics generated strong cuts via projections? */
270  char interiorcomputation;/**< how the interior point should be computed: 'a'ny point per constraint, 'm'ost interior per constraint */
271  char branchscoring; /**< method to use to compute score of branching candidates */
272  int enfolplimit; /**< maximum number of enforcement round before declaring the LP relaxation
273  * infeasible (-1: no limit); WARNING: if this parameter is not set to -1,
274  * SCIP might declare sub-optimal solutions optimal or feasible instances
275  * infeasible; thus, the result returned by SCIP might be incorrect!
276  */
277  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
278  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
279  SCIP_EVENTHDLR* eventhdlr; /**< our handler for variable bound change events */
280  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
281  SCIP_Bool sepanlp; /**< where linearization of the NLP relaxation solution added? */
282  SCIP_NODE* lastenfonode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
283  int nenforounds; /**< counter on number of enforcement rounds for the current node */
284  SCIP_QUADCONSUPGRADE** quadconsupgrades; /**< quadratic constraint upgrade methods for specializing quadratic constraints */
285  int quadconsupgradessize; /**< size of quadconsupgrade array */
286  int nquadconsupgrades; /**< number of quadratic constraint upgrade methods */
287 
288  BILINESTIMATOR* bilinestimators; /**< array containing all required information for using stronger estimators for each bilinear term in all quadratic constraints */
289  int nbilinterms; /**< number of bilinear terms in all quadratic constraints */
290 
291  SCIP_Bool usebilinineqbranch; /**< should linear inequalities be considered when computing the branching scores for bilinear terms? */
292  SCIP_Bool storedbilinearterms; /**< did we already try to store all bilinear terms? */
293 
294  SCIP_Real minscorebilinterms; /**< minimal required score in order to use linear inequalities for tighter bilinear relaxations */
295  SCIP_Real mincurvcollectbilinterms;/**< minimal curvature of constraints to be considered when returning bilinear terms to other plugins */
296  int bilinineqmaxseparounds; /**< maximum number of separation rounds to use linear inequalities for the bilinear term relaxation in a local node */
297 };
298 
299 
300 /*
301  * local methods for managing quadratic constraint update methods
302  */
303 
304 
305 /** checks whether a quadratic constraint upgrade method has already be registered */
306 static
308  SCIP* scip, /**< SCIP data structure */
309  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
310  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
311  const char* conshdlrname /**< name of the constraint handler */
312  )
313 {
314  int i;
315 
316  assert(scip != NULL);
317  assert(conshdlrdata != NULL);
318  assert(quadconsupgd != NULL);
319  assert(conshdlrname != NULL);
320 
321  for( i = conshdlrdata->nquadconsupgrades - 1; i >= 0; --i )
322  {
323  if( conshdlrdata->quadconsupgrades[i]->quadconsupgd == quadconsupgd )
324  {
325  SCIPwarningMessage(scip, "Try to add already known upgrade message for constraint handler <%s>.\n", conshdlrname);
326  return TRUE;
327  }
328  }
329 
330  return FALSE;
331 }
332 
333 /*
334  * Local methods
335  */
336 
337 /** translate from one value of infinity to another
338  *
339  * if val is >= infty1, then give infty2, else give val
340  */
341 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
343 /** catches variable bound change events on a linear variable in a quadratic constraint */
344 static
346  SCIP* scip, /**< SCIP data structure */
347  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
348  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
349  int linvarpos /**< position of variable in linear variables array */
350  )
351 {
352  SCIP_CONSDATA* consdata;
353  SCIP_QUADVAREVENTDATA* eventdata;
354  SCIP_EVENTTYPE eventtype;
355 
356  assert(scip != NULL);
357  assert(eventhdlr != NULL);
358  assert(cons != NULL);
359 
360  consdata = SCIPconsGetData(cons);
361  assert(consdata != NULL);
362 
363  assert(linvarpos >= 0);
364  assert(linvarpos < consdata->nlinvars);
365  assert(consdata->lineventdata != NULL);
366 
367  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
368 
369  eventdata->cons = cons;
370  eventdata->varidx = linvarpos;
371 
373  if( !SCIPisInfinity(scip, consdata->rhs) )
374  {
375  /* if right hand side is finite, then a tightening in the lower 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_LBCHANGED;
379  else
380  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
381  }
382  if( !SCIPisInfinity(scip, -consdata->lhs) )
383  {
384  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
385  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
386  if( consdata->lincoefs[linvarpos] > 0.0 )
387  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
388  else
389  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
390  }
391 
392  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
393 
394  consdata->lineventdata[linvarpos] = eventdata;
395 
396  /* invalidate activity information
397  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
398  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
399  */
400  consdata->minlinactivity = SCIP_INVALID;
401  consdata->maxlinactivity = SCIP_INVALID;
402  consdata->minlinactivityinf = -1;
403  consdata->maxlinactivityinf = -1;
404 
405  return SCIP_OKAY;
406 }
407 
408 /** drops variable bound change events on a linear variable in a quadratic constraint */
409 static
411  SCIP* scip, /**< SCIP data structure */
412  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
413  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
414  int linvarpos /**< position of variable in linear variables array */
415  )
416 {
417  SCIP_CONSDATA* consdata;
418  SCIP_EVENTTYPE eventtype;
419 
420  assert(scip != NULL);
421  assert(eventhdlr != NULL);
422  assert(cons != NULL);
423 
424  consdata = SCIPconsGetData(cons);
425  assert(consdata != NULL);
426 
427  assert(linvarpos >= 0);
428  assert(linvarpos < consdata->nlinvars);
429  assert(consdata->lineventdata != NULL);
430  assert(consdata->lineventdata[linvarpos] != NULL);
431  assert(consdata->lineventdata[linvarpos]->cons == cons);
432  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
433  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
434 
436  if( !SCIPisInfinity(scip, consdata->rhs) )
437  {
438  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest
439  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
440  if( consdata->lincoefs[linvarpos] > 0.0 )
441  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
442  else
443  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
444  }
445  if( !SCIPisInfinity(scip, -consdata->lhs) )
446  {
447  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest
448  * since we also want to keep activities in consdata up-to-date, we also need to know when the corresponding bound is relaxed */
449  if( consdata->lincoefs[linvarpos] > 0.0 )
450  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
451  else
452  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
453  }
454 
455  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
456 
457  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866 */
458 
459  return SCIP_OKAY;
460 }
461 
462 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
463 static
465  SCIP* scip, /**< SCIP data structure */
466  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
467  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
468  int quadvarpos /**< position of variable in quadratic variables array */
469  )
470 {
471  SCIP_CONSDATA* consdata;
472  SCIP_QUADVAREVENTDATA* eventdata;
473  SCIP_EVENTTYPE eventtype;
474 
475  assert(scip != NULL);
476  assert(eventhdlr != NULL);
477  assert(cons != NULL);
478 
479  consdata = SCIPconsGetData(cons);
480  assert(consdata != NULL);
481 
482  assert(quadvarpos >= 0);
483  assert(quadvarpos < consdata->nquadvars);
484  assert(consdata->quadvarterms[quadvarpos].eventdata == NULL);
485 
486  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
487 
489 #ifdef CHECKIMPLINBILINEAR
490  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
491 #endif
492  eventdata->cons = cons;
493  eventdata->varidx = -quadvarpos-1;
494  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
495 
496  consdata->quadvarterms[quadvarpos].eventdata = eventdata;
497 
498  /* invalidate activity information
499  * NOTE: It could happen that a constraint gets temporary deactivated and some variable bounds change. In this case
500  * we do not recognize those bound changes with the variable events and thus we have to recompute the activities.
501  */
502  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
503 
504  return SCIP_OKAY;
505 }
506 
507 /** catches variable bound change events on a quadratic variable in a quadratic constraint */
508 static
510  SCIP* scip, /**< SCIP data structure */
511  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
512  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
513  int quadvarpos /**< position of variable in quadratic variables array */
514  )
515 {
516  SCIP_CONSDATA* consdata;
517  SCIP_EVENTTYPE eventtype;
518 
519  assert(scip != NULL);
520  assert(eventhdlr != NULL);
521  assert(cons != NULL);
522 
523  consdata = SCIPconsGetData(cons);
524  assert(consdata != NULL);
525 
526  assert(quadvarpos >= 0);
527  assert(quadvarpos < consdata->nquadvars);
528  assert(consdata->quadvarterms[quadvarpos].eventdata != NULL);
529  assert(consdata->quadvarterms[quadvarpos].eventdata->cons == cons);
530  assert(consdata->quadvarterms[quadvarpos].eventdata->varidx == -quadvarpos-1);
531  assert(consdata->quadvarterms[quadvarpos].eventdata->filterpos >= 0);
532 
534 #ifdef CHECKIMPLINBILINEAR
535  eventtype |= SCIP_EVENTTYPE_IMPLADDED;
536 #endif
537 
538  SCIP_CALL( SCIPdropVarEvent(scip, consdata->quadvarterms[quadvarpos].var, eventtype, eventhdlr, (SCIP_EVENTDATA*)consdata->quadvarterms[quadvarpos].eventdata, consdata->quadvarterms[quadvarpos].eventdata->filterpos) );
539 
540  SCIPfreeBlockMemory(scip, &consdata->quadvarterms[quadvarpos].eventdata);
541 
542  return SCIP_OKAY;
543 }
544 
545 /** catch variable events */
546 static
548  SCIP* scip, /**< SCIP data structure */
549  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
550  SCIP_CONS* cons /**< constraint for which to catch bound change events */
551  )
552 {
553  SCIP_CONSDATA* consdata;
554  SCIP_VAR* var;
555  int i;
556 
557  assert(scip != NULL);
558  assert(cons != NULL);
559  assert(eventhdlr != NULL);
560 
561  consdata = SCIPconsGetData(cons);
562  assert(consdata != NULL);
563  assert(consdata->lineventdata == NULL);
564 
565  /* we will update isremovedfixings, so reset it to TRUE first */
566  consdata->isremovedfixings = TRUE;
567 
568  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
569  for( i = 0; i < consdata->nlinvars; ++i )
570  {
571  SCIP_CALL( catchLinearVarEvents(scip, eventhdlr, cons, i) );
572 
573  var = consdata->linvars[i];
574  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
575  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
576  }
577 
578  for( i = 0; i < consdata->nquadvars; ++i )
579  {
580  assert(consdata->quadvarterms[i].eventdata == NULL);
581 
582  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, i) );
583 
584  var = consdata->quadvarterms[i].var;
585  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
586  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
587  }
588 
589  consdata->ispropagated = FALSE;
590 
591  return SCIP_OKAY;
592 }
593 
594 /** drop variable events */
595 static
597  SCIP* scip, /**< SCIP data structure */
598  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
599  SCIP_CONS* cons /**< constraint for which to drop bound change events */
600  )
601 {
602  SCIP_CONSDATA* consdata;
603  int i;
604 
605  assert(scip != NULL);
606  assert(eventhdlr != NULL);
607  assert(cons != NULL);
608 
609  consdata = SCIPconsGetData(cons);
610  assert(consdata != NULL);
611 
612  if( consdata->lineventdata != NULL )
613  {
614  for( i = 0; i < consdata->nlinvars; ++i )
615  {
616  if( consdata->lineventdata[i] != NULL )
617  {
618  SCIP_CALL( dropLinearVarEvents(scip, eventhdlr, cons, i) );
619  }
620  }
621  SCIPfreeBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize);
622  }
623 
624  for( i = 0; i < consdata->nquadvars; ++i )
625  {
626  if( consdata->quadvarterms[i].eventdata != NULL )
627  {
628  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, i) );
629  }
630  }
631 
632  return SCIP_OKAY;
633 }
634 
635 /** locks a linear variable in a constraint */
636 static
638  SCIP* scip, /**< SCIP data structure */
639  SCIP_CONS* cons, /**< constraint where to lock a variable */
640  SCIP_VAR* var, /**< variable to lock */
641  SCIP_Real coef /**< coefficient of variable in constraint */
642  )
643 {
644  SCIP_CONSDATA* consdata;
645 
646  assert(scip != NULL);
647  assert(cons != NULL);
648  assert(var != NULL);
649  assert(coef != 0.0);
650 
651  consdata = SCIPconsGetData(cons);
652  assert(consdata != NULL);
653 
654  if( coef > 0.0 )
655  {
656  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
657  }
658  else
659  {
660  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
661  }
662 
663  return SCIP_OKAY;
664 }
665 
666 /** unlocks a linear variable in a constraint */
667 static
669  SCIP* scip, /**< SCIP data structure */
670  SCIP_CONS* cons, /**< constraint where to unlock a variable */
671  SCIP_VAR* var, /**< variable to unlock */
672  SCIP_Real coef /**< coefficient of variable in constraint */
673  )
674 {
675  SCIP_CONSDATA* consdata;
676 
677  assert(scip != NULL);
678  assert(cons != NULL);
679  assert(var != NULL);
680  assert(coef != 0.0);
681 
682  consdata = SCIPconsGetData(cons);
683  assert(consdata != NULL);
684 
685  if( coef > 0.0 )
686  {
687  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
688  }
689  else
690  {
691  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
692  }
693 
694  return SCIP_OKAY;
695 }
696 
697 /** locks a quadratic variable in a constraint */
698 static
700  SCIP* scip, /**< SCIP data structure */
701  SCIP_CONS* cons, /**< constraint where to lock a variable */
702  SCIP_VAR* var /**< variable to lock */
703  )
704 {
705  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
706 
707  return SCIP_OKAY;
708 }
709 
710 /** unlocks a quadratic variable in a constraint */
711 static
713  SCIP* scip, /**< SCIP data structure */
714  SCIP_CONS* cons, /**< constraint where to unlock a variable */
715  SCIP_VAR* var /**< variable to unlock */
716  )
717 {
718  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
719 
720  return SCIP_OKAY;
721 }
722 
723 /** computes the minimal and maximal activity for the linear part in a constraint data
724  *
725  * Only sums up terms that contribute finite values.
726  * Gives the number of terms that contribute infinite values.
727  * Only computes those activities where the corresponding side of the constraint is finite.
728  */
729 static
731  SCIP* scip, /**< SCIP data structure */
732  SCIP_CONSDATA* consdata, /**< constraint data */
733  SCIP_Real intervalinfty /**< infinity value used in interval operations */
734  )
735 { /*lint --e{666}*/
736  SCIP_ROUNDMODE prevroundmode;
737  int i;
738  SCIP_Real bnd;
739 
740  assert(scip != NULL);
741  assert(consdata != NULL);
742 
743  /* if variable bounds are not strictly consistent, then the activity update methods may yield inconsistent activities
744  * in this case, we also recompute the activities
745  */
746  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID && /*lint !e777 */
747  (consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity) )
748  {
749  /* activities should be up-to-date */
750  assert(consdata->minlinactivityinf >= 0);
751  assert(consdata->maxlinactivityinf >= 0);
752  return;
753  }
754 
755  consdata->minlinactivityinf = 0;
756  consdata->maxlinactivityinf = 0;
757 
758  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
759  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
760  */
761  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
762  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
763 
764  if( consdata->nlinvars == 0 )
765  return;
766 
767  /* if the activities computed here should be still up-to-date after bound changes,
768  * variable events need to be caught */
769  assert(consdata->lineventdata != NULL);
770 
771  prevroundmode = SCIPintervalGetRoundingMode();
772 
773  if( !SCIPisInfinity(scip, consdata->rhs) )
774  {
775  /* compute minimal activity only if there is a finite right hand side */
777 
778  for( i = 0; i < consdata->nlinvars; ++i )
779  {
780  assert(consdata->lineventdata[i] != NULL);
781  if( consdata->lincoefs[i] >= 0.0 )
782  {
783  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
784  if( SCIPisInfinity(scip, -bnd) )
785  {
786  ++consdata->minlinactivityinf;
787  continue;
788  }
789  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
790  }
791  else
792  {
793  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
794  if( SCIPisInfinity(scip, bnd) )
795  {
796  ++consdata->minlinactivityinf;
797  continue;
798  }
799  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
800  }
801  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
802  }
803  }
804 
805  if( !SCIPisInfinity(scip, -consdata->lhs) )
806  {
807  /* compute maximal activity only if there is a finite left hand side */
809 
810  for( i = 0; i < consdata->nlinvars; ++i )
811  {
812  assert(consdata->lineventdata[i] != NULL);
813  if( consdata->lincoefs[i] >= 0.0 )
814  {
815  bnd = MAX(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
816  if( SCIPisInfinity(scip, bnd) )
817  {
818  ++consdata->maxlinactivityinf;
819  continue;
820  }
821  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
822  }
823  else
824  {
825  bnd = MIN(SCIPvarGetLbLocal(consdata->linvars[i]), SCIPvarGetUbLocal(consdata->linvars[i]));
826  if( SCIPisInfinity(scip, -bnd) )
827  {
828  ++consdata->maxlinactivityinf;
829  continue;
830  }
831  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
832  }
833  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
834  }
835  }
836 
837  SCIPintervalSetRoundingMode(prevroundmode);
838 
839  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
840 }
841 
842 /** update the linear activities after a change in the lower bound of a variable */
843 static
845  SCIP* scip, /**< SCIP data structure */
846  SCIP_CONSDATA* consdata, /**< constraint data */
847  SCIP_Real coef, /**< coefficient of variable in constraint */
848  SCIP_Real oldbnd, /**< previous lower bound of variable */
849  SCIP_Real newbnd /**< new lower bound of variable */
850  )
851 {
852  SCIP_ROUNDMODE prevroundmode;
853 
854  assert(scip != NULL);
855  assert(consdata != NULL);
856  /* we can't deal with lower bounds at infinity */
857  assert(!SCIPisInfinity(scip, oldbnd));
858  assert(!SCIPisInfinity(scip, newbnd));
859 
860  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
861 
862  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
863  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
864  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
865  */
866 
867  if( coef > 0.0 )
868  {
869  /* we should only be called if rhs is finite */
870  assert(!SCIPisInfinity(scip, consdata->rhs));
871 
872  /* we have no min activities computed so far, so cannot update */
873  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
874  return;
875 
876  prevroundmode = SCIPintervalGetRoundingMode();
878 
879  /* update min activity */
880  if( SCIPisInfinity(scip, -oldbnd) )
881  {
882  --consdata->minlinactivityinf;
883  assert(consdata->minlinactivityinf >= 0);
884  }
885  else
886  {
887  SCIP_Real minuscoef;
888  minuscoef = -coef;
889  consdata->minlinactivity += minuscoef * oldbnd;
890  }
891 
892  if( SCIPisInfinity(scip, -newbnd) )
893  {
894  ++consdata->minlinactivityinf;
895  }
896  else
897  {
898  consdata->minlinactivity += coef * newbnd;
899  }
900 
901  SCIPintervalSetRoundingMode(prevroundmode);
902  }
903  else
904  {
905  /* we should only be called if lhs is finite */
906  assert(!SCIPisInfinity(scip, -consdata->lhs));
907 
908  /* we have no max activities computed so far, so cannot update */
909  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
910  return;
911 
912  prevroundmode = SCIPintervalGetRoundingMode();
914 
915  /* update max activity */
916  if( SCIPisInfinity(scip, -oldbnd) )
917  {
918  --consdata->maxlinactivityinf;
919  assert(consdata->maxlinactivityinf >= 0);
920  }
921  else
922  {
923  SCIP_Real minuscoef;
924  minuscoef = -coef;
925  consdata->maxlinactivity += minuscoef * oldbnd;
926  }
927 
928  if( SCIPisInfinity(scip, -newbnd) )
929  {
930  ++consdata->maxlinactivityinf;
931  }
932  else
933  {
934  consdata->maxlinactivity += coef * newbnd;
935  }
936 
937  SCIPintervalSetRoundingMode(prevroundmode);
938  }
939 }
940 
941 /** update the linear activities after a change in the upper bound of a variable */
942 static
944  SCIP* scip, /**< SCIP data structure */
945  SCIP_CONSDATA* consdata, /**< constraint data */
946  SCIP_Real coef, /**< coefficient of variable in constraint */
947  SCIP_Real oldbnd, /**< previous lower bound of variable */
948  SCIP_Real newbnd /**< new lower bound of variable */
949  )
950 {
951  SCIP_ROUNDMODE prevroundmode;
952 
953  assert(scip != NULL);
954  assert(consdata != NULL);
955  /* we can't deal with upper bounds at -infinity */
956  assert(!SCIPisInfinity(scip, -oldbnd));
957  assert(!SCIPisInfinity(scip, -newbnd));
958 
959  /* @todo since we check the linear activity for consistency later anyway, we may skip changing the rounding mode here */
960 
961  /* assume lhs <= a*x + y <= rhs, then the following bound changes can be deduced:
962  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
963  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
964  */
965 
966  if( coef > 0.0 )
967  {
968  /* we should only be called if lhs is finite */
969  assert(!SCIPisInfinity(scip, -consdata->lhs));
970 
971  /* we have no max activities computed so far, so cannot update */
972  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777 */
973  return;
974 
975  prevroundmode = SCIPintervalGetRoundingMode();
977 
978  /* update max activity */
979  if( SCIPisInfinity(scip, oldbnd) )
980  {
981  --consdata->maxlinactivityinf;
982  assert(consdata->maxlinactivityinf >= 0);
983  }
984  else
985  {
986  SCIP_Real minuscoef;
987  minuscoef = -coef;
988  consdata->maxlinactivity += minuscoef * oldbnd;
989  }
990 
991  if( SCIPisInfinity(scip, newbnd) )
992  {
993  ++consdata->maxlinactivityinf;
994  }
995  else
996  {
997  consdata->maxlinactivity += coef * newbnd;
998  }
999 
1000  SCIPintervalSetRoundingMode(prevroundmode);
1001  }
1002  else
1003  {
1004  /* we should only be called if rhs is finite */
1005  assert(!SCIPisInfinity(scip, consdata->rhs));
1006 
1007  /* we have no min activities computed so far, so cannot update */
1008  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777 */
1009  return;
1010 
1011  prevroundmode = SCIPintervalGetRoundingMode();
1013 
1014  /* update min activity */
1015  if( SCIPisInfinity(scip, oldbnd) )
1016  {
1017  --consdata->minlinactivityinf;
1018  assert(consdata->minlinactivityinf >= 0);
1019  }
1020  else
1021  {
1022  SCIP_Real minuscoef;
1023  minuscoef = -coef;
1024  consdata->minlinactivity += minuscoef * oldbnd;
1025  }
1026 
1027  if( SCIPisInfinity(scip, newbnd) )
1028  {
1029  ++consdata->minlinactivityinf;
1030  }
1031  else
1032  {
1033  consdata->minlinactivity += coef * newbnd;
1034  }
1035 
1036  SCIPintervalSetRoundingMode(prevroundmode);
1037  }
1038 }
1039 
1040 /** returns whether a quadratic variable domain can be reduced to its lower or upper bound; this is the case if the
1041  * quadratic variable is in just one single quadratic constraint and (sqrcoef > 0 and LHS = -infinity), or
1042  * (sqrcoef < 0 and RHS = +infinity) hold
1043  */
1044 static
1046  SCIP* scip, /**< SCIP data structure */
1047  SCIP_CONSDATA* consdata, /**< constraint data */
1048  int idx /**< index of quadratic variable */
1049  )
1050 {
1051  SCIP_VAR* var;
1052  SCIP_Real quadcoef;
1053  SCIP_Bool haslhs;
1054  SCIP_Bool hasrhs;
1055 
1056  assert(scip != NULL);
1057  assert(consdata != NULL);
1058  assert(idx >= 0 && idx < consdata->nquadvars);
1059 
1060  var = consdata->quadvarterms[idx].var;
1061  assert(var != NULL);
1062 
1063  quadcoef = consdata->quadvarterms[idx].sqrcoef;
1064  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
1065  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
1066 
1069  && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY && ((quadcoef < 0.0 && !haslhs) || (quadcoef > 0.0 && !hasrhs));
1070 }
1071 
1072 /** processes variable fixing or bound change event */
1073 static
1074 SCIP_DECL_EVENTEXEC(processVarEvent)
1076  SCIP_CONS* cons;
1077  SCIP_CONSDATA* consdata;
1078  SCIP_EVENTTYPE eventtype;
1079  int varidx;
1080 
1081  assert(scip != NULL);
1082  assert(event != NULL);
1083  assert(eventdata != NULL);
1084  assert(eventhdlr != NULL);
1085 
1086  cons = ((SCIP_QUADVAREVENTDATA*)eventdata)->cons;
1087  assert(cons != NULL);
1088  consdata = SCIPconsGetData(cons);
1089  assert(consdata != NULL);
1090 
1091  varidx = ((SCIP_QUADVAREVENTDATA*)eventdata)->varidx;
1092  assert(varidx < 0 || varidx < consdata->nlinvars);
1093  assert(varidx >= 0 || -varidx-1 < consdata->nquadvars);
1094 
1095  eventtype = SCIPeventGetType(event);
1096 
1097  /* process local bound changes */
1098  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1099  {
1100  if( varidx < 0 )
1101  {
1102  /* mark activity bounds for quad term as not up to date anymore */
1103  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
1104  }
1105  else
1106  {
1107  /* update activity bounds for linear terms */
1108  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
1109  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1110  else
1111  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
1112  }
1113 
1114  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1115  {
1116  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
1117  consdata->ispropagated = FALSE;
1118  }
1119  }
1120 
1121  /* process global bound changes */
1122  if( eventtype & SCIP_EVENTTYPE_GBDCHANGED )
1123  {
1124  SCIP_VAR* var;
1125 
1126  var = varidx < 0 ? consdata->quadvarterms[-varidx-1].var : consdata->linvars[varidx];
1127  assert(var != NULL);
1128 
1129  if( varidx < 0 )
1130  {
1131  SCIP_QUADVARTERM* quadvarterm;
1132 
1133  quadvarterm = &consdata->quadvarterms[-varidx-1];
1134 
1135  /* 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()
1136  * we currently do this only if the binary variable does not show up in any bilinear terms
1137  */
1139  quadvarterm->sqrcoef != 0.0 && quadvarterm->nadjbilin == 0 )
1140  {
1141  consdata->quadvarsmerged = FALSE;
1142  consdata->initialmerge = FALSE;
1143  }
1144  }
1145 
1146  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
1147  consdata->isremovedfixings = FALSE;
1148  }
1149 
1150  /* process variable fixing event */
1151  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1152  {
1153  consdata->isremovedfixings = FALSE;
1154  }
1155 
1156 #ifdef CHECKIMPLINBILINEAR
1157  if( eventtype & SCIP_EVENTTYPE_IMPLADDED )
1158  {
1159  assert(varidx < 0); /* we catch impladded events only for quadratic variables */
1160  /* 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 */
1161  if( SCIPvarIsBinary(SCIPeventGetVar(event)) && consdata->quadvarterms[-varidx-1].nadjbilin > 0 )
1162  consdata->isimpladded = TRUE;
1163  }
1164 #endif
1165 
1166  return SCIP_OKAY;
1167 }
1168 
1169 /** ensures, that linear vars and coefs arrays can store at least num entries */
1170 static
1172  SCIP* scip, /**< SCIP data structure */
1173  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1174  int num /**< minimum number of entries to store */
1175  )
1176 {
1177  assert(scip != NULL);
1178  assert(consdata != NULL);
1179  assert(consdata->nlinvars <= consdata->linvarssize);
1180 
1181  if( num > consdata->linvarssize )
1182  {
1183  int newsize;
1184 
1185  newsize = SCIPcalcMemGrowSize(scip, num);
1186  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1187  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1188  if( consdata->lineventdata != NULL )
1189  {
1190  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1191  }
1192  consdata->linvarssize = newsize;
1193  }
1194  assert(num <= consdata->linvarssize);
1195 
1196  return SCIP_OKAY;
1197 }
1198 
1199 /** ensures, that quadratic variable terms array can store at least num entries */
1200 static
1202  SCIP* scip, /**< SCIP data structure */
1203  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1204  int num /**< minimum number of entries to store */
1205  )
1206 {
1207  assert(scip != NULL);
1208  assert(consdata != NULL);
1209  assert(consdata->nquadvars <= consdata->quadvarssize);
1210 
1211  if( num > consdata->quadvarssize )
1212  {
1213  int newsize;
1214 
1215  newsize = SCIPcalcMemGrowSize(scip, num);
1216  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->quadvarterms, consdata->quadvarssize, newsize) );
1217  consdata->quadvarssize = newsize;
1218  }
1219  assert(num <= consdata->quadvarssize);
1220 
1221  return SCIP_OKAY;
1222 }
1223 
1224 /** ensures, that adjacency array can store at least num entries */
1225 static
1227  SCIP* scip, /**< SCIP data structure */
1228  SCIP_QUADVARTERM* quadvarterm, /**< quadratic variable term */
1229  int num /**< minimum number of entries to store */
1230  )
1231 {
1232  assert(scip != NULL);
1233  assert(quadvarterm != NULL);
1234  assert(quadvarterm->nadjbilin <= quadvarterm->adjbilinsize);
1235 
1236  if( num > quadvarterm->adjbilinsize )
1237  {
1238  int newsize;
1239 
1240  newsize = SCIPcalcMemGrowSize(scip, num);
1241  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &quadvarterm->adjbilin, quadvarterm->adjbilinsize, newsize) );
1242  quadvarterm->adjbilinsize = newsize;
1243  }
1244  assert(num <= quadvarterm->adjbilinsize);
1245 
1246  return SCIP_OKAY;
1247 }
1248 
1249 /** ensures, that bilinear term arrays can store at least num entries */
1250 static
1252  SCIP* scip, /**< SCIP data structure */
1253  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1254  int num /**< minimum number of entries to store */
1255  )
1256 {
1257  assert(scip != NULL);
1258  assert(consdata != NULL);
1259  assert(consdata->nbilinterms <= consdata->bilintermssize);
1260 
1261  if( num > consdata->bilintermssize )
1262  {
1263  int newsize;
1264 
1265  newsize = SCIPcalcMemGrowSize(scip, num);
1266  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize, newsize) );
1267  consdata->bilintermssize = newsize;
1268  }
1269  assert(num <= consdata->bilintermssize);
1270 
1271  return SCIP_OKAY;
1272 }
1273 
1274 /** creates empty constraint data structure */
1275 static
1277  SCIP* scip, /**< SCIP data structure */
1278  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1279  )
1280 {
1281  assert(scip != NULL);
1282  assert(consdata != NULL);
1283 
1284  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1285  BMSclearMemory(*consdata);
1286 
1287  (*consdata)->lhs = -SCIPinfinity(scip);
1288  (*consdata)->rhs = SCIPinfinity(scip);
1289 
1290  (*consdata)->linvarssorted = TRUE;
1291  (*consdata)->linvarsmerged = TRUE;
1292  (*consdata)->quadvarssorted = TRUE;
1293  (*consdata)->quadvarsmerged = TRUE;
1294  (*consdata)->bilinsorted = TRUE;
1295  (*consdata)->bilinmerged = TRUE;
1296 
1297  (*consdata)->isremovedfixings = TRUE;
1298  (*consdata)->ispropagated = TRUE;
1299  (*consdata)->initialmerge = FALSE;
1300 
1301  (*consdata)->linvar_maydecrease = -1;
1302  (*consdata)->linvar_mayincrease = -1;
1303 
1304  (*consdata)->minlinactivity = SCIP_INVALID;
1305  (*consdata)->maxlinactivity = SCIP_INVALID;
1306  (*consdata)->minlinactivityinf = -1;
1307  (*consdata)->maxlinactivityinf = -1;
1308 
1309  (*consdata)->isgaugeavailable = FALSE;
1310  (*consdata)->isedavailable = FALSE;
1311 
1312  return SCIP_OKAY;
1313 }
1314 
1315 /** creates constraint data structure */
1316 static
1318  SCIP* scip, /**< SCIP data structure */
1319  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1320  SCIP_Real lhs, /**< left hand side of constraint */
1321  SCIP_Real rhs, /**< right hand side of constraint */
1322  int nlinvars, /**< number of linear variables */
1323  SCIP_VAR** linvars, /**< array of linear variables */
1324  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1325  int nquadvars, /**< number of quadratic variables */
1326  SCIP_QUADVARTERM* quadvarterms, /**< array of quadratic variable terms */
1327  int nbilinterms, /**< number of bilinear terms */
1328  SCIP_BILINTERM* bilinterms, /**< array of bilinear terms */
1329  SCIP_Bool capturevars /**< whether we should capture variables */
1330  )
1331 {
1332  int i;
1333 
1334  assert(scip != NULL);
1335  assert(consdata != NULL);
1336 
1337  assert(nlinvars == 0 || linvars != NULL);
1338  assert(nlinvars == 0 || lincoefs != NULL);
1339  assert(nquadvars == 0 || quadvarterms != NULL);
1340  assert(nbilinterms == 0 || bilinterms != NULL);
1341 
1342  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1343  BMSclearMemory(*consdata);
1344 
1345  (*consdata)->minlinactivity = SCIP_INVALID;
1346  (*consdata)->maxlinactivity = SCIP_INVALID;
1347  (*consdata)->minlinactivityinf = -1;
1348  (*consdata)->maxlinactivityinf = -1;
1349 
1350  (*consdata)->lhs = lhs;
1351  (*consdata)->rhs = rhs;
1352 
1353  if( nlinvars > 0 )
1354  {
1355  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1356  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1357  (*consdata)->nlinvars = nlinvars;
1358  (*consdata)->linvarssize = nlinvars;
1359 
1360  if( capturevars )
1361  for( i = 0; i < nlinvars; ++i )
1362  {
1363  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1364  }
1365  }
1366  else
1367  {
1368  (*consdata)->linvarssorted = TRUE;
1369  (*consdata)->linvarsmerged = TRUE;
1370  (*consdata)->minlinactivity = 0.0;
1371  (*consdata)->maxlinactivity = 0.0;
1372  (*consdata)->minlinactivityinf = 0;
1373  (*consdata)->maxlinactivityinf = 0;
1374  }
1375 
1376  if( nquadvars > 0 )
1377  {
1378  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms, quadvarterms, nquadvars) );
1379 
1380  for( i = 0; i < nquadvars; ++i )
1381  {
1382  (*consdata)->quadvarterms[i].eventdata = NULL;
1383  if( quadvarterms[i].nadjbilin )
1384  {
1385  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->quadvarterms[i].adjbilin, quadvarterms[i].adjbilin, quadvarterms[i].nadjbilin) );
1386  (*consdata)->quadvarterms[i].adjbilinsize = quadvarterms[i].nadjbilin;
1387  }
1388  else
1389  {
1390  assert((*consdata)->quadvarterms[i].nadjbilin == 0);
1391  (*consdata)->quadvarterms[i].adjbilin = NULL;
1392  (*consdata)->quadvarterms[i].adjbilinsize = 0;
1393  }
1394  if( capturevars )
1395  {
1396  SCIP_CALL( SCIPcaptureVar(scip, quadvarterms[i].var) );
1397  }
1398  }
1399 
1400  (*consdata)->nquadvars = nquadvars;
1401  (*consdata)->quadvarssize = nquadvars;
1402  SCIPintervalSetEmpty(&(*consdata)->quadactivitybounds);
1403  }
1404  else
1405  {
1406  (*consdata)->quadvarssorted = TRUE;
1407  (*consdata)->quadvarsmerged = TRUE;
1408  SCIPintervalSet(&(*consdata)->quadactivitybounds, 0.0);
1409  }
1410 
1411  if( nbilinterms > 0 )
1412  {
1413  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->bilinterms, bilinterms, nbilinterms) );
1414  (*consdata)->nbilinterms = nbilinterms;
1415  (*consdata)->bilintermssize = nbilinterms;
1416  }
1417  else
1418  {
1419  (*consdata)->bilinsorted = TRUE;
1420  (*consdata)->bilinmerged = TRUE;
1421  }
1422 
1423  (*consdata)->linvar_maydecrease = -1;
1424  (*consdata)->linvar_mayincrease = -1;
1425 
1426  (*consdata)->activity = SCIP_INVALID;
1427  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1428  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1429 
1430  (*consdata)->isgaugeavailable = FALSE;
1431 
1432  return SCIP_OKAY;
1433 }
1434 
1435 /** frees constraint data structure */
1436 static
1438  SCIP* scip, /**< SCIP data structure */
1439  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1440  )
1441 {
1442  int i;
1443 
1444  assert(scip != NULL);
1445  assert(consdata != NULL);
1446  assert(*consdata != NULL);
1447 
1448  /* free sepa arrays, may exists if constraint is deleted in solving stage */
1449  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepaquadvars, (*consdata)->nquadvars);
1450  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->sepabilinvar2pos, (*consdata)->nbilinterms);
1451 
1452  /* release linear variables and free linear part */
1453  if( (*consdata)->linvarssize > 0 )
1454  {
1455  for( i = 0; i < (*consdata)->nlinvars; ++i )
1456  {
1457  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1458  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1459  }
1460  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1461  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1462  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1463  }
1464  assert((*consdata)->linvars == NULL);
1465  assert((*consdata)->lincoefs == NULL);
1466  assert((*consdata)->lineventdata == NULL);
1467 
1468  /* release quadratic variables and free quadratic variable term part */
1469  for( i = 0; i < (*consdata)->nquadvars; ++i )
1470  {
1471  assert((*consdata)->quadvarterms[i].eventdata == NULL); /* variable events should have been dropped earlier */
1472  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms[i].adjbilin, (*consdata)->quadvarterms[i].adjbilinsize);
1473  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->quadvarterms[i].var) );
1474  }
1475  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->quadvarterms, (*consdata)->quadvarssize);
1476 
1477  /* free bilinear terms */
1478  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilinterms, (*consdata)->bilintermssize);
1479 
1480  /* free nonlinear row representation */
1481  if( (*consdata)->nlrow != NULL )
1482  {
1483  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1484  }
1485 
1486  /* free interior point information, may exists if constraint is deleted in solving stage */
1487  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->interiorpoint, (*consdata)->nquadvars);
1488  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->gaugecoefs, (*consdata)->nquadvars);
1489 
1490  /* free eigen decomposition information */
1491  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvalues, (*consdata)->nquadvars);
1492  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->eigenvectors, (int)((*consdata)->nquadvars*(*consdata)->nquadvars));
1493  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bp, (*consdata)->nquadvars);
1494 
1495  /* free unique indices of bilinear terms array */
1496  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->bilintermsidx, (*consdata)->nbilinterms);
1497 
1498  SCIPfreeBlockMemory(scip, consdata);
1499  *consdata = NULL;
1500 
1501  return SCIP_OKAY;
1502 }
1503 
1504 /** sorts linear part of constraint data */
1505 static
1507  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1508  )
1509 {
1510  assert(consdata != NULL);
1511 
1512  if( consdata->linvarssorted )
1513  return;
1514 
1515  if( consdata->nlinvars <= 1 )
1516  {
1517  consdata->linvarssorted = TRUE;
1518  return;
1519  }
1520 
1521  if( consdata->lineventdata == NULL )
1522  {
1523  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1524  }
1525  else
1526  {
1527  int i;
1528 
1529  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1530 
1531  /* update variable indices in event data */
1532  for( i = 0; i < consdata->nlinvars; ++i )
1533  if( consdata->lineventdata[i] != NULL )
1534  consdata->lineventdata[i]->varidx = i;
1535  }
1536 
1537  consdata->linvarssorted = TRUE;
1538 }
1539 
1540 #ifdef SCIP_DISABLED_CODE /* no-one needs this routine currently */
1541 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1542 static
1543 int consdataFindLinearVar(
1544  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1545  SCIP_VAR* var /**< variable to search for */
1546  )
1547 {
1548  int pos;
1549 
1550  assert(consdata != NULL);
1551  assert(var != NULL);
1552 
1553  if( consdata->nlinvars == 0 )
1554  return -1;
1555 
1556  consdataSortLinearVars(consdata);
1557 
1558  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1559  pos = -1;
1560 
1561  return pos;
1562 }
1563 #endif
1564 
1565 /** index comparison method for quadratic variable terms: compares two indices of the quadratic variable set in the quadratic constraint */
1566 static
1567 SCIP_DECL_SORTINDCOMP(quadVarTermComp)
1568 { /*lint --e{715}*/
1569  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1570 
1571  assert(consdata != NULL);
1572  assert(0 <= ind1 && ind1 < consdata->nquadvars);
1573  assert(0 <= ind2 && ind2 < consdata->nquadvars);
1574 
1575  return SCIPvarCompare(consdata->quadvarterms[ind1].var, consdata->quadvarterms[ind2].var);
1576 }
1577 
1578 /** sorting of quadratic variable terms */
1579 static
1581  SCIP* scip, /**< SCIP data structure */
1582  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1583  )
1584 {
1585  int* perm;
1586  int i;
1587  int nexti;
1588  int v;
1589  SCIP_QUADVARTERM quadterm;
1590 
1591  assert(scip != NULL);
1592  assert(consdata != NULL);
1593 
1594  if( consdata->quadvarssorted )
1595  return SCIP_OKAY;
1596 
1597  if( consdata->nquadvars == 0 )
1598  {
1599  consdata->quadvarssorted = TRUE;
1600  return SCIP_OKAY;
1601  }
1602 
1603  /* get temporary memory to store the sorted permutation */
1604  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nquadvars) );
1605 
1606  /* call bubble sort */
1607  SCIPsort(perm, quadVarTermComp, (void*)consdata, consdata->nquadvars);
1608 
1609  /* permute the quadratic variable terms according to the resulting permutation */
1610  for( v = 0; v < consdata->nquadvars; ++v )
1611  {
1612  if( perm[v] != v )
1613  {
1614  quadterm = consdata->quadvarterms[v];
1615 
1616  i = v;
1617  do
1618  {
1619  assert(0 <= perm[i] && perm[i] < consdata->nquadvars);
1620  assert(perm[i] != i);
1621  consdata->quadvarterms[i] = consdata->quadvarterms[perm[i]];
1622  if( consdata->quadvarterms[i].eventdata != NULL )
1623  {
1624  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1625  }
1626  nexti = perm[i];
1627  perm[i] = i;
1628  i = nexti;
1629  }
1630  while( perm[i] != v );
1631  consdata->quadvarterms[i] = quadterm;
1632  if( consdata->quadvarterms[i].eventdata != NULL )
1633  {
1634  consdata->quadvarterms[i].eventdata->varidx = -i-1;
1635  }
1636  perm[i] = i;
1637  }
1638  }
1639  consdata->quadvarssorted = TRUE;
1640 
1641  /* free temporary memory */
1642  SCIPfreeBufferArray(scip, &perm);
1643 
1644  return SCIP_OKAY;
1645 }
1646 
1647 /** returns the position of variable in the quadratic variable terms array of a constraint, or -1 if not found */
1648 static
1650  SCIP* scip, /**< SCIP data structure */
1651  SCIP_CONSDATA* consdata, /**< quadratic constraint data */
1652  SCIP_VAR* var, /**< variable to search for */
1653  int* pos /**< buffer where to store position of var in quadvarterms array, or -1 if not found */
1654  )
1655 {
1656  int left;
1657  int right;
1658  int cmpres;
1659 
1660  assert(consdata != NULL);
1661  assert(var != NULL);
1662  assert(pos != NULL);
1663 
1664  if( consdata->nquadvars == 0 )
1665  {
1666  *pos = -1;
1667  return SCIP_OKAY;
1668  }
1669 
1670  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
1671 
1672  left = 0;
1673  right = consdata->nquadvars - 1;
1674  while( left <= right )
1675  {
1676  int middle;
1677 
1678  middle = (left+right)/2;
1679  assert(0 <= middle && middle < consdata->nquadvars);
1680 
1681  cmpres = SCIPvarCompare(var, consdata->quadvarterms[middle].var);
1682 
1683  if( cmpres < 0 )
1684  right = middle - 1;
1685  else if( cmpres > 0 )
1686  left = middle + 1;
1687  else
1688  {
1689  *pos = middle;
1690  return SCIP_OKAY;
1691  }
1692  }
1693  assert(left == right+1);
1694 
1695  *pos = -1;
1696 
1697  return SCIP_OKAY;
1698 }
1699 
1700 /** index comparison method for bilinear terms: compares two index pairs of the bilinear term set in the quadratic constraint */
1701 static
1702 SCIP_DECL_SORTINDCOMP(bilinTermComp)
1703 { /*lint --e{715}*/
1704  SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
1705  int var1cmp;
1706 
1707  assert(consdata != NULL);
1708  assert(0 <= ind1 && ind1 < consdata->nbilinterms);
1709  assert(0 <= ind2 && ind2 < consdata->nbilinterms);
1710 
1711  var1cmp = SCIPvarCompare(consdata->bilinterms[ind1].var1, consdata->bilinterms[ind2].var1);
1712  if( var1cmp != 0 )
1713  return var1cmp;
1714 
1715  return SCIPvarCompare(consdata->bilinterms[ind1].var2, consdata->bilinterms[ind2].var2);
1716 }
1717 
1718 #ifndef NDEBUG
1719 /** checks if all bilinear terms are sorted correctly */
1720 static
1722  SCIP_CONSDATA* consdata
1723  )
1724 {
1725  int i;
1726 
1727  assert(consdata != NULL);
1728 
1729  /* nothing to check if the bilinear terms have not been sorted yet */
1730  if( !consdata->bilinsorted )
1731  return TRUE;
1732 
1733  for( i = 0; i < consdata->nbilinterms - 1; ++i )
1734  {
1735  if( bilinTermComp(consdata, i, i+1) > 0 )
1736  return FALSE;
1737  }
1738  return TRUE;
1739 }
1740 #endif
1741 
1742 /** sorting of bilinear terms */
1743 static
1745  SCIP* scip, /**< SCIP data structure */
1746  SCIP_CONSDATA* consdata /**< quadratic constraint data */
1747  )
1748 {
1749  int* perm;
1750  int* invperm;
1751  int i;
1752  int nexti;
1753  int v;
1754  SCIP_BILINTERM bilinterm;
1755 
1756  assert(scip != NULL);
1757  assert(consdata != NULL);
1758 
1759  if( consdata->bilinsorted )
1760  return SCIP_OKAY;
1761 
1762  if( consdata->nbilinterms == 0 )
1763  {
1764  consdata->bilinsorted = TRUE;
1765  return SCIP_OKAY;
1766  }
1767 
1768  /* get temporary memory to store the sorted permutation and the inverse permutation */
1769  SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nbilinterms) );
1770  SCIP_CALL( SCIPallocBufferArray(scip, &invperm, consdata->nbilinterms) );
1771 
1772  /* call bubble sort */
1773  SCIPsort(perm, bilinTermComp, (void*)consdata, consdata->nbilinterms);
1774 
1775  /* compute inverted permutation */
1776  for( v = 0; v < consdata->nbilinterms; ++v )
1777  {
1778  assert(0 <= perm[v] && perm[v] < consdata->nbilinterms);
1779  invperm[perm[v]] = v;
1780  }
1781 
1782  /* permute the bilinear terms according to the resulting permutation */
1783  for( v = 0; v < consdata->nbilinterms; ++v )
1784  {
1785  if( perm[v] != v )
1786  {
1787  bilinterm = consdata->bilinterms[v];
1788 
1789  i = v;
1790  do
1791  {
1792  assert(0 <= perm[i] && perm[i] < consdata->nbilinterms);
1793  assert(perm[i] != i);
1794  consdata->bilinterms[i] = consdata->bilinterms[perm[i]];
1795  nexti = perm[i];
1796  perm[i] = i;
1797  i = nexti;
1798  }
1799  while( perm[i] != v );
1800  consdata->bilinterms[i] = bilinterm;
1801  perm[i] = i;
1802  }
1803  }
1804 
1805  /* update the adjacency information in the quadratic variable terms */
1806  for( v = 0; v < consdata->nquadvars; ++v )
1807  for( i = 0; i < consdata->quadvarterms[v].nadjbilin; ++i )
1808  consdata->quadvarterms[v].adjbilin[i] = invperm[consdata->quadvarterms[v].adjbilin[i]];
1809 
1810  consdata->bilinsorted = TRUE;
1811  assert(consdataCheckBilinTermsSort(consdata));
1812 
1813  /* free temporary memory */
1814  SCIPfreeBufferArray(scip, &invperm);
1815  SCIPfreeBufferArray(scip, &perm);
1816 
1817  return SCIP_OKAY;
1818 }
1819 
1820 /** moves a linear variable from one position to another */
1821 static
1823  SCIP_CONSDATA* consdata, /**< constraint data */
1824  int oldpos, /**< position of variable that shall be moved */
1825  int newpos /**< new position of variable */
1826  )
1827 {
1828  assert(consdata != NULL);
1829  assert(oldpos >= 0);
1830  assert(oldpos < consdata->nlinvars);
1831  assert(newpos >= 0);
1832  assert(newpos < consdata->linvarssize);
1833 
1834  if( newpos == oldpos )
1835  return;
1836 
1837  consdata->linvars [newpos] = consdata->linvars [oldpos];
1838  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1839 
1840  if( consdata->lineventdata != NULL )
1841  {
1842  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1843 
1844  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1845  consdata->lineventdata[newpos]->varidx = newpos;
1846 
1847  consdata->lineventdata[oldpos] = NULL;
1848  }
1849 
1850  consdata->linvarssorted = FALSE;
1851 }
1852 
1853 /** moves a quadratic variable from one position to another */
1854 static
1856  SCIP_CONSDATA* consdata, /**< constraint data */
1857  int oldpos, /**< position of variable that shall be moved */
1858  int newpos /**< new position of variable */
1859  )
1860 {
1861  assert(consdata != NULL);
1862  assert(oldpos >= 0);
1863  assert(oldpos < consdata->nquadvars);
1864  assert(newpos >= 0);
1865  assert(newpos < consdata->quadvarssize);
1866 
1867  if( newpos == oldpos )
1868  return;
1869 
1870  assert(newpos >= consdata->nquadvars || consdata->quadvarterms[newpos].eventdata == NULL);
1871 
1872  consdata->quadvarterms[newpos] = consdata->quadvarterms[oldpos];
1873 
1874  if( consdata->quadvarterms[newpos].eventdata != NULL )
1875  {
1876  consdata->quadvarterms[newpos].eventdata->varidx = -newpos-1;
1877  consdata->quadvarterms[oldpos].eventdata = NULL;
1878  }
1879 
1880  consdata->quadvarssorted = FALSE;
1881 }
1882 
1883 /** adds linear coefficient in quadratic constraint */
1884 static
1886  SCIP* scip, /**< SCIP data structure */
1887  SCIP_CONS* cons, /**< quadratic constraint */
1888  SCIP_VAR* var, /**< variable of constraint entry */
1889  SCIP_Real coef /**< coefficient of constraint entry */
1890  )
1891 {
1892  SCIP_CONSDATA* consdata;
1893  SCIP_Bool transformed;
1894 
1895  assert(scip != NULL);
1896  assert(cons != NULL);
1897  assert(var != NULL);
1898 
1899  /* ignore coefficient if it is nearly zero */
1900  if( SCIPisZero(scip, coef) )
1901  return SCIP_OKAY;
1902 
1903  consdata = SCIPconsGetData(cons);
1904  assert(consdata != NULL);
1905 
1906  /* are we in the transformed problem? */
1907  transformed = SCIPconsIsTransformed(cons);
1908 
1909  /* always use transformed variables in transformed constraints */
1910  if( transformed )
1911  {
1912  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1913  }
1914  assert(var != NULL);
1915  assert(transformed == SCIPvarIsTransformed(var));
1916 
1917  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1918  consdata->linvars [consdata->nlinvars] = var;
1919  consdata->lincoefs[consdata->nlinvars] = coef;
1920 
1921  ++consdata->nlinvars;
1922 
1923  /* catch variable events */
1924  if( SCIPconsIsEnabled(cons) )
1925  {
1926  SCIP_CONSHDLR* conshdlr;
1927  SCIP_CONSHDLRDATA* conshdlrdata;
1928 
1929  /* get event handler */
1930  conshdlr = SCIPconsGetHdlr(cons);
1931  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1932  assert(conshdlrdata != NULL);
1933  assert(conshdlrdata->eventhdlr != NULL);
1934 
1935  assert(consdata->lineventdata != NULL);
1936  consdata->lineventdata[consdata->nlinvars-1] = NULL;
1937 
1938  /* catch bound change events of variable */
1939  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nlinvars-1) );
1940  }
1941 
1942  /* invalidate activity information */
1943  consdata->activity = SCIP_INVALID;
1944  consdata->minlinactivity = SCIP_INVALID;
1945  consdata->maxlinactivity = SCIP_INVALID;
1946  consdata->minlinactivityinf = -1;
1947  consdata->maxlinactivityinf = -1;
1948 
1949  /* invalidate nonlinear row */
1950  if( consdata->nlrow != NULL )
1951  {
1952  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1953  }
1954 
1955  /* install rounding locks for new variable */
1956  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1957 
1958  /* capture new variable */
1959  SCIP_CALL( SCIPcaptureVar(scip, var) );
1960 
1961  consdata->ispropagated = FALSE;
1962  consdata->ispresolved = FALSE;
1963  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
1964  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
1965  if( consdata->nlinvars == 1 )
1966  consdata->linvarssorted = TRUE;
1967  else
1968  consdata->linvarssorted = consdata->linvarssorted && (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1969  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1970  consdata->linvarsmerged = FALSE;
1971 
1972  return SCIP_OKAY;
1973 }
1974 
1975 /** deletes linear coefficient at given position from quadratic constraint data */
1976 static
1978  SCIP* scip, /**< SCIP data structure */
1979  SCIP_CONS* cons, /**< quadratic constraint */
1980  int pos /**< position of coefficient to delete */
1981  )
1982 {
1983  SCIP_CONSDATA* consdata;
1984  SCIP_VAR* var;
1985  SCIP_Real coef;
1986 
1987  assert(scip != NULL);
1988  assert(cons != NULL);
1989 
1990  consdata = SCIPconsGetData(cons);
1991  assert(consdata != NULL);
1992  assert(0 <= pos && pos < consdata->nlinvars);
1993 
1994  var = consdata->linvars[pos];
1995  coef = consdata->lincoefs[pos];
1996  assert(var != NULL);
1997 
1998  /* remove rounding locks for deleted variable */
1999  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
2000 
2001  /* if we catch variable events, drop the events on the variable */
2002  if( consdata->lineventdata != NULL )
2003  {
2004  SCIP_CONSHDLR* conshdlr;
2005  SCIP_CONSHDLRDATA* conshdlrdata;
2006 
2007  /* get event handler */
2008  conshdlr = SCIPconsGetHdlr(cons);
2009  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2010  assert(conshdlrdata != NULL);
2011  assert(conshdlrdata->eventhdlr != NULL);
2012 
2013  /* drop bound change events of variable */
2014  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2015  }
2016 
2017  /* release variable */
2018  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
2019 
2020  /* move the last variable to the free slot */
2021  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
2022 
2023  --consdata->nlinvars;
2024 
2025  /* invalidate activity */
2026  consdata->activity = SCIP_INVALID;
2027  consdata->minlinactivity = SCIP_INVALID;
2028  consdata->maxlinactivity = SCIP_INVALID;
2029  consdata->minlinactivityinf = -1;
2030  consdata->maxlinactivityinf = -1;
2031 
2032  /* invalidate nonlinear row */
2033  if( consdata->nlrow != NULL )
2034  {
2035  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2036  }
2037 
2038  consdata->ispropagated = FALSE;
2039  consdata->ispresolved = FALSE;
2040 
2041  return SCIP_OKAY;
2042 }
2043 
2044 /** changes linear coefficient value at given position of quadratic constraint */
2045 static
2047  SCIP* scip, /**< SCIP data structure */
2048  SCIP_CONS* cons, /**< quadratic constraint */
2049  int pos, /**< position of linear coefficient to change */
2050  SCIP_Real newcoef /**< new value of linear coefficient */
2051  )
2052 {
2053  SCIP_CONSHDLR* conshdlr;
2054  SCIP_CONSHDLRDATA* conshdlrdata;
2055  SCIP_CONSDATA* consdata;
2056  SCIP_VAR* var;
2057  SCIP_Real coef;
2058 
2059  assert(scip != NULL);
2060  assert(cons != NULL);
2062  assert(!SCIPisZero(scip, newcoef));
2063 
2064  conshdlrdata = NULL;
2065 
2066  consdata = SCIPconsGetData(cons);
2067  assert(consdata != NULL);
2068  assert(0 <= pos);
2069  assert(pos < consdata->nlinvars);
2070  assert(!SCIPisZero(scip, newcoef));
2071 
2072  var = consdata->linvars[pos];
2073  coef = consdata->lincoefs[pos];
2074  assert(var != NULL);
2075  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
2076 
2077  /* invalidate activity */
2078  consdata->activity = SCIP_INVALID;
2079  consdata->minlinactivity = SCIP_INVALID;
2080  consdata->maxlinactivity = SCIP_INVALID;
2081  consdata->minlinactivityinf = -1;
2082  consdata->maxlinactivityinf = -1;
2083 
2084  /* invalidate nonlinear row */
2085  if( consdata->nlrow != NULL )
2086  {
2087  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2088  }
2089 
2090  /* if necessary, remove the rounding locks and event catching of the variable */
2091  if( newcoef * coef < 0.0 )
2092  {
2093  if( SCIPconsIsLocked(cons) )
2094  {
2095  assert(SCIPconsIsTransformed(cons));
2096 
2097  /* remove rounding locks for variable with old coefficient */
2098  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
2099  }
2100 
2101  if( consdata->lineventdata[pos] != NULL )
2102  {
2103  /* get event handler */
2104  conshdlr = SCIPconsGetHdlr(cons);
2105  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2106  assert(conshdlrdata != NULL);
2107  assert(conshdlrdata->eventhdlr != NULL);
2108 
2109  /* drop bound change events of variable */
2110  SCIP_CALL( dropLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2111  }
2112  }
2113 
2114  /* change the coefficient */
2115  consdata->lincoefs[pos] = newcoef;
2116 
2117  /* if necessary, install the rounding locks and event catching of the variable again */
2118  if( newcoef * coef < 0.0 )
2119  {
2120  if( SCIPconsIsLocked(cons) )
2121  {
2122  /* install rounding locks for variable with new coefficient */
2123  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
2124  }
2125 
2126  if( conshdlrdata != NULL )
2127  {
2128  assert(SCIPconsIsEnabled(cons));
2129 
2130  /* catch bound change events of variable */
2131  SCIP_CALL( catchLinearVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2132  }
2133  }
2134 
2135  consdata->ispropagated = FALSE;
2136  consdata->ispresolved = FALSE;
2137 
2138  return SCIP_OKAY;
2139 }
2140 
2141 /** adds quadratic variable term to quadratic constraint */
2142 static
2144  SCIP* scip, /**< SCIP data structure */
2145  SCIP_CONS* cons, /**< quadratic constraint */
2146  SCIP_VAR* var, /**< variable to add */
2147  SCIP_Real lincoef, /**< linear coefficient of variable */
2148  SCIP_Real sqrcoef /**< square coefficient of variable */
2149  )
2150 {
2151  SCIP_CONSDATA* consdata;
2152  SCIP_Bool transformed;
2153  SCIP_QUADVARTERM* quadvarterm;
2154 
2155  assert(scip != NULL);
2156  assert(cons != NULL);
2157  assert(var != NULL);
2158 
2159  consdata = SCIPconsGetData(cons);
2160  assert(consdata != NULL);
2161 
2162  /* are we in the transformed problem? */
2163  transformed = SCIPconsIsTransformed(cons);
2164 
2165  /* always use transformed variables in transformed constraints */
2166  if( transformed )
2167  {
2168  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
2169  }
2170  assert(var != NULL);
2171  assert(transformed == SCIPvarIsTransformed(var));
2172 
2173  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars+1) );
2174 
2175  quadvarterm = &consdata->quadvarterms[consdata->nquadvars];
2176  quadvarterm->var = var;
2177  quadvarterm->lincoef = lincoef;
2178  quadvarterm->sqrcoef = sqrcoef;
2179  quadvarterm->adjbilinsize = 0;
2180  quadvarterm->nadjbilin = 0;
2181  quadvarterm->adjbilin = NULL;
2182  quadvarterm->eventdata = NULL;
2183 
2184  ++consdata->nquadvars;
2185 
2186  /* capture variable */
2187  SCIP_CALL( SCIPcaptureVar(scip, var) );
2188 
2189  /* catch variable events, if we do so */
2190  if( SCIPconsIsEnabled(cons) )
2191  {
2192  SCIP_CONSHDLR* conshdlr;
2193  SCIP_CONSHDLRDATA* conshdlrdata;
2194 
2195  /* get event handler */
2196  conshdlr = SCIPconsGetHdlr(cons);
2197  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2198  assert(conshdlrdata != NULL);
2199  assert(conshdlrdata->eventhdlr != NULL);
2200 
2201  /* catch bound change events of variable */
2202  SCIP_CALL( catchQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, consdata->nquadvars-1) );
2203  }
2204 
2205  /* invalidate activity information */
2206  consdata->activity = SCIP_INVALID;
2207  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2208 
2209  /* invalidate nonlinear row */
2210  if( consdata->nlrow != NULL )
2211  {
2212  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2213  }
2214 
2215  /* install rounding locks for new variable */
2216  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2217 
2218  consdata->ispropagated = FALSE;
2219  consdata->ispresolved = FALSE;
2220  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2221  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2222  if( consdata->nquadvars == 1 )
2223  consdata->quadvarssorted = TRUE;
2224  else
2225  consdata->quadvarssorted = consdata->quadvarssorted &&
2226  (SCIPvarCompare(consdata->quadvarterms[consdata->nquadvars-2].var, consdata->quadvarterms[consdata->nquadvars-1].var) == -1);
2227  /* also set to FALSE if nquadvars == 1, since the new variable should be checked for linearity and other stuff in mergeAndClean ... */
2228  consdata->quadvarsmerged = FALSE;
2229 
2230  consdata->iscurvchecked = FALSE;
2231 
2232  return SCIP_OKAY;
2233 }
2234 
2235 /** deletes quadratic variable term at given position from quadratic constraint data */
2236 static
2238  SCIP* scip, /**< SCIP data structure */
2239  SCIP_CONS* cons, /**< quadratic constraint */
2240  int pos /**< position of term to delete */
2241  )
2242 {
2243  SCIP_CONSDATA* consdata;
2244  SCIP_VAR* var;
2245 
2246  assert(scip != NULL);
2247  assert(cons != NULL);
2248 
2249  consdata = SCIPconsGetData(cons);
2250  assert(consdata != NULL);
2251  assert(0 <= pos && pos < consdata->nquadvars);
2252 
2253  var = consdata->quadvarterms[pos].var;
2254  assert(var != NULL);
2255  assert(consdata->quadvarterms[pos].nadjbilin == 0);
2256 
2257  /* remove rounding locks for deleted variable */
2258  SCIP_CALL( unlockQuadraticVariable(scip, cons, var) );
2259 
2260  /* if we catch variable events, drop the events on the variable */
2261  if( consdata->quadvarterms[pos].eventdata != NULL )
2262  {
2263  SCIP_CONSHDLR* conshdlr;
2264  SCIP_CONSHDLRDATA* conshdlrdata;
2265 
2266  /* get event handler */
2267  conshdlr = SCIPconsGetHdlr(cons);
2268  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2269  assert(conshdlrdata != NULL);
2270  assert(conshdlrdata->eventhdlr != NULL);
2271 
2272  /* drop bound change events of variable */
2273  SCIP_CALL( dropQuadVarEvents(scip, conshdlrdata->eventhdlr, cons, pos) );
2274  }
2275 
2276  /* release variable */
2277  SCIP_CALL( SCIPreleaseVar(scip, &consdata->quadvarterms[pos].var) );
2278 
2279  /* free adjacency array */
2280  SCIPfreeBlockMemoryArrayNull(scip, &consdata->quadvarterms[pos].adjbilin, consdata->quadvarterms[pos].adjbilinsize);
2281 
2282  /* move the last variable term to the free slot */
2283  consdataMoveQuadVarTerm(consdata, consdata->nquadvars-1, pos);
2284 
2285  --consdata->nquadvars;
2286 
2287  /* invalidate activity */
2288  consdata->activity = SCIP_INVALID;
2289  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2290 
2291  /* invalidate nonlinear row */
2292  if( consdata->nlrow != NULL )
2293  {
2294  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2295  }
2296 
2297  consdata->ispropagated = FALSE;
2298  consdata->ispresolved = FALSE;
2299  consdata->iscurvchecked = FALSE;
2300 
2301  return SCIP_OKAY;
2302 }
2303 
2304 /** replace variable in quadratic variable term at given position of quadratic constraint data
2305  *
2306  * Allows to replace x by coef*y+offset, thereby maintaining linear and square coefficients and bilinear terms.
2307  */
2308 static
2310  SCIP* scip, /**< SCIP data structure */
2311  SCIP_CONS* cons, /**< quadratic constraint */
2312  int pos, /**< position of term to replace */
2313  SCIP_VAR* var, /**< new variable */
2314  SCIP_Real coef, /**< linear coefficient of new variable */
2315  SCIP_Real offset /**< offset of new variable */
2316  )
2317 {
2318  SCIP_CONSDATA* consdata;
2319  SCIP_QUADVARTERM* quadvarterm;
2320  SCIP_EVENTHDLR* eventhdlr;
2321  SCIP_BILINTERM* bilinterm;
2322  SCIP_Real constant;
2323 
2324  int i;
2325  SCIP_VAR* var2;
2326 
2327  consdata = SCIPconsGetData(cons);
2328  assert(consdata != NULL);
2329  assert(pos >= 0);
2330  assert(pos < consdata->nquadvars);
2331 
2332  quadvarterm = &consdata->quadvarterms[pos];
2333 
2334  /* remove rounding locks for old variable */
2335  SCIP_CALL( unlockQuadraticVariable(scip, cons, quadvarterm->var) );
2336 
2337  /* if we catch variable events, drop the events on the old variable */
2338  if( quadvarterm->eventdata != NULL )
2339  {
2340  SCIP_CONSHDLR* conshdlr;
2341  SCIP_CONSHDLRDATA* conshdlrdata;
2342 
2343  /* get event handler */
2344  conshdlr = SCIPconsGetHdlr(cons);
2345  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2346  assert(conshdlrdata != NULL);
2347  assert(conshdlrdata->eventhdlr != NULL);
2348 
2349  eventhdlr = conshdlrdata->eventhdlr;
2350 
2351  /* drop bound change events of variable */
2352  SCIP_CALL( dropQuadVarEvents(scip, eventhdlr, cons, pos) );
2353  }
2354  else
2355  {
2356  eventhdlr = NULL;
2357  }
2358 
2359  /* compute constant and put into lhs/rhs */
2360  constant = quadvarterm->lincoef * offset + quadvarterm->sqrcoef * offset * offset;
2361  if( constant != 0.0 )
2362  {
2363  /* maintain constant part */
2364  if( !SCIPisInfinity(scip, -consdata->lhs) )
2365  consdata->lhs -= constant;
2366  if( !SCIPisInfinity(scip, consdata->rhs) )
2367  consdata->rhs -= constant;
2368  }
2369 
2370  /* update linear and square coefficient */
2371  quadvarterm->lincoef *= coef;
2372  quadvarterm->lincoef += 2.0 * quadvarterm->sqrcoef * coef * offset;
2373  quadvarterm->sqrcoef *= coef * coef;
2374 
2375  /* update bilinear terms */
2376  for( i = 0; i < quadvarterm->nadjbilin; ++i )
2377  {
2378  bilinterm = &consdata->bilinterms[quadvarterm->adjbilin[i]];
2379 
2380  if( bilinterm->var1 == quadvarterm->var )
2381  {
2382  bilinterm->var1 = var;
2383  var2 = bilinterm->var2;
2384  }
2385  else
2386  {
2387  assert(bilinterm->var2 == quadvarterm->var);
2388  bilinterm->var2 = var;
2389  var2 = bilinterm->var1;
2390  }
2391 
2392  if( var == var2 )
2393  {
2394  /* looks like we actually have a square term here */
2395  quadvarterm->lincoef += bilinterm->coef * offset;
2396  quadvarterm->sqrcoef += bilinterm->coef * coef;
2397  /* deleting bilinear terms is expensive, since it requires updating adjacency information
2398  * thus, for now we just set the coefficient to 0.0 and clear in later when the bilinear terms are merged */
2399  bilinterm->coef = 0.0;
2400  continue;
2401  }
2402 
2403  /* swap var1 and var2 if they are in wrong order */
2404  if( SCIPvarCompare(bilinterm->var1, bilinterm->var2) > 0 )
2405  {
2406  SCIP_VAR* tmp;
2407  tmp = bilinterm->var1;
2408  bilinterm->var1 = bilinterm->var2;
2409  bilinterm->var2 = tmp;
2410  }
2411  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2412 
2413  if( offset != 0.0 )
2414  {
2415  /* need to find var2 and add offset*bilinterm->coef to linear coefficient */
2416  int var2pos;
2417 
2418  var2pos = 0;
2419  while( consdata->quadvarterms[var2pos].var != var2 )
2420  {
2421  ++var2pos;
2422  assert(var2pos < consdata->nquadvars);
2423  }
2424 
2425  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
2426  }
2427 
2428  bilinterm->coef *= coef;
2429  }
2430 
2431  /* release old variable */
2432  SCIP_CALL( SCIPreleaseVar(scip, &quadvarterm->var) );
2433 
2434  /* set new variable */
2435  quadvarterm->var = var;
2436 
2437  /* capture new variable */
2438  SCIP_CALL( SCIPcaptureVar(scip, quadvarterm->var) );
2439 
2440  /* catch variable events, if we do so */
2441  if( eventhdlr != NULL )
2442  {
2443  assert(SCIPconsIsEnabled(cons));
2444 
2445  /* catch bound change events of variable */
2446  SCIP_CALL( catchQuadVarEvents(scip, eventhdlr, cons, pos) );
2447  }
2448 
2449  /* invalidate activity information */
2450  consdata->activity = SCIP_INVALID;
2451  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2452 
2453  /* invalidate nonlinear row */
2454  if( consdata->nlrow != NULL )
2455  {
2456  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2457  }
2458 
2459  /* install rounding locks for new variable */
2460  SCIP_CALL( lockQuadraticVariable(scip, cons, var) );
2461 
2462  consdata->isremovedfixings = consdata->isremovedfixings && SCIPvarIsActive(var)
2463  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
2464  consdata->quadvarssorted = (consdata->nquadvars == 1);
2465  consdata->quadvarsmerged = FALSE;
2466  consdata->bilinsorted &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2467  consdata->bilinmerged &= (quadvarterm->nadjbilin == 0); /*lint !e514*/
2468 
2469  consdata->ispropagated = FALSE;
2470  consdata->ispresolved = FALSE;
2471  consdata->iscurvchecked = FALSE;
2472 
2473  return SCIP_OKAY;
2474 }
2475 
2476 /** adds a bilinear term to quadratic constraint */
2477 static
2479  SCIP* scip, /**< SCIP data structure */
2480  SCIP_CONS* cons, /**< quadratic constraint */
2481  int var1pos, /**< position of first variable in quadratic variables array */
2482  int var2pos, /**< position of second variable in quadratic variables array */
2483  SCIP_Real coef /**< coefficient of bilinear term */
2484  )
2485 {
2486  SCIP_CONSDATA* consdata;
2487  SCIP_BILINTERM* bilinterm;
2488 
2489  assert(scip != NULL);
2490  assert(cons != NULL);
2491 
2492  if( var1pos == var2pos )
2493  {
2494  SCIPerrorMessage("tried to add bilinear term where both variables are the same\n");
2495  return SCIP_INVALIDDATA;
2496  }
2497 
2498  consdata = SCIPconsGetData(cons);
2499  assert(consdata != NULL);
2500 
2501  /* check if the bilinear terms are sorted */
2502  assert(consdataCheckBilinTermsSort(consdata));
2503 
2504  assert(var1pos >= 0);
2505  assert(var1pos < consdata->nquadvars);
2506  assert(var2pos >= 0);
2507  assert(var2pos < consdata->nquadvars);
2508 
2509  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nbilinterms + 1) );
2510 
2511  bilinterm = &consdata->bilinterms[consdata->nbilinterms];
2512  if( SCIPvarCompare(consdata->quadvarterms[var1pos].var, consdata->quadvarterms[var2pos].var) < 0 )
2513  {
2514  bilinterm->var1 = consdata->quadvarterms[var1pos].var;
2515  bilinterm->var2 = consdata->quadvarterms[var2pos].var;
2516  }
2517  else
2518  {
2519  bilinterm->var1 = consdata->quadvarterms[var2pos].var;
2520  bilinterm->var2 = consdata->quadvarterms[var1pos].var;
2521  }
2522  bilinterm->coef = coef;
2523 
2524  if( bilinterm->var1 == bilinterm->var2 )
2525  {
2526  SCIPerrorMessage("tried to add bilinear term where both variables are the same, but appear at different positions in quadvarterms array\n");
2527  return SCIP_INVALIDDATA;
2528  }
2529  assert(SCIPvarCompare(bilinterm->var1, bilinterm->var2) == -1);
2530 
2531  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var1pos], consdata->quadvarterms[var1pos].nadjbilin + 1) );
2532  SCIP_CALL( consdataEnsureAdjBilinSize(scip, &consdata->quadvarterms[var2pos], consdata->quadvarterms[var2pos].nadjbilin + 1) );
2533 
2534  consdata->quadvarterms[var1pos].adjbilin[consdata->quadvarterms[var1pos].nadjbilin] = consdata->nbilinterms;
2535  consdata->quadvarterms[var2pos].adjbilin[consdata->quadvarterms[var2pos].nadjbilin] = consdata->nbilinterms;
2536  ++consdata->quadvarterms[var1pos].nadjbilin;
2537  ++consdata->quadvarterms[var2pos].nadjbilin;
2538 
2539  ++consdata->nbilinterms;
2540 
2541  /* invalidate activity information */
2542  consdata->activity = SCIP_INVALID;
2543  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2544 
2545  /* invalidate nonlinear row */
2546  if( consdata->nlrow != NULL )
2547  {
2548  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2549  }
2550 
2551  consdata->ispropagated = FALSE;
2552  consdata->ispresolved = FALSE;
2553  if( consdata->nbilinterms == 1 )
2554  {
2555  consdata->bilinsorted = TRUE;
2556 
2557  /* we have to take care of the bilinear term in mergeAndCleanBilinearTerms() if the coefficient is zero */
2558  consdata->bilinmerged = !SCIPisZero(scip, consdata->bilinterms[0].coef);
2559  }
2560  else
2561  {
2562  consdata->bilinsorted = consdata->bilinsorted
2563  && (bilinTermComp(consdata, consdata->nbilinterms-2, consdata->nbilinterms-1) <= 0);
2564  consdata->bilinmerged = FALSE;
2565  }
2566 
2567  consdata->iscurvchecked = FALSE;
2568 
2569  /* check if the bilinear terms are sorted */
2570  assert(consdataCheckBilinTermsSort(consdata));
2571 
2572  return SCIP_OKAY;
2573 }
2574 
2575 /** removes a set of bilinear terms and updates adjacency information in quad var terms
2576  *
2577  * Note: this function sorts the given array termposs.
2578  */
2579 static
2581  SCIP* scip, /**< SCIP data structure */
2582  SCIP_CONS* cons, /**< quadratic constraint */
2583  int nterms, /**< number of terms to delete */
2584  int* termposs /**< indices of terms to delete */
2585  )
2586 {
2587  SCIP_CONSDATA* consdata;
2588  int* newpos;
2589  int i;
2590  int j;
2591  int offset;
2592 
2593  assert(scip != NULL);
2594  assert(cons != NULL);
2595  assert(nterms == 0 || termposs != NULL);
2596 
2597  if( nterms == 0 )
2598  return SCIP_OKAY;
2599 
2600  consdata = SCIPconsGetData(cons);
2601  assert(consdata != NULL);
2602 
2603  SCIPsortInt(termposs, nterms);
2604 
2605  SCIP_CALL( SCIPallocBufferArray(scip, &newpos, consdata->nbilinterms) );
2606 
2607  i = 0;
2608  offset = 0;
2609  for( j = 0; j < consdata->nbilinterms; ++j )
2610  {
2611  /* if j'th term is deleted, increase offset and continue */
2612  if( i < nterms && j == termposs[i] )
2613  {
2614  ++offset;
2615  ++i;
2616  newpos[j] = -1;
2617  continue;
2618  }
2619 
2620  /* otherwise, move it forward and remember new position */
2621  if( offset > 0 )
2622  consdata->bilinterms[j-offset] = consdata->bilinterms[j];
2623  newpos[j] = j - offset;
2624  }
2625  assert(offset == nterms);
2626 
2627  /* update adjacency and activity information in quad var terms */
2628  for( i = 0; i < consdata->nquadvars; ++i )
2629  {
2630  offset = 0;
2631  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
2632  {
2633  assert(consdata->quadvarterms[i].adjbilin[j] < consdata->nbilinterms);
2634  if( newpos[consdata->quadvarterms[i].adjbilin[j]] == -1 )
2635  {
2636  /* corresponding bilinear term was deleted, thus increase offset */
2637  ++offset;
2638  }
2639  else
2640  {
2641  /* update index of j'th bilinear term and store at position j-offset */
2642  consdata->quadvarterms[i].adjbilin[j-offset] = newpos[consdata->quadvarterms[i].adjbilin[j]];
2643  }
2644  }
2645  consdata->quadvarterms[i].nadjbilin -= offset;
2646  /* some bilinear term was removed, so invalidate activity bounds */
2647  }
2648 
2649  consdata->nbilinterms -= nterms;
2650 
2651  SCIPfreeBufferArray(scip, &newpos);
2652 
2653  /* some quad vars may be linear now */
2654  consdata->quadvarsmerged = FALSE;
2655 
2656  consdata->ispropagated = FALSE;
2657  consdata->ispresolved = FALSE;
2658  consdata->iscurvchecked = FALSE;
2659 
2660  /* invalidate activity */
2661  consdata->activity = SCIP_INVALID;
2662  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2663 
2664  /* invalidate nonlinear row */
2665  if( consdata->nlrow != NULL )
2666  {
2667  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2668  }
2669 
2670  return SCIP_OKAY;
2671 }
2672 
2673 /** merges quad var terms that correspond to the same variable and does additional cleanup
2674  *
2675  * If a quadratic variable terms is actually linear, makes a linear term out of it
2676  * also replaces squares of binary variables by the binary variables, i.e., adds sqrcoef to lincoef.
2677  */
2678 static
2680  SCIP* scip, /**< SCIP data structure */
2681  SCIP_CONS* cons /**< quadratic constraint */
2682  )
2683 {
2684  SCIP_QUADVARTERM* quadvarterm;
2685  SCIP_CONSDATA* consdata;
2686  int i;
2687  int j;
2688 
2689  assert(scip != NULL);
2690  assert(cons != NULL);
2691 
2692  consdata = SCIPconsGetData(cons);
2693 
2694  if( consdata->quadvarsmerged )
2695  return SCIP_OKAY;
2696 
2697  if( consdata->nquadvars == 0 )
2698  {
2699  consdata->quadvarsmerged = TRUE;
2700  return SCIP_OKAY;
2701  }
2702 
2703  i = 0;
2704  while( i < consdata->nquadvars )
2705  {
2706  /* make sure quad var terms are sorted (do this in every round, since we may move variables around) */
2707  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
2708 
2709  quadvarterm = &consdata->quadvarterms[i];
2710 
2711  for( j = i+1; j < consdata->nquadvars && consdata->quadvarterms[j].var == quadvarterm->var; ++j )
2712  {
2713  /* add quad var term j to current term i */
2714  quadvarterm->lincoef += consdata->quadvarterms[j].lincoef;
2715  quadvarterm->sqrcoef += consdata->quadvarterms[j].sqrcoef;
2716  if( consdata->quadvarterms[j].nadjbilin > 0 )
2717  {
2718  /* move adjacency information from j to i */
2719  SCIP_CALL( consdataEnsureAdjBilinSize(scip, quadvarterm, quadvarterm->nadjbilin + consdata->quadvarterms[j].nadjbilin) );
2720  BMScopyMemoryArray(&quadvarterm->adjbilin[quadvarterm->nadjbilin], consdata->quadvarterms[j].adjbilin, consdata->quadvarterms[j].nadjbilin); /*lint !e866*/
2721  quadvarterm->nadjbilin += consdata->quadvarterms[j].nadjbilin;
2722  consdata->quadvarterms[j].nadjbilin = 0;
2723  }
2724  consdata->quadvarterms[j].lincoef = 0.0;
2725  consdata->quadvarterms[j].sqrcoef = 0.0;
2726  /* mark that activity information in quadvarterm is not up to date anymore */
2727  }
2728 
2729  /* remove quad var terms i+1..j-1 backwards */
2730  for( j = j-1; j > i; --j )
2731  {
2732  SCIP_CALL( delQuadVarTermPos(scip, cons, j) );
2733  }
2734 
2735  /* for binary variables, x^2 = x
2736  * however, we may destroy convexity of a quadratic term that involves also bilinear terms
2737  * thus, we do this step only if the variable does not appear in any bilinear term */
2738  if( quadvarterm->sqrcoef != 0.0 && SCIPvarIsBinary(quadvarterm->var) && quadvarterm->nadjbilin == 0 )
2739  {
2740  SCIPdebugMsg(scip, "replace square of binary variable by itself: <%s>^2 --> <%s>\n", SCIPvarGetName(quadvarterm->var), SCIPvarGetName(quadvarterm->var));
2741  quadvarterm->lincoef += quadvarterm->sqrcoef;
2742  quadvarterm->sqrcoef = 0.0;
2743 
2744  /* invalidate nonlinear row */
2745  if( consdata->nlrow != NULL )
2746  {
2747  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
2748  }
2749  }
2750 
2751  /* if its 0.0 or linear, get rid of it */
2752  if( SCIPisZero(scip, quadvarterm->sqrcoef) && quadvarterm->nadjbilin == 0 )
2753  {
2754  if( !SCIPisZero(scip, quadvarterm->lincoef) )
2755  {
2756  /* seem to be a linear term now, thus add as linear term */
2757  SCIP_CALL( addLinearCoef(scip, cons, quadvarterm->var, quadvarterm->lincoef) );
2758  }
2759  /* remove term at pos i */
2760  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
2761  }
2762  else
2763  {
2764  ++i;
2765  }
2766  }
2767 
2768  consdata->quadvarsmerged = TRUE;
2769  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2770 
2771  return SCIP_OKAY;
2772 }
2773 
2774 /** merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
2775 static
2777  SCIP* scip, /**< SCIP data structure */
2778  SCIP_CONS* cons /**< quadratic constraint */
2779  )
2780 {
2781  SCIP_CONSDATA* consdata;
2782  SCIP_Real newcoef;
2783  int i;
2784  int j;
2785  int qvarpos;
2786 
2787  assert(scip != NULL);
2788  assert(cons != NULL);
2789 
2790  consdata = SCIPconsGetData(cons);
2791 
2792  if( consdata->linvarsmerged )
2793  return SCIP_OKAY;
2794 
2795  if( consdata->nlinvars == 0 )
2796  {
2797  consdata->linvarsmerged = TRUE;
2798  return SCIP_OKAY;
2799  }
2800 
2801  i = 0;
2802  while( i < consdata->nlinvars )
2803  {
2804  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
2805  consdataSortLinearVars(consdata);
2806 
2807  /* sum up coefficients that correspond to variable i */
2808  newcoef = consdata->lincoefs[i];
2809  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
2810  newcoef += consdata->lincoefs[j];
2811  /* delete the additional variables in backward order */
2812  for( j = j-1; j > i; --j )
2813  {
2814  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
2815  }
2816 
2817  /* check if there is already a quadratic variable term with this variable */
2818  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->linvars[i], &qvarpos) );
2819  if( qvarpos >= 0)
2820  {
2821  /* add newcoef to linear coefficient of quadratic variable and mark linear variable as to delete */
2822  assert(qvarpos < consdata->nquadvars);
2823  assert(consdata->quadvarterms[qvarpos].var == consdata->linvars[i]);
2824  consdata->quadvarterms[qvarpos].lincoef += newcoef;
2825  newcoef = 0.0;
2826  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
2827  }
2828 
2829  /* delete also entry at position i, if it became zero (or was zero before) */
2830  if( SCIPisZero(scip, newcoef) )
2831  {
2832  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2833  }
2834  else
2835  {
2836  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
2837  ++i;
2838  }
2839  }
2840 
2841  consdata->linvarsmerged = TRUE;
2842 
2843  return SCIP_OKAY;
2844 }
2845 
2846 /** merges bilinear terms with same variables into a single term, removes bilinear terms with coefficient 0.0 */
2847 static
2849  SCIP* scip, /**< SCIP data structure */
2850  SCIP_CONS* cons /**< quadratic constraint */
2851  )
2852 {
2853  SCIP_CONSDATA* consdata;
2854  SCIP_BILINTERM* bilinterm;
2855  int i;
2856  int j;
2857  int* todelete;
2858  int ntodelete;
2859 
2860  assert(scip != NULL);
2861  assert(cons != NULL);
2862 
2863  consdata = SCIPconsGetData(cons);
2864 
2865  /* check if the bilinear terms are sorted */
2866  assert(consdataCheckBilinTermsSort(consdata));
2867 
2868  if( consdata->bilinmerged )
2869  return SCIP_OKAY;
2870 
2871  if( consdata->nbilinterms == 0 )
2872  {
2873  consdata->bilinmerged = TRUE;
2874  return SCIP_OKAY;
2875  }
2876 
2877  /* alloc memory for array of terms that need to be deleted finally */
2878  ntodelete = 0;
2879  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
2880 
2881  /* make sure bilinear terms are sorted */
2882  SCIP_CALL( consdataSortBilinTerms(scip, consdata) );
2883 
2884  i = 0;
2885  while( i < consdata->nbilinterms )
2886  {
2887  bilinterm = &consdata->bilinterms[i];
2888 
2889  /* sum up coefficients that correspond to same variables as term i */
2890  for( j = i+1; j < consdata->nbilinterms && bilinterm->var1 == consdata->bilinterms[j].var1 && bilinterm->var2 == consdata->bilinterms[j].var2; ++j )
2891  {
2892  bilinterm->coef += consdata->bilinterms[j].coef;
2893  todelete[ntodelete++] = j;
2894  }
2895 
2896  /* delete also entry at position i, if it became zero (or was zero before) */
2897  if( SCIPisZero(scip, bilinterm->coef) )
2898  {
2899  todelete[ntodelete++] = i;
2900  }
2901 
2902  /* continue with term after the current series */
2903  i = j;
2904  }
2905 
2906  /* delete bilinear terms */
2907  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
2908 
2909  SCIPfreeBufferArray(scip, &todelete);
2910 
2911  consdata->bilinmerged = TRUE;
2912 
2913  /* check if the bilinear terms are sorted */
2914  assert(consdataCheckBilinTermsSort(consdata));
2915 
2916  return SCIP_OKAY;
2917 }
2918 
2919 /** removes fixes (or aggregated) variables from a quadratic constraint */
2920 static
2922  SCIP* scip, /**< SCIP data structure */
2923  SCIP_CONS* cons /**< quadratic constraint */
2924  )
2925 {
2926  SCIP_CONSDATA* consdata;
2927  SCIP_BILINTERM* bilinterm;
2928  SCIP_Real bilincoef;
2929  SCIP_Real coef;
2930  SCIP_Real offset;
2931  SCIP_VAR* var;
2932  SCIP_VAR* var2;
2933  int var2pos;
2934  int i;
2935  int j;
2936  int k;
2937 
2938  SCIP_Bool have_change;
2939 
2940  assert(scip != NULL);
2941  assert(cons != NULL);
2942 
2943  consdata = SCIPconsGetData(cons);
2944 
2945  have_change = FALSE;
2946  i = 0;
2947  while( i < consdata->nlinvars )
2948  {
2949  var = consdata->linvars[i];
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 = consdata->lincoefs[i];
2960  offset = 0.0;
2961 
2962  if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
2963  {
2964  offset = coef * (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
2965  coef = 0.0;
2966  }
2967  else
2968  {
2969  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
2970  }
2971 
2972  SCIPdebugMsg(scip, " linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]),
2973  coef, SCIPvarGetName(var), offset);
2974 
2975  /* delete previous variable (this will move another variable to position i) */
2976  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
2977 
2978  /* put constant part into bounds */
2979  if( offset != 0.0 )
2980  {
2981  if( !SCIPisInfinity(scip, -consdata->lhs) )
2982  consdata->lhs -= offset;
2983  if( !SCIPisInfinity(scip, consdata->rhs) )
2984  consdata->rhs -= offset;
2985  }
2986 
2987  /* nothing left to do if variable had been fixed */
2988  if( coef == 0.0 )
2989  continue;
2990 
2991  /* if GetProbvar gave a linear variable, just add it
2992  * if it's a multilinear variable, add it's disaggregated variables */
2993  if( SCIPvarIsActive(var) )
2994  {
2995  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
2996  }
2997  else
2998  {
2999  int naggrs;
3000  SCIP_VAR** aggrvars;
3001  SCIP_Real* aggrscalars;
3002  SCIP_Real aggrconstant;
3003 
3004  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
3005 
3006  naggrs = SCIPvarGetMultaggrNVars(var);
3007  aggrvars = SCIPvarGetMultaggrVars(var);
3008  aggrscalars = SCIPvarGetMultaggrScalars(var);
3009  aggrconstant = SCIPvarGetMultaggrConstant(var);
3010 
3011  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
3012 
3013  for( j = 0; j < naggrs; ++j )
3014  {
3015  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
3016  }
3017 
3018  if( aggrconstant != 0.0 )
3019  {
3020  if( !SCIPisInfinity(scip, -consdata->lhs) )
3021  consdata->lhs -= coef * aggrconstant;
3022  if( !SCIPisInfinity(scip, consdata->rhs) )
3023  consdata->rhs -= coef * aggrconstant;
3024  }
3025  }
3026  }
3027 
3028  i = 0;
3029  while( i < consdata->nquadvars )
3030  {
3031  var = consdata->quadvarterms[i].var;
3032 
3033  if( SCIPvarIsActive(var) && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
3034  {
3035  ++i;
3036  continue;
3037  }
3038 
3039  have_change = TRUE;
3040 
3041  coef = 1.0;
3042  offset = 0.0;
3043 
3044  if( !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
3045  {
3046  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
3047  }
3048  else
3049  {
3050  coef = 0.0;
3051  offset = (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
3052  }
3053 
3054  SCIPdebugMsg(scip, " quadratic variable <%s> with status %d is replaced by %g * <%s> + %g\n", SCIPvarGetName(consdata->quadvarterms[i].var),
3055  SCIPvarGetStatus(consdata->quadvarterms[i].var), coef, SCIPvarGetName(var), offset);
3056 
3057  /* handle fixed variable */
3058  if( coef == 0.0 )
3059  {
3060  /* if not fixed to 0.0, add to linear coefs of vars in bilinear terms, and deal with linear and square term as constant */
3061  if( offset != 0.0 )
3062  {
3063  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
3064  {
3065  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
3066 
3067  var2 = bilinterm->var1 == consdata->quadvarterms[i].var ? bilinterm->var2 : bilinterm->var1;
3068  assert(var2 != consdata->quadvarterms[i].var);
3069 
3070  var2pos = 0;
3071  while( consdata->quadvarterms[var2pos].var != var2 )
3072  {
3073  ++var2pos;
3074  assert(var2pos < consdata->nquadvars);
3075  }
3076  consdata->quadvarterms[var2pos].lincoef += bilinterm->coef * offset;
3077  }
3078 
3079  offset = consdata->quadvarterms[i].lincoef * offset + consdata->quadvarterms[i].sqrcoef * offset * offset;
3080  if( !SCIPisInfinity(scip, -consdata->lhs) )
3081  consdata->lhs -= offset;
3082  if( !SCIPisInfinity(scip, consdata->rhs) )
3083  consdata->rhs -= offset;
3084  }
3085 
3086  /* remove bilinear terms */
3087  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3088 
3089  /* delete quad. var term i */
3090  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3091 
3092  continue;
3093  }
3094 
3095  assert(var != NULL);
3096 
3097  /* if GetProbvar gave an active variable, replace the quad var term so that it uses the new variable */
3098  if( SCIPvarIsActive(var) )
3099  {
3100  /* replace x by coef*y+offset */
3101  SCIP_CALL( replaceQuadVarTermPos(scip, cons, i, var, coef, offset) );
3102 
3103  continue;
3104  }
3105  else
3106  {
3107  /* if GetProbVar gave a multi-aggregated variable, add new quad var terms and new bilinear terms
3108  * x is replaced by coef * (sum_i a_ix_i + b) + offset
3109  * lcoef * x + scoef * x^2 + bcoef * x * y ->
3110  * (b*coef + offset) * (lcoef + (b*coef + offset) * scoef)
3111  * + sum_i a_i*coef * (lcoef + 2 (b*coef + offset) * scoef) x_i
3112  * + sum_i (a_i*coef)^2 * scoef * x_i^2
3113  * + 2 sum_{i,j, i<j} (a_i a_j coef^2 scoef) x_i x_j
3114  * + bcoef * (b*coef + offset + coef * sum_i a_ix_i) y
3115  */
3116  int naggrs;
3117  SCIP_VAR** aggrvars; /* x_i */
3118  SCIP_Real* aggrscalars; /* a_i */
3119  SCIP_Real aggrconstant; /* b */
3120  int nquadtermsold;
3121 
3122  SCIP_Real lcoef;
3123  SCIP_Real scoef;
3124 
3125  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
3126 
3127  naggrs = SCIPvarGetMultaggrNVars(var);
3128  aggrvars = SCIPvarGetMultaggrVars(var);
3129  aggrscalars = SCIPvarGetMultaggrScalars(var);
3130  aggrconstant = SCIPvarGetMultaggrConstant(var);
3131 
3132  lcoef = consdata->quadvarterms[i].lincoef;
3133  scoef = consdata->quadvarterms[i].sqrcoef;
3134 
3135  nquadtermsold = consdata->nquadvars;
3136 
3137  SCIP_CALL( consdataEnsureQuadVarTermsSize(scip, consdata, consdata->nquadvars + naggrs) );
3138 
3139  /* take care of constant part */
3140  if( aggrconstant != 0.0 || offset != 0.0 )
3141  {
3142  SCIP_Real constant;
3143  constant = (aggrconstant * coef + offset) * (lcoef + (aggrconstant * coef + offset) * scoef);
3144  if( !SCIPisInfinity(scip, -consdata->lhs) )
3145  consdata->lhs -= constant;
3146  if( !SCIPisInfinity(scip, consdata->rhs) )
3147  consdata->rhs -= constant;
3148  }
3149 
3150  /* add x_i's with linear and square coefficients */
3151  for( j = 0; j < naggrs; ++j )
3152  {
3153  SCIP_CALL( addQuadVarTerm(scip, cons, aggrvars[j],
3154  coef * aggrscalars[j] * (lcoef + 2.0 * scoef * (coef * aggrconstant + offset)),
3155  coef * coef * aggrscalars[j] * aggrscalars[j] * scoef) );
3156  }
3157 
3158  /* ensure space for bilinear terms */
3159  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, consdata->nquadvars + (scoef != 0.0 ? (naggrs * (naggrs-1))/2 : 0) + consdata->quadvarterms[j].nadjbilin * naggrs) );
3160 
3161  /* add x_j*x_k's */
3162  if( scoef != 0.0 )
3163  {
3164  for( j = 0; j < naggrs; ++j )
3165  for( k = 0; k < j; ++k )
3166  {
3167  assert(aggrvars[j] != aggrvars[k]);
3168  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, nquadtermsold + k,
3169  2.0 * aggrscalars[j] * aggrscalars[k] * coef * coef * scoef) );
3170  }
3171  }
3172 
3173  /* add x_i*y's */
3174  for( k = 0; k < consdata->quadvarterms[i].nadjbilin; ++k )
3175  {
3176  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[k]];
3177  bilincoef = bilinterm->coef; /* copy coef, as bilinterm pointer may become invalid by realloc in addBilinearTerm() below */
3178  var2 = (bilinterm->var1 == consdata->quadvarterms[i].var) ? bilinterm->var2 : bilinterm->var1;
3179  assert(var2 != consdata->quadvarterms[i].var);
3180 
3181  /* this is not efficient, but we cannot sort the quadratic terms here, since we currently iterate over them */
3182  var2pos = 0;
3183  while( consdata->quadvarterms[var2pos].var != var2 )
3184  {
3185  ++var2pos;
3186  assert(var2pos < consdata->nquadvars);
3187  }
3188 
3189  for( j = 0; j < naggrs; ++j )
3190  {
3191  if( aggrvars[j] == var2 )
3192  { /* x_i == y, so we have a square term here */
3193  consdata->quadvarterms[var2pos].sqrcoef += bilincoef * coef * aggrscalars[j];
3194  }
3195  else
3196  { /* x_i != y, so we need to add a bilinear term here */
3197  SCIP_CALL( addBilinearTerm(scip, cons, nquadtermsold + j, var2pos, bilincoef * coef * aggrscalars[j]) );
3198  }
3199  }
3200 
3201  consdata->quadvarterms[var2pos].lincoef += bilincoef * (aggrconstant * coef + offset);
3202  }
3203 
3204  /* remove bilinear terms */
3205  SCIP_CALL( removeBilinearTermsPos(scip, cons, consdata->quadvarterms[i].nadjbilin, consdata->quadvarterms[i].adjbilin) );
3206 
3207  /* delete quad. var term i */
3208  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
3209  }
3210  }
3211 
3212  consdata->isremovedfixings = TRUE;
3213 
3214  SCIPdebugMsg(scip, "removed fixations from <%s>\n -> ", SCIPconsGetName(cons));
3215  SCIPdebugPrintCons(scip, cons, NULL);
3216 
3217 #ifndef NDEBUG
3218  for( i = 0; i < consdata->nlinvars; ++i )
3219  assert(SCIPvarIsActive(consdata->linvars[i]));
3220 
3221  for( i = 0; i < consdata->nquadvars; ++i )
3222  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
3223 #endif
3224 
3225  if( !have_change )
3226  return SCIP_OKAY;
3227 
3228  /* some quadratic variable may have been replaced by an already existing linear variable
3229  * in this case, we want the linear variable to be removed, which happens in mergeAndCleanLinearVars
3230  */
3231  consdata->linvarsmerged = FALSE;
3232 
3233  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
3234  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
3235  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
3236 
3237 #ifndef NDEBUG
3238  for( i = 0; i < consdata->nbilinterms; ++i )
3239  {
3240  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
3241  assert(consdata->bilinterms[i].coef != 0.0);
3242  assert(SCIPvarCompare(consdata->bilinterms[i].var1, consdata->bilinterms[i].var2) < 0);
3243  }
3244 #endif
3245 
3246  return SCIP_OKAY;
3247 }
3248 
3249 /** create a nonlinear row representation of the constraint and stores them in consdata */
3250 static
3252  SCIP* scip, /**< SCIP data structure */
3253  SCIP_CONS* cons /**< quadratic constraint */
3254  )
3255 {
3256  SCIP_CONSDATA* consdata;
3257  int nquadvars; /* number of variables in quadratic terms */
3258  SCIP_VAR** quadvars; /* variables in quadratic terms */
3259  int nquadelems; /* number of quadratic elements (square and bilinear terms) */
3260  SCIP_QUADELEM* quadelems; /* quadratic elements (square and bilinear terms) */
3261  int nquadlinterms; /* number of linear terms using variables that are in quadratic terms */
3262  SCIP_VAR** quadlinvars; /* variables of linear terms using variables that are in quadratic terms */
3263  SCIP_Real* quadlincoefs; /* coefficients of linear terms using variables that are in quadratic terms */
3264  int i;
3265  int idx1;
3266  int idx2;
3267  int lincnt;
3268  int elcnt;
3269  SCIP_VAR* lastvar;
3270  int lastvaridx;
3271  SCIP_EXPRCURV curvature;
3272 
3273  assert(scip != NULL);
3274  assert(cons != NULL);
3275 
3276  consdata = SCIPconsGetData(cons);
3277  assert(consdata != NULL);
3278 
3279  if( consdata->nlrow != NULL )
3280  {
3281  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3282  }
3283 
3284  nquadvars = consdata->nquadvars;
3285  nquadelems = consdata->nbilinterms;
3286  nquadlinterms = 0;
3287  for( i = 0; i < nquadvars; ++i )
3288  {
3289  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3290  ++nquadelems;
3291  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3292  ++nquadlinterms;
3293  }
3294 
3295  SCIP_CALL( SCIPallocBufferArray(scip, &quadvars, nquadvars) );
3296  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
3297  SCIP_CALL( SCIPallocBufferArray(scip, &quadlinvars, nquadlinterms) );
3298  SCIP_CALL( SCIPallocBufferArray(scip, &quadlincoefs, nquadlinterms) );
3299 
3300  lincnt = 0;
3301  elcnt = 0;
3302  for( i = 0; i < nquadvars; ++i )
3303  {
3304  quadvars[i] = consdata->quadvarterms[i].var;
3305 
3306  if( consdata->quadvarterms[i].sqrcoef != 0.0 )
3307  {
3308  assert(elcnt < nquadelems);
3309  quadelems[elcnt].idx1 = i;
3310  quadelems[elcnt].idx2 = i;
3311  quadelems[elcnt].coef = consdata->quadvarterms[i].sqrcoef;
3312  ++elcnt;
3313  }
3314 
3315  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) )
3316  {
3317  assert(lincnt < nquadlinterms);
3318  quadlinvars [lincnt] = consdata->quadvarterms[i].var;
3319  quadlincoefs[lincnt] = consdata->quadvarterms[i].lincoef;
3320  ++lincnt;
3321  }
3322  }
3323  assert(lincnt == nquadlinterms);
3324 
3325  /* bilinear terms are sorted first by first variable, then by second variable
3326  * 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 */
3327  lastvar = NULL;
3328  lastvaridx = -1;
3329  for( i = 0; i < consdata->nbilinterms; ++i )
3330  {
3331  if( lastvar == consdata->bilinterms[i].var1 )
3332  {
3333  assert(lastvaridx >= 0);
3334  assert(consdata->quadvarterms[lastvaridx].var == consdata->bilinterms[i].var1);
3335  }
3336  else
3337  {
3338  lastvar = consdata->bilinterms[i].var1;
3339  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, lastvar, &lastvaridx) );
3340  }
3341  idx1 = lastvaridx;
3342 
3343  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &idx2) );
3344 
3345  assert(elcnt < nquadelems);
3346  quadelems[elcnt].idx1 = MIN(idx1, idx2);
3347  quadelems[elcnt].idx2 = MAX(idx1, idx2);
3348  quadelems[elcnt].coef = consdata->bilinterms[i].coef;
3349  ++elcnt;
3350  }
3351  assert(elcnt == nquadelems);
3352 
3353  /* set curvature for the nonlinear row */
3354  if( consdata->isconcave && consdata->isconvex )
3355  {
3356  assert(consdata->nbilinterms == 0 && consdata->nquadvars == 0);
3357  curvature = SCIP_EXPRCURV_LINEAR;
3358  }
3359  else if( consdata->isconcave )
3360  curvature = SCIP_EXPRCURV_CONCAVE;
3361  else if( consdata->isconvex )
3362  curvature = SCIP_EXPRCURV_CONVEX;
3363  else
3364  curvature = SCIP_EXPRCURV_UNKNOWN;
3365 
3366  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3367  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
3368  nquadvars, quadvars, nquadelems, quadelems,
3369  NULL, consdata->lhs, consdata->rhs,
3370  curvature) );
3371 
3372  SCIP_CALL( SCIPaddLinearCoefsToNlRow(scip, consdata->nlrow, nquadlinterms, quadlinvars, quadlincoefs) );
3373 
3374  SCIPfreeBufferArray(scip, &quadlincoefs);
3375  SCIPfreeBufferArray(scip, &quadlinvars);
3376  SCIPfreeBufferArray(scip, &quadelems);
3377  SCIPfreeBufferArray(scip, &quadvars);
3378 
3379  return SCIP_OKAY;
3380 }
3381 
3382 /** solve constraint as presolving */
3383 static
3385  SCIP* scip, /**< SCIP data structure */
3386  SCIP_CONS* cons, /**< constraint */
3387  SCIP_RESULT* result, /**< to store result of solve: cutoff, success, or do-not-find */
3388  SCIP_Bool* redundant, /**< to store whether constraint is redundant now (should be deleted) */
3389  int* naggrvars /**< counter on number of variable aggregations */
3390  )
3391 {
3392  SCIP_CONSDATA* consdata;
3393 
3394  assert(scip != NULL);
3395  assert(cons != NULL);
3396  assert(result != NULL);
3397  assert(redundant != NULL);
3398 
3399  *result = SCIP_DIDNOTFIND;
3400  *redundant = FALSE;
3401 
3402  consdata = SCIPconsGetData(cons);
3403  assert(consdata != NULL);
3404 
3405  /* if constraint is an equality with two variables, at least one of them binary,
3406  * and linear after fixing the binary, then we can aggregate the variables */
3407  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && consdata->nlinvars == 0 && consdata->nquadvars == 2 &&
3408  ((SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ||
3409  (SCIPvarIsBinary(consdata->quadvarterms[1].var) && consdata->quadvarterms[0].sqrcoef == 0.0)) )
3410  {
3411  SCIP_Bool infeasible;
3412  SCIP_Bool aggregated;
3413  SCIP_Real a;
3414  SCIP_Real b;
3415  SCIP_Real c;
3416  SCIP_VAR* x;
3417  SCIP_VAR* y;
3418  int binvaridx;
3419 
3420  /* constraint is a*(x+x^2) + b*y + c*x*y = rhs, with x binary variable
3421  * x = 0 -> b*y == rhs
3422  * x = 1 -> (b+c)*y == rhs - a
3423  *
3424  * 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
3425  */
3426 
3427  binvaridx = (SCIPvarIsBinary(consdata->quadvarterms[0].var) && consdata->quadvarterms[1].sqrcoef == 0.0) ? 0 : 1;
3428 
3429  x = consdata->quadvarterms[binvaridx].var;
3430  a = consdata->quadvarterms[binvaridx].sqrcoef + consdata->quadvarterms[binvaridx].lincoef;
3431 
3432  y = consdata->quadvarterms[1-binvaridx].var;
3433  b = consdata->quadvarterms[1-binvaridx].lincoef;
3434 
3435  assert(consdata->nbilinterms <= 1); /* should actually be 1, since constraint is otherwise linear */
3436  c = (consdata->nbilinterms == 1) ? consdata->bilinterms[0].coef : 0.0;
3437 
3438  if( !SCIPisZero(scip, b) && !SCIPisZero(scip, b+c) )
3439  {
3440  SCIPdebugMsg(scip, "<%s> = 0 -> %g*<%s> = %g and <%s> = 1 -> %g*<%s> = %g\n", SCIPvarGetName(x), b, SCIPvarGetName(y), consdata->rhs,
3441  SCIPvarGetName(x), b+c, SCIPvarGetName(y), consdata->rhs - a);
3442  SCIPdebugMsg(scip, "=> attempt aggregation <%s> = %g*<%s> + %g\n", SCIPvarGetName(y), (consdata->rhs-a)/(b+c) - consdata->rhs/b,
3443  SCIPvarGetName(x), consdata->rhs/b);
3444 
3445  SCIP_CALL( SCIPaggregateVars(scip, x, y, (consdata->rhs-a)/(b+c) - consdata->rhs/b, -1.0, -consdata->rhs/b, &infeasible, redundant, &aggregated) );
3446  if( infeasible )
3447  *result = SCIP_CUTOFF;
3448  else if( *redundant || aggregated )
3449  {
3450  /* aggregated (or were already aggregated), so constraint is now redundant */
3451  *result = SCIP_SUCCESS;
3452  *redundant = TRUE;
3453 
3454  if( aggregated )
3455  ++*naggrvars;
3456  }
3457  }
3458 
3459  /* @todo if b is 0 or b+c is 0, or lhs != rhs, then could replace by varbound constraint */
3460  }
3461 
3462  return SCIP_OKAY;
3463 }
3464 
3465 
3466 /** reformulates products of binary variables as AND constraint
3467  *
3468  * 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.
3469  */
3470 static
3472  SCIP* scip, /**< SCIP data structure */
3473  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3474  SCIP_CONS* cons, /**< constraint */
3475  int* naddconss /**< buffer where to add the number of AND constraints added */
3476  )
3477 {
3478  SCIP_CONSHDLRDATA* conshdlrdata;
3479  SCIP_CONSDATA* consdata;
3480  char name[SCIP_MAXSTRLEN];
3481  SCIP_VAR* vars[2];
3482  SCIP_VAR* auxvar;
3483  SCIP_CONS* andcons;
3484  int i;
3485  int ntodelete;
3486  int* todelete;
3487 
3488  assert(scip != NULL);
3489  assert(conshdlr != NULL);
3490  assert(cons != NULL);
3491  assert(naddconss != NULL);
3492 
3493  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3494  assert(conshdlrdata != NULL);
3495 
3496  /* if no binary variables, then we will find nothing to reformulate here
3497  * (note that this does not count in integer variables with {0,1} bounds...)
3498  */
3499  if( SCIPgetNBinVars(scip) == 0 )
3500  return SCIP_OKAY;
3501 
3502  /* if user does not like AND very much, then return */
3503  if( conshdlrdata->empathy4and < 2 )
3504  return SCIP_OKAY;
3505 
3506  consdata = SCIPconsGetData(cons);
3507  assert(consdata != NULL);
3508 
3509  if( consdata->nbilinterms == 0 )
3510  return SCIP_OKAY;
3511 
3512  /* get array to store indices of bilinear terms that shall be deleted */
3513  SCIP_CALL( SCIPallocBufferArray(scip, &todelete, consdata->nbilinterms) );
3514  ntodelete = 0;
3515 
3516  for( i = 0; i < consdata->nbilinterms; ++i )
3517  {
3518  vars[0] = consdata->bilinterms[i].var1;
3519  if( !SCIPvarIsBinary(vars[0]) )
3520  continue;
3521 
3522  vars[1] = consdata->bilinterms[i].var2;
3523  if( !SCIPvarIsBinary(vars[1]) )
3524  continue;
3525 
3526  /* create auxiliary variable */
3527  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]), SCIPconsGetName(cons));
3528  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
3529  SCIPvarIsInitial(vars[0]) || SCIPvarIsInitial(vars[1]), SCIPvarIsRemovable(vars[0]) && SCIPvarIsRemovable(vars[1]), NULL, NULL, NULL, NULL, NULL) );
3530  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3531 #ifdef WITH_DEBUG_SOLUTION
3532  if( SCIPdebugIsMainscip(scip) )
3533  {
3534  SCIP_Real var0val;
3535  SCIP_Real var1val;
3536  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[0], &var0val) );
3537  SCIP_CALL( SCIPdebugGetSolVal(scip, vars[1], &var1val) );
3538  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3539  }
3540 #endif
3541 
3542  /* create AND-constraint auxvar = x and y, need to be enforced as not redundant */
3543  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3544  SCIP_CALL( SCIPcreateConsAnd(scip, &andcons, name, auxvar, 2, vars,
3545  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3546  SCIPconsIsSeparated(cons), TRUE, TRUE,
3549  SCIP_CALL( SCIPaddCons(scip, andcons) );
3550  SCIPdebugMsg(scip, "added AND constraint: ");
3551  SCIPdebugPrintCons(scip, andcons, NULL);
3552  SCIP_CALL( SCIPreleaseCons(scip, &andcons) );
3553  ++*naddconss;
3554 
3555  /* add bilincoef * auxvar to linear terms */
3556  SCIP_CALL( addLinearCoef(scip, cons, auxvar, consdata->bilinterms[i].coef) );
3557  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3558 
3559  /* remember that we have to delete this bilinear term */
3560  assert(ntodelete < consdata->nbilinterms);
3561  todelete[ntodelete++] = i;
3562  }
3563 
3564  /* remove bilinear terms that have been replaced */
3565  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
3566  SCIPfreeBufferArray(scip, &todelete);
3567 
3568  return SCIP_OKAY;
3569 }
3570 
3571 /** gets bounds of variable y if x takes a certain value; checks whether x = xval has implications on y */
3572 static
3574  SCIP* scip, /**< SCIP data structure */
3575  SCIP_VAR* x, /**< variable which implications to check */
3576  SCIP_Bool xval, /**< value of x to check for (TRUE for 1, FALSE for 0) */
3577  SCIP_VAR* y, /**< variable to check if bounds can be reduced */
3578  SCIP_INTERVAL* resultant /**< buffer to store bounds on y */
3579  )
3580 {
3581  SCIP_VAR** implvars;
3582  SCIP_BOUNDTYPE* impltypes;
3583  SCIP_Real* implbounds;
3584  int nimpls;
3585  int pos;
3586 
3587  assert(scip != NULL);
3588  assert(x != NULL);
3589  assert(y != NULL);
3590  assert(resultant != NULL);
3591 
3593 
3594  if( !SCIPvarIsBinary(x) || !SCIPvarIsActive(x) )
3595  return SCIP_OKAY;
3596 
3597  /* check in cliques for binary to binary implications */
3598  if( SCIPvarIsBinary(y) )
3599  {
3600  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 0.0));
3601  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 1.0));
3602 
3603  if( SCIPhaveVarsCommonClique(scip, x, xval, y, TRUE, FALSE) )
3604  {
3605  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, 0.0));
3606  }
3607  else if( SCIPhaveVarsCommonClique(scip, x, xval, y, FALSE, FALSE) )
3608  {
3609  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, 1.0));
3610  }
3611 
3612  return SCIP_OKAY;
3613  }
3614 
3615  /* analyze implications for x = xval */
3616  nimpls = SCIPvarGetNImpls(x, xval);
3617  if( nimpls == 0 )
3618  return SCIP_OKAY;
3619 
3620  implvars = SCIPvarGetImplVars (x, xval);
3621  impltypes = SCIPvarGetImplTypes (x, xval);
3622  implbounds = SCIPvarGetImplBounds(x, xval);
3623 
3624  assert(implvars != NULL);
3625  assert(impltypes != NULL);
3626  assert(implbounds != NULL);
3627 
3628  /* find implications */
3629  if( !SCIPsortedvecFindPtr((void**)implvars, SCIPvarComp, (void*)y, nimpls, &pos) )
3630  return SCIP_OKAY;
3631 
3632  /* if there are several implications on y, go to the first one */
3633  while( pos > 0 && implvars[pos-1] == y )
3634  --pos;
3635 
3636  /* update implied lower and upper bounds on y
3637  * but make sure that resultant will not be empty, due to tolerances
3638  */
3639  while( pos < nimpls && implvars[pos] == y )
3640  {
3641  if( impltypes[pos] == SCIP_BOUNDTYPE_LOWER )
3642  resultant->inf = MAX(resultant->inf, MIN(resultant->sup, implbounds[pos]));
3643  else
3644  resultant->sup = MIN(resultant->sup, MAX(resultant->inf, implbounds[pos]));
3645  ++pos;
3646  }
3647 
3648  assert(resultant->sup >= resultant->inf);
3649 
3650  return SCIP_OKAY;
3651 }
3652 
3653 /** Reformulates products of binary times bounded continuous variables as system of linear inequalities (plus auxiliary variable).
3654  *
3655  * For a product x*y, with y a binary variable and x a continous variable with finite bounds,
3656  * 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.
3657  *
3658  * 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.
3659  * For each product of linear term of length at most maxnrvar with y, an auxiliary z and linear inequalities are added.
3660  *
3661  * If y is a binary variable, the AND constraint \f$ z = x \wedge y \f$ may be added instead of linear constraints.
3662  */
3663 static
3665  SCIP* scip, /**< SCIP data structure */
3666  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3667  SCIP_CONS* cons, /**< constraint */
3668  int* naddconss /**< buffer where to add the number of auxiliary constraints added */
3669  )
3670 { /*lint --e{666} */
3671  SCIP_CONSHDLRDATA* conshdlrdata;
3672  SCIP_CONSDATA* consdata;
3673  SCIP_VAR** xvars;
3674  SCIP_Real* xcoef;
3675  SCIP_INTERVAL xbndszero;
3676  SCIP_INTERVAL xbndsone;
3677  SCIP_INTERVAL act0;
3678  SCIP_INTERVAL act1;
3679  int nxvars;
3680  SCIP_VAR* y;
3681  SCIP_VAR* bvar;
3682  char name[SCIP_MAXSTRLEN];
3683  int nbilinterms;
3684  SCIP_VAR* auxvar;
3685  SCIP_CONS* auxcons;
3686  int i;
3687  int j;
3688  int k;
3689  int bilinidx;
3690  SCIP_Real bilincoef;
3691  SCIP_Real mincoef;
3692  SCIP_Real maxcoef;
3693  int* todelete;
3694  int ntodelete;
3695  int maxnrvar;
3696  SCIP_Bool integral;
3697  SCIP_Longint gcd;
3698  SCIP_Bool auxvarinitial;
3699  SCIP_Bool auxvarremovable;
3700 
3701  assert(scip != NULL);
3702  assert(conshdlr != NULL);
3703  assert(cons != NULL);
3704  assert(naddconss != NULL);
3705 
3706  /* if no binary variables, then we will find nothing to reformulate here
3707  * (note that this does not count in integer variables with {0,1} bounds...)
3708  */
3709  if( SCIPgetNBinVars(scip) == 0 )
3710  return SCIP_OKAY;
3711 
3712  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3713  assert(conshdlrdata != NULL);
3714 
3715  maxnrvar = conshdlrdata->replacebinaryprodlength;
3716  if( maxnrvar == 0 )
3717  return SCIP_OKAY;
3718 
3719  consdata = SCIPconsGetData(cons);
3720  assert(consdata != NULL);
3721 
3722  xvars = NULL;
3723  xcoef = NULL;
3724  todelete = NULL;
3725  gcd = 0;
3726 
3727  for( i = 0; i < consdata->nquadvars; ++i )
3728  {
3729  y = consdata->quadvarterms[i].var;
3730  if( !SCIPvarIsBinary(y) )
3731  continue;
3732 
3733  nbilinterms = consdata->quadvarterms[i].nadjbilin;
3734  if( nbilinterms == 0 )
3735  continue;
3736 
3737  SCIP_CALL( SCIPreallocBufferArray(scip, &xvars, MIN(maxnrvar, nbilinterms)+2) ); /* add 2 for later use when creating linear constraints */
3738  SCIP_CALL( SCIPreallocBufferArray(scip, &xcoef, MIN(maxnrvar, nbilinterms)+2) );
3739 
3740  /* alloc array to store indices of bilinear terms that shall be deleted */
3741  SCIP_CALL( SCIPreallocBufferArray(scip, &todelete, nbilinterms) );
3742  ntodelete = 0;
3743 
3744  auxvarinitial = SCIPvarIsInitial(y);
3745  auxvarremovable = SCIPvarIsRemovable(y);
3746 
3747  /* 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)
3748  * and compute range of sum_i a_i*x_i for the cases y = 0 and y = 1
3749  * we may need several rounds if maxnrvar < nbilinterms
3750  */
3751  j = 0;
3752  do
3753  {
3754  nxvars = 0;
3755  SCIPintervalSet(&xbndszero, 0.0);
3756  SCIPintervalSet(&xbndsone, 0.0);
3757 
3758  mincoef = SCIPinfinity(scip);
3759  maxcoef = 0.0;
3760  integral = TRUE;
3761 
3762  /* collect at most maxnrvar variables for x term */
3763  for( ; j < nbilinterms && nxvars < maxnrvar; ++j )
3764  {
3765  bilinidx = consdata->quadvarterms[i].adjbilin[j];
3766  assert(bilinidx >= 0);
3767  assert(bilinidx < consdata->nbilinterms);
3768 
3769  bvar = consdata->bilinterms[bilinidx].var1;
3770  if( bvar == y )
3771  bvar = consdata->bilinterms[bilinidx].var2;
3772  assert(bvar != y);
3773 
3774  /* skip products with unbounded variables */
3775  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(bvar)) || SCIPisInfinity(scip, SCIPvarGetUbGlobal(bvar)) )
3776  {
3777  SCIPdebugMsg(scip, "skip reform of <%s><%s> due to unbounded second variable [%g,%g]\n",
3779  continue;
3780  }
3781 
3782  /* skip products with non-binary variables if binreformbinaryonly is set */
3783  if( conshdlrdata->binreformbinaryonly && !SCIPvarIsBinary(bvar) )
3784  {
3785  SCIPdebugMsg(scip, "skip reform of <%s><%s> because second variable is not binary\n",
3786  SCIPvarGetName(y), SCIPvarGetName(bvar));
3787  continue;
3788  }
3789 
3790  bilincoef = consdata->bilinterms[bilinidx].coef;
3791  assert(bilincoef != 0.0);
3792 
3793  /* get activity of bilincoef * x if y = 0 */
3794  SCIP_CALL( getImpliedBounds(scip, y, FALSE, bvar, &act0) );
3795  SCIPintervalMulScalar(SCIPinfinity(scip), &act0, act0, bilincoef);
3796 
3797  /* get activity of bilincoef * x if y = 1 */
3798  SCIP_CALL( getImpliedBounds(scip, y, TRUE, bvar, &act1) );
3799  SCIPintervalMulScalar(SCIPinfinity(scip), &act1, act1, bilincoef);
3800 
3801  /* skip products that give rise to very large coefficients (big big-M's) */
3802  if( SCIPfeastol(scip) * REALABS(act0.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act0.sup) >= conshdlrdata->binreformmaxcoef )
3803  {
3804  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 0.0\n",
3805  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act0), SCIPintervalGetSup(act0), SCIPvarGetName(y));
3806  continue;
3807  }
3808  if( SCIPfeastol(scip) * REALABS(act1.inf) >= conshdlrdata->binreformmaxcoef || SCIPfeastol(scip) * REALABS(act1.sup) >= conshdlrdata->binreformmaxcoef )
3809  {
3810  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity [%g,%g] for <%s> = 1.0\n",
3811  bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar), SCIPintervalGetInf(act1), SCIPintervalGetSup(act1), SCIPvarGetName(y));
3812  continue;
3813  }
3814  if( !SCIPisZero(scip, MIN(REALABS(act0.inf), REALABS(act0.sup))) &&
3815  SCIPfeastol(scip) * MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)) >= conshdlrdata->binreformmaxcoef )
3816  {
3817  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3818  MAX(REALABS(act0.inf), REALABS(act0.sup)) / MIN(REALABS(act0.inf), REALABS(act0.sup)), SCIPvarGetName(y));
3819  continue;
3820  }
3821  if( !SCIPisZero(scip, MIN(REALABS(act1.inf), REALABS(act1.sup))) &&
3822  SCIPfeastol(scip) * MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)) >= conshdlrdata->binreformmaxcoef )
3823  {
3824  SCIPdebugMsg(scip, "skip reform of %g<%s><%s> due to huge activity ratio %g for <%s> = 0.0\n", bilincoef, SCIPvarGetName(y), SCIPvarGetName(bvar),
3825  MAX(REALABS(act1.inf), REALABS(act1.sup)) / MIN(REALABS(act1.inf), REALABS(act1.sup)), SCIPvarGetName(y));
3826  continue;
3827  }
3828 
3829  /* add bvar to x term */
3830  xvars[nxvars] = bvar;
3831  xcoef[nxvars] = bilincoef;
3832  ++nxvars;
3833 
3834  /* update bounds on x term */
3835  SCIPintervalAdd(SCIPinfinity(scip), &xbndszero, xbndszero, act0);
3836  SCIPintervalAdd(SCIPinfinity(scip), &xbndsone, xbndsone, act1);
3837 
3838  if( REALABS(bilincoef) < mincoef )
3839  mincoef = ABS(bilincoef);
3840  if( REALABS(bilincoef) > maxcoef )
3841  maxcoef = ABS(bilincoef);
3842 
3843  /* update whether all coefficients will be integral and if so, compute their gcd */
3844  integral &= (SCIPvarGetType(bvar) < SCIP_VARTYPE_CONTINUOUS) && SCIPisIntegral(scip, bilincoef); /*lint !e514 */
3845  if( integral )
3846  {
3847  if( nxvars == 1 )
3848  gcd = (SCIP_Longint)SCIPround(scip, REALABS(bilincoef));
3849  else
3850  gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)SCIPround(scip, REALABS(bilincoef)));
3851  }
3852 
3853  /* if bvar is initial, then also the auxiliary variable should be initial
3854  * if bvar is not removable, then also the auxiliary variable should not be removable
3855  */
3856  auxvarinitial |= SCIPvarIsInitial(bvar);
3857  auxvarremovable &= SCIPvarIsRemovable(bvar);
3858 
3859  /* remember that we have to remove this bilinear term later */
3860  assert(ntodelete < nbilinterms);
3861  todelete[ntodelete++] = bilinidx;
3862  }
3863 
3864  if( nxvars == 0 ) /* all (remaining) x_j seem to be unbounded */
3865  break;
3866 
3867  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndszero)));
3868  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndszero)));
3869  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(xbndsone)));
3870  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(xbndsone)));
3871 
3872 #ifdef SCIP_DEBUG
3873  if( SCIPintervalGetInf(xbndszero) != SCIPintervalGetInf(xbndsone) || /*lint !e777*/
3874  +SCIPintervalGetSup(xbndszero) != SCIPintervalGetSup(xbndsone) ) /*lint !e777*/
3875  {
3876  SCIPdebugMsg(scip, "got different bounds for y = 0: [%g, %g] and y = 1: [%g, %g]\n", xbndszero.inf, xbndszero.sup, xbndsone.inf, xbndsone.sup);
3877  }
3878 #endif
3879 
3880  if( nxvars == 1 && conshdlrdata->empathy4and >= 1 && SCIPvarIsBinary(xvars[0]) )
3881  {
3882  /* product of two binary variables, replace by auxvar and AND constraint */
3883  /* add auxiliary variable z */
3884  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3885  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT,
3886  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3887  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3888 
3889 #ifdef WITH_DEBUG_SOLUTION
3890  if( SCIPdebugIsMainscip(scip) )
3891  {
3892  SCIP_Real var0val;
3893  SCIP_Real var1val;
3894  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[0], &var0val) );
3895  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &var1val) );
3896  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, var0val * var1val) );
3897  }
3898 #endif
3899 
3900  /* add constraint z = x and y; need to be enforced, as it is not redundant w.r.t. existing constraints */
3901  xvars[1] = y;
3902  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%sAND%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3903  SCIP_CALL( SCIPcreateConsAnd(scip, &auxcons, name, auxvar, 2, xvars,
3904  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
3905  SCIPconsIsSeparated(cons), TRUE, TRUE,
3908  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3909  SCIPdebugMsg(scip, "added AND constraint: ");
3910  SCIPdebugPrintCons(scip, auxcons, NULL);
3911  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3912  ++*naddconss;
3913 
3914  /* add linear term coef*auxvar */
3915  SCIP_CALL( addLinearCoef(scip, cons, auxvar, xcoef[0]) );
3916 
3917  /* forget about auxvar */
3918  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3919  }
3920  else
3921  {
3922  /* product of binary variable with more than one binary or with continuous variables or with binary and user
3923  * did not like AND -> replace by auxvar and linear constraints */
3924  SCIP_Real scale;
3925 
3926  /* scale auxiliary constraint by some nice value,
3927  * if all coefficients are integral, take a value that preserves integrality (-> gcd), so we can make the auxiliary variable impl. integer
3928  */
3929  if( integral )
3930  {
3931  scale = (SCIP_Real)gcd;
3932  assert(scale >= 1.0);
3933  }
3934  else if( nxvars == 1 )
3935  {
3936  /* scaling by the only coefficient gives auxiliary variable = x * y, which thus will be implicit integral provided y is not continuous */
3937  assert(mincoef == maxcoef); /*lint !e777 */
3938  scale = mincoef;
3939  integral = SCIPvarGetType(xvars[0]) < SCIP_VARTYPE_CONTINUOUS;
3940  }
3941  else
3942  {
3943  scale = 1.0;
3944  if( maxcoef < 0.5 )
3945  scale = maxcoef;
3946  if( mincoef > 2.0 )
3947  scale = mincoef;
3948  if( scale != 1.0 )
3949  scale = SCIPselectSimpleValue(scale / 2.0, 1.5 * scale, MAXDNOM);
3950  }
3951  assert(scale > 0.0);
3952  assert(!SCIPisInfinity(scip, scale));
3953 
3954  /* if x-term is always negative for y = 1, negate scale so we get a positive auxiliary variable; maybe this is better sometimes? */
3955  if( !SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
3956  scale = -scale;
3957 
3958  SCIPdebugMsg(scip, "binary reformulation using scale %g, nxvars = %d, integral = %u\n", scale, nxvars, integral);
3959  if( scale != 1.0 )
3960  {
3961  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndszero, xbndszero, scale);
3962  SCIPintervalDivScalar(SCIPinfinity(scip), &xbndsone, xbndsone, scale);
3963  for( k = 0; k < nxvars; ++k )
3964  xcoef[k] /= scale;
3965  }
3966 
3967  /* add auxiliary variable z */
3968  if( nxvars == 1 )
3969  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3970  else
3971  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "prod%s_%s_more_%s", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
3972  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, MIN(0., SCIPintervalGetInf(xbndsone)), MAX(0., SCIPintervalGetSup(xbndsone)),
3974  auxvarinitial, auxvarremovable, NULL, NULL, NULL, NULL, NULL) );
3975  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3976 
3977  /* compute value of auxvar in debug solution */
3978 #ifdef WITH_DEBUG_SOLUTION
3979  if( SCIPdebugIsMainscip(scip) )
3980  {
3981  SCIP_Real debugval;
3982  SCIP_Real varval;
3983 
3984  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &varval) );
3985  if( SCIPisZero(scip, varval) )
3986  {
3987  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, 0.0) );
3988  }
3989  else
3990  {
3991  assert(SCIPisEQ(scip, varval, 1.0));
3992 
3993  debugval = 0.0;
3994  for( k = 0; k < nxvars; ++k )
3995  {
3996  SCIP_CALL( SCIPdebugGetSolVal(scip, xvars[k], &varval) );
3997  debugval += xcoef[k] * varval;
3998  }
3999  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
4000  }
4001  }
4002 #endif
4003 
4004  /* add auxiliary constraints
4005  * it seems to be advantageous to make the varbound constraints initial and the linear constraints not initial
4006  * maybe because it is more likely that a binary variable takes value 0 instead of 1, and thus the varbound constraints
4007  * are more often active, compared to the linear constraints added below
4008  * also, the varbound constraints are more sparse than the linear cons
4009  */
4010  if( SCIPisNegative(scip, SCIPintervalGetInf(xbndsone)) )
4011  {
4012  /* add 0 <= z - xbndsone.inf * y constraint (as varbound constraint), need to be enforced as not redundant */
4013  if( nxvars == 1 )
4014  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4015  else
4016  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_1", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4017  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetInf(xbndsone), 0.0, SCIPinfinity(scip),
4018  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
4019  SCIPconsIsSeparated(cons), TRUE, TRUE,
4022  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4023  SCIPdebugMsg(scip, "added varbound constraint: ");
4024  SCIPdebugPrintCons(scip, auxcons, NULL);
4025  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4026  ++*naddconss;
4027  }
4028  if( SCIPisPositive(scip, SCIPintervalGetSup(xbndsone)) )
4029  {
4030  /* add z - xbndsone.sup * y <= 0 constraint (as varbound constraint), need to be enforced as not redundant */
4031  if( nxvars == 1 )
4032  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4033  else
4034  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_2", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4035  SCIP_CALL( SCIPcreateConsVarbound(scip, &auxcons, name, auxvar, y, -SCIPintervalGetSup(xbndsone), -SCIPinfinity(scip), 0.0,
4036  SCIPconsIsInitial(cons) /*&& conshdlrdata->binreforminitial*/,
4037  SCIPconsIsSeparated(cons), TRUE, TRUE,
4040  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4041  SCIPdebugMsg(scip, "added varbound constraint: ");
4042  SCIPdebugPrintCons(scip, auxcons, NULL);
4043  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4044  ++*naddconss;
4045  }
4046 
4047  /* add xbndszero.inf <= sum_i a_i*x_i + xbndszero.inf * y - z constraint, need to be enforced as not redundant */
4048  xvars[nxvars] = y;
4049  xvars[nxvars+1] = auxvar;
4050  xcoef[nxvars] = SCIPintervalGetInf(xbndszero);
4051  xcoef[nxvars+1] = -1;
4052 
4053  if( nxvars == 1 )
4054  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4055  else
4056  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_3", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4057  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, SCIPintervalGetInf(xbndszero), SCIPinfinity(scip),
4058  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
4059  SCIPconsIsSeparated(cons), TRUE, TRUE,
4062  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4063  SCIPdebugMsg(scip, "added linear constraint: ");
4064  SCIPdebugPrintCons(scip, auxcons, NULL);
4065  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4066  ++*naddconss;
4067 
4068  /* add sum_i a_i*x_i + xbndszero.sup * y - z <= xbndszero.sup constraint, need to be enforced as not redundant */
4069  xcoef[nxvars] = SCIPintervalGetSup(xbndszero);
4070 
4071  if( nxvars == 1 )
4072  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4073  else
4074  (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "linreform%s*%s*more_%s_4", SCIPvarGetName(y), SCIPvarGetName(xvars[0]), SCIPconsGetName(cons));
4075  SCIP_CALL( SCIPcreateConsLinear(scip, &auxcons, name, nxvars+2, xvars, xcoef, -SCIPinfinity(scip), SCIPintervalGetSup(xbndszero),
4076  SCIPconsIsInitial(cons) && conshdlrdata->binreforminitial,
4077  SCIPconsIsSeparated(cons), TRUE, TRUE,
4080  SCIP_CALL( SCIPaddCons(scip, auxcons) );
4081  SCIPdebugMsg(scip, "added linear constraint: ");
4082  SCIPdebugPrintCons(scip, auxcons, NULL);
4083  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
4084  ++*naddconss;
4085 
4086  /* add linear term scale*auxvar to this constraint */
4087  SCIP_CALL( addLinearCoef(scip, cons, auxvar, scale) );
4088 
4089  /* forget about auxvar */
4090  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4091  }
4092  }
4093  while( j < nbilinterms );
4094 
4095  /* remove bilinear terms that have been replaced */
4096  SCIP_CALL( removeBilinearTermsPos(scip, cons, ntodelete, todelete) );
4097  }
4098  SCIPdebugMsg(scip, "resulting quadratic constraint: ");
4099  SCIPdebugPrintCons(scip, cons, NULL);
4100 
4101  SCIPfreeBufferArrayNull(scip, &todelete);
4102  SCIPfreeBufferArrayNull(scip, &xcoef);
4103  SCIPfreeBufferArrayNull(scip, &xvars);
4104 
4105  return SCIP_OKAY;
4106 }
4107 
4108 /** tries to automatically convert a quadratic constraint (or a part of it) into a more specific and more specialized constraint */
4109 static
4111  SCIP* scip, /**< SCIP data structure */
4112  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4113  SCIP_CONS* cons, /**< source constraint to try to convert */
4114  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
4115  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
4116  int* naddconss, /**< buffer to increase with number of additional constraints created during upgrade */
4117  SCIP_PRESOLTIMING presoltiming /**< current presolving timing */
4118  )
4119 {
4120  SCIP_CONSHDLRDATA* conshdlrdata;
4121  SCIP_CONSDATA* consdata;
4122  SCIP_VAR* var;
4123  SCIP_Real lincoef;
4124  SCIP_Real quadcoef;
4125  SCIP_Real lb;
4126  SCIP_Real ub;
4127  int nbinlin;
4128  int nbinquad;
4129  int nintlin;
4130  int nintquad;
4131  int nimpllin;
4132  int nimplquad;
4133  int ncontlin;
4134  int ncontquad;
4135  SCIP_Bool integral;
4136  int i;
4137  int j;
4138  SCIP_CONS** upgdconss;
4139  int upgdconsssize;
4140  int nupgdconss_;
4141 
4142  assert(scip != NULL);
4143  assert(conshdlr != NULL);
4144  assert(cons != NULL);
4145  assert(!SCIPconsIsModifiable(cons));
4146  assert(upgraded != NULL);
4147  assert(nupgdconss != NULL);
4148  assert(naddconss != NULL);
4149 
4150  *upgraded = FALSE;
4151 
4152  nupgdconss_ = 0;
4153 
4154  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4155  assert(conshdlrdata != NULL);
4156 
4157  /* if there are no upgrade methods, we can also stop */
4158  if( conshdlrdata->nquadconsupgrades == 0 )
4159  return SCIP_OKAY;
4160 
4161  upgdconsssize = 2;
4162  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
4163 
4164  consdata = SCIPconsGetData(cons);
4165  assert(consdata != NULL);
4166 
4167  /* calculate some statistics on quadratic constraint */
4168  nbinlin = 0;
4169  nbinquad = 0;
4170  nintlin = 0;
4171  nintquad = 0;
4172  nimpllin = 0;
4173  nimplquad = 0;
4174  ncontlin = 0;
4175  ncontquad = 0;
4176  integral = TRUE;
4177  for( i = 0; i < consdata->nlinvars; ++i )
4178  {
4179  var = consdata->linvars[i];
4180  lincoef = consdata->lincoefs[i];
4181  lb = SCIPvarGetLbLocal(var);
4182  ub = SCIPvarGetUbLocal(var);
4183  assert(!SCIPisZero(scip, lincoef));
4184 
4185  switch( SCIPvarGetType(var) )
4186  {
4187  case SCIP_VARTYPE_BINARY:
4188  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4189  integral = integral && SCIPisIntegral(scip, lincoef);
4190  nbinlin++;
4191  break;
4192  case SCIP_VARTYPE_INTEGER:
4193  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4194  integral = integral && SCIPisIntegral(scip, lincoef);
4195  nintlin++;
4196  break;
4197  case SCIP_VARTYPE_IMPLINT:
4198  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4199  integral = integral && SCIPisIntegral(scip, lincoef);
4200  nimpllin++;
4201  break;
4203  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb);
4204  ncontlin++;
4205  break;
4206  default:
4207  SCIPerrorMessage("unknown variable type\n");
4208  return SCIP_INVALIDDATA;
4209  }
4210  }
4211 
4212  for( i = 0; i < consdata->nquadvars; ++i )
4213  {
4214  var = consdata->quadvarterms[i].var;
4215  lincoef = consdata->quadvarterms[i].lincoef;
4216  quadcoef = consdata->quadvarterms[i].sqrcoef;
4217  lb = SCIPvarGetLbLocal(var);
4218  ub = SCIPvarGetUbLocal(var);
4219 
4220  switch( SCIPvarGetType(var) )
4221  {
4222  case SCIP_VARTYPE_BINARY:
4223  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4224  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4225  nbinquad++;
4226  break;
4227  case SCIP_VARTYPE_INTEGER:
4228  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4229  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4230  nintquad++;
4231  break;
4232  case SCIP_VARTYPE_IMPLINT:
4233  if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
4234  integral = integral && SCIPisIntegral(scip, lincoef) && SCIPisIntegral(scip, quadcoef);
4235  nimplquad++;
4236  break;
4238  integral = integral && SCIPisRelEQ(scip, lb, ub) && SCIPisIntegral(scip, lincoef * lb + quadcoef * lb * lb);
4239  ncontquad++;
4240  break;
4241  default:
4242  SCIPerrorMessage("unknown variable type\n");
4243  return SCIP_INVALIDDATA;
4244  }
4245  }
4246 
4247  if( integral )
4248  {
4249  for( i = 0; i < consdata->nbilinterms && integral; ++i )
4250  {
4251  if( SCIPvarGetType(consdata->bilinterms[i].var1) < SCIP_VARTYPE_CONTINUOUS && SCIPvarGetType(consdata->bilinterms[i].var2) < SCIP_VARTYPE_CONTINUOUS )
4252  integral = integral && SCIPisIntegral(scip, consdata->bilinterms[i].coef);
4253  else
4254  integral = FALSE;
4255  }
4256  }
4257 
4258  /* call the upgrading methods */
4259 
4260  SCIPdebugMsg(scip, "upgrading quadratic constraint <%s> (%d upgrade methods):\n",
4261  SCIPconsGetName(cons), conshdlrdata->nquadconsupgrades);
4262  SCIPdebugMsg(scip, " binlin=%d binquad=%d intlin=%d intquad=%d impllin=%d implquad=%d contlin=%d contquad=%d integral=%u\n",
4263  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral);
4264  SCIPdebugPrintCons(scip, cons, NULL);
4265 
4266  /* try all upgrading methods in priority order in case the upgrading step is enable */
4267  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
4268  {
4269  if( !conshdlrdata->quadconsupgrades[i]->active )
4270  continue;
4271 
4272  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4273  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4274  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4275 
4276  while( nupgdconss_ < 0 )
4277  {
4278  /* upgrade function requires more memory: resize upgdconss and call again */
4279  assert(-nupgdconss_ > upgdconsssize);
4280  upgdconsssize = -nupgdconss_;
4281  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
4282 
4283  SCIP_CALL( conshdlrdata->quadconsupgrades[i]->quadconsupgd(scip, cons,
4284  nbinlin, nbinquad, nintlin, nintquad, nimpllin, nimplquad, ncontlin, ncontquad, integral,
4285  &nupgdconss_, upgdconss, upgdconsssize, presoltiming) );
4286 
4287  assert(nupgdconss_ != 0);
4288  }
4289 
4290  if( nupgdconss_ > 0 )
4291  {
4292  /* got upgrade */
4293  SCIPdebugPrintCons(scip, cons, NULL);
4294  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
4295 
4296  /* add the upgraded constraints to the problem and forget them */
4297  for( j = 0; j < nupgdconss_; ++j )
4298  {
4299  SCIPdebugMsgPrint(scip, "\t");
4300  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
4301 
4302  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
4303  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
4304  }
4305 
4306  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
4307  *nupgdconss += 1;
4308  *naddconss += nupgdconss_ - 1;
4309  *upgraded = TRUE;
4310 
4311  /* delete upgraded constraint */
4312  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
4313  SCIP_CALL( SCIPdelCons(scip, cons) );
4314 
4315  break;
4316  }
4317  }
4318 
4319  SCIPfreeBufferArray(scip, &upgdconss);
4320 
4321  return SCIP_OKAY;
4322 }
4323 
4324 /** helper function for presolveDisaggregate */
4325 static
4327  SCIP* scip, /**< SCIP data structure */
4328  SCIP_CONSDATA* consdata, /**< constraint data */
4329  int quadvaridx, /**< index of quadratic variable to mark */
4330  SCIP_HASHMAP* var2component, /**< variables to components mapping */
4331  int componentnr, /**< the component number to mark to */
4332  int* componentsize /**< buffer to store size of component (incremented by 1) */
4333  )
4334 {
4335  SCIP_QUADVARTERM* quadvarterm;
4336  SCIP_VAR* othervar;
4337  int othervaridx;
4338  int i;
4339 
4340  assert(consdata != NULL);
4341  assert(quadvaridx >= 0);
4342  assert(quadvaridx < consdata->nquadvars);
4343  assert(var2component != NULL);
4344  assert(componentnr >= 0);
4345 
4346  quadvarterm = &consdata->quadvarterms[quadvaridx];
4347 
4348  if( SCIPhashmapExists(var2component, quadvarterm->var) )
4349  {
4350  /* if we saw the variable before, then it should have the same component number */
4351  assert(SCIPhashmapGetImageInt(var2component, quadvarterm->var) == componentnr);
4352  return SCIP_OKAY;
4353  }
4354 
4355  /* assign component number to variable */
4356  SCIP_CALL( SCIPhashmapInsertInt(var2component, quadvarterm->var, componentnr) );
4357  ++*componentsize;
4358 
4359  /* assign same component number to all variables this variable is multiplied with */
4360  for( i = 0; i < quadvarterm->nadjbilin; ++i )
4361  {
4362  othervar = consdata->bilinterms[quadvarterm->adjbilin[i]].var1 == quadvarterm->var ?
4363  consdata->bilinterms[quadvarterm->adjbilin[i]].var2 : consdata->bilinterms[quadvarterm->adjbilin[i]].var1;
4364  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, othervar, &othervaridx) );
4365  assert(othervaridx >= 0);
4366  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, othervaridx, var2component, componentnr, componentsize) );
4367  }
4368 
4369  return SCIP_OKAY;
4370 }
4371 
4372 /** merges components in variables connectivity graph */
4373 static
4375  SCIP* scip, /**< SCIP data structure */
4376  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4377  SCIP_HASHMAP* var2component, /**< variables to component mapping */
4378  int nvars, /**< number of variables */
4379  int* ncomponents, /**< number of components */
4380  int* componentssize /**< size of components */
4381  )
4382 {
4383  SCIP_CONSHDLRDATA* conshdlrdata;
4384  SCIP_HASHMAPENTRY* entry;
4385  int maxncomponents;
4386  int* oldcompidx;
4387  int* newcompidx;
4388  int i;
4389  int oldcomponent;
4390  int newcomponent;
4391 
4392  assert(scip != NULL);
4393  assert(conshdlr != NULL);
4394  assert(var2component != NULL);
4395  assert(ncomponents != NULL);
4396  assert(componentssize != NULL);
4397 
4398  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4399  assert(conshdlrdata != NULL);
4400 
4401  maxncomponents = conshdlrdata->maxdisaggrsize;
4402  assert(maxncomponents > 0);
4403 
4404  /* if already not too many components, then nothing to do */
4405  if( *ncomponents <= maxncomponents )
4406  return SCIP_OKAY;
4407 
4408  /*
4409  printf("component sizes before:");
4410  for( i = 0; i < *ncomponents; ++i )
4411  printf(" %d", componentssize[i]);
4412  printf("\n");
4413  */
4414 
4415  SCIP_CALL( SCIPallocBufferArray(scip, &oldcompidx, *ncomponents) );
4416  SCIP_CALL( SCIPallocBufferArray(scip, &newcompidx, *ncomponents) );
4417 
4418  for( i = 0; i < *ncomponents; ++i )
4419  oldcompidx[i] = i;
4420 
4421  switch( conshdlrdata->disaggrmergemethod )
4422  {
4423  case 's' :
4424  /* sort components by size, increasing order */
4425  SCIPsortIntInt(componentssize, oldcompidx, *ncomponents);
4426  break;
4427  case 'b' :
4428  case 'm' :
4429  /* sort components by size, decreasing order */
4430  SCIPsortDownIntInt(componentssize, oldcompidx, *ncomponents);
4431  break;
4432  default :
4433  SCIPerrorMessage("invalid value for constraints/quadratic/disaggrmergemethod parameter");
4434  return SCIP_PARAMETERWRONGVAL;
4435  }
4436 
4437  SCIPdebugMsg(scip, "%-30s: % 4d components of size % 4d to % 4d, median: % 4d\n", SCIPgetProbName(scip), *ncomponents, componentssize[0], componentssize[*ncomponents-1], componentssize[*ncomponents/2]);
4438 
4439  if( conshdlrdata->disaggrmergemethod == 'm' )
4440  {
4441  SCIP_Real targetsize;
4442  int count = 0;
4443 
4444  /* a minimal component size we should reach to have all components roughly the same size */
4445  targetsize = nvars / maxncomponents; /*lint !e653*/
4446  for( i = 0; i < *ncomponents; ++i )
4447  {
4448  newcompidx[oldcompidx[i]] = i;
4449  count += componentssize[i];
4450 
4451  /* fill with small components until we reach targetsize
4452  * Since targetsize might be fractional, we also add another component if
4453  * the number of variables remaining (=nvars-count) is larger than
4454  * what we expect to put into the remaining components (=targetsize * (maxncomponents - i-1)).
4455  * Thus, from time to time, a component is made larger than the targetsize to avoid
4456  * having to add much into the last component.
4457  */
4458  while( i < *ncomponents-1 && (componentssize[i] + componentssize[*ncomponents-1] <= targetsize ||
4459  nvars - count > targetsize * (maxncomponents - i)) )
4460  {
4461  /* map last (=smallest) component to component i */
4462  newcompidx[oldcompidx[*ncomponents-1]] = i;
4463 
4464  /* increase size of component i accordingly */
4465  componentssize[i] += componentssize[*ncomponents-1];
4466  count += componentssize[*ncomponents-1];
4467 
4468  /* forget about last component */
4469  --*ncomponents;
4470  }
4471  }
4472  assert(count == nvars);
4473  }
4474  else
4475  {
4476  /* get inverse permutation */
4477  for( i = 0; i < *ncomponents; ++i )
4478  newcompidx[oldcompidx[i]] = i;
4479  }
4480 
4481  /* assign new component numbers to variables, cutting off at maxncomponents */
4482  for( i = 0; i < SCIPhashmapGetNEntries(var2component); ++i )
4483  {
4484  entry = SCIPhashmapGetEntry(var2component, i);
4485  if( entry == NULL )
4486  continue;
4487 
4488  oldcomponent = (int)(size_t)SCIPhashmapEntryGetImage(entry);
4489 
4490  newcomponent = newcompidx[oldcomponent];
4491  if( newcomponent >= maxncomponents )
4492  {
4493  newcomponent = maxncomponents-1;
4494  ++componentssize[maxncomponents-1];
4495  }
4496 
4497  SCIPhashmapEntrySetImage(entry, (void*)(size_t)newcomponent); /*lint !e571*/
4498  }
4499  if( *ncomponents > maxncomponents )
4500  *ncomponents = maxncomponents;
4501 
4502  /*
4503  printf("component sizes after :");
4504  for( i = 0; i < *ncomponents; ++i )
4505  printf(" %d", componentssize[i]);
4506  printf("\n");
4507  */
4508 
4509  SCIPfreeBufferArray(scip, &newcompidx);
4510  SCIPfreeBufferArray(scip, &oldcompidx);
4511 
4512  return SCIP_OKAY;
4513 }
4514 
4515 /** compute the next highest power of 2 for a 32-bit argument
4516  *
4517  * Source: https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
4518  *
4519  * @note Returns 0 for v=0.
4520  */
4521 static
4522 unsigned int nextPowerOf2(
4523  unsigned int v /**< input */
4524  )
4525 {
4526  v--;
4527  v |= v >> 1;
4528  v |= v >> 2;
4529  v |= v >> 4;
4530  v |= v >> 8;
4531  v |= v >> 16;
4532  v++;
4533 
4534  return v;
4535 }
4536 
4537 
4538 /** for quadratic constraints that consists of a sum of quadratic terms, disaggregates the sum into a set of constraints by introducing auxiliary variables
4539  *
4540  * Assume the quadratic constraint can be written in the form
4541  * lhs <= b'x + sum_{k=1..p} q_k(x_k) <= rhs
4542  * where x_k denotes a subset of the variables in x and these subsets are pairwise disjunct
4543  * and q_k(.) is a quadratic form.
4544  * p is selected as large as possible, but to be <= conshdlrdata->maxdisaggrsize.
4545  *
4546  * Without additional scaling, the constraint is disaggregated into
4547  * lhs <= b'x + sum_k c_k z_k <= rhs
4548  * c_k z_k ~ q_k(x)
4549  * where "~" is either "<=", "==", or ">=", depending on whether lhs or rhs are infinite.
4550  * Further, c_k is chosen to be the maximal absolute value of the coefficients of the quadratic terms in q_k(x).
4551  * This is done to ensure that z_k takes values with a similar magnitute as the variables in x_k (better for separation).
4552  *
4553  * However, a solution of this disaggregated system can violate the original constraint by (p+1)*epsilon
4554  * (assuming unscaled violations are used, which is the default).
4555  * Therefore, all constraints are scaled by p+1:
4556  * (p+1)*lhs <= (p+1)*b'x + (p+1) * sum_k c_k z_k <= (p+1) * rhs
4557  * (p+1)*c_k z_k ~ (p+1)*q_k(x)
4558  */
4559 static
4561  SCIP* scip, /**< SCIP data structure */
4562  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
4563  SCIP_CONS* cons, /**< source constraint to try to convert */
4564  int* naddconss /**< pointer to counter of added constraints */
4565  )
4566 {
4567  SCIP_CONSDATA* consdata;
4568  SCIP_HASHMAP* var2component;
4569  int* componentssize;
4570  int ncomponents;
4571  int i;
4572  int comp;
4573  SCIP_CONS** auxconss;
4574  SCIP_VAR** auxvars;
4575  SCIP_Real* auxcoefs;
4576 #ifdef WITH_DEBUG_SOLUTION
4577  SCIP_Real* auxsolvals; /* value of auxiliary variable in debug solution */
4578 #endif
4579  SCIP_Real scale;
4580  char name[SCIP_MAXSTRLEN];
4581 
4582  assert(scip != NULL);
4583  assert(conshdlr != NULL);
4584  assert(cons != NULL);
4585  assert(naddconss != NULL);
4586 
4587  consdata = SCIPconsGetData(cons);
4588  assert(consdata != NULL);
4589 
4590  /* skip if constraint has been already disaggregated */
4591  if( consdata->isdisaggregated )
4592  return SCIP_OKAY;
4593 
4594  consdata->isdisaggregated = TRUE;
4595 
4596  /* make sure there are no quadratic variables without coefficients */
4597  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4598  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
4599 
4600  if( consdata->nquadvars <= 1 )
4601  return SCIP_OKAY;
4602 
4603  /* sort quadratic variable terms here, so we can later search in it without reordering the array */
4604  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4605 
4606  /* check how many quadratic terms with non-overlapping variables we have
4607  * in other words, the number of components in the sparsity graph of the quadratic term matrix
4608  */
4609  ncomponents = 0;
4610  SCIP_CALL( SCIPhashmapCreate(&var2component, SCIPblkmem(scip), consdata->nquadvars) );
4611  SCIP_CALL( SCIPallocBufferArray(scip, &componentssize, consdata->nquadvars) );
4612  for( i = 0; i < consdata->nquadvars; ++i )
4613  {
4614  /* if variable was marked already, skip it */
4615  if( SCIPhashmapExists(var2component, (void*)consdata->quadvarterms[i].var) )
4616  continue;
4617 
4618  /* start a new component with variable i */
4619  componentssize[ncomponents] = 0;
4620  SCIP_CALL( presolveDisaggregateMarkComponent(scip, consdata, i, var2component, ncomponents, componentssize + ncomponents) );
4621  ++ncomponents;
4622  }
4623 
4624  assert(ncomponents >= 1);
4625 
4626  /* if there is only one component, we cannot disaggregate
4627  * @todo we could still split the constraint into several while keeping the number of variables sharing several constraints as small as possible
4628  */
4629  if( ncomponents == 1 )
4630  {
4631  SCIPhashmapFree(&var2component);
4632  SCIPfreeBufferArray(scip, &componentssize);
4633  return SCIP_OKAY;
4634  }
4635 
4636  /* merge some components, if necessary */
4637  SCIP_CALL( presolveDisaggregateMergeComponents(scip, conshdlr, var2component, consdata->nquadvars, &ncomponents, componentssize) );
4638 
4639  SCIPfreeBufferArray(scip, &componentssize);
4640 
4641  /* scale all new constraints (ncomponents+1 many) by ncomponents+1 (or its next power of 2), so violations sum up to at most epsilon */
4642  scale = nextPowerOf2((unsigned int)ncomponents + 1);
4643 
4644  SCIP_CALL( SCIPallocBufferArray(scip, &auxconss, ncomponents) );
4645  SCIP_CALL( SCIPallocBufferArray(scip, &auxvars, ncomponents) );
4646  SCIP_CALL( SCIPallocBufferArray(scip, &auxcoefs, ncomponents) );
4647 #ifdef WITH_DEBUG_SOLUTION
4648  SCIP_CALL( SCIPallocClearBufferArray(scip, &auxsolvals, ncomponents) );
4649 #endif
4650 
4651  /* create auxiliary variables and empty constraints for each component */
4652  for( comp = 0; comp < ncomponents; ++comp )
4653  {
4654  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_comp%d", SCIPconsGetName(cons), comp);
4655 
4656  SCIP_CALL( SCIPcreateVar(scip, &auxvars[comp], name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
4658 
4659  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &auxconss[comp], name, 0, NULL, NULL, 0, NULL, 0, NULL,
4660  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : 0.0),
4661  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : 0.0),
4664  SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons)) );
4665 
4666  auxcoefs[comp] = SCIPinfinity(scip);
4667  }
4668 
4669  /* add quadratic variables to each component constraint
4670  * delete adjacency information */
4671  for( i = 0; i < consdata->nquadvars; ++i )
4672  {
4673  assert(SCIPhashmapExists(var2component, consdata->quadvarterms[i].var));
4674 
4675  comp = SCIPhashmapGetImageInt(var2component, consdata->quadvarterms[i].var);
4676  assert(comp >= 0);
4677  assert(comp < ncomponents);
4678 
4679  /* add variable term to corresponding constraint */
4680  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, auxconss[comp], consdata->quadvarterms[i].var, scale * consdata->quadvarterms[i].lincoef, scale * consdata->quadvarterms[i].sqrcoef) );
4681 
4682  /* reduce coefficient of aux variable */
4683  if( !SCIPisZero(scip, consdata->quadvarterms[i].lincoef) && ABS(consdata->quadvarterms[i].lincoef) < auxcoefs[comp] )
4684  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].lincoef);
4685  if( !SCIPisZero(scip, consdata->quadvarterms[i].sqrcoef) && ABS(consdata->quadvarterms[i].sqrcoef) < auxcoefs[comp] )
4686  auxcoefs[comp] = REALABS(consdata->quadvarterms[i].sqrcoef);
4687 
4688  SCIPfreeBlockMemoryArray(scip, &consdata->quadvarterms[i].adjbilin, consdata->quadvarterms[i].adjbilinsize);
4689  consdata->quadvarterms[i].nadjbilin = 0;
4690  consdata->quadvarterms[i].adjbilinsize = 0;
4691 
4692 #ifdef WITH_DEBUG_SOLUTION
4693  if( SCIPdebugIsMainscip(scip) )
4694  {
4695  SCIP_Real debugvarval;
4696 
4697  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->quadvarterms[i].var, &debugvarval) );
4698  auxsolvals[comp] += consdata->quadvarterms[i].lincoef * debugvarval + consdata->quadvarterms[i].sqrcoef * debugvarval * debugvarval;
4699  }
4700 #endif
4701  }
4702 
4703  /* add bilinear terms to each component constraint */
4704  for( i = 0; i < consdata->nbilinterms; ++i )
4705  {
4706  assert(SCIPhashmapExists(var2component, consdata->bilinterms[i].var1));
4707  assert(SCIPhashmapExists(var2component, consdata->bilinterms[i].var2));
4708 
4709  comp = SCIPhashmapGetImageInt(var2component, consdata->bilinterms[i].var1);
4710  assert(comp == SCIPhashmapGetImageInt(var2component, consdata->bilinterms[i].var2));
4711  assert(!SCIPisZero(scip, consdata->bilinterms[i].coef));
4712 
4713  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, auxconss[comp],
4714  consdata->bilinterms[i].var1, consdata->bilinterms[i].var2, scale * consdata->bilinterms[i].coef) );
4715 
4716  if( ABS(consdata->bilinterms[i].coef) < auxcoefs[comp] )
4717  auxcoefs[comp] = ABS(consdata->bilinterms[i].coef);
4718 
4719 #ifdef WITH_DEBUG_SOLUTION
4720  if( SCIPdebugIsMainscip(scip) )
4721  {
4722  SCIP_Real debugvarval1;
4723  SCIP_Real debugvarval2;
4724 
4725  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->bilinterms[i].var1, &debugvarval1) );
4726  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->bilinterms[i].var2, &debugvarval2) );
4727  auxsolvals[comp] += consdata->bilinterms[i].coef * debugvarval1 * debugvarval2;
4728  }
4729 #endif
4730  }
4731 
4732  /* forget about bilinear terms in cons */
4733  SCIPfreeBlockMemoryArray(scip, &consdata->bilinterms, consdata->bilintermssize);
4734  consdata->nbilinterms = 0;
4735  consdata->bilintermssize = 0;
4736 
4737  /* remove quadratic variable terms from cons */
4738  for( i = consdata->nquadvars - 1; i >= 0; --i )
4739  {
4740  SCIP_CALL( delQuadVarTermPos(scip, cons, i) );
4741  }
4742  assert(consdata->nquadvars == 0);
4743 
4744  /* scale remaining linear variables and sides by scale */
4745  for( i = 0; i < consdata->nlinvars; ++i )
4746  {
4747  SCIP_CALL( chgLinearCoefPos(scip, cons, i, scale * consdata->lincoefs[i]) );
4748  }
4749  if( !SCIPisInfinity(scip, -consdata->lhs) )
4750  {
4751  consdata->lhs *= scale;
4752  assert(!SCIPisInfinity(scip, -consdata->lhs) );
4753  }
4754  if( !SCIPisInfinity(scip, consdata->rhs) )
4755  {
4756  consdata->rhs *= scale;
4757  assert(!SCIPisInfinity(scip, consdata->rhs) );
4758  }
4759 
4760  /* add auxiliary variables to auxiliary constraints
4761  * add aux vars and constraints to SCIP
4762  * add aux vars to this constraint
4763  * set value of aux vars in debug solution, if any
4764  */
4765  SCIPdebugMsg(scip, "add %d constraints for disaggregation of quadratic constraint <%s>\n", ncomponents, SCIPconsGetName(cons));
4766  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + ncomponents) );
4767  for( comp = 0; comp < ncomponents; ++comp )
4768  {
4769  SCIP_CONSDATA* auxconsdata;
4770 
4771  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, auxconss[comp], auxvars[comp], -scale * auxcoefs[comp]) );
4772 
4773  SCIP_CALL( SCIPaddVar(scip, auxvars[comp]) );
4774 
4775  SCIP_CALL( SCIPaddCons(scip, auxconss[comp]) );
4776  SCIPdebugPrintCons(scip, auxconss[comp], NULL);
4777 
4778  SCIP_CALL( addLinearCoef(scip, cons, auxvars[comp], scale * auxcoefs[comp]) );
4779 
4780  /* mark that the constraint should not further be disaggregated */
4781  auxconsdata = SCIPconsGetData(auxconss[comp]);
4782  assert(auxconsdata != NULL);
4783  auxconsdata->isdisaggregated = TRUE;
4784 
4785 #ifdef WITH_DEBUG_SOLUTION
4786  if( SCIPdebugIsMainscip(scip) )
4787  {
4788  /* auxvar should take value from auxsolvals in debug solution, but we also scaled auxvar by auxcoefs[comp] */
4789  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvars[comp], auxsolvals[comp] / auxcoefs[comp]) );
4790  }
4791 #endif
4792 
4793  SCIP_CALL( SCIPreleaseCons(scip, &auxconss[comp]) );
4794  SCIP_CALL( SCIPreleaseVar(scip, &auxvars[comp]) );
4795  }
4796  *naddconss += ncomponents;
4797 
4798  SCIPdebugPrintCons(scip, cons, NULL);
4799 
4800  SCIPfreeBufferArray(scip, &auxconss);
4801  SCIPfreeBufferArray(scip, &auxvars);
4802  SCIPfreeBufferArray(scip, &auxcoefs);
4803 #ifdef WITH_DEBUG_SOLUTION
4804  SCIPfreeBufferArray(scip, &auxsolvals);
4805 #endif
4806  SCIPhashmapFree(&var2component);
4807 
4808  return SCIP_OKAY;
4809 }
4810 
4811 #ifdef CHECKIMPLINBILINEAR
4812 /** checks if there are bilinear terms x*y with a binary variable x and an implication x = {0,1} -> y = 0
4813  *
4814  * In this case, the bilinear term can be removed (x=0 case) or replaced by y (x=1 case).
4815  */
4816 static
4817 SCIP_RETCODE presolveApplyImplications(
4818  SCIP* scip, /**< SCIP data structure */
4819  SCIP_CONS* cons, /**< quadratic constraint */
4820  int* nbilinremoved /**< buffer to store number of removed bilinear terms */
4821  )
4822 {
4823  SCIP_CONSDATA* consdata;
4824  SCIP_VAR* x;
4825  SCIP_VAR* y;
4826  SCIP_INTERVAL implbnds;
4827  int i;
4828  int j;
4829  int k;
4830 
4831  assert(scip != NULL);
4832  assert(cons != NULL);
4833  assert(nbilinremoved != NULL);
4834 
4835  *nbilinremoved = 0;
4836 
4837  consdata = SCIPconsGetData(cons);
4838  assert(consdata != NULL);
4839 
4840  SCIPdebugMsg(scip, "apply implications in <%s>\n", SCIPconsGetName(cons));
4841 
4842  /* sort quadvarterms in case we need to search */
4843  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
4844 
4845  for( i = 0; i < consdata->nquadvars; ++i )
4846  {
4847  x = consdata->quadvarterms[i].var;
4848  assert(x != NULL);
4849 
4850  if( consdata->quadvarterms[i].nadjbilin == 0 )
4851  continue;
4852 
4853  if( !SCIPvarIsBinary(x) )
4854  continue;
4855 
4856  if( !SCIPvarIsActive(x) )
4857  continue;
4858 
4859  if( SCIPvarGetNImpls(x, TRUE) == 0 && SCIPvarGetNImpls(x, FALSE) == 0 )
4860  continue;
4861 
4862  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
4863  {
4864  k = consdata->quadvarterms[i].adjbilin[j];
4865  assert(k >= 0);
4866  assert(k < consdata->nbilinterms);
4867 
4868  if( consdata->bilinterms[k].coef == 0.0 )
4869  continue;
4870 
4871  y = consdata->bilinterms[k].var1 == x ? consdata->bilinterms[k].var2 : consdata->bilinterms[k].var1;
4872  assert(x != y);
4873 
4874  SCIP_CALL( getImpliedBounds(scip, x, TRUE, y, &implbnds) );
4875  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4876  {
4877  /* if x = 1 implies y = 0, then we can remove the bilinear term x*y, since it is always 0
4878  * we only set the coefficient to 0.0 here and mark the bilinterms as not merged */
4879  SCIPdebugMsg(scip, "remove bilinear term %g<%s><%s> from <%s> due to implication\n", consdata->bilinterms[k].coef, SCIPvarGetName(x), SCIPvarGetName(y), SCIPconsGetName(cons));
4880  consdata->bilinterms[k].coef = 0.0;
4881  consdata->bilinmerged = FALSE;
4882  ++*nbilinremoved;
4883  continue;
4884  }
4885 
4886  SCIP_CALL( getImpliedBounds(scip, x, FALSE, y, &implbnds) );
4887  if( SCIPisZero(scip, implbnds.inf) && SCIPisZero(scip, implbnds.sup) )
4888  {
4889  /* if x = 0 implies y = 0, then we can replace the bilinear term x*y by y
4890  * we only move the coefficient to the linear coef of y here and mark the bilinterms as not merged */
4891  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));
4892  assert(consdata->quadvarssorted);
4893  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, cons, y, consdata->bilinterms[k].coef) );
4894  consdata->bilinterms[k].coef = 0.0;
4895  consdata->bilinmerged = FALSE;
4896  ++*nbilinremoved;
4897  }
4898  }
4899  }
4900 
4901  if( *nbilinremoved > 0 )
4902  {
4903  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
4904 
4905  /* invalidate nonlinear row */
4906  if( consdata->nlrow != NULL )
4907  {
4908  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4909  }
4910 
4911  consdata->ispropagated = FALSE;
4912  consdata->ispresolved = FALSE;
4913  consdata->iscurvchecked = FALSE;
4914  }
4915 
4916  consdata->isimpladded = FALSE;
4917 
4918  return SCIP_OKAY;
4919 }
4920 #endif
4921 
4922 /** checks a quadratic constraint for convexity and/or concavity without checking multivariate functions */
4923 static
4924 void checkCurvatureEasy(
4925  SCIP* scip, /**< SCIP data structure */
4926  SCIP_CONS* cons, /**< quadratic constraint */
4927  SCIP_Bool* determined, /**< pointer to store whether the curvature could be determined */
4928  SCIP_Bool checkmultivariate /**< whether curvature will be checked later on for multivariate functions */
4929  )
4930 {
4931  SCIP_CONSDATA* consdata;
4932  int nquadvars;
4933 
4934  assert(scip != NULL);
4935  assert(cons != NULL);
4936  assert(determined != NULL);
4937 
4938  consdata = SCIPconsGetData(cons);
4939  assert(consdata != NULL);
4940 
4941  nquadvars = consdata->nquadvars;
4942  *determined = TRUE;
4943 
4944  if( consdata->iscurvchecked )
4945  return;
4946 
4947  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> without multivariate functions\n", SCIPconsGetName(cons));
4948 
4949  consdata->maxnonconvexity = 0.0;
4950  if( nquadvars == 1 )
4951  {
4952  assert(consdata->nbilinterms == 0);
4953  consdata->isconvex = !SCIPisNegative(scip, consdata->quadvarterms[0].sqrcoef);
4954  consdata->isconcave = !SCIPisPositive(scip, consdata->quadvarterms[0].sqrcoef);
4955  consdata->iscurvchecked = TRUE;
4956 
4957  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[0].sqrcoef > 0.0 )
4958  consdata->maxnonconvexity = consdata->quadvarterms[0].sqrcoef;
4959  if( !SCIPisInfinity(scip, consdata->rhs) && consdata->quadvarterms[0].sqrcoef < 0.0 )
4960  consdata->maxnonconvexity = -consdata->quadvarterms[0].sqrcoef;
4961  }
4962  else if( nquadvars == 0 )
4963  {
4964  consdata->isconvex = TRUE;
4965  consdata->isconcave = TRUE;
4966  consdata->iscurvchecked = TRUE;
4967  }
4968  else if( consdata->nbilinterms == 0 )
4969  {
4970  int v;
4971 
4972  consdata->isconvex = TRUE;
4973  consdata->isconcave = TRUE;
4974 
4975  for( v = nquadvars - 1; v >= 0; --v )
4976  {
4977  consdata->isconvex = consdata->isconvex && !SCIPisNegative(scip, consdata->quadvarterms[v].sqrcoef);
4978  consdata->isconcave = consdata->isconcave && !SCIPisPositive(scip, consdata->quadvarterms[v].sqrcoef);
4979 
4980  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[v].sqrcoef > consdata->maxnonconvexity )
4981  consdata->maxnonconvexity = consdata->quadvarterms[0].sqrcoef;
4982  if( !SCIPisInfinity(scip, consdata->rhs) && -consdata->quadvarterms[v].sqrcoef > consdata->maxnonconvexity )
4983  consdata->maxnonconvexity = -consdata->quadvarterms[0].sqrcoef;
4984  }
4985 
4986  consdata->iscurvchecked = TRUE;
4987  }
4988  else if( !checkmultivariate )
4989  {
4990  consdata->isconvex = FALSE;
4991  consdata->isconcave = FALSE;
4992  consdata->iscurvchecked = TRUE;
4993  consdata->maxnonconvexity = SCIPinfinity(scip);
4994  }
4995  else
4996  *determined = FALSE;
4997 }
4998 
4999 /** checks a quadratic constraint for convexity and/or concavity */
5000 static
5002  SCIP* scip, /**< SCIP data structure */
5003  SCIP_CONS* cons, /**< quadratic constraint */
5004  SCIP_Bool checkmultivariate /**< whether curvature should also be checked for multivariate functions */
5005  )
5006 {
5007  SCIP_CONSDATA* consdata;
5008  double* matrix;
5009  SCIP_HASHMAP* var2index;
5010  int i;
5011  int n;
5012  int nn;
5013  int row;
5014  int col;
5015  double* alleigval;
5016  SCIP_Bool determined;
5017 
5018  assert(scip != NULL);
5019  assert(cons != NULL);
5020 
5021  consdata = SCIPconsGetData(cons);
5022  assert(consdata != NULL);
5023 
5024  n = consdata->nquadvars;
5025 
5026  if( consdata->iscurvchecked )
5027  return SCIP_OKAY;
5028 
5029  /* easy checks for curvature detection */
5030  checkCurvatureEasy(scip, cons, &determined, checkmultivariate);
5031 
5032  /* if curvature was already detected stop */
5033  if( determined )
5034  {
5035  return SCIP_OKAY;
5036  }
5037 
5038  SCIPdebugMsg(scip, "Checking curvature of constraint <%s> with multivariate functions\n", SCIPconsGetName(cons));
5039 
5040  if( n == 2 )
5041  {
5042  SCIP_Real tracehalf;
5043  SCIP_Real discriminantroot;
5044 
5045  /* compute eigenvalues by hand */
5046  assert(consdata->nbilinterms == 1);
5047  consdata->isconvex =
5048  consdata->quadvarterms[0].sqrcoef >= 0 &&
5049  consdata->quadvarterms[1].sqrcoef >= 0 &&
5050  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
5051  consdata->isconcave =
5052  consdata->quadvarterms[0].sqrcoef <= 0 &&
5053  consdata->quadvarterms[1].sqrcoef <= 0 &&
5054  4 * consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef >= consdata->bilinterms[0].coef * consdata->bilinterms[0].coef;
5055 
5056  /* store largest eigenvalue causing nonconvexity according to sides */
5057  tracehalf = (consdata->quadvarterms[0].sqrcoef + consdata->quadvarterms[1].sqrcoef) / 2.0;
5058  discriminantroot = consdata->quadvarterms[0].sqrcoef * consdata->quadvarterms[1].sqrcoef - SQR(consdata->bilinterms[0].coef / 2.0);
5059  discriminantroot = SQR(tracehalf) - discriminantroot;
5060  assert(!SCIPisNegative(scip, discriminantroot));
5061  discriminantroot = SQRT(MAX(0.0, discriminantroot));
5062 
5063  consdata->maxnonconvexity = 0.0;
5064  if( !SCIPisInfinity(scip, -consdata->lhs) )
5065  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, tracehalf + discriminantroot);
5066  if( !SCIPisInfinity(scip, consdata->rhs) )
5067  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, discriminantroot - tracehalf);
5068 
5069  consdata->iscurvchecked = TRUE;
5070  return SCIP_OKAY;
5071  }
5072 
5073  /* do not check curvature if n is too large */
5074  nn = n * n;
5075  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
5076  {
5077  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "cons_quadratic - n is too large to check the curvature\n");
5078  consdata->isconvex = FALSE;
5079  consdata->isconcave = FALSE;
5080  consdata->iscurvchecked = TRUE;
5081  consdata->maxnonconvexity = SCIPinfinity(scip);
5082  return SCIP_OKAY;
5083  }
5084 
5085  /* lower triangular of quadratic term matrix */
5086  SCIP_CALL( SCIPallocBufferArray(scip, &matrix, nn) );
5087  BMSclearMemoryArray(matrix, nn);
5088 
5089  consdata->isconvex = TRUE;
5090  consdata->isconcave = TRUE;
5091  consdata->maxnonconvexity = 0.0;
5092 
5093  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
5094  for( i = 0; i < n; ++i )
5095  {
5096  if( consdata->quadvarterms[i].nadjbilin > 0 )
5097  {
5098  SCIP_CALL( SCIPhashmapInsertInt(var2index, consdata->quadvarterms[i].var, i) );
5099  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
5100  }
5101  else
5102  {
5103  /* if pure square term, then update maximal nonconvex eigenvalue, as it will not be considered in lapack call below */
5104  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->quadvarterms[i].sqrcoef > consdata->maxnonconvexity )
5105  consdata->maxnonconvexity = consdata->quadvarterms[i].sqrcoef;
5106  if( !SCIPisInfinity(scip, consdata->rhs) && -consdata->quadvarterms[i].sqrcoef > consdata->maxnonconvexity )
5107  consdata->maxnonconvexity = -consdata->quadvarterms[i].sqrcoef;
5108  }
5109  /* nonzero elements on diagonal tell a lot about convexity/concavity */
5110  if( SCIPisNegative(scip, consdata->quadvarterms[i].sqrcoef) )
5111  consdata->isconvex = FALSE;
5112  if( SCIPisPositive(scip, consdata->quadvarterms[i].sqrcoef) )
5113  consdata->isconcave = FALSE;
5114  }
5115 
5116  /* skip lapack call, if we know already that we are indefinite
5117  * NOTE: this will leave out updating consdata->maxnonconvexity, so that it only provides a lower bound in this case
5118  */
5119  if( !consdata->isconvex && !consdata->isconcave )
5120  {
5121  SCIPfreeBufferArray(scip, &matrix);
5122  SCIPhashmapFree(&var2index);
5123  consdata->iscurvchecked = TRUE;
5124  /* make sure that maxnonconvexity is strictly different from zero if nonconvex
5125  * TODO one could think about doing some eigenvalue estimation here (Gershgorin)
5126  */
5127  consdata->maxnonconvexity = MAX(1000.0, consdata->maxnonconvexity);
5128  return SCIP_OKAY;
5129  }
5130 
5132  {
5133  for( i = 0; i < consdata->nbilinterms; ++i )
5134  {
5135  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
5136  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
5137  row = SCIPhashmapGetImageInt(var2index, consdata->bilinterms[i].var1);
5138  col = SCIPhashmapGetImageInt(var2index, consdata->bilinterms[i].var2);
5139  if( row < col )
5140  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
5141  else
5142  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
5143  }
5144 
5145  SCIP_CALL( SCIPallocBufferArray(scip, &alleigval, n) );
5146  /* @todo Can we compute only min and max eigen value?
5147  * @todo Can we estimate the numerical error?
5148  * @todo Trying a cholesky factorization may be much faster.
5149  */
5150  if( LapackDsyev(FALSE, n, matrix, alleigval) != SCIP_OKAY )
5151  {
5152  SCIPwarningMessage(scip, "Failed to compute eigenvalues of quadratic coefficient matrix of constraint %s. Assuming matrix is indefinite.\n", SCIPconsGetName(cons));
5153  consdata->isconvex = FALSE;
5154  consdata->isconcave = FALSE;
5155  }
5156  else
5157  {
5158  /* deconvexification reformulates a stricly convex quadratic function in binaries such that it becomes not-strictly convex
5159  * by adding the -lambda*(x^2-x) terms for lambda the smallest eigenvalue of the matrix
5160  * 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
5161  */
5162 #ifdef DECONVEXIFY
5163  SCIP_Bool allbinary;
5164  printf("cons <%s>[%g,%g] spectrum = [%g,%g]\n", SCIPconsGetName(cons), consdata->lhs, consdata->rhs, alleigval[0], alleigval[n-1]);
5165 #endif
5166  consdata->isconvex &= !SCIPisNegative(scip, alleigval[0]); /*lint !e514*/
5167  consdata->isconcave &= !SCIPisPositive(scip, alleigval[n-1]); /*lint !e514*/
5168  consdata->iscurvchecked = TRUE;
5169 #ifdef DECONVEXIFY
5170  for( i = 0; i < consdata->nquadvars; ++i )
5171  if( !SCIPvarIsBinary(consdata->quadvarterms[i].var) )
5172  break;
5173  allbinary = i == consdata->nquadvars;
5174 
5175  if( !SCIPisInfinity(scip, consdata->rhs) && alleigval[0] > 0.1 && allbinary )
5176  {
5177  printf("deconvexify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[0]);
5178  for( i = 0; i < consdata->nquadvars; ++i )
5179  {
5180  consdata->quadvarterms[i].sqrcoef -= alleigval[0];
5181  consdata->quadvarterms[i].lincoef += alleigval[0];
5182  }
5183  }
5184 
5185  if( !SCIPisInfinity(scip, consdata->lhs) && alleigval[n-1] < -0.1 && allbinary )
5186  {
5187  printf("deconcavify cons <%s> by shifting hessian by %g\n", SCIPconsGetName(cons), alleigval[n-1]);
5188  for( i = 0; i < consdata->nquadvars; ++i )
5189  {
5190  consdata->quadvarterms[i].sqrcoef -= alleigval[n-1];
5191  consdata->quadvarterms[i].lincoef += alleigval[n-1];
5192  }
5193  }
5194 #endif
5195  }
5196 
5197  /* update largest eigenvalue causing nonconvexity according to sides */
5198  if( !SCIPisInfinity(scip, -consdata->lhs) )
5199  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, alleigval[n-1]);
5200  if( !SCIPisInfinity(scip, consdata->rhs) )
5201  consdata->maxnonconvexity = MAX(consdata->maxnonconvexity, -alleigval[0]);
5202 
5203  SCIPfreeBufferArray(scip, &alleigval);
5204  }
5205  else
5206  {
5207  consdata->isconvex = FALSE;
5208  consdata->isconcave = FALSE;
5209  consdata->iscurvchecked = TRUE; /* set to TRUE since it does not help to repeat this procedure again and again (that will not bring Ipopt in) */
5210  consdata->maxnonconvexity = SCIPinfinity(scip);
5211  }
5212 
5213  SCIPhashmapFree(&var2index);
5214  SCIPfreeBufferArray(scip, &matrix);
5215 
5216  return SCIP_OKAY;
5217 }
5218 
5219 /** check whether indefinite constraint function is factorable and store corresponding coefficients */
5220 static
5222  SCIP* scip, /**< SCIP data structure */
5223  SCIP_CONS* cons /**< constraint */
5224  )
5225 {
5226  SCIP_BILINTERM* bilinterm;
5227  SCIP_CONSDATA* consdata;
5228  SCIP_Real* a;
5229  SCIP_Real* eigvals;
5230  SCIP_Real sigma1;
5231  SCIP_Real sigma2;
5232  SCIP_Bool success;
5233  int n;
5234  int i;
5235  int idx1;
5236  int idx2;
5237  int posidx;
5238  int negidx;
5239 
5240  assert(scip != NULL);
5241  assert(cons != NULL);
5242 
5243  consdata = SCIPconsGetData(cons);
5244  assert(consdata != NULL);
5245  assert(consdata->factorleft == NULL);
5246  assert(consdata->factorright == NULL);
5247 
5248  /* we don't need this if there are no bilinear terms */
5249  if( consdata->nbilinterms == 0 )
5250  return SCIP_OKAY;
5251 
5252  /* write constraint as lhs <= linear + x'^T A x' <= rhs where x' = (x,1) and
5253  * A = ( Q b/2 )
5254  * ( b^T/2 0 )
5255  * compute an eigenvalue factorization of A and check if there are one positive and one negative eigenvalue
5256  * 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
5257  * thus, x'^T A x' = sigma1^2 (v1^T x')^2 - sigma2^2 (v2^T x')^2
5258  * = (sigma1 (v1^T x') - sigma2 (v2^T x')) * (sigma1 (v1^T x') + sigma2 (v2^T x'))
5259  * we then store sigma1 v1^T - sigma2 v2^T as left factor coef, and sigma1 v1^T + sigma2 v2^T as right factor coef
5260  */
5261 
5262  /* if we already know that there are only positive or only negative eigenvalues, then don't try */
5263  if( consdata->iscurvchecked && (consdata->isconvex || consdata->isconcave) )
5264  return SCIP_OKAY;
5265 
5266  n = consdata->nquadvars + 1;
5267 
5268  /* @todo handle case n=3 explicitly */
5269 
5270  /* skip too large matrices */
5271  if( n > 50 )
5272  return SCIP_OKAY;
5273 
5274  /* need routine to compute eigenvalues/eigenvectors */
5275  if( !SCIPisIpoptAvailableIpopt() )
5276  return SCIP_OKAY;
5277 
5278  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
5279 
5280  SCIP_CALL( SCIPallocBufferArray(scip, &a, n*n) );
5281  BMSclearMemoryArray(a, n*n);
5282 
5283  /* set lower triangular entries of A corresponding to bilinear terms */
5284  for( i = 0; i < consdata->nbilinterms; ++i )
5285  {
5286  bilinterm = &consdata->bilinterms[i];
5287 
5288  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
5289  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
5290  assert(idx1 >= 0);
5291  assert(idx2 >= 0);
5292  assert(idx1 != idx2);
5293 
5294  a[MIN(idx1,idx2) * n + MAX(idx1,idx2)] = bilinterm->coef / 2.0;
5295  }
5296 
5297  /* set lower triangular entries of A corresponding to square and linear terms */
5298  for( i = 0; i < consdata->nquadvars; ++i )
5299  {
5300  a[i*n + i] = consdata->quadvarterms[i].sqrcoef;
5301  a[i*n + n-1] = consdata->quadvarterms[i].lincoef / 2.0;
5302  }
5303 
5304  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, n) );
5305  if( LapackDsyev(TRUE, n, a, eigvals) != SCIP_OKAY )
5306  {
5307  SCIPdebugMsg(scip, "Failed to compute eigenvalues and eigenvectors of augmented quadratic form matrix for constraint <%s>.\n", SCIPconsGetName(cons));
5308  goto CLEANUP;
5309  }
5310 
5311  /* check if there is exactly one positive and one negative eigenvalue */
5312  posidx = -1;
5313  negidx = -1;
5314  for( i = 0; i < n; ++i )
5315  {
5316  if( SCIPisPositive(scip, eigvals[i]) )
5317  {
5318  if( posidx == -1 )
5319  posidx = i;
5320  else
5321  break;
5322  }
5323  else if( SCIPisNegative(scip, eigvals[i]) )
5324  {
5325  if( negidx == -1 )
5326  negidx = i;
5327  else
5328  break;
5329  }
5330  }
5331  if( i < n || posidx == -1 || negidx == -1 )
5332  {
5333  SCIPdebugMsg(scip, "Augmented quadratic form of constraint <%s> is not factorable.\n", SCIPconsGetName(cons));
5334  goto CLEANUP;
5335  }
5336  assert(SCIPisPositive(scip, eigvals[posidx]));
5337  assert(SCIPisNegative(scip, eigvals[negidx]));
5338 
5339  /* compute factorleft and factorright */
5340  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1) );
5341  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1) );
5342 
5343  /* eigenvectors are stored in a, inverse eigenvector matrix is transposed of a
5344  * it seems that v1 and v2 are at &a[posidx*n] and &a[negidx*n]
5345  */
5346  sigma1 = sqrt( eigvals[posidx]);
5347  sigma2 = sqrt(-eigvals[negidx]);
5348  for( i = 0; i < n; ++i )
5349  {
5350  consdata->factorleft[i] = sigma1 * a[posidx * n + i] - sigma2 * a[negidx * n + i];
5351  consdata->factorright[i] = sigma1 * a[posidx * n + i] + sigma2 * a[negidx * n + i];
5352  /* set almost-zero elements to zero */
5353  if( SCIPisZero(scip, consdata->factorleft[i]) )
5354  consdata->factorleft[i] = 0.0;
5355  if( SCIPisZero(scip, consdata->factorright[i]) )
5356  consdata->factorright[i] = 0.0;
5357  }
5358 
5359 #ifdef SCIP_DEBUG
5360  SCIPdebugMsg(scip, "constraint <%s> has factorable quadratic form: (%g", SCIPconsGetName(cons), consdata->factorleft[n-1]);
5361  for( i = 0; i < consdata->nquadvars; ++i )
5362  {
5363  if( consdata->factorleft[i] != 0.0 )
5364  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorleft[i], SCIPvarGetName(consdata->quadvarterms[i].var));
5365  }
5366  SCIPdebugMsgPrint(scip, ") * (%g", consdata->factorright[n-1]);
5367  for( i = 0; i < consdata->nquadvars; ++i )
5368  {
5369  if( consdata->factorright[i] != 0.0 )
5370  SCIPdebugMsgPrint(scip, " %+g<%s>", consdata->factorright[i], SCIPvarGetName(consdata->quadvarterms[i].var));
5371  }
5372  SCIPdebugMsgPrint(scip, ")\n");
5373 #endif
5374 
5375  /* check whether factorleft * factorright^T is matrix of augmented quadratic form
5376  * we check here only the nonzero entries from the quadratic form
5377  */
5378  success = TRUE;
5379 
5380  /* check bilinear terms */
5381  for( i = 0; i < consdata->nbilinterms; ++i )
5382  {
5383  bilinterm = &consdata->bilinterms[i];
5384 
5385  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var1, &idx1) );
5386  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, bilinterm->var2, &idx2) );
5387 
5388  if( !SCIPisRelEQ(scip, consdata->factorleft[idx1] * consdata->factorright[idx2] + consdata->factorleft[idx2] * consdata->factorright[idx1], bilinterm->coef) )
5389  {
5390  success = FALSE;
5391  break;
5392  }
5393  }
5394 
5395  /* set lower triangular entries of A corresponding to square and linear terms */
5396  for( i = 0; i < consdata->nquadvars; ++i )
5397  {
5398  if( !SCIPisRelEQ(scip, consdata->factorleft[i] * consdata->factorright[i], consdata->quadvarterms[i].sqrcoef) )
5399  {
5400  success = FALSE;
5401  break;
5402  }
5403 
5404  if( !SCIPisRelEQ(scip, consdata->factorleft[n-1] * consdata->factorright[i] + consdata->factorleft[i] * consdata->factorright[n-1], consdata->quadvarterms[i].lincoef) )
5405  {
5406  success = FALSE;
5407  break;
5408  }
5409  }
5410 
5411  if( !success )
5412  {
5413  SCIPdebugMsg(scip, "Factorization not accurate enough. Dropping it.\n");
5414  SCIPfreeBlockMemoryArray(scip, &consdata->factorleft, consdata->nquadvars + 1);
5415  SCIPfreeBlockMemoryArray(scip, &consdata->factorright, consdata->nquadvars + 1);
5416  }
5417 
5418  CLEANUP:
5419  SCIPfreeBufferArray(scip, &eigvals);
5420  SCIPfreeBufferArray(scip, &a);
5421 
5422  return SCIP_OKAY;
5423 }
5424 
5425 /** computes activity and violation of a constraint
5426  *
5427  * If solution violates bounds by more than feastol, the violation is still computed, but *solviolbounds is set to TRUE
5428  */
5429 static
5431  SCIP* scip, /**< SCIP data structure */
5432  SCIP_CONS* cons, /**< constraint */
5433  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5434  SCIP_Bool* solviolbounds /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol */
5435  )
5436 { /*lint --e{666}*/
5437  SCIP_CONSDATA* consdata;
5438  SCIP_Real varval;
5439  SCIP_Real varval2;
5440  SCIP_Real absviol;
5441  SCIP_Real relviol;
5442  SCIP_VAR* var;
5443  SCIP_VAR* var2;
5444  int i;
5445  int j;
5446 
5447  assert(scip != NULL);
5448  assert(cons != NULL);
5449  assert(solviolbounds != NULL);
5450 
5451  consdata = SCIPconsGetData(cons);
5452  assert(consdata != NULL);
5453 
5454  *solviolbounds = FALSE;
5455  consdata->activity = 0.0;
5456  consdata->lhsviol = 0.0;
5457  consdata->rhsviol = 0.0;
5458 
5459  for( i = 0; i < consdata->nlinvars; ++i )
5460  {
5461  SCIP_Real activity;
5462 
5463  var = consdata->linvars[i];
5464  varval = SCIPgetSolVal(scip, sol, var);
5465  activity = consdata->lincoefs[i] * varval;
5466 
5467  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
5468  * 0.0 otherwise
5469  */
5470  if( SCIPisInfinity(scip, REALABS(varval)) )
5471  {
5472  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5473  {
5474  consdata->activity = SCIPinfinity(scip);
5475  consdata->rhsviol = SCIPinfinity(scip);
5476  return SCIP_OKAY;
5477  }
5478 
5479  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5480  {
5481  consdata->activity = -SCIPinfinity(scip);
5482  consdata->lhsviol = SCIPinfinity(scip);
5483  return SCIP_OKAY;
5484  }
5485  }
5486 
5487  consdata->activity += activity;
5488  }
5489 
5490  for( j = 0; j < consdata->nquadvars; ++j )
5491  {
5492  SCIP_Real activity;
5493 
5494  var = consdata->quadvarterms[j].var;
5495  varval = SCIPgetSolVal(scip, sol, var);
5496  activity = (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5497 
5498  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
5499  * 0.0 otherwise
5500  */
5501  if( SCIPisInfinity(scip, REALABS(varval)) )
5502  {
5503  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5504  {
5505  consdata->activity = SCIPinfinity(scip);
5506  consdata->rhsviol = SCIPinfinity(scip);
5507  return SCIP_OKAY;
5508  }
5509 
5510  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5511  {
5512  consdata->activity = -SCIPinfinity(scip);
5513  consdata->lhsviol = SCIPinfinity(scip);
5514  return SCIP_OKAY;
5515  }
5516  }
5517 
5518  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5519  if( sol == NULL )
5520  {
5521  /* 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 */
5522  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
5523  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
5524  *solviolbounds = TRUE;
5525  else
5526  {
5527  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5528  activity = (consdata->quadvarterms[j].lincoef + consdata->quadvarterms[j].sqrcoef * varval) * varval;
5529  }
5530  }
5531 
5532  consdata->activity += activity;
5533  }
5534 
5535  for( j = 0; j < consdata->nbilinterms; ++j )
5536  {
5537  SCIP_Real activity;
5538 
5539  var = consdata->bilinterms[j].var1;
5540  var2 = consdata->bilinterms[j].var2;
5541  varval = SCIPgetSolVal(scip, sol, var);
5542  varval2 = SCIPgetSolVal(scip, sol, var2);
5543 
5544  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
5545  if( sol == NULL )
5546  {
5547  /* 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 */
5548  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
5549  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
5550  *solviolbounds = TRUE;
5551  else
5552  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
5553 
5554  /* 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 */
5555  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var2)) && !SCIPisFeasGE(scip, varval2, SCIPvarGetLbLocal(var2))) ||
5556  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var2)) && !SCIPisFeasLE(scip, varval2, SCIPvarGetUbLocal(var2))) )
5557  *solviolbounds = TRUE;
5558  else
5559  varval2 = MAX(SCIPvarGetLbLocal(var2), MIN(SCIPvarGetUbLocal(var2), varval2));
5560  }
5561 
5562  activity = consdata->bilinterms[j].coef * varval * varval2;
5563 
5564  /* consider var*var2 as a new variable and handle it as it would appear linearly */
5565  if( SCIPisInfinity(scip, REALABS(varval*varval2)) )
5566  {
5567  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
5568  {
5569  consdata->activity = SCIPinfinity(scip);
5570  consdata->rhsviol = SCIPinfinity(scip);
5571  return SCIP_OKAY;
5572  }
5573 
5574  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
5575  {
5576  consdata->activity = -SCIPinfinity(scip);
5577  consdata->lhsviol = SCIPinfinity(scip);
5578  return SCIP_OKAY;
5579  }
5580  }
5581 
5582  consdata->activity += activity;
5583  }
5584 
5585  absviol = 0.0;
5586  relviol = 0.0;
5587  /* compute absolute violation left hand side */
5588  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
5589  {
5590  consdata->lhsviol = consdata->lhs - consdata->activity;
5591  absviol = consdata->lhsviol;
5592  relviol = SCIPrelDiff(consdata->lhs, consdata->activity);
5593  }
5594  else
5595  consdata->lhsviol = 0.0;
5596 
5597  /* compute absolute violation right hand side */
5598  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
5599  {
5600  consdata->rhsviol = consdata->activity - consdata->rhs;
5601  absviol = consdata->rhsviol;
5602  relviol = SCIPrelDiff(consdata->activity, consdata->rhs);
5603  }
5604  else
5605  consdata->rhsviol = 0.0;
5606 
5607  /* update absolute and relative violation of the solution */
5608  if( sol != NULL )
5609  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
5610 
5611  return SCIP_OKAY;
5612 }
5613 
5614 /** computes violation of a set of constraints */
5615 static
5617  SCIP* scip, /**< SCIP data structure */
5618  SCIP_CONS** conss, /**< constraints */
5619  int nconss, /**< number of constraints */
5620  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
5621  SCIP_Bool* solviolbounds, /**< buffer to store whether quadratic variables in solution are outside their bounds by more than feastol in some constraint */
5622  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
5623  )
5624 {
5625  SCIP_CONSDATA* consdata;
5626  SCIP_Real viol;
5627  SCIP_Real maxviol;
5628  SCIP_Bool solviolbounds1;
5629  int c;
5630 
5631  assert(scip != NULL);
5632  assert(conss != NULL || nconss == 0);
5633  assert(solviolbounds != NULL);
5634  assert(maxviolcon != NULL);
5635 
5636  *solviolbounds = FALSE;
5637  *maxviolcon = NULL;
5638 
5639  maxviol = 0.0;
5640 
5641  for( c = 0; c < nconss; ++c )
5642  {
5643  assert(conss != NULL);
5644  assert(conss[c] != NULL);
5645 
5646  SCIP_CALL( computeViolation(scip, conss[c], sol, &solviolbounds1) );
5647  *solviolbounds |= solviolbounds1;
5648 
5649  consdata = SCIPconsGetData(conss[c]);
5650  assert(consdata != NULL);
5651 
5652  viol = MAX(consdata->lhsviol, consdata->rhsviol);
5653  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
5654  {
5655  maxviol = viol;
5656  *maxviolcon = conss[c];
5657  }
5658  }
5659 
5660  return SCIP_OKAY;
5661 }
5662 
5663 
5664 /** index comparison method for bilinear terms */
5665 static
5666 SCIP_DECL_SORTINDCOMP(bilinTermComp2)
5667 { /*lint --e{715}*/
5668  SCIP_BILINTERM* bilinterms = (SCIP_BILINTERM*)dataptr;
5669  int var1cmp;
5670 
5671  assert(bilinterms != NULL);
5672 
5673  var1cmp = SCIPvarCompare(bilinterms[ind1].var1, bilinterms[ind2].var1);
5674  if( var1cmp != 0 )
5675  return var1cmp;
5676 
5677  return SCIPvarCompare(bilinterms[ind1].var2, bilinterms[ind2].var2);
5678 }
5679 
5680 /** volume comparison method for bilinear terms; prioritizes bilinear products with a larger volume */
5681 static
5682 SCIP_DECL_SORTINDCOMP(bilinTermCompVolume)
5683 { /*lint --e{715}*/
5684  SCIP_BILINTERM* bilinterms = (SCIP_BILINTERM*)dataptr;
5685  SCIP_Real vol1;
5686  SCIP_Real vol2;
5687 
5688  assert(bilinterms != NULL);
5689 
5690  vol1 = (SCIPvarGetUbLocal(bilinterms[ind1].var1) - SCIPvarGetLbLocal(bilinterms[ind1].var1))
5691  * (SCIPvarGetUbLocal(bilinterms[ind1].var2) - SCIPvarGetLbLocal(bilinterms[ind1].var2));
5692  vol2 = (SCIPvarGetUbLocal(bilinterms[ind2].var1) - SCIPvarGetLbLocal(bilinterms[ind2].var1))
5693  * (SCIPvarGetUbLocal(bilinterms[ind2].var2) - SCIPvarGetLbLocal(bilinterms[ind2].var2));
5694 
5695  if( vol1 > vol2 )
5696  return -1;
5697  else if( vol1 < vol2 )
5698  return 1;
5699  return bilinTermComp2(dataptr, ind1, ind2);
5700 }
5701 
5702 /** helper function to sort all bilinear terms in the constraint handler data */
5703 static
5705  SCIP* scip, /**< SCIP data structure */
5706  SCIP_BILINTERM* bilinterms, /**< array containing all bilinear terms */
5707  int nbilinterms, /**< total number of bilinear terms */
5708  SCIP_CONS** bilinconss, /**< array for mapping each term to its constraint */
5709  int* bilinposs /**< array for mapping each term to its position in the corresponding
5710  * bilinconss constraint */
5711  )
5712 {
5713  int* perm;
5714  int i;
5715  int nexti;
5716  int v;
5717  SCIP_BILINTERM bilinterm;
5718  SCIP_CONS* bilincons;
5719  int bilinpos;
5720 
5721  assert(scip != NULL);
5722  assert(bilinterms != NULL);
5723  assert(nbilinterms > 0);
5724  assert(bilinconss != NULL);
5725  assert(bilinposs != NULL);
5726 
5727  /* get temporary memory to store the sorted permutation and the inverse permutation */
5728  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nbilinterms) );
5729 
5730  /* call quicksort */
5731  SCIPsort(perm, bilinTermCompVolume, (void*)bilinterms, nbilinterms);
5732 
5733  /* permute the bilinear terms according to the resulting permutation */
5734  for( v = 0; v < nbilinterms; ++v )
5735  {
5736  if( perm[v] != v )
5737  {
5738  bilinterm = bilinterms[v];
5739  bilincons = bilinconss[v];
5740  bilinpos = bilinposs[v];
5741 
5742  i = v;
5743  do
5744  {
5745  assert(0 <= perm[i] && perm[i] < nbilinterms);
5746  assert(perm[i] != i);
5747 
5748  bilinterms[i] = bilinterms[perm[i]];
5749  bilinconss[i] = bilinconss[perm[i]];
5750  bilinposs[i] = bilinposs[perm[i]];
5751 
5752  nexti = perm[i];
5753  perm[i] = i;
5754  i = nexti;
5755  }
5756  while( perm[i] != v );
5757  bilinterms[i] = bilinterm;
5758  bilinconss[i] = bilincons;
5759  bilinposs[i] = bilinpos;
5760  perm[i] = i;
5761  }
5762  }
5763 
5764  /* free temporary memory */
5765  SCIPfreeBufferArray(scip, &perm);
5766 
5767  return SCIP_OKAY;
5768 }
5769 
5770 /** stores all bilinear terms in the quadratic constraint handler data; in addition, for each bilinear term we store
5771  * the number of nonconvex constraints that require to over- or underestimate this term, which only depends on the
5772  * lhs, rhs, and the bilinear coefficient
5773  */
5774 static
5776  SCIP* scip, /**< SCIP data structure */
5777  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5778  SCIP_CONS** conss, /**< constraints to process */
5779  int nconss /**< number of constraints */
5780  )
5781 {
5782  SCIP_BILINTERM* bilinterms;
5783  SCIP_CONS** bilincons;
5784  int* bilinpos;
5785  int nbilinterms;
5786  int pos;
5787  int c;
5788  int i;
5789 
5790  assert(scip != NULL);
5791  assert(conshdlrdata != NULL);
5792  assert(conss != NULL);
5793 
5794  /* check for all cases for which we don't want to spend time for collecting all bilinear terms */
5795  if( nconss == 0 || conshdlrdata->storedbilinearterms || SCIPgetSubscipDepth(scip) != 0 || SCIPgetDepth(scip) >= 1
5796  || SCIPinProbing(scip) || SCIPinDive(scip) )
5797  return SCIP_OKAY;
5798 
5799  assert(conshdlrdata->bilinestimators == NULL);
5800  assert(conshdlrdata->nbilinterms == 0);
5801 
5802  conshdlrdata->storedbilinearterms = TRUE;
5803  nbilinterms = 0;
5804 
5805  /* count the number of bilinear terms (including duplicates) */
5806  for( c = 0; c < nconss; ++c )
5807  {
5808  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5809  assert(consdata != NULL);
5810  nbilinterms += consdata->nbilinterms;
5811  }
5812 
5813  /* no bilinear terms available -> stop */
5814  if( nbilinterms == 0 )
5815  return SCIP_OKAY;
5816 
5817  /* allocate temporary memory for sorting all bilinear terms (including duplicates) */
5818  SCIP_CALL( SCIPallocBufferArray(scip, &bilinterms, nbilinterms) );
5819  SCIP_CALL( SCIPallocBufferArray(scip, &bilincons, nbilinterms) );
5820  SCIP_CALL( SCIPallocBufferArray(scip, &bilinpos, nbilinterms) );
5821 
5822  /* copy all bilinear terms; note that we need separate entries for x*y and y*x */
5823  pos = 0;
5824  for( c = 0; c < nconss; ++c )
5825  {
5826  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5827 
5828  /* allocate memory to store the later computed indices of each bilinear term in the bilinterms array of the
5829  * constraint handler data
5830  */
5831  if( consdata->nbilinterms > 0 )
5832  {
5833  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->bilintermsidx, consdata->nbilinterms) );
5834  }
5835 
5836  for( i = 0; i < consdata->nbilinterms; ++i )
5837  {
5838  assert(consdata->bilinterms != NULL);
5839  assert(consdata->bilinterms[i].var1 != consdata->bilinterms[i].var2);
5840 
5841  /* add xy */
5842  bilinterms[pos] = consdata->bilinterms[i];
5843  bilincons[pos] = conss[c];
5844  bilinpos[pos] = i;
5845  ++pos;
5846 
5847  /* invalidate bilinear term index */
5848  assert(consdata->bilintermsidx != NULL);
5849  consdata->bilintermsidx[i] = -1;
5850  }
5851  }
5852  assert(pos == nbilinterms);
5853 
5854  /* sorts all bilinear terms (including duplicates) */
5855  SCIP_CALL( sortAllBilinTerms(scip, bilinterms, nbilinterms, bilincons, bilinpos) );
5856 
5857  /* count the number of bilinear terms without duplicates */
5858  conshdlrdata->nbilinterms = nbilinterms;
5859  for( i = 0; i < nbilinterms - 1; ++i )
5860  {
5861  assert(bilinTermCompVolume((void*)bilinterms, i, i+1) != 0 || bilinTermComp2((void*)bilinterms, i, i+1) <= 0);
5862 
5863  if( bilinTermComp2((void*)bilinterms, i, i+1) == 0 )
5864  --(conshdlrdata->nbilinterms);
5865  }
5866  assert(conshdlrdata->nbilinterms <= nbilinterms && conshdlrdata->nbilinterms > 0);
5867 
5868  /* store all information for each bilinear term into the constraint handler data */
5869  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &conshdlrdata->bilinestimators, conshdlrdata->nbilinterms) );
5870 
5871  /* filter duplicates and update entries in the corresponding constraint datas */
5872  pos = 0;
5873  for( i = 0; i < nbilinterms; ++i )
5874  {
5875  SCIP_CONSDATA* consdata = SCIPconsGetData(bilincons[i]);
5876  SCIP_VAR* x;
5877  SCIP_Bool haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5878  SCIP_Bool hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5879 
5880  assert(consdata != NULL);
5881  assert(bilinpos[i] >= 0 && bilinpos[i] < consdata->nbilinterms);
5882 
5883  /* check for a new bilinear term */
5884  if( i == 0 || bilinTermComp2((void*)bilinterms, i-1, i) != 0 )
5885  {
5886  conshdlrdata->bilinestimators[pos].x = bilinterms[i].var1;
5887  conshdlrdata->bilinestimators[pos].y = bilinterms[i].var2;
5888  conshdlrdata->bilinestimators[pos].lastimprfac = 0.0;
5889  conshdlrdata->bilinestimators[pos].maxnonconvexity = 0.0;
5890  ++pos;
5891  }
5892 
5893  /* store whether under- or overestimation is needed for each bilinear term; note that we do not consider convex
5894  * constraints because they will not be used in separated generateCutNonConvex(), which is the only function that
5895  * uses a term-wise relaxation
5896  */
5897  if( SCIPisPositive(scip, bilinterms[i].coef) )
5898  {
5899  conshdlrdata->bilinestimators[pos-1].nunderest += (hasrhs && !consdata->isconvex) ? 1 : 0;
5900  conshdlrdata->bilinestimators[pos-1].noverest += (haslhs && !consdata->isconcave) ? 1 : 0;
5901  conshdlrdata->bilinestimators[pos-1].maxnonconvexity = MAX(conshdlrdata->bilinestimators[pos-1].maxnonconvexity, consdata->maxnonconvexity);
5902  }
5903  else
5904  {
5905  assert(SCIPisNegative(scip, bilinterms[i].coef));
5906  conshdlrdata->bilinestimators[pos-1].nunderest += (haslhs && !consdata->isconcave) ? 1 : 0;
5907  conshdlrdata->bilinestimators[pos-1].noverest += (hasrhs && !consdata->isconvex) ? 1 : 0;
5908  conshdlrdata->bilinestimators[pos-1].maxnonconvexity = MAX(conshdlrdata->bilinestimators[pos-1].maxnonconvexity, consdata->maxnonconvexity);
5909  }
5910 
5911  /* update index of bilinear term in the constraint data */
5912  x = consdata->bilinterms[bilinpos[i]].var1;
5913 
5914  assert(pos > 0);
5915  if( x == conshdlrdata->bilinestimators[pos-1].x )
5916  {
5917  assert(consdata->bilinterms[bilinpos[i]].var2 == conshdlrdata->bilinestimators[pos-1].y);
5918  consdata->bilintermsidx[bilinpos[i]] = pos-1;
5919  }
5920  }
5921  assert(pos == conshdlrdata->nbilinterms);
5922 
5923 #ifndef NDEBUG
5924  /* check whether
5925  * - all bilintermsidx entries have been set
5926  * - variables in bilinear terms of each constraint data and the constraint handler data match
5927  */
5928  for( c = 0; c < nconss; ++c )
5929  {
5930  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]);
5931  assert(consdata != NULL);
5932 
5933  for( i = 0; i < consdata->nbilinterms; ++i )
5934  {
5935  SCIP_VAR* x = consdata->bilinterms[i].var1;
5936  SCIP_VAR* y = consdata->bilinterms[i].var2;
5937  int idx = consdata->bilintermsidx[i];
5938 
5939  assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
5940  assert(x == conshdlrdata->bilinestimators[idx].x);
5941  assert(y == conshdlrdata->bilinestimators[idx].y);
5942 
5943  /* at least one direction is important if the constraint is not convex */
5944  if( !SCIPisInfinity(scip, consdata->rhs) && !consdata->isconvex )
5945  assert(conshdlrdata->bilinestimators[idx].nunderest + conshdlrdata->bilinestimators[idx].noverest > 0);
5946  if( !SCIPisInfinity(scip, -consdata->lhs) && !consdata->isconcave )
5947  assert(conshdlrdata->bilinestimators[idx].nunderest + conshdlrdata->bilinestimators[idx].noverest > 0);
5948  }
5949  }
5950 #endif
5951 
5952  /* free memory */
5953  SCIPfreeBufferArray(scip, &bilinpos);
5954  SCIPfreeBufferArray(scip, &bilincons);
5955  SCIPfreeBufferArray(scip, &bilinterms);
5956 
5957  return SCIP_OKAY;
5958 }
5959 
5960 /** frees memory allocated in storeAllBilinearTerms() */
5961 static
5963  SCIP* scip, /**< SCIP data structure */
5964  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5965  SCIP_CONS** conss, /**< constraints to process */
5966  int nconss /**< number of constraints */
5967 
5968  )
5969 {
5970  int c;
5971 
5972  assert(conshdlrdata != NULL);
5973 
5974  for( c = 0; c < nconss; ++c )
5975  {
5976  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
5977  assert(consdata != NULL);
5978 
5979  SCIPfreeBlockMemoryArrayNull(scip, &consdata->bilintermsidx, consdata->nbilinterms);
5980  }
5981 
5982  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinestimators, conshdlrdata->nbilinterms);
5983 
5984  conshdlrdata->nbilinterms = 0;
5985  conshdlrdata->storedbilinearterms = FALSE;
5986 
5987  return SCIP_OKAY;
5988 }
5989 
5990 /** tries to compute cut for multleft * <coefleft, x'> * multright <= rhs / (multright * <coefright, x'>) where x'=(x,1) */
5991 static
5993  SCIP* scip, /**< SCIP data structure */
5994  SCIP_CONS* cons, /**< constraint */
5995  SCIP_Real* ref, /**< reference solution where to generate the cut */
5996  SCIP_Real multleft, /**< multiplicator on lhs */
5997  SCIP_Real* coefleft, /**< coefficient for factor on lhs */
5998  SCIP_Real multright, /**< multiplicator on both sides */
5999  SCIP_Real* coefright, /**< coefficient for factor that goes to rhs */
6000  SCIP_Real rightminactivity, /**< minimal activity of <coefright, x> */
6001  SCIP_Real rightmaxactivity, /**< maximal activity of <coefright, x> */
6002  SCIP_Real rhs, /**< denominator on rhs */
6003  SCIP_ROWPREP* rowprep, /**< rowprep to store cut coefs and constant */
6004  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6005  )
6006 {
6007  SCIP_CONSDATA* consdata;
6008  SCIP_Real constant;
6009  SCIP_Real coef;
6010  int i;
6011 
6012  assert(rowprep != NULL);
6013  assert(rightminactivity * multright > 0.0);
6014  assert(rightmaxactivity * multright > 0.0);
6015  assert(multright == 1.0 || multright == -1.0);
6016 
6017  consdata = SCIPconsGetData(cons);
6018  assert(consdata != NULL);
6019 
6020  rowprep->sidetype = SCIP_SIDETYPE_RIGHT;
6021 
6022  if( rhs > 0.0 )
6023  {
6024  /* if rhs > 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need secant:
6025  * 1 / multright*<coefright, x'> <= 1/minact + 1/maxact - 1/(minact * maxact) multright*<coefright, x'>
6026  * where [minact, maxact] = multright * [rightminactivity, rightmaxactivity]
6027  *
6028  * assuming multright is either -1 or 1, and substituting gives
6029  * multright/rightminactivity + multright/rightmaxactivity - multright/(rightminactivity * rightmaxactivity) *<coefright, x'>
6030  *
6031  * multiplying by rhs, gives the estimate
6032  * rhs / (multright * <coefright, x'>) <= rhs * multright * (1/rightminactivity + 1/rightmaxactivity - 1/(rightminactivity * rightmaxactivity) * <coefright, x'>)
6033  */
6034 
6035  /* cannot do if unbounded */
6036  if( SCIPisInfinity(scip, rightmaxactivity * multright) )
6037  {
6038  *success = FALSE;
6039  return SCIP_OKAY;
6040  }
6041 
6042  assert(SCIPisFeasLE(scip, rightminactivity, rightmaxactivity));
6043 
6044  constant = multleft * multright * coefleft[consdata->nquadvars];
6045  constant -= rhs * multright * (1.0 / rightminactivity + 1.0 / rightmaxactivity);
6046  constant += rhs * multright * coefright[consdata->nquadvars] / (rightminactivity * rightmaxactivity);
6047 
6048  SCIPaddRowprepConstant(rowprep, constant);
6049 
6050  for( i = 0; i < consdata->nquadvars; ++i )
6051  {
6052  coef = multleft * multright * coefleft[i];
6053  coef += rhs * multright / (rightminactivity * rightmaxactivity) * coefright[i];
6054  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coef) );
6055  }
6056 
6057  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_factorablesecant_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6058 
6059  rowprep->local = TRUE;
6060  }
6061  else
6062  {
6063  SCIP_Real refvalue;
6064 
6065  /* if rhs < 0.0, then rhs / (multright * <coefright, x'>) is convex, thus need linearization:
6066  * rhs / (multright * <coefright, x'>)
6067  * <= rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'> - multright * <coefright, ref'>)
6068  * = 2*rhs / (multright * <coefright, ref'>) - rhs / (multright * <coefright, ref'>)^2 * (multright * <coefright, x'>)
6069  *
6070  * where ref' = (ref, 1)
6071  */
6072 
6073  /* compute <coefright, ref'> */
6074  refvalue = coefright[consdata->nquadvars];
6075  for( i = 0; i < consdata->nquadvars; ++i )
6076  refvalue += coefright[i] * ref[i];
6077 
6078  /* should not happen, since we checked activity of <coefright,x> before, and assume ref within bounds */
6079  assert(!SCIPisZero(scip, refvalue));
6080 
6081  constant = multleft * multright * coefleft[consdata->nquadvars];
6082  constant -= 2.0 * rhs / (multright * refvalue);
6083  constant += rhs / (refvalue * refvalue) * multright * coefright[consdata->nquadvars];
6084 
6085  SCIPaddRowprepConstant(rowprep, constant);
6086 
6087  for( i = 0; i < consdata->nquadvars; ++i )
6088  {
6089  coef = multleft * multright * coefleft[i];
6090  coef += rhs / (refvalue * refvalue) * multright * coefright[i];
6091  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coef) );
6092  }
6093 
6094  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_factorablelinearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
6095  }
6096 
6097  *success = TRUE;
6098 
6099  return SCIP_OKAY;
6100 }
6101 
6102 /** tries to generate a cut if constraint quadratic function is factorable and there are no linear variables
6103  * (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
6104  */
6105 static
6107  SCIP* scip, /**< SCIP data structure */
6108  SCIP_CONS* cons, /**< constraint */
6109  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6110  SCIP_Real* ref, /**< reference solution where to generate the cut */
6111  SCIP_ROWPREP* rowprep, /**< data structure to store cut coefficients */
6112  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6113  )
6114 {
6115  SCIP_CONSDATA* consdata;
6116  SCIP_Real leftminactivity;
6117  SCIP_Real leftmaxactivity;
6118  SCIP_Real rightminactivity;
6119  SCIP_Real rightmaxactivity;
6120  SCIP_Real leftminactivityglobal;
6121  SCIP_Real leftmaxactivityglobal;
6122  SCIP_Real rightminactivityglobal;
6123  SCIP_Real rightmaxactivityglobal;
6124  SCIP_Real multleft;
6125  SCIP_Real multright;
6126  SCIP_Real rhs;
6127  int i;
6128 
6129  assert(scip != NULL);
6130  assert(cons != NULL);
6131  assert(ref != NULL);
6132  assert(rowprep != NULL);
6133  assert(success != NULL);
6134 
6135  consdata = SCIPconsGetData(cons);
6136  assert(consdata != NULL);
6137  assert(consdata->nlinvars == 0);
6138  assert(consdata->factorleft != NULL);
6139  assert(consdata->factorright != NULL);
6140 
6141  *success = FALSE;
6142 
6143  leftminactivityglobal = leftminactivity = consdata->factorleft[consdata->nquadvars];
6144  leftmaxactivityglobal = leftmaxactivity = consdata->factorleft[consdata->nquadvars];
6145  rightminactivityglobal = rightminactivity = consdata->factorright[consdata->nquadvars];
6146  rightmaxactivityglobal = rightmaxactivity = consdata->factorright[consdata->nquadvars];
6147  for( i = 0; i < consdata->nquadvars; ++i )
6148  {
6149  if( !SCIPisInfinity(scip, -leftminactivity) )
6150  {
6151  if( consdata->factorleft[i] > 0.0 )
6152  {
6153  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6154  leftminactivity = -SCIPinfinity(scip);
6155  else
6156  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6157  }
6158  else if( consdata->factorleft[i] < 0.0 )
6159  {
6160  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6161  leftminactivity = -SCIPinfinity(scip);
6162  else
6163  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6164  }
6165  }
6166  if( !SCIPisInfinity(scip, leftmaxactivity) )
6167  {
6168  if( consdata->factorleft[i] > 0.0 )
6169  {
6170  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6171  leftmaxactivity = SCIPinfinity(scip);
6172  else
6173  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6174  }
6175  else if( consdata->factorleft[i] < 0.0 )
6176  {
6177  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6178  leftmaxactivity = SCIPinfinity(scip);
6179  else
6180  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6181  }
6182  }
6183 
6184  if( !SCIPisInfinity(scip, -rightminactivity) )
6185  {
6186  if( consdata->factorright[i] > 0.0 )
6187  {
6188  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6189  rightminactivity = -SCIPinfinity(scip);
6190  else
6191  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6192  }
6193  else if( consdata->factorright[i] < 0.0 )
6194  {
6195  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6196  rightminactivity = -SCIPinfinity(scip);
6197  else
6198  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6199  }
6200  }
6201  if( !SCIPisInfinity(scip, rightmaxactivity) )
6202  {
6203  if( consdata->factorright[i] > 0.0 )
6204  {
6205  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
6206  rightmaxactivity = SCIPinfinity(scip);
6207  else
6208  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
6209  }
6210  else if( consdata->factorright[i] < 0.0 )
6211  {
6212  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
6213  rightmaxactivity = SCIPinfinity(scip);
6214  else
6215  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
6216  }
6217  }
6218 
6219  if( SCIPgetDepth(scip) > 0 )
6220  {
6221  if( !SCIPisInfinity(scip, -leftminactivityglobal) )
6222  {
6223  if( consdata->factorleft[i] > 0.0 )
6224  {
6225  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6226  leftminactivityglobal = -SCIPinfinity(scip);
6227  else
6228  leftminactivityglobal += consdata->factorleft[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6229  }
6230  else if( consdata->factorleft[i] < 0.0 )
6231  {
6232  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6233  leftminactivityglobal = -SCIPinfinity(scip);
6234  else
6235  leftminactivityglobal += consdata->factorleft[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6236  }
6237  }
6238  if( !SCIPisInfinity(scip, leftmaxactivityglobal) )
6239  {
6240  if( consdata->factorleft[i] > 0.0 )
6241  {
6242  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6243  leftmaxactivityglobal = SCIPinfinity(scip);
6244  else
6245  leftmaxactivityglobal += consdata->factorleft[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6246  }
6247  else if( consdata->factorleft[i] < 0.0 )
6248  {
6249  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6250  leftmaxactivityglobal = SCIPinfinity(scip);
6251  else
6252  leftmaxactivityglobal += consdata->factorleft[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6253  }
6254  }
6255 
6256  if( !SCIPisInfinity(scip, -rightminactivityglobal) )
6257  {
6258  if( consdata->factorright[i] > 0.0 )
6259  {
6260  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6261  rightminactivityglobal = -SCIPinfinity(scip);
6262  else
6263  rightminactivityglobal += consdata->factorright[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6264  }
6265  else if( consdata->factorright[i] < 0.0 )
6266  {
6267  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6268  rightminactivityglobal = -SCIPinfinity(scip);
6269  else
6270  rightminactivityglobal += consdata->factorright[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6271  }
6272  }
6273  if( !SCIPisInfinity(scip, rightmaxactivityglobal) )
6274  {
6275  if( consdata->factorright[i] > 0.0 )
6276  {
6277  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->quadvarterms[i].var)) )
6278  rightmaxactivityglobal = SCIPinfinity(scip);
6279  else
6280  rightmaxactivityglobal += consdata->factorright[i] * SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
6281  }
6282  else if( consdata->factorright[i] < 0.0 )
6283  {
6284  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->quadvarterms[i].var)) )
6285  rightmaxactivityglobal = SCIPinfinity(scip);
6286  else
6287  rightmaxactivityglobal += consdata->factorright[i] * SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
6288  }
6289  }
6290  }
6291  }
6292 
6293  /* write violated constraints as multleft * factorleft * factorright <= rhs */
6294  if( violside == SCIP_SIDETYPE_RIGHT )
6295  {
6296  rhs = consdata->rhs;
6297  multleft = 1.0;
6298  }
6299  else
6300  {
6301  rhs = -consdata->lhs;
6302  multleft = -1.0;
6303  }
6304 
6305  if( SCIPisZero(scip, rhs) )
6306  {
6307  /* @todo do something for rhs == 0.0? */
6308  return SCIP_OKAY;
6309  }
6310 
6311  if( !SCIPisFeasPositive(scip, leftminactivity) && !SCIPisFeasNegative(scip, leftmaxactivity) )
6312  {
6313  /* left factor has 0 within activity bounds, or is very close, at least */
6314  if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
6315  {
6316  /* right factor also has 0 within activity bounds, or is very close, at least
6317  * -> cannot separate
6318  */
6319  return SCIP_OKAY;
6320  }
6321 
6322  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
6323  * such that multright * factorright > 0.0
6324  */
6325  if( rightminactivity < 0.0 )
6326  multright = -1.0;
6327  else
6328  multright = 1.0;
6329 
6330  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
6331  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, rowprep, success) );
6332 
6333  /* if right factor has 0 within global activity bounds, then the added linearization is not globally valid */
6334  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && rightminactivityglobal < 0.0 && rightmaxactivityglobal > 0.0 )
6335  rowprep->local = TRUE;
6336  }
6337  else if( !SCIPisFeasPositive(scip, rightminactivity) && !SCIPisFeasNegative(scip, rightmaxactivity) )
6338  {
6339  /* left factor is bounded away from 0
6340  * right factor has 0 within activity bounds, or is very close, at least
6341  * -> so divide by left factor
6342  */
6343 
6344  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
6345  * such that multright * factorleft > 0.0
6346  */
6347  if( leftminactivity < 0.0 )
6348  multright = -1.0;
6349  else
6350  multright = 1.0;
6351 
6352  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
6353  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, rowprep, success) );
6354 
6355  /* if left factor has 0 within global activity bounds, then the added linearization is not globally valid */
6356  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && leftminactivityglobal < 0.0 && leftmaxactivityglobal > 0.0 )
6357  rowprep->local = TRUE;
6358  }
6359  else if( SCIPisInfinity(scip, -leftminactivity) || SCIPisInfinity(scip, leftmaxactivity) ||
6360  (!SCIPisInfinity(scip, -rightminactivity) && !SCIPisInfinity(scip, rightmaxactivity) && rightmaxactivity - rightminactivity < leftmaxactivity - leftminactivity) )
6361  {
6362  /* both factors are bounded away from 0, but the right one has a smaller activity range, so divide by that one */
6363 
6364  /* write violated constraint as multleft * factorleft * multright * (multright * factorright) <= rhs
6365  * such that multright * factorright > 0.0
6366  */
6367  if( rightminactivity < 0.0 )
6368  multright = -1.0;
6369  else
6370  multright = 1.0;
6371 
6372  /* generate cut for multleft * factorleft * multright <= rhs / (factorright * multright) */
6373  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorleft, multright, consdata->factorright, rightminactivity, rightmaxactivity, rhs, rowprep, success) );
6374 
6375  /* if right factor has 0 within global activity bounds, then the added linearization is not globally valid */
6376  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && rightminactivityglobal < 0.0 && rightmaxactivityglobal > 0.0 )
6377  rowprep->local = TRUE;
6378  }
6379  else
6380  {
6381  /* both factors are bounded away from 0, but the left one has a smaller activity range, so divide by that one */
6382 
6383  /* write violated constraint as multleft * factorright * multright * (multright * factorleft) <= rhs
6384  * such that multright * factorleft > 0.0
6385  */
6386  if( leftminactivity < 0.0 )
6387  multright = -1.0;
6388  else
6389  multright = 1.0;
6390 
6391  /* generate cut for multleft * factorright * multright <= rhs / (factorleft * multright) */
6392  SCIP_CALL( generateCutFactorableDo(scip, cons, ref, multleft, consdata->factorright, multright, consdata->factorleft, leftminactivity, leftmaxactivity, rhs, rowprep, success) );
6393 
6394  /* if left factor has 0 within global activity bounds, then the added linearization is not globally valid */
6395  if( rhs < 0.0 && SCIPgetDepth(scip) > 0 && leftminactivityglobal < 0.0 && leftmaxactivityglobal > 0.0 )
6396  rowprep->local = TRUE;
6397  }
6398 
6399  return SCIP_OKAY;
6400 }
6401 
6402 /* finds intersections of a parametric line (x,y) = (x0,y0) + t [(x1,y1) - (x0,y0)] on curves x*y = wl and x*y = wu;
6403  * returns TRUE if unsuccessful and FALSE otherwise
6404  */
6405 static
6407  SCIP* scip,
6408  SCIP_Real x0,
6409  SCIP_Real y0_,
6410  SCIP_Real x1,
6411  SCIP_Real y1_,
6412  SCIP_Real wl,
6413  SCIP_Real wu,
6414  SCIP_Real* xl,
6415  SCIP_Real* yl,
6416  SCIP_Real* xu,
6417  SCIP_Real* yu
6418  )
6419 {
6420  SCIP_Real a;
6421  SCIP_Real b;
6422  SCIP_Real c;
6423  SCIP_Real tl;
6424  SCIP_Real tu;
6425 
6426  assert(wl == SCIP_INVALID || (xl != NULL && yl != NULL)); /*lint !e777 */
6427  assert(wu == SCIP_INVALID || (xu != NULL && yu != NULL)); /*lint !e777 */
6428 
6429  /* The parametric line is of the form
6430  *
6431  * x = x0 + t (x1-x0)
6432  * y = y0 + t (y1-y0)
6433  *
6434  * and for that to satisfy xy = wl and xy = wu we must have
6435  *
6436  * x0 y0 + t [x0 (y1-y0) + y0 (x1-x0)] + t^2 (x1-x0) (y1-y0) = wl
6437  * = wu
6438  *
6439  * or a t^2 + b t + c - wl = 0 for proper values of a,b,c.
6440  * a t^2 + b t + c - wu = 0
6441  *
6442  * Because of the way this procedure will be used, one of the two
6443  * solutions found we must always use the minimum nonnegative one
6444  */
6445 
6446  a = (x1 - x0) * (y1_ - y0_);
6447  c = x0 * y0_;
6448  b = x0 * y1_ + y0_ * x1 - 2.0 * c;
6449 
6450  tl = 0.0;
6451  tu = 0.0;
6452 
6453  if( !SCIPisZero(scip, (SCIP_Real)a) )
6454  {
6455  if( wl != SCIP_INVALID ) /*lint !e777 */
6456  {
6457  SCIP_Real tl1;
6458  SCIP_Real tl2;
6459  SCIP_Real denom;
6460  SCIP_Real q;
6461 
6462  if( b * b - 4.0 * a * (c - wl) < 0.0 )
6463  {
6464  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6465  return TRUE;
6466  }
6467 
6468  denom = sqrt(b * b - 4.0 * a * (c - wl));
6469  q = -0.5 * (b + COPYSIGN(denom, b));
6470  tl1 = q / a;
6471  tl2 = (c - wl) / q;
6472 
6473  /* choose the smallest non-negative root */
6474  tl = (tl1 >= 0.0 && (tl2 < 0.0 || tl1 < tl2)) ? tl1 : tl2;
6475  }
6476 
6477  if( wu != SCIP_INVALID ) /*lint !e777 */
6478  {
6479  SCIP_Real tu1;
6480  SCIP_Real tu2;
6481  SCIP_Real denom;
6482  SCIP_Real q;
6483 
6484  if( b * b - 4.0 * a * (c - wu) < 0.0 )
6485  {
6486  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6487  return TRUE;
6488  }
6489 
6490  denom = sqrt(b * b - 4.0 * a * (c - wu));
6491  q = -0.5 * (b + COPYSIGN(denom, b));
6492  tu1 = q / a;
6493  tu2 = (c - wu) / q;
6494 
6495  /* choose the smallest non-negative root */
6496  tu = (tu1 >= 0.0 && (tu2 < 0.0 || tu1 < tu2)) ? tu1 : tu2;
6497  }
6498  }
6499  else if( !SCIPisZero(scip, (SCIP_Real)b) )
6500  {
6501  if( wl != SCIP_INVALID ) /*lint !e777 */
6502  tl = (wl - c) / b;
6503  if( wu != SCIP_INVALID ) /*lint !e777 */
6504  tu = (wu - c) / b;
6505  }
6506  else
6507  {
6508  /* no or infinitely many solutions */
6509  return TRUE;
6510  }
6511 
6512  if( wl != SCIP_INVALID ) /*lint !e777 */
6513  {
6514  *xl = (SCIP_Real)(x0 + tl * (x1 - x0 ));
6515  *yl = (SCIP_Real)(y0_ + tl * (y1_ - y0_));
6516 
6517  if( !SCIPisRelEQ(scip, *xl * *yl, wl) )
6518  {
6519  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6520  return TRUE;
6521  }
6522  }
6523 
6524  if( wu != SCIP_INVALID ) /*lint !e777 */
6525  {
6526  *xu = (SCIP_Real)(x0 + tu * (x1 - x0));
6527  *yu = (SCIP_Real)(y0_ + tu * (y1_ - y0_));
6528 
6529  if( !SCIPisRelEQ(scip, *xu * *yu, wu) )
6530  {
6531  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6532  return TRUE;
6533  }
6534  }
6535 
6536  /* do not use the computed points if one of the components is infinite */
6537  if( (xu != NULL && SCIPisInfinity(scip, *xu)) || (xl != NULL && SCIPisInfinity(scip, -*xl)) ||
6538  (yu != NULL && SCIPisInfinity(scip, *yu)) || (yl != NULL && SCIPisInfinity(scip, -*yl)) )
6539  {
6540  SCIPdebugMsg(scip, "probable numerical difficulties, give up\n");
6541  return TRUE;
6542  }
6543 
6544  return FALSE;
6545 }
6546 
6547 /** generate coefficients for a plane through points (x1, y1_, x1*y1) and (x2, y2, x2*y2)
6548  * such that intersecting it with one of them (the first if whichuse is FALSE, the second otherwise)
6549  * gives a tangent to the curve x*y = k
6550  *
6551  * Returns TRUE on error and FALSE on success.
6552  */
6553 static
6555  SCIP* scip,
6556  SCIP_Real x1,
6557  SCIP_Real y1_,
6558  SCIP_Real x2,
6559  SCIP_Real y2,
6560  SCIP_Bool whichuse,
6561  SCIP_Real* cx,
6562  SCIP_Real* cy,
6563  SCIP_Real* cw
6564  )
6565 {
6566  SCIP_Real xd;
6567  SCIP_Real yd;
6568  SCIP_Real xo;
6569  SCIP_Real yo;
6570 
6571  assert(cx != NULL);
6572  assert(cy != NULL);
6573  assert(cw != NULL);
6574 
6575  /* the x-y slope of this constraint must be tangent to a curve x*y = k at (xD,yD) */
6576  if( !whichuse )
6577  {
6578  xd = x1;
6579  xo = x2;
6580  yd = y1_;
6581  yo = y2;
6582  }
6583  else
6584  {
6585  xd = x2;
6586  xo = x1;
6587  yd = y2;
6588  yo = y1_;
6589  }
6590 
6591  *cx = yd;
6592  *cy = xd;
6593 
6594  /* lift it so that it touches the other curve */
6595 
6596  /* if the two points are on the same curve, then no cut */
6597  if( SCIPisZero(scip, xo * yo - xd * yd) )
6598  return TRUE;
6599 
6600  /* should ALWAYS be negative */
6601  *cw = (2.0 * xd * yd - (*cx * xo + *cy * yo)) / (xo * yo - xd * yd);
6602 
6603  return FALSE;
6604 }
6605 
6606 /** computes coefficients of a lifted-tangent inequality for x*y = w
6607  *
6608  * The code is an adaptation of the methods in exprMul-upperHull.cpp in Couenne/stable/0.4 rev773,
6609  * written by P. Belotti and licensed under Eclipse Public License.
6610  */
6611 static
6613  SCIP* scip, /**< SCIP data structure */
6614  SCIP_Real xl, /**< lower bound on x */
6615  SCIP_Real xu, /**< upper bound on x */
6616  SCIP_Real x0, /**< reference point for x */
6617  SCIP_Real yl, /**< lower bound on y */
6618  SCIP_Real yu, /**< upper bound on y */
6619  SCIP_Real y0_, /**< reference point for y */
6620  SCIP_Real wl, /**< lower bound on w */
6621  SCIP_Real wu, /**< upper bound on w */
6622  SCIP_Real w0, /**< reference point for w */
6623  SCIP_Real* cx, /**< buffer where to store cut coefficient for x */
6624  SCIP_Real* cy, /**< buffer where to store cut coefficient for y */
6625  SCIP_Real* cw, /**< buffer where to store cut coefficient for w */
6626  SCIP_Real* c0, /**< buffer where to store cut left-hand-side */
6627  SCIP_Bool* success /**< buffer where to indicate whether cut coefficients were computed */
6628  )
6629 {
6630  SCIP_Bool flipx;
6631  SCIP_Bool flipy;
6632  SCIP_Bool flipw;
6633  SCIP_Real tmp;
6634  SCIP_Real xlow;
6635  SCIP_Real ylow;
6636  SCIP_Real xupp;
6637  SCIP_Real yupp;
6638  SCIP_Real c0x;
6639  SCIP_Real c0y;
6640  SCIP_Real c0w;
6641 
6642  assert(scip != NULL);
6643  assert(cx != NULL);
6644  assert(cy != NULL);
6645  assert(cw != NULL);
6646  assert(c0 != NULL);
6647  assert(success != NULL);
6648 
6649  *success = FALSE;
6650  *cx = 0.0;
6651  *cy = 0.0;
6652  *cw = 0.0;
6653  *c0 = 0.0;
6654 
6655  SCIPdebugMsg(scip, "entering points:\n");
6656  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
6657  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
6658  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
6659 
6660  /* generateCutLTI should have recognized these */
6661  assert(wl >= 0.0 || wu <= 0.0);
6662  assert(!SCIPisInfinity(scip, -wl));
6663  assert(!SCIPisInfinity(scip, wu));
6664 
6665  assert(SCIPisFeasGE(scip, x0, xl));
6666  assert(SCIPisFeasLE(scip, x0, xu));
6667  assert(SCIPisFeasGE(scip, y0_, yl));
6668  assert(SCIPisFeasLE(scip, y0_, yu));
6669 
6670  /* preliminary bound tightening */
6671  if( wl >= 0.0 )
6672  {
6673  if( xl >= 0.0 || yl >= 0.0 || SCIPisLT(scip, xl * yl, wl) )
6674  {
6675  xl = MAX(xl, 0.0);
6676  yl = MAX(yl, 0.0);
6677  }
6678  else if( xu <= 0.0 || yu <= 0.0 || SCIPisLT(scip, xu * yu, wl) )
6679  {
6680  xu = MIN(xu, 0.0);
6681  yu = MIN(yu, 0.0);
6682  }
6683  else
6684  {
6685  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yl and xu*yu are feasible
6686  * cannot generate cut for this
6687  */
6688  return;
6689  }
6690  }
6691  else
6692  {
6693  if( xl >= 0.0 || yu <= 0.0 || SCIPisGT(scip, xl * yu, wu) )
6694  {
6695  xl = MAX(xl, 0.0);
6696  yu = MIN(yu, 0.0);
6697  }
6698  else if( xu <= 0.0 || yl >= 0.0 || SCIPisGT(scip, xu * yl, wu))
6699  {
6700  xu = MIN(xu, 0.0);
6701  yl = MAX(yl, 0.0);
6702  }
6703  else
6704  {
6705  /* both variables have mixed sign (xl < 0 && xu > 0 && yl < 0 && yu > 0) and both xl*yu and xu*yl are feasible
6706  * cannot generate cut for this
6707  */
6708  return;
6709  }
6710  }
6711 
6712  /* if x or y is fixed now or even infeasible, then do not think about a cut */
6713  if( SCIPisGE(scip, xl, xu) || SCIPisGE(scip, yl, yu) )
6714  return;
6715 
6716  /* reduce to positive orthant by flipping variables */
6717  if( xl < 0.0 )
6718  {
6719  flipx = TRUE;
6720  tmp = xu;
6721  xu = -xl;
6722  xl = -tmp;
6723  x0 = -x0;
6724  }
6725  else
6726  flipx = FALSE;
6727 
6728  if( yl < 0.0 )
6729  {
6730  flipy = TRUE;
6731  tmp = yu;
6732  yu = -yl;
6733  yl = -tmp;
6734  y0_ = -y0_;
6735  }
6736  else
6737  flipy = FALSE;
6738 
6739  if( flipx ^ flipy )
6740  {
6741  flipw = TRUE;
6742  tmp = wu;
6743  wu = -wl;
6744  wl = -tmp;
6745  w0 = -w0;
6746  }
6747  else
6748  flipw = FALSE;
6749 
6750  /* project refpoint into box not only for numerical reasons, but also due to preliminary bound tightening above */
6751  x0 = MIN(xu, MAX(x0, xl));
6752  y0_ = MIN(yu, MAX(y0_, yl));
6753  w0 = MIN(wu, MAX(w0, wl));
6754 
6755  SCIPdebugMsg(scip, "reduced points:\n");
6756  SCIPdebugMsg(scip, "x: %9g\t[%9g\t%9g]\n", x0, xl, xu);
6757  SCIPdebugMsg(scip, "y: %9g\t[%9g\t%9g]\n", y0_, yl, yu);
6758  SCIPdebugMsg(scip, "w: %9g\t[%9g\t%9g]\n", w0, wl, wu);
6759 
6760  if( SCIPisGE(scip, xl * yl, wl) && SCIPisLE(scip, xu * yu, wu) )
6761  {
6762  SCIPdebugMsg(scip, "box for x and y inside feasible region -> nothing to separate\n");
6763  return;
6764  }
6765  if( SCIPisGE(scip, x0 * y0_, w0) )
6766  {
6767  SCIPdebugMsg(scip, "point to separate not below curve -> cannot separate\n");
6768  return;
6769  }
6770 
6771  /* find intersections of halfline from origin
6772  * return if no proper point could be found
6773  */
6774  if( generateCutLTIfindIntersection(scip, 0.0, 0.0, x0, y0_, wl, wu, &xlow, &ylow, &xupp, &yupp) )
6775  return;
6776 
6777  SCIPdebugMsg(scip, "intersections:\n");
6778  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6779  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6780 
6781  /* Case 1: If both are outside of bounding box, either NW or SE, then McCormick is sufficient, so return */
6782  if( (xlow <= xl && yupp >= yu) || (ylow <= yl && xupp >= xu) )
6783  return;
6784 
6785  /* There will be at least one cut. Define coefficients and rhs ---will have to change them back if (flipX || flipY) */
6786  if( xlow >= xl && xupp <= xu && ylow >= yl && yupp <= yu )
6787  {
6788  /* Case 2: both are inside. Easy lifting... */
6789  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6790  return;
6791 
6792  c0x = *cx * xlow;
6793  c0y = *cy * ylow;
6794  c0w = *cw * wl;
6795  }
6796  else if( xlow >= xl && ylow >= yl && (xupp > xu || yupp > yu) )
6797  {
6798  /* Case 3a and 3b: through lower curve, but not upper. */
6799  if( yupp > yu )
6800  {
6801  /* upper intersect is North; place it within box */
6802  assert(!SCIPisInfinity(scip, yu));
6803  yupp = yu;
6804  xupp = wu / yu;
6805  }
6806  else
6807  {
6808  /* upper intersect is East; place it within box */
6809  assert(!SCIPisInfinity(scip, xu));
6810  xupp = xu;
6811  yupp = wu / xu;
6812  }
6813 
6814  /* find intersection on low curve on half line through new point and (x0,y0_) */
6815  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow, &ylow, NULL, NULL) )
6816  return;
6817 
6818  /* check whether McCormick is sufficient */
6819  if( xlow < xl || ylow < yl )
6820  return;
6821 
6822  /* lift inequality on lower point */
6823  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6824  return;
6825 
6826  c0x = *cx * xlow;
6827  c0y = *cy * ylow;
6828  c0w = *cw * wl;
6829  }
6830  else if( xupp <= xu && yupp <= yu && (xlow < xl || ylow < yl) )
6831  {
6832  /* Case 4a and 4b: viceversa (lift for validity) */
6833  if( ylow < yl )
6834  {
6835  /* upper intersect is South; place it within box */
6836  assert(!SCIPisZero(scip, yl));
6837  ylow = yl;
6838  xlow = wl / yl;
6839  }
6840  else
6841  {
6842  /* upper intersect is West; place it within box */
6843  assert(!SCIPisZero(scip, xl));
6844  xlow = xl;
6845  ylow = wl / xl;
6846  }
6847 
6848  /* find intersection on low curve on half line through new point and (x0,y0) */
6849  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp, &yupp) )
6850  return;
6851 
6852  /* check whether McCormick is sufficient */
6853  if( xupp > xu || yupp > yu )
6854  return;
6855 
6856  /* lift inequality on UPPER point */
6857  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
6858  return;
6859 
6860  c0x = *cx * xupp;
6861  c0y = *cy * yupp;
6862  c0w = *cw * wu;
6863  }
6864  else if( (xlow < xl && xupp > xu) || (ylow < yl && yupp > yu) )
6865  {
6866  /* Case 5: both outside of bounding box, N and S or W and E. */
6867 #if 0
6868  SCIP_Real xlow2;
6869  SCIP_Real ylow2;
6870  SCIP_Real xupp2;
6871  SCIP_Real yupp2;
6872 #endif
6873 
6874  if( ylow < yl )
6875  {
6876  /* upper intersect is South; place it within box */
6877  assert(!SCIPisZero(scip, yl));
6878  assert(!SCIPisZero(scip, yu));
6879  ylow = yl;
6880  yupp = yu;
6881  xlow = wl / yl;
6882  xupp = wu / yu;
6883  }
6884  else
6885  {
6886  /* upper intersect is West; place it within box */
6887  assert(!SCIPisZero(scip, xl));
6888  assert(!SCIPisZero(scip, xu));
6889  xlow = xl;
6890  xupp = xu;
6891  ylow = wl / xl;
6892  yupp = wu / xu;
6893  }
6894 
6895  SCIPdebugMsg(scip, "New intersections:\n");
6896  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6897  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6898 
6899 #if 1
6900  /* Nothing to find. Just separate two inequalities at the same point, just using different support */
6901  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, FALSE, cx, cy, cw) )
6902  {
6903  if( generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp, yupp, TRUE, cx, cy, cw) )
6904  return;
6905 
6906  c0x = *cx * xupp;
6907  c0y = *cy * yupp;
6908  c0w = *cw * wu;
6909  }
6910  else
6911  {
6912  c0x = *cx * xlow;
6913  c0y = *cy * ylow;
6914  c0w = *cw * wl;
6915  }
6916 
6917 #else
6918  /* find the intersection on the lower (upper) curve on the line through xLP and the upper (lower) point
6919  * this does not seem to work (cuts off solution at nous2), so it is disabled for now
6920  */
6921  if( generateCutLTIfindIntersection(scip, xlow, ylow, x0, y0_, SCIP_INVALID, wu, NULL, NULL, &xupp2, &yupp2) ||
6922  generateCutLTIgenMulCoeff(scip, xlow, ylow, xupp2, yupp2, FALSE, cx, cx, cw) )
6923  {
6924  if( generateCutLTIfindIntersection(scip, xupp, yupp, x0, y0_, wl, SCIP_INVALID, &xlow2, &ylow2, NULL, NULL) ||
6925  generateCutLTIgenMulCoeff(scip, xlow2, ylow2, xupp, yupp, TRUE, cx, cy, cw) )
6926  return;
6927 
6928  c0x = *cx * xupp;
6929  c0y = *cy * yupp;
6930  c0w = *cw * wu;
6931  }
6932  else
6933  {
6934  c0x = *cx * xlow;
6935  c0y = *cy * ylow;
6936  c0w = *cw * wl;
6937  }
6938 #endif
6939  }
6940  else
6941  {
6942  SCIPdebugMsg(scip, "points are in a weird position:\n");
6943  SCIPdebugMsg(scip, "lower: %9g\t%9g\tprod %9g\n", xlow, ylow, xlow*ylow);
6944  SCIPdebugMsg(scip, "upper: %9g\t%9g\tprod %9g\n", xupp, yupp, xupp*yupp);
6945 
6946  return;
6947  }
6948 
6949  SCIPdebugMsg(scip, "cut w.r.t. reduced points: %gx-%g %+gy-%g %+gw-%g >= 0\n",
6950  *cx, c0x, *cy, c0y, *cw, c0w);
6951 
6952  /* re-transform back into original variables */
6953  if( flipx )
6954  *cx = -*cx;
6955  if( flipy )
6956  *cy = -*cy;
6957  if( flipw )
6958  *cw = -*cw;
6959 
6960  *c0 = c0x + c0y + c0w;
6961 
6962  *success = TRUE;
6963 }
6964 
6965 /** tries to generate a cut if constraint quadratic function is factorable and there are linear variables
6966  *
6967  * Computes what is called a lifted tangent inequality described in@n
6968  * Belotti, Miller, Namazifar, Lifted inequalities for bounded products of variables, SIAG/OPT Views-and-News 22:1, 2011
6969  */
6970 static
6972  SCIP* scip, /**< SCIP data structure */
6973  SCIP_CONS* cons, /**< constraint */
6974  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
6975  SCIP_Real* ref, /**< reference solution where to generate the cut */
6976  SCIP_SOL* sol, /**< solution that shall be cutoff, NULL for LP solution */
6977  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
6978  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
6979  )
6980 {
6981  SCIP_CONSDATA* consdata;
6982  SCIP_Real leftminactivity;
6983  SCIP_Real leftmaxactivity;
6984  SCIP_Real leftrefactivity;
6985  SCIP_Real rightminactivity;
6986  SCIP_Real rightmaxactivity;
6987  SCIP_Real rightrefactivity;
6988  SCIP_Real rhsminactivity;
6989  SCIP_Real rhsmaxactivity;
6990  SCIP_Real rhsrefactivity;
6991  SCIP_Real coefleft;
6992  SCIP_Real coefright;
6993  SCIP_Real coefrhs;
6994  SCIP_Real cutlhs;
6995  int i;
6996 
6997  assert(scip != NULL);
6998  assert(cons != NULL);
6999  assert(ref != NULL);
7000  assert(rowprep != NULL);
7001  assert(success != NULL);
7002  /* currently only separate LP solution or solutions given as SCIP_SOL, i.e., no cutgeneration during initlp */
7003  assert(sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);
7004 
7005  consdata = SCIPconsGetData(cons);
7006  assert(consdata != NULL);
7007  assert(consdata->nlinvars > 0);
7008  assert(consdata->factorleft != NULL);
7009  assert(consdata->factorright != NULL);
7010 
7011  *success = FALSE;
7012  rowprep->sidetype = SCIP_SIDETYPE_LEFT;
7013 
7014  /* write violated constraints as factorleft * factorright '==' rhs
7015  * where rhs are constraint sides - activity bound of linear part
7016  */
7017  rhsminactivity = consdata->lhs;
7018  rhsmaxactivity = consdata->rhs;
7019  rhsrefactivity = (violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7020 
7021  for( i = 0; i < consdata->nlinvars; ++i )
7022  {
7023  if( !SCIPisInfinity(scip, -rhsminactivity) )
7024  {
7025  if( consdata->lincoefs[i] < 0.0 )
7026  {
7027  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
7028  rhsminactivity = -SCIPinfinity(scip);
7029  else
7030  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7031  }
7032  else
7033  {
7034  assert(consdata->lincoefs[i] > 0.0);
7035  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
7036  rhsminactivity = -SCIPinfinity(scip);
7037  else
7038  rhsminactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7039  }
7040  }
7041  if( !SCIPisInfinity(scip, rhsmaxactivity) )
7042  {
7043  if( consdata->lincoefs[i] < 0.0 )
7044  {
7045  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
7046  rhsmaxactivity = SCIPinfinity(scip);
7047  else
7048  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
7049  }
7050  else
7051  {
7052  assert(consdata->lincoefs[i] > 0.0);
7053  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
7054  rhsmaxactivity = SCIPinfinity(scip);
7055  else
7056  rhsmaxactivity -= consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
7057  }
7058  }
7059  rhsrefactivity -= consdata->lincoefs[i] * SCIPgetSolVal(scip, sol, consdata->linvars[i]);
7060  }
7061 
7062  if( SCIPisInfinity(scip, -rhsminactivity) || SCIPisInfinity(scip, rhsmaxactivity) )
7063  {
7064  /* if right hand side is unbounded, then cannot do LTI */
7065  return SCIP_OKAY;
7066  }
7067 
7068  if( !SCIPisFeasPositive(scip, rhsminactivity) && !SCIPisFeasNegative(scip, rhsmaxactivity) )
7069  {
7070  /* if right hand side has 0 inside activity, then cannot do anything
7071  * if it has 0.0 as min or max activity, then a usual McCormick should be sufficient, too
7072  */
7073  return SCIP_OKAY;
7074  }
7075 
7076  leftminactivity = consdata->factorleft[consdata->nquadvars];
7077  leftmaxactivity = consdata->factorleft[consdata->nquadvars];
7078  leftrefactivity = consdata->factorleft[consdata->nquadvars];
7079  rightminactivity = consdata->factorright[consdata->nquadvars];
7080  rightmaxactivity = consdata->factorright[consdata->nquadvars];
7081  rightrefactivity = consdata->factorright[consdata->nquadvars];
7082  for( i = 0; i < consdata->nquadvars; ++i )
7083  {
7084  if( !SCIPisInfinity(scip, -leftminactivity) )
7085  {
7086  if( consdata->factorleft[i] > 0.0 )
7087  {
7088  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7089  leftminactivity = -SCIPinfinity(scip);
7090  else
7091  leftminactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7092  }
7093  else if( consdata->factorleft[i] < 0.0 )
7094  {
7095  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7096  leftminactivity = -SCIPinfinity(scip);
7097  else
7098  leftminactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7099  }
7100  }
7101  if( !SCIPisInfinity(scip, leftmaxactivity) )
7102  {
7103  if( consdata->factorleft[i] > 0.0 )
7104  {
7105  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7106  leftmaxactivity = SCIPinfinity(scip);
7107  else
7108  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7109  }
7110  else if( consdata->factorleft[i] < 0.0 )
7111  {
7112  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7113  leftmaxactivity = SCIPinfinity(scip);
7114  else
7115  leftmaxactivity += consdata->factorleft[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7116  }
7117  }
7118  leftrefactivity += consdata->factorleft[i] * ref[i];
7119 
7120  if( !SCIPisInfinity(scip, -rightminactivity) )
7121  {
7122  if( consdata->factorright[i] > 0.0 )
7123  {
7124  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7125  rightminactivity = -SCIPinfinity(scip);
7126  else
7127  rightminactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7128  }
7129  else if( consdata->factorright[i] < 0.0 )
7130  {
7131  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7132  rightminactivity = -SCIPinfinity(scip);
7133  else
7134  rightminactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7135  }
7136  }
7137  if( !SCIPisInfinity(scip, rightmaxactivity) )
7138  {
7139  if( consdata->factorright[i] > 0.0 )
7140  {
7141  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
7142  rightmaxactivity = SCIPinfinity(scip);
7143  else
7144  rightmaxactivity += consdata->factorright[i] * SCIPvarGetUbLocal(consdata->quadvarterms[i].var);
7145  }
7146  else if( consdata->factorright[i] < 0.0 )
7147  {
7148  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->quadvarterms[i].var)) )
7149  rightmaxactivity = SCIPinfinity(scip);
7150  else
7151  rightmaxactivity += consdata->factorright[i] * SCIPvarGetLbLocal(consdata->quadvarterms[i].var);
7152  }
7153  }
7154  rightrefactivity += consdata->factorright[i] * ref[i];
7155  }
7156 
7157  /* if activities exceed "opposite" infinity, huge bounds seem to be involved, for which the below method is not prepared */
7158  if( SCIPisInfinity(scip, leftminactivity) || SCIPisInfinity(scip, -leftmaxactivity) ||
7159  SCIPisInfinity(scip, rightminactivity) || SCIPisInfinity(scip, -rightmaxactivity) )
7160  return SCIP_OKAY;
7161 
7162  /* if activity in reference point exceeds value for infinity, then the below method will also not work properly */
7163  if( SCIPisInfinity(scip, REALABS(leftrefactivity)) || SCIPisInfinity(scip, REALABS(rightrefactivity)) )
7164  return SCIP_OKAY;
7165 
7166  /* if any of the factors is essentially fixed, give up and do usual method (numerically less sensitive, I hope) */
7167  if( SCIPisRelEQ(scip, leftminactivity, leftmaxactivity) || SCIPisRelEQ(scip, rightminactivity, rightmaxactivity) )
7168  return SCIP_OKAY;
7169 
7170  /* success can only be expected for separation of violated x*y <= w, assuming x>=0, y>=0
7171  * @todo we should check this early? */
7172 
7173  /* call Couenne magic */
7175  leftminactivity, leftmaxactivity, leftrefactivity,
7176  rightminactivity, rightmaxactivity, rightrefactivity,
7177  rhsminactivity, rhsmaxactivity, rhsrefactivity,
7178  &coefleft, &coefright, &coefrhs, &cutlhs,
7179  success);
7180 
7181  if( !*success )
7182  return SCIP_OKAY;
7183 
7184  SCIPdebugMsg(scip, "LTI for x[%g,%g] * y[%g,%g] = w[%g,%g]: %gx %+gy %+gw >= %g; feas: %g\n",
7185  leftminactivity, leftmaxactivity, rightminactivity, rightmaxactivity, rhsminactivity, rhsmaxactivity,
7186  coefleft, coefright, coefrhs, cutlhs,
7187  coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity - cutlhs
7188  );
7189 
7190  if( coefleft * leftrefactivity + coefright * rightrefactivity + coefrhs * rhsrefactivity >= cutlhs )
7191  {
7192  SCIPdebugMsg(scip, "does not cutoff point? :-(\n");
7193  *success = FALSE;
7194  return SCIP_OKAY;
7195  }
7196 
7197  /* setup cut coefs for
7198  * coefleft * leftfactor + coefright * rightfactor + coefrhs * w >= cutlhs, where conslhs - lincoefs <= w <= consrhs - lincoefs
7199  */
7200  for( i = 0; i < consdata->nquadvars; ++i )
7201  {
7202  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->quadvarterms[i].var, coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i]) );
7203  }
7204  SCIPaddRowprepConstant(rowprep, coefleft * consdata->factorleft[i] + coefright * consdata->factorright[i]);
7205 
7206  for( i = 0; i < consdata->nlinvars; ++i )
7207  {
7208  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, consdata->linvars[i], -coefrhs * consdata->lincoefs[i]) );
7209  }
7210  if( coefrhs > 0.0 )
7211  {
7212  /* use coefrhs * w <= coefrhs * (consrhs - lincoefs) */
7213  assert(!SCIPisInfinity(scip, consdata->rhs));
7214  SCIPaddRowprepConstant(rowprep, coefrhs * consdata->rhs);
7215  }
7216  else
7217  {
7218  /* use coefrhs * w <= coeflhs * (conslhs - lincoefs) */
7219  assert(!SCIPisInfinity(scip, -consdata->lhs));
7220  SCIPaddRowprepConstant(rowprep, coefrhs * consdata->lhs);
7221  }
7222  SCIPaddRowprepSide(rowprep, cutlhs);
7223 
7224  rowprep->local = TRUE;
7225 
7226  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_lti_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
7227 
7228  *success = TRUE;
7229 
7230  return SCIP_OKAY;
7231 }
7232 
7233 /** computes cut coefficients by linearizing a quadratic function */
7234 static
7236  SCIP* scip, /**< SCIP data structure */
7237  SCIP_CONS* cons, /**< constraint */
7238  SCIP_SIDETYPE violside, /**< side for which to generate cut */
7239  SCIP_Real* ref, /**< reference solution where to generate the cut */
7240  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
7241  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
7242  )
7243 {
7244  SCIP_CONSDATA* consdata;
7245  SCIP_BILINTERM* bilinterm;
7246  SCIP_Real constant;
7247  SCIP_Real coef;
7248  SCIP_Real coef2;
7249  SCIP_VAR* var;
7250  int var2pos;
7251  int j;
7252  int k;
7253 
7254  assert(scip != NULL);
7255  assert(cons != NULL);
7256  assert(ref != NULL);
7257  assert(success != NULL);
7258 
7259  consdata = SCIPconsGetData(cons);
7260  assert(consdata != NULL);
7261 
7262  *success = TRUE;
7263 
7264  /* do first-order Taylor for each term */
7265  for( j = 0; j < consdata->nquadvars && *success; ++j )
7266  {
7267  var = consdata->quadvarterms[j].var;
7268 
7269  /* initialize coefficients to linear coefficients of quadratic variables */
7270  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, consdata->quadvarterms[j].lincoef) );
7271 
7272  /* add linearization of square term */
7273  coef = 0.0;
7274  constant = 0.0;
7275  SCIPaddSquareLinearization(scip, consdata->quadvarterms[j].sqrcoef, ref[j],
7276  consdata->quadvarterms[j].nadjbilin == 0 && SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef, &constant, success);
7277  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7278  SCIPaddRowprepConstant(rowprep, constant);
7279 
7280  /* add linearization of bilinear terms that have var as first variable */
7281  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && *success; ++k )
7282  {
7283  bilinterm = &consdata->bilinterms[consdata->quadvarterms[j].adjbilin[k]];
7284  if( bilinterm->var1 != var )
7285  continue;
7286  assert(bilinterm->var2 != var);
7287  assert(consdata->sepabilinvar2pos != NULL);
7288 
7289  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
7290  assert(var2pos >= 0);
7291  assert(var2pos < consdata->nquadvars);
7292  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
7293 
7294  coef = 0.0;
7295  coef2 = 0.0;
7296  constant = 0.0;
7297  SCIPaddBilinLinearization(scip, bilinterm->coef, ref[j], ref[var2pos], &coef, &coef2, &constant, success);
7298  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7299  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, bilinterm->var2, coef2) );
7300  SCIPaddRowprepConstant(rowprep, constant);
7301  }
7302  }
7303 
7304  if( !*success )
7305  {
7306  SCIPdebugMsg(scip, "no success in linearization of <%s> in reference point\n", SCIPconsGetName(cons));
7307  return SCIP_OKAY;
7308  }
7309 
7310  rowprep->sidetype = violside;
7311  SCIPaddRowprepSide(rowprep, violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7312 
7313  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_side%d_linearization_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
7314 
7315  return SCIP_OKAY;
7316 }
7317 
7318 /** helper function to update the best relaxation for a bilinear term when using valid linear inequalities */
7319 static
7321  SCIP* scip, /**< SCIP data structure */
7322  SCIP_VAR* RESTRICT x, /**< first variable */
7323  SCIP_VAR* RESTRICT y, /**< second variable */
7324  SCIP_Real bilincoef, /**< coefficient of the bilinear term */
7325  SCIP_SIDETYPE violside, /**< side of quadratic constraint that is violated */
7326  SCIP_Real refx, /**< reference point for the x variable */
7327  SCIP_Real refy, /**< reference point for the y variable */
7328  SCIP_Real* RESTRICT ineqs, /**< coefficients of each linear inequality; stored as triple (xcoef,ycoef,constant) */
7329  int nineqs, /**< total number of inequalities */
7330  SCIP_Real mccormickval, /**< value of the McCormick relaxation at the reference point */
7331  SCIP_Real* RESTRICT bestcoefx, /**< pointer to update the x coefficient */
7332  SCIP_Real* RESTRICT bestcoefy, /**< pointer to update the y coefficient */
7333  SCIP_Real* RESTRICT bestconst, /**< pointer to update the constant */
7334  SCIP_Real* RESTRICT bestval, /**< value of the best relaxation that have been found so far */
7335  SCIP_Bool* success /**< buffer to store whether we found a better relaxation */
7336  )
7337 {
7338  SCIP_Real constshift[2] = {0.0, 0.0};
7339  SCIP_Real constant;
7340  SCIP_Real xcoef;
7341  SCIP_Real ycoef;
7342  SCIP_Real lbx;
7343  SCIP_Real ubx;
7344  SCIP_Real lby;
7345  SCIP_Real uby;
7346  SCIP_Bool update;
7347  SCIP_Bool overestimate;
7348  int i;
7349 
7350  assert(x != y);
7351  assert(!SCIPisZero(scip, bilincoef));
7352  assert(nineqs >= 0 && nineqs <= 2);
7353  assert(bestcoefx != NULL);
7354  assert(bestcoefy != NULL);
7355  assert(bestconst != NULL);
7356  assert(bestval != NULL);
7357 
7358  /* no inequalities available */
7359  if( nineqs == 0 )
7360  return;
7361  assert(ineqs != NULL);
7362 
7363  lbx = SCIPvarGetLbLocal(x);
7364  ubx = SCIPvarGetUbLocal(x);
7365  lby = SCIPvarGetLbLocal(y);
7366  uby = SCIPvarGetUbLocal(y);
7367  overestimate = (violside == SCIP_SIDETYPE_LEFT);
7368 
7369  /* check cases for which we can't compute a tighter relaxation */
7370  if( SCIPisFeasLE(scip, refx, lbx) || SCIPisFeasGE(scip, refx, ubx)
7371  || SCIPisFeasLE(scip, refy, lby) || SCIPisFeasGE(scip, refy, uby) )
7372  return;
7373 
7374  /* due to the feasibility tolerances of the LP and NLP solver, it might possible that the reference point is
7375  * violating the linear inequalities; to ensure that we compute a valid underestimate, we relax the linear
7376  * inequality by changing its constant part
7377  */
7378  for( i = 0; i < nineqs; ++i )
7379  {
7380  constshift[i] = MAX(0.0, ineqs[3*i] * refx - ineqs[3*i+1] * refy - ineqs[3*i+2]);
7381  SCIPdebugMsg(scip, "constant shift of inequality %d = %.16f\n", constshift[i]);
7382  }
7383 
7384  /* try to use both inequalities */
7385  if( nineqs == 2 )
7386  {
7387  SCIPcomputeBilinEnvelope2(scip, bilincoef, lbx, ubx, refx, lby, uby, refy, overestimate, ineqs[0], ineqs[1],
7388  ineqs[2] + constshift[0], ineqs[3], ineqs[4], ineqs[5] + constshift[1], &xcoef, &ycoef, &constant, &update);
7389 
7390  if( update )
7391  {
7392  SCIP_Real val = xcoef * refx + ycoef * refy + constant;
7393  SCIP_Real relimpr = 1.0 - (REALABS(val - bilincoef * refx * refy) + 1e-4) / (REALABS(*bestval - bilincoef * refx * refy) + 1e-4);
7394  SCIP_Real absimpr = REALABS(val - (*bestval));
7395 
7396  /* update relaxation if possible */
7397  if( relimpr > 0.05 && absimpr > 1e-3 && ((overestimate && SCIPisRelLT(scip, val, *bestval)) || (!overestimate && SCIPisRelGT(scip, val, *bestval))) )
7398  {
7399  *bestcoefx = xcoef;
7400  *bestcoefy = ycoef;
7401  *bestconst = constant;
7402  *bestval = val;
7403  *success = TRUE;
7404  }
7405  }
7406  }
7407 
7408  /* use inequalities individually */
7409  for( i = 0; i < nineqs; ++i )
7410  {
7411  SCIPcomputeBilinEnvelope1(scip, bilincoef, lbx, ubx, refx, lby, uby, refy, overestimate, ineqs[3*i], ineqs[3*i+1],
7412  ineqs[3*i+2] + constshift[i], &xcoef, &ycoef, &constant, &update);
7413 
7414  if( update )
7415  {
7416  SCIP_Real val = xcoef * refx + ycoef * refy + constant;
7417  SCIP_Real relimpr = 1.0 - (REALABS(val - bilincoef * refx * refy) + 1e-4) / (REALABS(mccormickval - bilincoef * refx * refy) + 1e-4);
7418  SCIP_Real absimpr = REALABS(val - (*bestval));
7419 
7420  /* update relaxation if possible */
7421  if( relimpr > 0.05 && absimpr > 1e-3 && ((overestimate && SCIPisRelLT(scip, val, *bestval)) || (!overestimate && SCIPisRelGT(scip, val, *bestval))) )
7422  {
7423  *bestcoefx = xcoef;
7424  *bestcoefy = ycoef;
7425  *bestconst = constant;
7426  *bestval = val;
7427  *success = TRUE;
7428  }
7429  }
7430  }
7431 }
7432 
7433 /* returns the interiority of a reference point w.r.t. given bounds */
7434 static
7436  SCIP* scip, /**< SCIP data structure */
7437  SCIP_Real lbx, /**< lower bound of the first variable */
7438  SCIP_Real ubx, /**< upper bound of the first variable */
7439  SCIP_Real refx, /**< reference point of the first variable */
7440  SCIP_Real lby, /**< lower bound of the second variable */
7441  SCIP_Real uby, /**< upper bound of the second variable */
7442  SCIP_Real refy /**< reference point of the second variable */
7443  )
7444 {
7445  SCIP_Real interiorityx;
7446  SCIP_Real interiorityy;
7447 
7448  interiorityx = MIN(refx-lbx, ubx-refx) / MAX(ubx-lbx, SCIPepsilon(scip)); /*lint !e666*/
7449  interiorityy = MIN(refy-lby, uby-refy) / MAX(uby-lby, SCIPepsilon(scip)); /*lint !e666*/
7450 
7451  return 2.0*MIN(interiorityx, interiorityy);
7452 }
7453 
7454 /** computes cut coefficients for a nonconvex quadratic function */
7455 static
7457  SCIP* scip, /**< SCIP data structure */
7458  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7459  SCIP_CONS* cons, /**< constraint */
7460  SCIP_SIDETYPE violside, /**< side for which to generate cut */
7461  SCIP_Real* ref, /**< reference solution where to generate the cut */
7462  SCIP_ROWPREP* rowprep, /**< rowprep to store cut data */
7463  SCIP_Bool* success /**< buffer to indicate whether a cut was successfully computed */
7464  )
7465 {
7466  SCIP_CONSDATA* consdata;
7467  SCIP_BILINTERM* bilinterm;
7468  SCIP_Real sqrcoef;
7469  SCIP_Real coef;
7470  SCIP_Real coef2;
7471  SCIP_Real constant;
7472  SCIP_VAR* var;
7473  int var2pos;
7474  int j;
7475  int k;
7476 
7477  assert(scip != NULL);
7478  assert(conshdlrdata != NULL);
7479  assert(cons != NULL);
7480  assert(ref != NULL);
7481  assert(success != NULL);
7482 
7483  consdata = SCIPconsGetData(cons);
7484  assert(consdata != NULL);
7485 
7486  rowprep->local = TRUE;
7487  *success = TRUE;
7488 
7489  /* underestimate (secant, McCormick) or linearize each term separately */
7490  for( j = 0; j < consdata->nquadvars && *success; ++j )
7491  {
7492  var = consdata->quadvarterms[j].var;
7493 
7494  /* initialize coefficients to linear coefficients of quadratic variables */
7495  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, consdata->quadvarterms[j].lincoef) );
7496 
7497  sqrcoef = consdata->quadvarterms[j].sqrcoef;
7498  if( sqrcoef != 0.0 )
7499  {
7500  coef = 0.0;
7501  constant = 0.0;
7502  if( (violside == SCIP_SIDETYPE_LEFT && sqrcoef <= 0.0) || (violside == SCIP_SIDETYPE_RIGHT && sqrcoef > 0.0) )
7503  {
7504  /* convex -> linearize */
7505  SCIPaddSquareLinearization(scip, sqrcoef, ref[j], SCIPvarGetType(var) < SCIP_VARTYPE_CONTINUOUS, &coef,
7506  &constant, success);
7507  }
7508  else
7509  {
7510  /* not convex -> secant approximation */
7511  SCIPaddSquareSecant(scip, sqrcoef, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), ref[j], &coef,
7512  &constant, success);
7513  }
7514  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7515  SCIPaddRowprepConstant(rowprep, constant);
7516  }
7517 
7518  /* relax each bilinear term */
7519  for( k = 0; k < consdata->quadvarterms[j].nadjbilin && (*success); ++k )
7520  {
7521  SCIP_VAR* x;
7522  SCIP_VAR* y;
7523  SCIP_Real refx;
7524  SCIP_Real refy;
7525  SCIP_Real lbx;
7526  SCIP_Real ubx;
7527  SCIP_Real lby;
7528  SCIP_Real uby;
7529  int idx;
7530 
7531  idx = consdata->quadvarterms[j].adjbilin[k];
7532  bilinterm = &consdata->bilinterms[idx];
7533  if( bilinterm->var1 != var )
7534  continue;
7535  assert(bilinterm->var2 != var);
7536  assert(consdata->sepabilinvar2pos != NULL);
7537 
7538  var2pos = consdata->sepabilinvar2pos[consdata->quadvarterms[j].adjbilin[k]];
7539  assert(var2pos >= 0);
7540  assert(var2pos < consdata->nquadvars);
7541  assert(consdata->quadvarterms[var2pos].var == bilinterm->var2);
7542 
7543  /* get data of the variables in the bilinear term */
7544  x = var;
7545  y = bilinterm->var2;
7546  refx = ref[j];
7547  refy = ref[var2pos];
7548  lbx = SCIPvarGetLbLocal(x);
7549  ubx = SCIPvarGetUbLocal(x);
7550  lby = SCIPvarGetLbLocal(y);
7551  uby = SCIPvarGetUbLocal(y);
7552  SCIPdebugMsg(scip, "bilinear term %g %s %s with (%g,%g) in [%g,%g]x[%g,%g] overestimate=%u\n", bilinterm->coef,
7553  SCIPvarGetName(x), SCIPvarGetName(y), refx, refy, lbx, ubx, lby, uby, violside == SCIP_SIDETYPE_LEFT);
7554 
7555  /* use the McCormick relaxation for under- or overestimating the bilinear term */
7556  coef = 0.0;
7557  coef2 = 0.0;
7558  constant = 0.0;
7559  SCIPaddBilinMcCormick(scip, bilinterm->coef, lbx, ubx, refx, lby, uby, refy,
7560  violside == SCIP_SIDETYPE_LEFT, &coef, &coef2, &constant, success);
7561  SCIPdebugMsg(scip, "McCormick = %g (%u)\n", refx * coef + refy * coef2 + constant, *success);
7562 
7563  /* tries to compute a tighter relaxation for xy by using valid linear inequalities */
7564  if( conshdlrdata->bilinestimators != NULL && ubx - lbx >= 0.1 && uby - lby >= 0.1
7565  && (SCIPgetNSepaRounds(scip) <= conshdlrdata->bilinineqmaxseparounds || SCIPgetDepth(scip) == 0) )
7566  {
7567  BILINESTIMATOR* bilinestimator;
7568  SCIP_Real mccormick;
7569  SCIP_Real score;
7570  int bilintermidx;
7571 
7572  mccormick = refx * coef + refy * coef2 + constant;
7573  score = getInteriority(scip, lbx, ubx, refx, lby, uby, refy);
7574 
7575  /* get data for bilinear term */
7576  bilintermidx = consdata->bilintermsidx[idx];
7577  assert(conshdlrdata->bilinestimators != NULL);
7578  bilinestimator = &(conshdlrdata->bilinestimators[bilintermidx]);
7579  assert(bilinestimator->x == x);
7580  assert(bilinestimator->y == y);
7581 
7582  /* reset the last improvement factor (used for getting better branching decisions) */
7583  bilinestimator->lastimprfac = 0.0;
7584 
7585  /* compute tighter relaxation for xy if the current score is large enough */
7586  if( SCIPisGE(scip, score, conshdlrdata->minscorebilinterms)
7587  && bilinestimator->nineqoverest + bilinestimator->ninequnderest > 0 )
7588  {
7589  SCIP_Real bestval = mccormick;
7590  SCIP_Bool updaterelax = FALSE;
7591 
7592  /*
7593  * note that we check the sign of the bilinear coefficient together with violside in
7594  * updateBilinearRelaxation in order to decide whether a valid under- or overestimate can be computed
7595  */
7596 
7597  /* use overestimates */
7598  updateBilinearRelaxation(scip, x, y, bilinterm->coef, violside, refx, refy, bilinestimator->ineqoverest,
7599  bilinestimator->nineqoverest, mccormick, &coef, &coef2, &constant, &bestval, &updaterelax);
7600 
7601  /* use underestimates */
7602  updateBilinearRelaxation(scip, x, y, bilinterm->coef, violside, refx, refy, bilinestimator->inequnderest,
7603  bilinestimator->ninequnderest, mccormick, &coef, &coef2, &constant, &bestval, &updaterelax);
7604 
7605  SCIPdebugMsg(scip, "found better relaxation value: %u (%g)\n", updaterelax, bestval);
7606 
7607  /* check whether the new relaxation is under- or overestimating xy properly */
7608  if( updaterelax )
7609  {
7610  /* update improvement factor */
7611  bilinestimator->lastimprfac = 1.0 - REALABS(bestval - bilinterm->coef * refx * refy) / REALABS(mccormick - bilinterm->coef * refx * refy);
7612 
7613 #ifndef NDEBUG
7614  assert(SCIPisEQ(scip, bestval, coef * refx + coef2 * refy + constant));
7615  if( violside == SCIP_SIDETYPE_LEFT )
7616  {
7617  assert(SCIPisRelGE(scip, bestval, bilinterm->coef * refx * refy));
7618  assert(SCIPisRelLE(scip, bestval, mccormick));
7619  }
7620  else
7621  {
7622  assert(SCIPisRelLE(scip, bestval, bilinterm->coef * refx * refy));
7623  assert(SCIPisRelGE(scip, bestval, mccormick));
7624  }
7625 #endif
7626  }
7627  }
7628  }
7629 
7630  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, coef) );
7631  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, bilinterm->var2, coef2) );
7632  SCIPaddRowprepConstant(rowprep, constant);
7633  }
7634  }
7635 
7636  if( !*success )
7637  {
7638  SCIPdebugMsg(scip, "no success to find estimator for nonconvex <%s>\n", SCIPconsGetName(cons));
7639  return SCIP_OKAY;
7640  }
7641 
7642  rowprep->sidetype = violside;
7643  SCIPaddRowprepSide(rowprep, violside == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
7644 
7645  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_side%d_estimation_%d", SCIPconsGetName(cons), violside, SCIPgetNLPs(scip));
7646 
7647  return SCIP_OKAY;
7648 }
7649 
7650 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a given reference point */
7651 static
7653  SCIP* scip, /**< SCIP data structure */
7654  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7655  SCIP_CONS* cons, /**< constraint */
7656  SCIP_Real* ref, /**< reference solution where to generate the cut */
7657  SCIP_SOL* sol, /**< point that we aim to separate, or NULL for LP solution */
7658  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
7659  SCIP_ROW** row, /**< storage for cut */
7660  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
7661  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
7662  SCIP_Real minefficacy /**< minimal required efficacy */
7663  )
7664 {
7665  SCIP_CONSHDLRDATA* conshdlrdata;
7666  SCIP_CONSDATA* consdata;
7667  SCIP_ROWPREP* rowprep;
7668  SCIP_Bool success;
7669  SCIP_Real viol = 0.0;
7670 
7671  assert(scip != NULL);
7672  assert(conshdlr != NULL);
7673  assert(cons != NULL);
7674  assert(ref != NULL);
7675  assert(row != NULL);
7676 
7677  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7678  assert(conshdlrdata != NULL);
7679 
7680  consdata = SCIPconsGetData(cons);
7681  assert(consdata != NULL);
7682  assert(violside != SCIP_SIDETYPE_LEFT || !SCIPisInfinity(scip, -consdata->lhs));
7683  assert(violside != SCIP_SIDETYPE_RIGHT || !SCIPisInfinity(scip, consdata->rhs));
7684 
7685  *row = NULL;
7686 
7688  success = FALSE;
7689 
7690  /* if constraint function is factorable, then try to use factorable form to generate cut */
7691  if( consdata->factorleft != NULL )
7692  {
7693  if( consdata->nlinvars == 0 )
7694  {
7695  SCIP_CALL( generateCutFactorable(scip, cons, violside, ref, rowprep, &success) );
7696  }
7697  else if( sol != NULL || SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
7698  {
7699  /* generateCutLTI needs reference values also for the linear variables, which we only have if sol is given or LP has been solved */
7700  SCIP_CALL( generateCutLTI(scip, cons, violside, ref, sol, rowprep, &success) );
7701  }
7702  }
7703 
7704  /* if constraint is not factorable or failed to generate cut, try default method */
7705  if( !success )
7706  {
7707  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
7708 
7709  if( (violside == SCIP_SIDETYPE_LEFT && consdata->isconcave) || (violside == SCIP_SIDETYPE_RIGHT && consdata->isconvex) )
7710  {
7711  SCIP_CALL( generateCutConvex(scip, cons, violside, ref, rowprep, &success) );
7712  }
7713  else
7714  {
7715  SCIP_CALL( generateCutNonConvex(scip, conshdlrdata, cons, violside, ref, rowprep, &success) );
7716  }
7717 
7718  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
7719  }
7720 
7721  /* check if reference point violates cut at least a little bit */
7722  if( success && !SCIPisInfinity(scip, -minefficacy) )
7723  {
7724  viol = SCIPgetRowprepViolation(scip, rowprep, sol);
7725  if( viol <= 0.0 ) /*lint !e644*/
7726  {
7727  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), viol, minefficacy);
7728  success = FALSE;
7729  }
7730  }
7731 
7732  /* cleanup and improve cut */
7733  if( success )
7734  {
7735  SCIP_Real coefrange;
7736 
7737  /* merge terms */
7738  SCIPmergeRowprepTerms(scip, rowprep);
7739 
7740  /* improve coefficients */
7741  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, conshdlrdata->cutmaxrange, minefficacy, &coefrange, &viol) );
7742  success = coefrange <= conshdlrdata->cutmaxrange;
7743  }
7744 
7745  /* check that side is finite */ /*lint --e{514} */
7746  success &= !SCIPisInfinity(scip, REALABS(rowprep->side)); /*lint !e514*/
7747 
7748  /* check whether maximal coef is finite, if any */ /*lint --e{514} */
7749  success &= (rowprep->nvars == 0) || !SCIPisInfinity(scip, REALABS(rowprep->coefs[0])); /*lint !e514*/
7750 
7751  /* check if reference point violates cut sufficiently */
7752  if( success && !SCIPisInfinity(scip, -minefficacy) && viol < minefficacy ) /*lint !e644*/
7753  {
7754  SCIPdebugMsg(scip, "skip cut for constraint <%s> because efficacy %g too low (< %g)\n", SCIPconsGetName(cons), viol, minefficacy);
7755  success = FALSE;
7756  }
7757 
7758  /* generate row */
7759  if( success )
7760  {
7761  SCIP_CALL( SCIPgetRowprepRowCons(scip, row, rowprep, SCIPconsGetHdlr(cons)) );
7762 
7763  SCIPdebugMsg(scip, "found cut <%s>, lhs=%g, rhs=%g, mincoef=%g, maxcoef=%g, range=%g, nnz=%d, efficacy=%g\n",
7764  SCIProwGetName(*row), SCIProwGetLhs(*row), SCIProwGetRhs(*row),
7765  rowprep->nvars > 0 ? rowprep->coefs[rowprep->nvars-1] : 0.0, rowprep->nvars > 0 ? rowprep->coefs[0] : 0.0,
7766  rowprep->nvars > 0 ? rowprep->coefs[0]/rowprep->coefs[rowprep->nvars-1] : 1.0,
7767  SCIProwGetNNonz(*row), viol); /*lint !e414 */
7768 
7769  if( efficacy != NULL )
7770  *efficacy = viol;
7771  }
7772 
7773  SCIPfreeRowprep(scip, &rowprep);
7774 
7775  return SCIP_OKAY;
7776 }
7777 
7778 /** computes eigen decomposition of A, where \f$ f(x) = x^T A x + b^T x \f$.
7779  *
7780  * The eigen decomposition is given by A = P D P^T, where D is diagonal formed by the eigenvalues and P is orthonormal
7781  * whose columns are the eigenvectors; we also compute b^T * P, in case one needs the change of variables P^T x = y <=>
7782  * 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
7783  * of P^T is stored in eigenvector[0..n-1], the second row is stored in eigenvectors[n..2n-1], etc; equivalently, the
7784  * first eigenvector is eigenvector[0..n-1], the second one is eigenvectors[n..2n-1], etc.
7785  *
7786  * @todo: - at the moment of writing, checkCurvature computes the eigenvalues (and vectors) for determining curvature
7787  * when it can't to it via other considerations. so one could try to merge both methods together.
7788  * - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A' so one
7789  * could do better in terms of memory and speed. For instance, when the matrix is diagonal, the eigenvectors
7790  * are the identity matrix and the eigenvalues are readily available from the constraint, so one could adapt
7791  * the functions that uses the eigenvectors in this particular case. One could also think about storing the
7792  * eigenvectors in a sparse fashion, though eigenvectors are seldom sparse.
7793  */
7794 static
7796  SCIP* scip, /**< SCIP data structure */
7797  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7798  SCIP_CONS* cons /**< constraint */
7799  )
7800 {
7801  SCIP_CONSDATA* consdata;
7802  int n;
7803  int nn;
7804  int row;
7805  int col;
7806  int i;
7807  int j;
7808  double* matrix;
7809  SCIP_HASHMAP* var2index;
7810 
7811  SCIPdebugMsg(scip, "computing ED for cons %s\n", SCIPconsGetName(cons));
7812 
7813  assert(scip != NULL);
7814  assert(conshdlr != NULL);
7815  assert(cons != NULL);
7816 
7817  consdata = SCIPconsGetData(cons);
7818  assert(consdata != NULL);
7819 
7820  /* function has to be convex with finite rhs or concave with finite lhs */
7821  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
7822  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7823 
7824  /* can't compute eigenvectors without IPOPT */
7825  if( !SCIPisIpoptAvailableIpopt() )
7826  {
7827  consdata->isedavailable = FALSE;
7828  return SCIP_OKAY;
7829  }
7830 
7831  /* @todo: - it seems that if A is of the form [I 0; 0 A'], one only needs to compute the decomposition for A'
7832  * so one could do better in terms of memory and speed
7833  * - if n too big don't compute SVD
7834  */
7835  n = consdata->nquadvars;
7836 
7837  /* do not compute eigendecomposition if n is too large */
7838  nn = n * n;
7839  if( nn < 0 || (unsigned) (int) nn > UINT_MAX / sizeof(SCIP_Real) )
7840  {
7841  SCIPdebugMsg(scip, "n is too large to compute eigendecomposition\n");
7842  consdata->isedavailable = FALSE;
7843  return SCIP_OKAY;
7844  }
7845 
7846  /* we just need to pass the upper triangle of A since it is symmetric; build it here */
7847  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvectors, nn) );
7848  matrix = consdata->eigenvectors;
7849  BMSclearMemoryArray(matrix, nn);
7850 
7851  /* @todo if we are called in solving stage (or late from initsol), we can avoid the hashmap by using sepabilinvar2pos */
7852  SCIP_CALL( SCIPhashmapCreate(&var2index, SCIPblkmem(scip), n) );
7853 
7854  for( i = 0; i < n; ++i )
7855  {
7856  SCIP_CALL( SCIPhashmapInsertInt(var2index, consdata->quadvarterms[i].var, i) );
7857  matrix[i*n + i] = consdata->quadvarterms[i].sqrcoef;
7858 #ifdef DEBUG_PROJ
7859  printf("inserting in position %d, value %g\n", i*n + i, consdata->quadvarterms[i].sqrcoef);
7860 #endif
7861  }
7862 
7863  for( i = 0; i < consdata->nbilinterms; ++i )
7864  {
7865  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var1));
7866  assert(SCIPhashmapExists(var2index, consdata->bilinterms[i].var2));
7867  row = SCIPhashmapGetImageInt(var2index, consdata->bilinterms[i].var1);
7868  col = SCIPhashmapGetImageInt(var2index, consdata->bilinterms[i].var2);
7869  if( row < col )
7870  {
7871  matrix[row * n + col] = consdata->bilinterms[i].coef/2;
7872 #ifdef DEBUG_PROJ
7873  printf("inserting in position %d, value %g\n", row*n + col, consdata->bilinterms[i].coef/2);
7874 #endif
7875  }
7876  else
7877  {
7878  matrix[col * n + row] = consdata->bilinterms[i].coef/2;
7879 #ifdef DEBUG_PROJ
7880  printf("inserting in position %d, value %g\n", col*n + row, consdata->bilinterms[i].coef/2);
7881 #endif
7882  }
7883  }
7884 
7885 #ifdef DEBUG_PROJ
7886  printf("matrix built:\n");
7887  for( i = 0; i < n; i++ )
7888  {
7889  for( j = 0; j < n; j++ )
7890  printf("%g ", matrix[i*n + j]);
7891  printf("\n");
7892  }
7893 #endif
7894 
7895  /* compute eigenvalues and eigenvectors */
7896  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eigenvalues, n) );
7897 
7898  if( LapackDsyev(TRUE, n, matrix, consdata->eigenvalues) != SCIP_OKAY )
7899  {
7900  SCIPdebugMsg(scip, "couldn't compute ED for cons %s\n", SCIPconsGetName(cons));
7901  consdata->isedavailable = FALSE;
7902  }
7903  else
7904  {
7905  consdata->isedavailable = TRUE;
7906 
7907  /* compute b^T*P */
7908  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &consdata->bp, n) );
7909  for( i = 0; i < n; i++ )
7910  for( j = 0; j < n; j++ )
7911  consdata->bp[i] += consdata->quadvarterms[j].lincoef * matrix[i*n + j];
7912 
7913 #ifdef DEBUG_PROJ
7914  printf("eigenvalues:\n");
7915  for( j = 0; j < n; j++ )
7916  printf("%g ", consdata->eigenvalues[j]);
7917 
7918  printf("\neigenvectors (P^T):\n");
7919  for( i = 0; i < n; i++ )
7920  {
7921  for( j = 0; j < n; j++ )
7922  printf("%g ", matrix[i*n + j]);
7923  printf("\n");
7924  }
7925 
7926  printf("b*P^T:\n");
7927  for( j = 0; j < n; j++ )
7928  printf("%g ", consdata->bp[j]);
7929  printf("svd computed successfully\n");
7930 #endif
7931  }
7932 
7933  SCIPhashmapFree(&var2index);
7934 
7935  return SCIP_OKAY;
7936 }
7937 
7938 /** computes an interior point for the quadratic part of the convex constraint
7939  *
7940  * There are different methods for computing the interior point
7941  * - 'a'ny: solves min 0, f(x) <= rhs, x in bounds
7942  * - 'm'ost interior: solves min f(x), x in bounds
7943  *
7944  * @todo: other methods for computing an interior point?
7945  */
7946 static
7948  SCIP* scip, /**< SCIP data structure */
7949  SCIP_CONS* cons, /**< constraint */
7950  char method, /**< method for computing interior point ('a' any point, 'm'ost interior) */
7951  SCIP_Bool* success /**< buffer to store if an interior point was found */
7952  )
7953 {
7954  SCIP_CONSDATA* consdata;
7955  SCIP_QUADELEM* nlrowquadelems;
7956  SCIP_NLPIPROBLEM* prob;
7957  SCIP_NLPI* nlpi;
7958  SCIP_Real* interiorpoint;
7959  SCIP_Real* lbs;
7960  SCIP_Real* ubs;
7961  SCIP_Real* lincoefs;
7962  SCIP_Real nlpiside;
7963  char probname[SCIP_MAXSTRLEN];
7964  int* lininds;
7965  int nlrownquadelems;
7966  int nquadvars;
7967  int i;
7968 
7969  assert(scip != NULL);
7970  assert(cons != NULL);
7971 
7972  assert(success != NULL);
7973  *success = FALSE;
7974 
7975  consdata = SCIPconsGetData(cons);
7976  assert(consdata != NULL);
7977 
7978  assert((consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
7979  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
7980 
7981  /* need an NLP solver */
7982  if( SCIPgetNNlpis(scip) == 0 )
7983  return SCIP_OKAY;
7984 
7985  nlpi = NULL;
7986  prob = NULL;
7987  lbs = NULL;
7988  ubs = NULL;
7989  lincoefs = NULL;
7990  lininds = NULL;
7991 
7992 #ifdef SCIP_DEBUG_INT
7993  SCIPinfoMessage(scip, NULL, "Computing interior point for\n");
7994  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7995  SCIPinfoMessage(scip, NULL, ";\n");
7996 #endif
7997 
7998  /* in the convex case, we try to find an interior point of x^T A x + b^T x <= rhs - maximum activity linear part
7999  * in the concave case: lhs - minimum activity linear part <= x^T A x + b^T x; we compute activities ourselves,
8000  * since consdata->max(min)linactivity are only computed when lhs (rhs) is finite and this not always holds
8001  */
8002  if( consdata->isconvex )
8003  {
8004  /* compute maximum activity */
8005  nlpiside = 0;
8006  for( i = 0; i < consdata->nlinvars; ++i )
8007  {
8008  if( consdata->lincoefs[i] >= 0.0 )
8009  {
8010  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i]) ) )
8011  nlpiside = SCIPinfinity(scip);
8012  else
8013  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
8014  }
8015  else
8016  {
8017  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i]) ) )
8018  nlpiside = SCIPinfinity(scip);
8019  else
8020  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
8021  }
8022 
8023  if( SCIPisInfinity(scip, nlpiside) )
8024  {
8025  SCIPdebugMsg(scip, "maximum activity is infinity: there is no interior point for fun <= rhs - maxlinactivity!\n");
8026  return SCIP_OKAY;
8027  }
8028  }
8029 
8030  if( consdata->nlinvars == 0 )
8031  nlpiside = INTERIOR_EPS;
8032 
8033  nlpiside = consdata->rhs - nlpiside;
8034  }
8035  else
8036  {
8037  /* compute minimum activity */
8038  nlpiside = 0;
8039  for( i = 0; i < consdata->nlinvars; ++i )
8040  {
8041  if( consdata->lincoefs[i] >= 0.0 )
8042  {
8043  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(consdata->linvars[i])) )
8044  nlpiside = -SCIPinfinity(scip);
8045  else
8046  nlpiside += consdata->lincoefs[i] * SCIPvarGetLbLocal(consdata->linvars[i]);
8047  }
8048  else
8049  {
8050  if( SCIPisInfinity(scip, SCIPvarGetUbLocal(consdata->linvars[i])) )
8051  nlpiside = -SCIPinfinity(scip);
8052  else
8053  nlpiside += consdata->lincoefs[i] * SCIPvarGetUbLocal(consdata->linvars[i]);
8054  }
8055 
8056  if( SCIPisInfinity(scip, -nlpiside) )
8057  {
8058  SCIPdebugMsg(scip, "minimum activity is -infinity: there is no interior point for fun >= lhs - minlinactivity!\n");
8059  return SCIP_OKAY;
8060  }
8061  }
8062 
8063  if( consdata->nlinvars == 0 )
8064  nlpiside = INTERIOR_EPS;
8065 
8066  nlpiside = consdata->lhs - nlpiside;
8067  }
8068 
8069  nquadvars = consdata->nquadvars;
8070 
8071  /* if we are looking for any interior point and the 0 is one, then use it */
8072  if( method == 'a' && ((consdata->isconvex && SCIPisGE(scip, nlpiside, 0.0))
8073  || (consdata->isconcave && SCIPisLE(scip, nlpiside, 0.0))) )
8074  {
8075  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
8076 
8077  *success = TRUE;
8078  goto TERMINATE;
8079  }
8080 
8081  /* build nlrow */
8082  if( consdata->nlrow == NULL )
8083  {
8084  SCIP_CALL( createNlRow(scip, cons) );
8085  assert(consdata->nlrow != NULL);
8086  }
8087 
8088  nlpi = SCIPgetNlpis(scip)[0];
8089  assert(nlpi != NULL);
8090 
8091  /* initializing the subproblem */
8092  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s_subquad", SCIPgetProbName(scip));
8093  SCIP_CALL( SCIPnlpiCreateProblem(nlpi, &prob, probname) );
8094  assert(prob != NULL);
8095 
8096 #ifdef SCIP_DEBUG_INT
8098 #endif
8099  /* TODO: maybe one should set some generous iteration limit and/or a timelimit (remaining scip solve time)? */
8100 
8101  /* ask for memory to store data needed to create vars and linear coefficients */
8102  SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nquadvars) );
8103  SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nquadvars) );
8104  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nquadvars) );
8105  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nquadvars) );
8106 
8107  /* get bounds and linear coefficients */
8108  for( i = 0; i < nquadvars; i++ )
8109  {
8110  lbs[i] = SCIPvarGetLbGlobal(consdata->quadvarterms[i].var);
8111  ubs[i] = SCIPvarGetUbGlobal(consdata->quadvarterms[i].var);
8112 
8113  lincoefs[i] = consdata->quadvarterms[i].lincoef;
8114  lininds[i] = i;
8115  }
8116 
8117  /* add vars */
8118  SCIP_CALL( SCIPnlpiAddVars(nlpi, prob, nquadvars, lbs, ubs, NULL) );
8119 
8120  /* get nlrow info */
8121  nlrownquadelems = SCIPnlrowGetNQuadElems(consdata->nlrow);
8122  nlrowquadelems = SCIPnlrowGetQuadElems(consdata->nlrow);
8123 
8124 #ifndef NDEBUG
8125  {
8126  SCIP_VAR** nlrowquadvars;
8127 
8128  nlrowquadvars = SCIPnlrowGetQuadVars(consdata->nlrow);
8129  for( i = 0; i < nlrownquadelems; i++ )
8130  {
8131  assert(nlrowquadvars[nlrowquadelems[i].idx1] == consdata->quadvarterms[nlrowquadelems[i].idx1].var);
8132  assert(nlrowquadvars[nlrowquadelems[i].idx2] == consdata->quadvarterms[nlrowquadelems[i].idx2].var);
8133  }
8134  }
8135 #endif
8136 
8137  (void) SCIPsnprintf(probname, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
8138 
8139  switch( method )
8140  {
8141  case 'a':
8142  /* add constraint */
8143  if( consdata->isconvex )
8144  {
8145  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, NULL, &nlpiside, &nquadvars, &lininds, &lincoefs,
8146  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
8147  }
8148  else
8149  {
8150  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, prob, 1, &nlpiside, NULL, &nquadvars, &lininds, &lincoefs,
8151  &nlrownquadelems, &nlrowquadelems, NULL, NULL, NULL) );
8152  }
8153  break;
8154 
8155  case 'm':
8156  /* add objective */
8157  if( consdata->isconvex )
8158  {
8159  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
8160  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
8161  }
8162  else
8163  {
8164  /* NLPI assumes minimization: change signs */
8165  for( i = 0; i < nquadvars; i++ )
8166  lincoefs[i] *= -1;
8167 
8168  /* WARNING: this pointer is not ours, information should be restored! */
8169  for( i = 0; i < nlrownquadelems; i++ )
8170  nlrowquadelems->coef *= -1;
8171 
8172  SCIP_CALL( SCIPnlpiSetObjective(nlpi, prob, nquadvars, lininds, lincoefs,
8173  nlrownquadelems, nlrowquadelems, NULL, NULL, 0.0) );
8174 
8175  /* WARNING: restore information! */
8176  for( i = 0; i < nlrownquadelems; i++ )
8177  nlrowquadelems->coef *= -1;
8178  }
8179  break;
8180 
8181  default:
8182  SCIPerrorMessage("undefined method for computing interior point: %c\n", method);
8183  return SCIP_INVALIDDATA;
8184  }
8185 
8186  /* set NLP tolerances; we don't really need an optimal solution to this NLP */
8187  SCIP_CALL( SCIPnlpiSetRealPar(nlpi, prob, SCIP_NLPPAR_FEASTOL, SCIPfeastol(scip)) ); /*lint !e666*/
8188  SCIP_CALL( SCIPnlpiSetRealPar(nlpi, prob, SCIP_NLPPAR_RELOBJTOL, MAX(SCIPfeastol(scip), SCIPdualfeastol(scip))) ); /*lint !e666*/
8189 
8190  /* solve NLP problem */
8191  SCIP_CALL( SCIPnlpiSolve(nlpi, prob) );
8192 
8193  /* check termination status */
8194  if( SCIPnlpiGetTermstat(nlpi, prob) != SCIP_NLPTERMSTAT_OKAY )
8195  {
8196  SCIPdebugMsg(scip, "cons <%s>: NLP Solver termination status not okay: %d\n",
8197  SCIPconsGetName(cons), SCIPnlpiGetTermstat(nlpi, prob));
8198  *success = FALSE;
8199  goto TERMINATE;
8200  }
8201 
8202  /* check solution status */
8203  switch( SCIPnlpiGetSolstat(nlpi, prob) )
8204  {
8208  /* fallthrough */
8209  SCIPdebugMsg(scip, "cons <%s>: found an interior point. solution status: %d, termination status: %d\n",
8210  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8211  break;
8212 
8216  /* fallthrough */
8217  /* TODO: we could still use the point, and let evaluateGauge decide whether the point is interior or not */
8218  SCIPdebugMsg(scip, "cons <%s>: failed to find an interior point. solution status: %d, termination status: %d\n",
8219  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8220  goto TERMINATE;
8221 
8223  default:
8224  /* fallthrough */
8225  SCIPerrorMessage("cons <%s>: undefined behaviour of NLP Solver. solution status: %d, termination status: %d\n",
8226  SCIPconsGetName(cons), SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8227  SCIPABORT();
8228  goto TERMINATE; /*lint !e527*/
8229  }
8230 
8231  /* fetch solution
8232  * note: nlpiGetSolution (at least for IPOPT) makes interiorpoint point to the internal solution stored in the
8233  * nlpi problem data structure; we need to copy it here because it will be destroyed once the problem is free'd
8234  */
8235  SCIP_CALL( SCIPnlpiGetSolution(nlpi, prob, &interiorpoint, NULL, NULL, NULL, NULL) );
8236 
8237  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->interiorpoint), nquadvars) );
8238 
8239  for( i = 0; i < nquadvars; i++ )
8240  {
8241  if( SCIPisFeasZero(scip, interiorpoint[i]) )
8242  consdata->interiorpoint[i] = 0.0;
8243  else
8244  consdata->interiorpoint[i] = interiorpoint[i];
8245  }
8246 
8247  *success = TRUE;
8248 
8249 TERMINATE:
8250 
8251 #ifdef SCIP_DEBUG_INT
8252  printf("Computation of interior point for cons <%s>:\n", SCIPconsGetName(cons));
8253  printf(" - has %d linear variables\n", consdata->nlinvars);
8254  if( consdata->isconvex )
8255  {
8256  printf(" - is convex. rhs: %g maximum activity of linear variables: %g\n", consdata->rhs, consdata->rhs - nlpiside);
8257  printf(" - searched for point whose quadratic part is <= %g\n", nlpiside);
8258  }
8259  else
8260  {
8261  printf(" - is concave. lhs: %g minimum activity of linear variables: %g\n", consdata->lhs, consdata->lhs - nlpiside);
8262  printf(" - searched for point whose quadratic part is >= %g\n", nlpiside);
8263  }
8264 
8265  if( *success )
8266  {
8267  if( prob == NULL )
8268  {
8269  printf("Computation successful, 0 is interior point.\n");
8270  for( i = 0; i < nquadvars; i++ )
8271  {
8272  assert(consdata->interiorpoint[i] == 0.0);
8273  }
8274  }
8275  else
8276  {
8277  printf("Computation successful, NLP soltat: %d, termstat: %d\nPoint found:\n",
8278  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8279  for( i = 0; i < nquadvars; i++ )
8280  {
8281  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[i].var), consdata->interiorpoint[i]);
8282  }
8283  }
8284  }
8285  else
8286  {
8287  printf("Computation failed. NLP soltat: %d, termstat: %d\n",
8288  SCIPnlpiGetSolstat(nlpi, prob), SCIPnlpiGetTermstat(nlpi, prob));
8289  printf("run with SCIP_DEBUG for more info\n");
8290  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
8291  SCIPinfoMessage(scip, NULL, ";\n");
8292  /* FIXME: instance camshape100 says that there is no interior point (interior empty)
8293  * is there something intelligent that can be said?
8294  */
8295  }
8296 #endif
8297 
8298  /* free memory */
8299  SCIPfreeBufferArrayNull(scip, &lbs);
8300  SCIPfreeBufferArrayNull(scip, &ubs);
8301  SCIPfreeBufferArrayNull(scip, &lininds);
8302  SCIPfreeBufferArrayNull(scip, &lincoefs);
8303 
8304  if( prob != NULL )
8305  {
8306  SCIP_CALL( SCIPnlpiFreeProblem(nlpi, &prob) );
8307  }
8308 
8309  return SCIP_OKAY;
8310 }
8311 
8312 /** 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$.
8313  *
8314  * Here, \f$ f(x) \f$ is a purely quadratic (i.e, all \f$x\f$ variables appear in a bilinear or quadratic term).
8315  * Explicitly, \f$ f(x) = \pm x^T A x \pm b^T x \f$ depending whether \f$A\f$
8316  * is positive semidefinite (+) or negative semidefinite (-).
8317  * The constant \f$c\f$ is rhs - maximum activity of the purely linear part of the constraint
8318  * if \f$A \succeq 0\f$ and minimum activity - lhs if \f$A \preceq 0\f$.
8319  * This is computed only at INITSOL.
8320  *
8321  * The method does:
8322  * 1. compute interior point
8323  * 2. compute gauge function
8324  */
8325 static
8327  SCIP* scip, /**< SCIP data structure */
8328  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8329  SCIP_CONS* cons /**< constraint */
8330  )
8331 {
8332  SCIP_CONSHDLRDATA* conshdlrdata;
8333  SCIP_CONSDATA* consdata;
8334  SCIP_QUADVARTERM* quadvarterm;
8335  SCIP_BILINTERM* bilinterm;
8336  SCIP_Bool success;
8337  SCIP_Bool convex;
8338  int i;
8339  int j;
8340 
8341  assert(scip != NULL);
8342  assert(conshdlr != NULL);
8343  assert(cons != NULL);
8344 
8345  consdata = SCIPconsGetData(cons);
8346  assert(consdata != NULL);
8347 
8348  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8349  assert(conshdlrdata != NULL);
8350  assert(conshdlrdata->gaugecuts);
8351 
8352  /* function has to be convex with finite rhs or concave with finite lhs */
8353  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
8354  assert(convex || (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)));
8355 
8356  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
8357 
8358  /* 1. */
8359  SCIP_CALL( computeInteriorPoint(scip, cons, conshdlrdata->interiorcomputation, &success) );
8360 
8361  /* if success, compute gaugecoefs (b_gauge) and gaugeconst (c_gauge) */
8362  if( !success )
8363  {
8364  SCIPdebugMsg(scip, "failed to compute gauge function\n");
8365  consdata->isgaugeavailable = FALSE;
8366  return SCIP_OKAY;
8367  }
8368 
8369  /* 2.
8370  * we are going to evaluate the function at interiorpoint; so, we need to compute interiorpoint^T A interiorpoint;
8371  * therefore, we need a mechanism that for a given variable, it returns its interior point value
8372  * fortunately, sepabilinvar2pos in consdata gives us all the information that we need
8373  */
8374 
8375  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(consdata->gaugecoefs), consdata->nquadvars) );
8376 
8377  /* compute value of quadratic part at interior point, build map and compute gaugeconst (c_gauge) */
8378  consdata->interiorpointval = 0;
8379  consdata->gaugeconst = 0;
8380  for( i = 0; i < consdata->nquadvars; i++ )
8381  {
8382  SCIP_Real val;
8383  SCIP_Real val2;
8384 
8385  val = consdata->interiorpoint[i];
8386  quadvarterm = &consdata->quadvarterms[i];
8387 
8388  consdata->interiorpointval += (quadvarterm->lincoef + quadvarterm->sqrcoef * val) * val;
8389  consdata->gaugeconst += quadvarterm->sqrcoef * val * val;
8390 
8391  for( j = 0; j < quadvarterm->nadjbilin; ++j )
8392  {
8393  int bilintermidx;
8394 
8395  bilintermidx = quadvarterm->adjbilin[j];
8396  bilinterm = &consdata->bilinterms[bilintermidx];
8397 
8398  if( bilinterm->var1 != quadvarterm->var )
8399  continue;
8400 
8401  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
8402  assert(consdata->sepabilinvar2pos != NULL); /* this should have been computed in INITSOL */
8403  assert(consdata->quadvarterms[consdata->sepabilinvar2pos[bilintermidx]].var == bilinterm->var2);
8404 
8405  val2 = consdata->interiorpoint[consdata->sepabilinvar2pos[bilintermidx]];
8406 
8407  consdata->interiorpointval += bilinterm->coef * val * val2;
8408  consdata->gaugeconst += bilinterm->coef * val * val2;
8409  }
8410  }
8411 
8412  /* compute gaugecoefs (b_gauge = b + 2 * A * interiorpoint) */
8413  for( i = 0; i < consdata->nquadvars; i++ )
8414  {
8415  quadvarterm = &consdata->quadvarterms[i];
8416  consdata->gaugecoefs[i] += quadvarterm->lincoef + 2.0 * quadvarterm->sqrcoef * consdata->interiorpoint[i];
8417 
8418  for( j = 0; j < quadvarterm->nadjbilin; j++ )
8419  {
8420  int varpos;
8421  int bilintermidx;
8422 
8423  bilintermidx = quadvarterm->adjbilin[j];
8424  bilinterm = &consdata->bilinterms[bilintermidx];
8425 
8426  if( bilinterm->var1 == quadvarterm->var )
8427  {
8428  varpos = consdata->sepabilinvar2pos[bilintermidx];
8429 
8430  /* the index of the variable associated with var2 in bilinterm should be given by sepabilinvar2pos */
8431  assert(consdata->quadvarterms[varpos].var == bilinterm->var2);
8432 
8433  consdata->gaugecoefs[i] += bilinterm->coef * consdata->interiorpoint[varpos];
8434  consdata->gaugecoefs[varpos] += bilinterm->coef * consdata->interiorpoint[i];
8435  }
8436  }
8437  }
8438 
8439 #ifdef SCIP_DEBUG_INT
8440  printf("quadratic part at interior point: %g\n", consdata->interiorpointval);
8441 
8442  for( j = 0; j < consdata->nquadvars; j++ )
8443  {
8444  printf("b_gauge[%s] = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), consdata->gaugecoefs[j]);
8445  }
8446  printf("c_gauge = %g\n", consdata->gaugeconst);
8447 #endif
8448 
8449  SCIPdebugMsg(scip, "gauge function computed successfully\n");
8450  consdata->isgaugeavailable = TRUE;
8451 
8452  return SCIP_OKAY;
8453 }
8454 
8455 /** 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$.
8456  *
8457  * \f$ S = \{ x : f(x) \le c \}\f$ at \f$sol - s_0\f$;
8458  * see computeGauge() for more details
8459  *
8460  * @todo Think about if user should tell that function is convex or ...
8461  */
8462 static
8464  SCIP* scip, /**< SCIP data structure */
8465  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8466  SCIP_CONS* cons, /**< constraint */
8467  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
8468  SCIP_Real* gaugeval, /**< buffer to store the value of the gauge function */
8469  SCIP_Bool* success /**< buffer to store if evaluation was successful */
8470  )
8471 {
8472  SCIP_CONSDATA* consdata;
8473  SCIP_Real side;
8474  SCIP_Real aterm;
8475  SCIP_Real bterm;
8476  SCIP_Real cterm;
8477  SCIP_Bool convex;
8478  int i;
8479 
8480  assert(scip != NULL);
8481  assert(conshdlr != NULL);
8482  assert(cons != NULL);
8483 
8484  consdata = SCIPconsGetData(cons);
8485  assert(consdata != NULL);
8486  assert(consdata->isgaugeavailable);
8487 
8488  *success = FALSE;
8489 
8490  convex = consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs);
8491 
8492  SCIPdebugMsg(scip, "cons %s: is %s\n", SCIPconsGetName(cons), convex ? "convex" : "concave");
8493 
8494  /* evaluate gauge function at x0 = (refsol - interior point)
8495  *
8496  * compute aterm = side - function(interior point)
8497  */
8498  if( convex )
8499  {
8500  side = consdata->rhs;
8501  for( i = 0; i < consdata->nlinvars; i++ )
8502  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
8503 
8504  aterm = side - consdata->interiorpointval;
8505 
8506  /* it can happen that the interior point is not really interior, since we are not so strict at the moment of
8507  * computing the interior point, which makes sense in the case that the constraint is quadratic <= linear expr,
8508  * since we compute a point in quadratic <= min linear expr and it might be that this set consists of a single
8509  * point which will not be interior. furthermore, if this set is empty, we could just take any point and it could
8510  * happen that for some value of linear expr, the point is actually interior, but for many it could not be.
8511  * also, if min linear expr = -infinity, we might have computed an interior point using some finite value.
8512  * the point will not be an interior point, if and only if aterm is negative.
8513  */
8514 #ifdef SCIP_DEBUG_GAUGE
8515  if( SCIPisLE(scip, aterm, 0.0) )
8516  {
8517  printf("For current level, there is no interior point. ");
8518  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
8519  if( consdata->nlinvars == 1 )
8520  {
8521  SCIP_VAR* var;
8522 
8523  var = consdata->linvars[0];
8524  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
8525  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
8526  }
8527  }
8528  else
8529  {
8530  printf("For current level, there is interior point. ");
8531  printf("rhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->rhs, side, consdata->interiorpointval);
8532  }
8533 #endif
8534  if( !SCIPisPositive(scip, aterm) )
8535  {
8536  *gaugeval = -1.0;
8537  return SCIP_OKAY;
8538  }
8539  }
8540  else
8541  {
8542  side = consdata->lhs;
8543  for( i = 0; i < consdata->nlinvars; i++ )
8544  side -= SCIPgetSolVal(scip, refsol, consdata->linvars[i]) * consdata->lincoefs[i];
8545 
8546  aterm = side - consdata->interiorpointval;
8547 
8548 #ifdef SCIP_DEBUG_GAUGE
8549  if( SCIPisGE(scip, aterm, 0.0) )
8550  {
8551  printf("For current level, there is no interior point. ");
8552  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
8553  if( consdata->nlinvars == 1 )
8554  {
8555  SCIP_VAR* var;
8556 
8557  var = consdata->linvars[0];
8558  printf("var <%s> = %g in [%15.20g, %15.20g] is linpart\n", SCIPvarGetName(var),
8559  SCIPgetSolVal(scip, refsol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
8560  }
8561  }
8562  else
8563  {
8564  printf("For current level, there is interior point. ");
8565  printf("lhs: %g level: %15.20g interiorpointval: %15.20g\n", consdata->lhs, side, consdata->interiorpointval);
8566  }
8567 #endif
8568  if( !SCIPisNegative(scip, aterm) )
8569  {
8570  *gaugeval = -1.0;
8571  return SCIP_OKAY;
8572  }
8573  }
8574 
8575  /* compute bterm = b_gauge^T * refsol - f(interiorpoint) - c_gauge
8576  * compute cterm = f(refsol) - b_gauge^T * refsol + c_gauge */
8577  bterm = -consdata->interiorpointval - consdata->gaugeconst;
8578  cterm = consdata->gaugeconst;
8579  for( i = 0; i < consdata->nquadvars; i++ )
8580  {
8581  SCIP_Real val;
8582 
8583  val = SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var);
8584  bterm += consdata->gaugecoefs[i] * val;
8585  cterm -= consdata->gaugecoefs[i] * val;
8586  cterm += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val) * val;
8587  }
8588 
8589  for( i = 0; i < consdata->nbilinterms; i++ )
8590  {
8591  SCIP_VAR* var1;
8592  SCIP_VAR* var2;
8593 
8594  var1 = consdata->bilinterms[i].var1;
8595  var2 = consdata->bilinterms[i].var2;
8596  cterm += consdata->bilinterms[i].coef * SCIPgetSolVal(scip, refsol, var1) * SCIPgetSolVal(scip, refsol, var2);
8597  }
8598 
8599  /* now compute gauge */
8600  if( convex && cterm < 0.0 )
8601  {
8602  assert(SCIPisZero(scip, cterm));
8603  cterm = 0.0;
8604  }
8605  else if( !convex && cterm > 0.0 )
8606  {
8607  assert(SCIPisZero(scip, cterm));
8608  cterm = 0.0;
8609  }
8610  assert(bterm*bterm + 4*aterm*cterm >= 0);
8611 
8612  if( convex )
8613  {
8614  *gaugeval = bterm + sqrt(bterm*bterm + 4 * aterm * cterm);
8615  *gaugeval = *gaugeval / (2 * aterm);
8616  }
8617  else
8618  {
8619  *gaugeval = bterm - sqrt(bterm*bterm + 4 * aterm * cterm);
8620  *gaugeval = *gaugeval / (2 * aterm);
8621  }
8622  assert(!SCIPisNegative(scip, *gaugeval));
8623  *success = TRUE;
8624 
8625 #ifdef SCIP_DEBUG_GAUGE
8626  printf("Gauge's aterm = %g, bterm = %g, cterm = %g\n", aterm, bterm, cterm);
8627 #endif
8628  return SCIP_OKAY;
8629 }
8630 
8631 /** compute projection of refsol onto feasible region of cons; stores the projection in ref
8632  *
8633  * This method solves
8634  * \f[
8635  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x \le c \}
8636  * \f]
8637  * where \f$ \bar x \f$ is refsol.
8638  * Note that \f$ \bar x \f$ is not feasible, so the optimal solution actually satisfies
8639  * \f[
8640  * \min \{ ||x - \bar x||^2 : x^T A x + 2 b^T x = c \}
8641  * \f]
8642  * Using the eigendecomposition \f$ A = P D P^T \f$, the change of variables \f$ y = P^T x
8643  * \f$ and the optimality conditions, this reduces to finding \f$ \rho \f$ such that
8644  * \f[
8645  * y(\rho) = (I + \rho D)^{-1} (\bar y - \rho \bar b)
8646  * \f]
8647  * 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$
8648  * D \neq 0 \f$, the function
8649  * \f[
8650  * \varphi(\rho) := y(\rho)^T D y(\rho) + 2 \bar b^T y(\rho) - c
8651  * \f]
8652  * is strictly convex. So this method actually computes the unique 0 of this function using Newton's method.
8653  */
8654 static
8656  SCIP* scip, /**< SCIP data structure */
8657  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8658  SCIP_CONS* cons, /**< constraint */
8659  SCIP_SOL* refsol, /**< the given point to project, or NULL if LP solution should be used */
8660  SCIP_Real* ref /**< array to store reference point */
8661  )
8662 {
8663  SCIP_CONSDATA* consdata;
8664  SCIP_Real* pt; /* stores P^T */
8665  SCIP_Real* bp;
8666  SCIP_Real* D;
8667  SCIP_Real* y0_;
8668  SCIP_Real* yrho;
8669  SCIP_Real* yrhoprime;
8670  SCIP_Real c;
8671  SCIP_Real c1;
8672  SCIP_Real c2;
8673  SCIP_Real rho;
8674  SCIP_Real phirho;
8675  SCIP_Real phirhoprime;
8676  SCIP_Bool isconcave;
8677  int iter;
8678  int i;
8679  int j;
8680  int n;
8681 
8682  assert(scip != NULL);
8683  assert(conshdlr != NULL);
8684  assert(cons != NULL);
8685 
8686  consdata = SCIPconsGetData(cons);
8687  assert(consdata != NULL);
8688  assert(consdata->isedavailable);
8689 
8690  SCIPdebugMessage("computing projection\n");
8691 
8692  /* get the data we need */
8693  pt = consdata->eigenvectors;
8694  D = consdata->eigenvalues;
8695  n = consdata->nquadvars;
8696  bp = consdata->bp;
8697  c = consdata->rhs;
8698  c1 = 0;
8699  c2 = 0;
8700  for( i = 0; i < consdata->nlinvars; i++ )
8701  {
8702  c1 += consdata->lincoefs[i] * SCIPgetSolVal(scip, refsol, consdata->linvars[i]);
8703  c2 -= consdata->lincoefs[i] * consdata->lincoefs[i];
8704  }
8705  c2 /= 2.0;
8706 
8707  /* determine if convex or concave */
8708  isconcave = consdata->isconcave;
8709  assert((isconcave && !SCIPisInfinity(scip, -consdata->lhs)) || !SCIPisInfinity(scip, consdata->rhs));
8710 
8711  SCIP_CALL( SCIPallocClearBufferArray(scip, &y0_, n) );
8712  SCIP_CALL( SCIPallocBufferArray(scip, &yrho, n) );
8713  SCIP_CALL( SCIPallocBufferArray(scip, &yrhoprime, n) );
8714 
8715  /* change data if function is concave */
8716  if( isconcave )
8717  {
8718  c = -consdata->lhs;
8719  c1 = - c1;
8720  for( i = 0; i < n; i++ )
8721  {
8722  D[i] = -D[i];
8723  bp[i] = -bp[i];
8724  }
8725  }
8726 
8727  /* change coordinates: compute y(0) = x_0' * P */
8728  for( i = 0; i < n; i++ )
8729  for( j = 0; j < n; j++ )
8730  y0_[i] += SCIPgetSolVal(scip, refsol, consdata->quadvarterms[j].var) * pt[i*n + j];
8731 
8732 #ifdef DEBUG_PROJ
8733  /* debug output */
8734  printf("\nP^T:\n");
8735  for( i = 0; i < n; i++ )
8736  {
8737  for( j = 0; j < n; j++ )
8738  printf("%g ", pt[i*n + j]);
8739  printf("\n");
8740  }
8741  printf("x_0: ");
8742  for( i = 0; i < n; i++ )
8743  printf("%g ", SCIPgetSolVal(scip, refsol, consdata->quadvarterms[i].var));
8744  printf("\n");
8745  printf("P^T x_0: ");
8746  for( i = 0; i < n; i++ )
8747  printf("%g ", y0_[i]);
8748  printf("\n");
8749  printf("P^T b: ");
8750  for( i = 0; i < n; i++ )
8751  printf("%g ", bp[i]);
8752  printf("\n");
8753  printf("<d,linvars> = %g\n", c1);
8754  printf("-norm(d)^2/2 = %g\n", c2);
8755 #endif
8756 
8757  /* perform newton's method: rho^+ = rho - phi(rho)/phi'(rho) */
8758  rho = 0.0;
8759  phirho = c;
8760  phirhoprime = 1.0;
8761  for( iter = 0; iter < 9; iter++ )
8762  {
8763  assert(phirhoprime != 0.0);
8764  rho = rho - (phirho - c)/ phirhoprime;
8765 
8766  /* compute phi(rho) and phi'(rho):
8767  * note that formulas were deduced for constraints of the form x' A x + 2 b x, so we use b/2 in the formulas:
8768  * c1 = <lin_coefs, sol_lin_vars>
8769  * c2 = - norm(lin_coefs)^2/2
8770  * y(rho) = (I + rho * D)^-1 * (y(0) - rho * bp/2)
8771  * y'(rho) = -(I + rho * D)^-2 * (D y(0) + bp/2)
8772  * phi(rho) = <y(rho), D * y(rho) + pb> + c1 + c2*rho
8773  * phi'(rho) = <y'(rho), 2 * D * y(rho) + pb> + c2
8774  */
8775  phirho = 0.0;
8776  phirhoprime = 0.0;
8777  for( i = 0; i < n; i++ )
8778  {
8779  assert(1.0 + rho * D[i] != 0.0);
8780  yrho[i] = (y0_[i] - rho * bp[i]/2.0) / (1.0 + rho * D[i]);
8781  yrhoprime[i] = -(D[i] * y0_[i] + bp[i]/2.0) / ( (1.0 + rho * D[i])*(1.0 + rho * D[i]) );
8782  phirho += yrho[i] * (yrho[i] * D[i] + bp[i]);
8783  phirhoprime += yrhoprime[i] * (2 * D[i] * yrho[i] + bp[i]);
8784  }
8785  phirho += c2 * rho + c1;
8786  phirhoprime += c2;
8787 #ifdef DEBUG_PROJ
8788  printf("iteration %d: rho = %g, phirho = %g, phirho' = %g\n", iter, rho, phirho, phirhoprime);
8789 #endif
8790  }
8791 
8792  /* come back to the original coordinates: new ref point is P*yrho */
8793  for( i = 0; i < n; i++ )
8794  {
8795  ref[i] = 0.0;
8796 
8797  for( j = 0; j < n; j++ )
8798  ref[i] += pt[j*n + i] * yrho[j];
8799  }
8800 
8801  /* change data back if function is concave */
8802  if( isconcave )
8803  {
8804  for( i = 0; i < n; i++ )
8805  {
8806  D[i] = -D[i];
8807  bp[i] = -bp[i];
8808  }
8809  }
8810 
8811 #ifdef SCIP_DISABLED_CODE
8812  /* project onto bounds; this is important for some cut generation methods such as generateCutLTI */
8813  for( j = 0; j < consdata->nquadvars; ++j )
8814  {
8815  SCIP_Real lb;
8816  SCIP_Real ub;
8817  SCIP_VAR* var;
8818 
8819  var = consdata->quadvarterms[j].var;
8820  lb = SCIPvarGetLbLocal(var);
8821  ub = SCIPvarGetUbLocal(var);
8822  /* do not like variables at infinity */
8823  assert(!SCIPisInfinity(scip, lb));
8824  assert(!SCIPisInfinity(scip, -ub));
8825 
8826  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8827  }
8828 #endif
8829 
8830 #ifdef DEBUG_PROJ
8831  printf("modified reference point by a projection:\n");
8832  for( j = 0; j < consdata->nquadvars; ++j )
8833  {
8834  printf("%s = %g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
8835  }
8836 #endif
8837 
8838  SCIPfreeBufferArray(scip, &y0_);
8839  SCIPfreeBufferArray(scip, &yrho);
8840  SCIPfreeBufferArray(scip, &yrhoprime);
8841 
8842  return SCIP_OKAY;
8843 }
8844 
8845 /** compute reference point suggested by gauge function */
8846 static
8848  SCIP* scip, /**< SCIP data structure */
8849  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8850  SCIP_CONS* cons, /**< constraint */
8851  SCIP_SOL* refsol, /**< reference point where to compute gauge, or NULL if LP solution should be used */
8852  SCIP_Real* ref, /**< array to store reference point */
8853  SCIP_Bool* success /**< buffer to store whether we succeeded computing reference point */
8854  )
8855 {
8856  SCIP_CONSDATA* consdata;
8857  SCIP_Real gaugeval;
8858  SCIP_Real intpoint;
8859  SCIP_Real lb;
8860  SCIP_Real ub;
8861  SCIP_VAR* var;
8862  int j;
8863 
8864  assert(scip != NULL);
8865  assert(conshdlr != NULL);
8866  assert(cons != NULL);
8867 
8868  consdata = SCIPconsGetData(cons);
8869  assert(consdata != NULL);
8870  assert(consdata->isgaugeavailable);
8871 
8872  SCIPdebugMsg(scip, "evaluating gauge\n");
8873  SCIP_CALL( evaluateGauge(scip, conshdlr, cons, refsol, &gaugeval, success) );
8874 
8875  if( !(*success) )
8876  {
8877 #ifdef SCIP_DEBUG_GAUGE
8878  printf("Couldn't evaluate gauge!\n");
8879 #endif
8880  return SCIP_OKAY;
8881  }
8882 
8883 #ifdef SCIP_DEBUG_GAUGE
8884  {
8885  SCIP_Real level;
8886 
8887  level = consdata->rhs;
8888  for( j = 0; j < consdata->nlinvars; j++ )
8889  level -= SCIPgetSolVal(scip, refsol, consdata->linvars[j]) * consdata->lincoefs[j];
8890 
8891  printf("Summary:\n");
8892  printf("For cons <%s>: gauge at level %g evaluated at (refsol - intpoint) is %.10f\n",
8893  SCIPconsGetName(cons), level, gaugeval);
8894  printf("refsol - intpoint:\n");
8895 
8896  for( j = 0; j < consdata->nquadvars; ++j )
8897  {
8898  SCIP_VAR* vvar;
8899  vvar = consdata->quadvarterms[j].var;
8900  printf("%s: % 20.15g - %g = %g\n", SCIPvarGetName(vvar), SCIPgetSolVal(scip, refsol, vvar),
8901  consdata->interiorpoint[j], SCIPgetSolVal(scip, refsol, vvar) - consdata->interiorpoint[j]);
8902  }
8903  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
8904  printf("refsol is in the closure of the region (gaugeval <= 1), don't modify reference point\n");
8905  }
8906 #endif
8907 
8908  /* scale gauge value so that final point is close to the boundary, but not on the boundary (weakens the cut) */
8909  gaugeval *= GAUGESCALE;
8910 
8911  /* if the point is not sufficiently violated, we don't modify it */
8912  if( SCIPisFeasLE(scip, gaugeval, 1.0) )
8913  {
8914  *success = FALSE;
8915  return SCIP_OKAY;
8916  }
8917 
8918  /* set reference to (refsol - interior point)/gaugeval + interior point and project onto bounds this is important for
8919  * some cut generation methods such as generateCutLTI
8920  * @todo remove the projection onto the bounds; generateCutLTI shouldn't be called for convex constraints
8921  */
8922  for( j = 0; j < consdata->nquadvars; ++j )
8923  {
8924  var = consdata->quadvarterms[j].var;
8925  lb = SCIPvarGetLbLocal(var);
8926  ub = SCIPvarGetUbLocal(var);
8927  /* do not like variables at infinity */
8928  assert(!SCIPisInfinity(scip, lb));
8929  assert(!SCIPisInfinity(scip, -ub));
8930 
8931  intpoint = consdata->interiorpoint[j];
8932  ref[j] = (SCIPgetSolVal(scip, refsol, var) - intpoint) / gaugeval + intpoint;
8933  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
8934  }
8935 
8936 #ifdef SCIP_DEBUG_GAUGE
8937  printf("successful application of guage: %g\n", gaugeval);
8938  printf("modified reference point:\n");
8939  for( j = 0; j < consdata->nquadvars; ++j )
8940  {
8941  printf("%s = % 20.15g\n", SCIPvarGetName(consdata->quadvarterms[j].var), ref[j]);
8942  }
8943 #endif
8944 
8945  return SCIP_OKAY;
8946 }
8947 
8948 /** generates a cut based on linearization (if convex) or McCormick (if nonconvex) in a solution
8949  * @note mode indicates whether we should modify the point we want to cutoff (sol) via gauge or projection,
8950  * or if just normal linearization should be use, or the default way (whatever is specified via settings)
8951  */
8952 static
8954  SCIP* scip, /**< SCIP data structure */
8955  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8956  SCIP_CONS* cons, /**< constraint */
8957  SCIP_SOL* sol, /**< solution where to generate cut, or NULL if LP solution should be used */
8958  SCIP_SOL* refsol, /**< reference point where to generate cut, or NULL if sol should be used */
8959  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
8960  SCIP_ROW** row, /**< storage for cut */
8961  SCIP_Real* efficacy, /**< buffer to store efficacy of row in reference solution, or NULL if not of interest */
8962  SCIP_Bool checkcurvmultivar, /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
8963  SCIP_Real minefficacy, /**< minimal required efficacy */
8964  char mode /**< mode of execution 'g'auge, 'p'rojection, 'l'inearization gradient, 'd'efault */
8965  )
8966 {
8967  SCIP_CONSHDLRDATA* conshdlrdata;
8968  SCIP_CONSDATA* consdata;
8969  SCIP_VAR* var;
8970  SCIP_Real lb;
8971  SCIP_Real ub;
8972  SCIP_Real* ref;
8973  SCIP_Bool success;
8974  int j;
8975 
8976  assert(scip != NULL);
8977  assert(conshdlr != NULL);
8978  assert(cons != NULL);
8979 
8980  consdata = SCIPconsGetData(cons);
8981  assert(consdata != NULL);
8982 
8983  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8984  assert(conshdlrdata != NULL);
8985 
8986  if( refsol == NULL )
8987  refsol = sol;
8988 
8989  /* get reference point */
8990  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
8991  success = FALSE;
8992 
8993  if( mode == 'd')
8994  {
8995  if( (consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
8996  (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
8997  {
8998  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
8999  {
9000  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
9001  }
9002  else if( conshdlrdata->projectedcuts && consdata->isedavailable )
9003  {
9004  SCIPdebugMessage("use the projection of refsol onto the region defined by the constraint as reference point\n");
9005  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
9006  success = TRUE;
9007  }
9008  }
9009 
9010  if( success )
9011  {
9012  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9013 
9014  /* if cut fails, try again without modifying reference point */
9015  if( *row == NULL || (efficacy != NULL && !SCIPisGT(scip, *efficacy, minefficacy)) || !SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
9016  {
9017  SCIPdebugMsg(scip, "%s cut fail, try without modifying\n", conshdlrdata->gaugecuts ? "gauge" : "projected");
9018  success = FALSE;
9019  }
9020  }
9021 
9022  /* note that this is not the same as calling this method with mode 'l', 'l' assume convex/concave function */
9023  if( !success )
9024  {
9025  for( j = 0; j < consdata->nquadvars; ++j )
9026  {
9027  var = consdata->quadvarterms[j].var;
9028  lb = SCIPvarGetLbLocal(var);
9029  ub = SCIPvarGetUbLocal(var);
9030  /* do not like variables at infinity */
9031  assert(!SCIPisInfinity(scip, lb));
9032  assert(!SCIPisInfinity(scip, -ub));
9033 
9034  ref[j] = SCIPgetSolVal(scip, refsol, var);
9035  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
9036  }
9037 
9038  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9039  }
9040  }
9041  /* gauge cut */
9042  if( mode == 'g' )
9043  {
9044  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
9045  if( conshdlrdata->gaugecuts && consdata->isgaugeavailable )
9046  {
9047  SCIP_CALL( computeReferencePointGauge(scip, conshdlr, cons, refsol, ref, &success) );
9048  }
9049  if( success )
9050  {
9051  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9052  }
9053  }
9054  /* projection cut */
9055  if( mode == 'p' )
9056  {
9057  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
9058  if( conshdlrdata->projectedcuts && consdata->isedavailable )
9059  {
9060  SCIP_CALL( computeReferencePointProjection(scip, conshdlr, cons, refsol, ref) );
9061  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9062  }
9063  }
9064  /* gradient linearization cut at refsol */
9065  if( mode == 'l' )
9066  {
9067  assert((consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) || (consdata->isconcave && violside == SCIP_SIDETYPE_LEFT));
9068  for( j = 0; j < consdata->nquadvars; ++j )
9069  {
9070  var = consdata->quadvarterms[j].var;
9071  lb = SCIPvarGetLbLocal(var);
9072  ub = SCIPvarGetUbLocal(var);
9073  /* do not like variables at infinity */
9074  assert(!SCIPisInfinity(scip, lb));
9075  assert(!SCIPisInfinity(scip, -ub));
9076 
9077  ref[j] = SCIPgetSolVal(scip, refsol, var);
9078  ref[j] = MIN(ub, MAX(lb, ref[j])); /* project value into bounds */
9079  }
9080  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, sol, violside, row, efficacy, checkcurvmultivar, minefficacy) );
9081  }
9082 
9083  SCIPfreeBufferArray(scip, &ref);
9084 
9085  return SCIP_OKAY;
9086 }
9087 
9088 /** tries to find a cut that intersects with an unbounded ray of the LP
9089  *
9090  * For convex functions, we do this by linearizing in the feasible solution of the LPI.
9091  * For nonconvex functions, we just call generateCutSol with the unbounded solution as reference point.
9092  */
9093 static
9095  SCIP* scip, /**< SCIP data structure */
9096  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9097  SCIP_CONS* cons, /**< constraint */
9098  SCIP_SIDETYPE violside, /**< for which side a cut should be generated */
9099  SCIP_ROW** row, /**< storage for cut */
9100  SCIP_Real* rowrayprod, /**< buffer to store product of ray with row coefficients, or NULL if not of interest */
9101  SCIP_Bool checkcurvmultivar /**< are we allowed to check the curvature of a multivariate quadratic function, if not done yet */
9102  )
9103 {
9104  SCIP_CONSDATA* consdata;
9105  SCIP_BILINTERM* bilinterm;
9106  SCIP_VAR* var;
9107  SCIP_Real* ref;
9108  SCIP_Real matrixrayprod;
9109  SCIP_Real linrayprod;
9110  SCIP_Real quadrayprod;
9111  SCIP_Real rayval;
9112  int i;
9113  int j;
9114 
9115  assert(scip != NULL);
9116  assert(conshdlr != NULL);
9117  assert(cons != NULL);
9118  assert(row != NULL);
9120 
9121  consdata = SCIPconsGetData(cons);
9122  assert(consdata != NULL);
9123 
9124  *row = NULL;
9125 
9126  if( !SCIPhasPrimalRay(scip) )
9127  {
9128  SCIPdebugMsg(scip, "do not have primal ray, thus cannot resolve unboundedness\n");
9129  return SCIP_OKAY;
9130  }
9131 
9132  SCIP_CALL( checkCurvature(scip, cons, checkcurvmultivar) );
9133  if( (!consdata->isconvex && violside == SCIP_SIDETYPE_RIGHT) ||
9134  (!consdata->isconcave && violside == SCIP_SIDETYPE_LEFT) )
9135  {
9136  /* if not convex, just call generateCut and hope it's getting something useful */
9137  SCIP_CALL( generateCutSol(scip, conshdlr, cons, NULL, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip), 'd') );
9138 
9139  /* compute product of cut coefficients with ray, if required */
9140  if( *row != NULL && rowrayprod != NULL )
9141  {
9142  *rowrayprod = 0.0;
9143  for( i = 0; i < SCIProwGetNNonz(*row); ++i )
9144  {
9145  assert(SCIProwGetCols(*row)[i] != NULL);
9146  var = SCIPcolGetVar(SCIProwGetCols(*row)[i]);
9147  assert(var != NULL);
9148 
9149  *rowrayprod += SCIProwGetVals(*row)[i] * SCIPgetPrimalRayVal(scip, var);
9150  }
9151  }
9152 
9153  return SCIP_OKAY;
9154  }
9155 
9156  /* we seek for a linearization of the quadratic function such that it intersects with the unbounded ray
9157  * that is, we need a reference point ref such that for the gradient g of xAx+bx in ref, we have
9158  * <g, ray> > 0.0 if rhs is finite and <g, ray> < 0.0 if lhs is finite
9159  * Since g = 2*A*ref + b, we have <g, ray> = <2*A*ref + b, ray> = <ref, 2*A*ray> + <b,ray>
9160  * 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)
9161  * <ref, 2*A*ray> + <b,ray> is sufficiently larger 0.0, we call generateCut for this point, otherwise, we scale up ref
9162  */
9163 
9164  quadrayprod = 0.0; /* <ref, 2*A*ray> */
9165  linrayprod = 0.0; /* <b, ray> */
9166  SCIP_CALL( SCIPallocBufferArray(scip, &ref, consdata->nquadvars) );
9167  for( i = 0; i < consdata->nquadvars; ++i )
9168  {
9169  var = consdata->quadvarterms[i].var;
9170  rayval = SCIPgetPrimalRayVal(scip, var);
9171 
9172  /* compute i-th entry of (2*A*ray) */
9173  matrixrayprod = 2.0 * consdata->quadvarterms[i].sqrcoef * rayval;
9174  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
9175  {
9176  bilinterm = &consdata->bilinterms[consdata->quadvarterms[i].adjbilin[j]];
9177  matrixrayprod += bilinterm->coef * SCIPgetPrimalRayVal(scip, bilinterm->var1 == var ? bilinterm->var2 : bilinterm->var1);
9178  }
9179 
9180  if( SCIPisPositive(scip, matrixrayprod) )
9181  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? 1.0 : -1.0);
9182  else if( SCIPisNegative(scip, matrixrayprod) )
9183  ref[i] = (violside == SCIP_SIDETYPE_RIGHT ? -1.0 : 1.0);
9184  else
9185  ref[i] = 0.0;
9186 
9187  quadrayprod += matrixrayprod * ref[i];
9188  linrayprod += consdata->quadvarterms[i].lincoef * rayval;
9189  }
9190  assert((violside == SCIP_SIDETYPE_RIGHT && quadrayprod >= 0.0) || (violside == SCIP_SIDETYPE_LEFT && quadrayprod <= 0.0));
9191 
9192  if( SCIPisZero(scip, quadrayprod) )
9193  {
9194  SCIPdebugMsg(scip, "ray is zero along cons <%s>\n", SCIPconsGetName(cons));
9195  SCIPfreeBufferArray(scip, &ref);
9196  return SCIP_OKAY;
9197  }
9198 
9199  /* add linear part to linrayprod */
9200  for( i = 0; i < consdata->nlinvars; ++i )
9201  linrayprod += consdata->lincoefs[i] * SCIPgetPrimalRayVal(scip, consdata->linvars[i]);
9202 
9203  SCIPdebugMsg(scip, "initially have <b,ray> = %g and <ref, 2*A*ref> = %g\n", linrayprod, quadrayprod);
9204 
9205  /* 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
9206  * if <b,ray> is zero, then we scale refpoint up if |<ref, 2*A*ray>| < 1.0
9207  */
9208  if( (!SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_RIGHT && quadrayprod < -2*linrayprod) ||
9209  ( !SCIPisZero(scip, linrayprod) && violside == SCIP_SIDETYPE_LEFT && quadrayprod > -2*linrayprod) ||
9210  (SCIPisZero(scip, linrayprod) && REALABS(quadrayprod) < 1.0) )
9211  {
9212  SCIP_Real scale;
9213 
9214  if( !SCIPisZero(scip, linrayprod) )
9215  scale = 2*REALABS(linrayprod/quadrayprod); /*lint !e795 */
9216  else
9217  scale = 1.0/REALABS(quadrayprod);
9218 
9219  SCIPdebugMsg(scip, "scale refpoint by %g\n", scale);
9220  for( i = 0; i < consdata->nquadvars; ++i )
9221  ref[i] *= scale;
9222  quadrayprod *= scale;
9223  }
9224 
9225  if( rowrayprod != NULL )
9226  *rowrayprod = quadrayprod + linrayprod;
9227 
9228  SCIPdebugMsg(scip, "calling generateCut, expecting ray product %g\n", quadrayprod + linrayprod);
9229  SCIP_CALL( generateCut(scip, conshdlr, cons, ref, NULL, violside, row, NULL, FALSE, -SCIPinfinity(scip)) );
9230 
9231  SCIPfreeBufferArray(scip, &ref);
9232 
9233  return SCIP_OKAY;
9234 }
9235 
9236 /** processes a cut for constraint cons, i.e., checks numerics and possibly adds cut to sepastore */
9237 static
9239  SCIP* scip, /**< SCIP data structure */
9240  SCIP_ROW** row, /**< cut to process */
9241  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9242  SCIP_CONS* cons, /**< constraint */
9243  SCIP_Real efficacy, /**< efficacy of row in reference solution */
9244  SCIP_Real minefficacy, /**< minimal efficacy */
9245  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
9246  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 */
9247  SCIP_RESULT* result /**< result of separation */
9248  )
9249 {
9250  SCIP_CONSDATA* consdata;
9251  SCIP_CONSHDLRDATA* conshdlrdata;
9252 
9253  assert(scip != NULL);
9254  assert(row != NULL);
9255  assert(conshdlr != NULL);
9256  assert(result != NULL);
9257  assert(cons != NULL);
9258 
9259  /* no cut to process */
9260  if( *row == NULL )
9261  return SCIP_OKAY;
9262 
9263  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9264  assert(conshdlrdata != NULL);
9265 
9266  consdata = SCIPconsGetData(cons);
9267  assert(consdata != NULL);
9268 
9269  if( SCIPisGT(scip, efficacy, minefficacy) && SCIPisCutApplicable(scip, *row) ) /*lint !e644 */
9270  {
9271  SCIP_Bool infeasible;
9272 
9273  /* cut cuts off solution */
9274  SCIP_CALL( SCIPaddRow(scip, *row, FALSE /* forcecut */, &infeasible) );
9275  if( infeasible )
9276  {
9277  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(cons));
9278  *result = SCIP_CUTOFF;
9279  }
9280  else
9281  {
9282  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy,
9283  SCIPconsGetName(cons), consdata->lhsviol+consdata->rhsviol);
9284  *result = SCIP_SEPARATED;
9285  }
9286  SCIP_CALL( SCIPresetConsAge(scip, cons) );
9287 
9288  /* mark row as not removable from LP for current node, if in enforcement */
9289  if( inenforcement && !conshdlrdata->enfocutsremovable )
9290  SCIPmarkRowNotRemovableLocal(scip, *row);
9291  }
9292  if( bestefficacy != NULL && efficacy > *bestefficacy )
9293  *bestefficacy = efficacy;
9294 
9295  SCIP_CALL( SCIPreleaseRow (scip, row) );
9296  return SCIP_OKAY;
9297 }
9298 
9299 /** tries to separate solution or LP solution by a linear cut
9300  *
9301  * assumes that constraint violations have been computed
9302  */
9303 static
9305  SCIP* scip, /**< SCIP data structure */
9306  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9307  SCIP_CONS** conss, /**< constraints */
9308  int nconss, /**< number of constraints */
9309  int nusefulconss, /**< number of constraints that seem to be useful */
9310  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
9311  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
9312  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
9313  SCIP_RESULT* result, /**< result of separation */
9314  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 */
9315  )
9316 {
9317  SCIP_CONSHDLRDATA* conshdlrdata;
9318  SCIP_CONSDATA* consdata;
9319  SCIP_Real efficacy;
9320  SCIP_SIDETYPE violside;
9321  int c;
9322  SCIP_ROW* row;
9323 
9324  assert(scip != NULL);
9325  assert(conshdlr != NULL);
9326  assert(conss != NULL || nconss == 0);
9327  assert(nusefulconss <= nconss);
9328  assert(result != NULL);
9329 
9330  *result = SCIP_FEASIBLE;
9331 
9332  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9333  assert(conshdlrdata != NULL);
9334 
9335  if( bestefficacy != NULL )
9336  *bestefficacy = 0.0;
9337 
9338  row = NULL;
9339  /* loop over both sides of each constraint */
9340  for( c = 0, violside = SCIP_SIDETYPE_LEFT; c < nconss; c = (violside == SCIP_SIDETYPE_LEFT ? c : c+1), violside = (violside == SCIP_SIDETYPE_LEFT ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT) )
9341  {
9342  assert(conss != NULL);
9343  consdata = SCIPconsGetData(conss[c]);
9344  assert(consdata != NULL);
9345 
9346  /* if side not violated, then go on */
9347  if( !SCIPisGT(scip, violside == SCIP_SIDETYPE_LEFT ? consdata->lhsviol : consdata->rhsviol, SCIPfeastol(scip)) )
9348  continue;
9349 
9350  /* we are not feasible anymore */
9351  if( *result == SCIP_FEASIBLE )
9352  *result = SCIP_DIDNOTFIND;
9353 
9354  /* generate cut */
9355  if( sol == NULL && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
9356  {
9357  /* if the LP is unbounded, then we need a cut that cuts into the direction of a hopefully existing primal ray
9358  * 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
9359  * given a cut lhs <= <c,x> <= rhs, we check whether it imposes an upper bound on t and thus bounds the ray
9360  * 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>
9361  * similar, lhs > -infinity and <c,r> < 0 is good
9362  */
9363  SCIP_Real rayprod;
9364 
9365  rayprod = 0.0; /* for compiler */
9366  SCIP_CALL( generateCutUnboundedLP(scip, conshdlr, conss[c], violside, &row, &rayprod, conshdlrdata->checkcurvature) );
9367 
9368  if( row != NULL )
9369  {
9370  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) && SCIPisPositive(scip, rayprod) )
9371  efficacy = rayprod;
9372  else if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) && SCIPisNegative(scip, rayprod) )
9373  efficacy = -rayprod;
9374  else
9375  efficacy = 0.0;
9376 
9377  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], efficacy, minefficacy, inenforcement, bestefficacy, result) );
9378  }
9379  continue;
9380  }
9381  else
9382  {
9383  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], sol, NULL, violside, &row, &efficacy,
9384  conshdlrdata->checkcurvature, minefficacy, 'd') );
9385 
9386  SCIP_CALL( processCut(scip, &row, conshdlr, conss[c], efficacy, minefficacy, inenforcement, bestefficacy, result) );
9387  }
9388 
9389  if( *result == SCIP_CUTOFF )
9390  break;
9391 
9392  /* enforce only useful constraints
9393  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
9394  */
9395  if( c >= nusefulconss && *result == SCIP_SEPARATED )
9396  break;
9397  }
9398 
9399  return SCIP_OKAY;
9400 }
9401 
9402 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
9403  *
9404  * - 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.
9405  * - If separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only.
9406  * - If separatedlpsol is NULL, then cut is added to cutpool only.
9407  */
9408 static
9410  SCIP* scip, /**< SCIP data structure */
9411  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
9412  SCIP_CONS** conss, /**< constraints */
9413  int nconss, /**< number of constraints */
9414  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
9415  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP,
9416  * or NULL if adding to cutpool only */
9417  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
9418  )
9419 {
9420  SCIP_CONSHDLRDATA* conshdlrdata;
9421  SCIP_CONSDATA* consdata;
9422  SCIP_Bool addedtolp;
9423  SCIP_ROW* row;
9424  int c;
9425 
9426  assert(scip != NULL);
9427  assert(conshdlr != NULL);
9428  assert(conss != NULL || nconss == 0);
9429 
9430  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9431  assert(conshdlrdata != NULL);
9432 
9433  if( separatedlpsol != NULL )
9434  *separatedlpsol = FALSE;
9435 
9436  for( c = 0; c < nconss; ++c )
9437  {
9438  assert(conss[c] != NULL); /*lint !e613 */
9439 
9440  if( SCIPconsIsLocal(conss[c]) || !SCIPconsIsEnabled(conss[c]) ) /*lint !e613 */
9441  continue;
9442 
9443  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
9444 
9445  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
9446  assert(consdata != NULL);
9447 
9448  if( consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
9449  {
9450  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_RIGHT, &row, NULL,
9451  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
9452  }
9453  else if( consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
9454  {
9455  SCIP_CALL( generateCutSol(scip, conshdlr, conss[c], NULL, ref, SCIP_SIDETYPE_LEFT, &row, NULL,
9456  conshdlrdata->checkcurvature, -SCIPinfinity(scip), 'l') ); /*lint !e613 */
9457  }
9458  else
9459  continue;
9460 
9461  if( row == NULL )
9462  continue;
9463 
9464  addedtolp = FALSE;
9465 
9466  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
9467  if( separatedlpsol != NULL )
9468  {
9469  SCIP_Real efficacy;
9470 
9471  efficacy = -SCIPgetRowLPFeasibility(scip, row);
9472  if( efficacy >= minefficacy )
9473  {
9474  SCIP_Bool infeasible;
9475 
9476  *separatedlpsol = TRUE;
9477  addedtolp = TRUE;
9478  SCIP_CALL( SCIPaddRow(scip, row, TRUE, &infeasible) );
9479  assert( ! infeasible );
9480  SCIPdebugMsg(scip, "added linearization cut <%s> to LP, efficacy = %g\n", SCIProwGetName(row), efficacy);
9481  }
9482  }
9483 
9484  if( !SCIProwIsLocal(row) && !addedtolp )
9485  {
9486  SCIP_CALL( SCIPaddPoolCut(scip, row) );
9487  SCIPdebugMsg(scip, "added linearization cut <%s> to cutpool\n", SCIProwGetName(row));
9488  }
9489 
9490  SCIP_CALL( SCIPreleaseRow(scip, &row) );
9491  }
9492 
9493  return SCIP_OKAY;
9494 }
9495 
9496 /** processes the event that a new primal solution has been found */
9497 static
9498 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
9500  SCIP_CONSHDLRDATA* conshdlrdata;
9501  SCIP_CONSHDLR* conshdlr;
9502  SCIP_CONS** conss;
9503  int nconss;
9504  SCIP_SOL* sol;
9505 
9506  assert(scip != NULL);
9507  assert(event != NULL);
9508  assert(eventdata != NULL);
9509  assert(eventhdlr != NULL);
9510 
9511  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
9512 
9513  conshdlr = (SCIP_CONSHDLR*)eventdata;
9514 
9515  nconss = SCIPconshdlrGetNConss(conshdlr);
9516 
9517  if( nconss == 0 )
9518  return SCIP_OKAY;
9519 
9520  sol = SCIPeventGetSol(event);
9521  assert(sol != NULL);
9522 
9523  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9524  assert(conshdlrdata != NULL);
9525 
9526  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
9527  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
9528  * or are from the tree, but postprocessed via proposeFeasibleSolution
9529  */
9530  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
9531  return SCIP_OKAY;
9532 
9533  conss = SCIPconshdlrGetConss(conshdlr);
9534  assert(conss != NULL);
9535 
9536  SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
9537 
9538  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
9539 
9540  return SCIP_OKAY;
9541 }
9542 
9543 /** registers branching candidates according to convexification gap rule
9544  *
9545  * That is, computes for every nonconvex term the gap between the terms value in the LP solution and the value of the underestimator
9546  * as it would be (and maybe has been) constructed by the separation routines of this constraint handler. Then it registers all
9547  * variables occurring in each term with the computed gap. If variables appear in more than one term, they are registered several times.
9548  */
9549 static
9551  SCIP* scip, /**< SCIP data structure */
9552  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9553  SCIP_CONS** conss, /**< constraints to check */
9554  int nconss, /**< number of constraints to check */
9555  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9556  int* nnotify /**< counter for number of notifications performed */
9557  )
9558 {
9559  SCIP_CONSHDLRDATA* conshdlrdata;
9560  SCIP_CONSDATA* consdata;
9561  int c;
9562  int j;
9563  SCIP_Bool xbinary;
9564  SCIP_Bool ybinary;
9565  SCIP_Bool xunbounded;
9566  SCIP_Bool yunbounded;
9567  SCIP_VAR* x;
9568  SCIP_VAR* y;
9569  SCIP_Real xlb;
9570  SCIP_Real xub;
9571  SCIP_Real xval;
9572  SCIP_Real ylb;
9573  SCIP_Real yub;
9574  SCIP_Real yval;
9575  SCIP_Real gap;
9576  SCIP_Real coef_;
9577 
9578  assert(scip != NULL);
9579  assert(conshdlr != NULL);
9580  assert(conss != NULL || nconss == 0);
9581 
9582  *nnotify = 0;
9583  yval = SCIP_INVALID;
9584  xval = SCIP_INVALID;
9585 
9586  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9587  assert(conshdlr != NULL);
9588 
9589  for( c = 0; c < nconss; ++c )
9590  {
9591  assert(conss != NULL);
9592  consdata = SCIPconsGetData(conss[c]);
9593  assert(consdata != NULL);
9594 
9595  if( !consdata->nquadvars )
9596  continue;
9597 
9598  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9599  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9600  continue;
9601  SCIPdebugMsg(scip, "cons <%s> violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9602 
9603  /* square terms */
9604  for( j = 0; j < consdata->nquadvars; ++j )
9605  {
9606  x = consdata->quadvarterms[j].var;
9607  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef < 0) ||
9608  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->quadvarterms[j].sqrcoef > 0) )
9609  {
9610  xlb = SCIPvarGetLbLocal(x);
9611  xub = SCIPvarGetUbLocal(x);
9612  if( SCIPisRelEQ(scip, xlb, xub) )
9613  {
9614  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9615  continue;
9616  }
9617 
9618  xval = SCIPgetSolVal(scip, sol, x);
9619 
9620  /* if variable is at bounds, then no need to branch, since secant is exact there */
9621  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
9622  continue;
9623 
9624  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
9625  gap = SCIPinfinity(scip);
9626  else
9627  gap = (xval-xlb)*(xub-xval)/(1+2*ABS(xval));
9628  assert(!SCIPisFeasNegative(scip, gap));
9629  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(gap, 0.0), SCIP_INVALID) );
9630  ++*nnotify;
9631  }
9632  }
9633 
9634  /* bilinear terms */
9635  for( j = 0; j < consdata->nbilinterms; ++j )
9636  {
9637  /* if any of the variables if fixed, then it actually behaves like a linear term, so we don't need to branch on it */
9638  x = consdata->bilinterms[j].var1;
9639  xlb = SCIPvarGetLbLocal(x);
9640  xub = SCIPvarGetUbLocal(x);
9641  if( SCIPisRelEQ(scip, xlb, xub) )
9642  continue;
9643 
9644  y = consdata->bilinterms[j].var2;
9645  ylb = SCIPvarGetLbLocal(y);
9646  yub = SCIPvarGetUbLocal(y);
9647  if( SCIPisRelEQ(scip, ylb, yub) )
9648  continue;
9649 
9650  xunbounded = SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub);
9651  yunbounded = SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub);
9652 
9653  /* compute gap, if both variable are bounded */
9654  gap = SCIPinfinity(scip);
9655  if( !xunbounded && !yunbounded )
9656  {
9657  xval = SCIPgetSolVal(scip, sol, x);
9658  yval = SCIPgetSolVal(scip, sol, y);
9659 
9660  /* if both variables are at one of its bounds, then no need to branch, since McCormick is exact there */
9661  if( (SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub)) &&
9662  ( SCIPisLE(scip, yval, ylb) || SCIPisGE(scip, yval, yub)) )
9663  continue;
9664 
9665  xval = MAX(xlb, MIN(xval, xub));
9666  yval = MAX(ylb, MIN(yval, yub));
9667 
9668  coef_ = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? -consdata->bilinterms[j].coef : consdata->bilinterms[j].coef;
9669  if( coef_ > 0.0 )
9670  {
9671  if( (xub-xlb)*yval + (yub-ylb)*xval <= xub*yub - xlb*ylb )
9672  gap = (xval*yval - xlb*yval - ylb*xval + xlb*ylb) / (1+sqrt(xval*xval + yval*yval));
9673  else
9674  gap = (xval*yval - xval*yub - yval*xub + xub*yub) / (1+sqrt(xval*xval + yval*yval));
9675  }
9676  else
9677  { /* coef_ < 0 */
9678  if( (xub-xlb)*yval - (yub-ylb)*xval <= xub*ylb - xlb*yub )
9679  gap = -(xval*yval - xval*ylb - yval*xub + xub*ylb) / (1+sqrt(xval*xval + yval*yval));
9680  else
9681  gap = -(xval*yval - xval*yub - yval*xlb + xlb*yub) / (1+sqrt(xval*xval + yval*yval));
9682  }
9683 
9684  assert(!SCIPisNegative(scip, gap / MAX3(MAX(REALABS(xlb), REALABS(xub)), MAX(REALABS(ylb), REALABS(yub)), 1.0))); /*lint !e666*/
9685  if( gap < 0.0 )
9686  gap = 0.0;
9687 
9688  /* use tighter relaxation when using linear inequalities to adjust the branching scores for bilinear terms */
9689  if( consdata->bilintermsidx != NULL && conshdlrdata->usebilinineqbranch )
9690  {
9691  BILINESTIMATOR* bilinestimator;
9692  int bilinidx;
9693 
9694  assert(conshdlrdata->bilinestimators != NULL);
9695 
9696  bilinidx = consdata->bilintermsidx[j];
9697  assert(bilinidx >= 0 && bilinidx < conshdlrdata->nbilinterms);
9698 
9699  bilinestimator = &conshdlrdata->bilinestimators[bilinidx];
9700  assert(bilinestimator != NULL);
9701  assert(bilinestimator->x == x);
9702  assert(bilinestimator->y == y);
9703 
9704  if( SCIPisGT(scip, bilinestimator->lastimprfac, 0.0) )
9705  gap *= MAX(0.0, 1.0 - bilinestimator->lastimprfac);
9706  }
9707  }
9708 
9709  /* if one of the variables is binary or integral with domain width 1, then branching on this makes the term linear, so prefer this */
9710  xbinary = SCIPvarIsBinary(x) || (SCIPvarIsIntegral(x) && xub - xlb < 1.5);
9711  ybinary = SCIPvarIsBinary(y) || (SCIPvarIsIntegral(y) && yub - ylb < 1.5);
9712  if( xbinary )
9713  {
9715  ++*nnotify;
9716  }
9717  if( ybinary )
9718  {
9720  ++*nnotify;
9721  }
9722  if( xbinary || ybinary )
9723  continue;
9724 
9725  /* if one of the variables is unbounded, then branch on it first */
9726  if( xunbounded )
9727  {
9729  ++*nnotify;
9730  }
9731  if( yunbounded )
9732  {
9734  ++*nnotify;
9735  }
9736  if( xunbounded || yunbounded )
9737  continue;
9738 
9739  /* if both variables are integral, prefer the one with the smaller domain, so variable gets fixed soon
9740  * does not seem to work well on tln instances, so disable for now and may look at it later again
9741  */
9742 #ifdef BRANCHTOLINEARITY
9743  if( SCIPvarIsIntegral(x) && SCIPvarIsIntegral(y) )
9744  {
9745  if( SCIPisLT(scip, xub-xlb, yub-ylb) )
9746  {
9748  ++*nnotify;
9749  continue;
9750  }
9751  if( SCIPisGT(scip, xub-xlb, yub-ylb) )
9752  {
9754  ++*nnotify;
9755  continue;
9756  }
9757  }
9758 #endif
9759 
9760  /* in the regular case, suggest those variables which are not at its bounds for branching
9761  * this is, because after branching both variables will be one the bounds, and McCormick will be exact then */
9762  if( !SCIPisLE(scip, xval, xlb) && !SCIPisGE(scip, xval, xub) )
9763  {
9765  ++*nnotify;
9766  }
9767  if( !SCIPisLE(scip, yval, ylb) && !SCIPisGE(scip, yval, yub) )
9768  {
9770  ++*nnotify;
9771  }
9772  }
9773  }
9774 
9775  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9776 
9777  return SCIP_OKAY;
9778 }
9779 
9780 /** registers branching candidates according to constraint violation rule
9781  *
9782  * That is, registers all variables appearing in nonconvex terms^1 with a score that is the violation of the constraint.
9783  * This is the same rule as is applied in cons_nonlinear and other nonlinear constraint handlers.
9784  *
9785  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
9786  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
9787  */
9788 static
9790  SCIP* scip, /**< SCIP data structure */
9791  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9792  SCIP_CONS** conss, /**< constraints to check */
9793  int nconss, /**< number of constraints to check */
9794  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9795  int* nnotify /**< counter for number of notifications performed */
9796  )
9797 {
9798  SCIP_CONSDATA* consdata;
9799  SCIP_QUADVARTERM* quadvarterm;
9800  int c;
9801  int j;
9802  SCIP_VAR* x;
9803  SCIP_Real xlb;
9804  SCIP_Real xub;
9805  SCIP_Real xval;
9806 
9807  assert(scip != NULL);
9808  assert(conshdlr != NULL);
9809  assert(conss != NULL || nconss == 0);
9810 
9811  *nnotify = 0;
9812 
9813  for( c = 0; c < nconss; ++c )
9814  {
9815  assert(conss != NULL);
9816  consdata = SCIPconsGetData(conss[c]);
9817  assert(consdata != NULL);
9818 
9819  if( !consdata->nquadvars )
9820  continue;
9821 
9822  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9823  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9824  continue;
9825  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9826 
9827  for( j = 0; j < consdata->nquadvars; ++j )
9828  {
9829  quadvarterm = &consdata->quadvarterms[j];
9830  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
9831  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
9832  quadvarterm->nadjbilin > 0 )
9833  {
9834  x = quadvarterm->var;
9835  xlb = SCIPvarGetLbLocal(x);
9836  xub = SCIPvarGetUbLocal(x);
9837 
9838  if( quadvarterm->nadjbilin == 0 )
9839  {
9840  xval = SCIPgetSolVal(scip, sol, x);
9841 
9842  /* if variable is at bounds and only in a nonconvex square term, then no need to branch, since secant is exact there */
9843  if( SCIPisLE(scip, xval, xlb) || SCIPisGE(scip, xval, xub) )
9844  continue;
9845  }
9846 
9847  if( SCIPisRelEQ(scip, xlb, xub) )
9848  {
9849  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9850  continue;
9851  }
9852 
9853  SCIP_CALL( SCIPaddExternBranchCand(scip, x, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
9854  ++*nnotify;
9855  }
9856  }
9857  }
9858 
9859  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9860 
9861  return SCIP_OKAY;
9862 }
9863 
9864 /** registers branching candidates according to centrality rule
9865  *
9866  * That is, registers all variables appearing in nonconvex terms^1 with a score that is given by the distance of the
9867  * variable value from its bounds. This rule should not make sense, as the distance to the bounds is also (often) considered
9868  * by the branching rule later on.
9869  *
9870  * 1) We mean all quadratic variables that appear either in a nonconvex square term or in a bilinear term, if the constraint
9871  * itself is nonconvex. (and this under the assumption that the rhs is violated; for violated lhs, swap terms)
9872  */
9873 static
9875  SCIP* scip, /**< SCIP data structure */
9876  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9877  SCIP_CONS** conss, /**< constraints to check */
9878  int nconss, /**< number of constraints to check */
9879  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9880  int* nnotify /**< counter for number of notifications performed */
9881  )
9882 {
9883  SCIP_CONSDATA* consdata;
9884  SCIP_QUADVARTERM* quadvarterm;
9885  int c;
9886  int j;
9887  SCIP_VAR* x;
9888  SCIP_Real xlb;
9889  SCIP_Real xub;
9890  SCIP_Real xval;
9891  SCIP_Real score;
9892 
9893  assert(scip != NULL);
9894  assert(conshdlr != NULL);
9895  assert(conss != NULL || nconss == 0);
9896 
9897  *nnotify = 0;
9898 
9899  for( c = 0; c < nconss; ++c )
9900  {
9901  assert(conss != NULL);
9902  consdata = SCIPconsGetData(conss[c]);
9903  assert(consdata != NULL);
9904 
9905  if( !consdata->nquadvars )
9906  continue;
9907 
9908  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || consdata->isconcave) &&
9909  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || consdata->isconvex ) )
9910  continue;
9911  SCIPdebugMsg(scip, "cons %s violation: %g %g convex: %u %u\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->isconvex, consdata->isconcave);
9912 
9913  for( j = 0; j < consdata->nquadvars; ++j )
9914  {
9915  quadvarterm = &consdata->quadvarterms[j];
9916  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef < 0) ||
9917  (SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && quadvarterm->sqrcoef > 0) ||
9918  quadvarterm->nadjbilin > 0 )
9919  {
9920  x = quadvarterm->var;
9921  xlb = SCIPvarGetLbLocal(x);
9922  xub = SCIPvarGetUbLocal(x);
9923 
9924  if( SCIPisRelEQ(scip, xlb, xub) )
9925  {
9926  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], diff %g\n", SCIPvarGetName(x), xlb, xub, xub-xlb);
9927  continue;
9928  }
9929 
9930  xval = SCIPgetSolVal(scip, sol, x);
9931  xval = MAX(xlb, MIN(xub, xval));
9932 
9933  /* compute relative difference of xval to each of its bounds
9934  * and scale such that if xval were in the middle, we get a score of 1
9935  * and if xval is on one its bounds, the score is 0
9936  */
9937  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
9938  {
9939  if( (!SCIPisInfinity(scip, -xlb) && SCIPisEQ(scip, xval, xlb)) || (!SCIPisInfinity(scip, xub) && SCIPisEQ(scip, xval, xub)) )
9940  score = 0.0;
9941  else
9942  score = 1.0;
9943  }
9944  else
9945  {
9946  score = 4.0 * (xval - xlb) * (xub - xval) / ((xub - xlb) * (xub - xlb));
9947  }
9948 
9949  SCIP_CALL( SCIPaddExternBranchCand(scip, x, score, SCIP_INVALID) );
9950  ++*nnotify;
9951  }
9952  }
9953  }
9954 
9955  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
9956 
9957  return SCIP_OKAY;
9958 }
9959 
9960 /** registers branching candidates */
9961 static
9963  SCIP* scip, /**< SCIP data structure */
9964  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9965  SCIP_CONS** conss, /**< constraints to check */
9966  int nconss, /**< number of constraints to check */
9967  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
9968  int* nnotify /**< counter for number of notifications performed */
9969  )
9970 {
9971  SCIP_CONSHDLRDATA* conshdlrdata;
9972 
9973  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9974  assert(conshdlrdata != NULL);
9975 
9976  switch( conshdlrdata->branchscoring )
9977  {
9978  case 'g' :
9979  SCIP_CALL( registerBranchingCandidatesGap(scip, conshdlr, conss, nconss, sol, nnotify) );
9980  break;
9981 
9982  case 'v' :
9983  SCIP_CALL( registerBranchingCandidatesViolation(scip, conshdlr, conss, nconss, sol, nnotify) );
9984  break;
9985 
9986  case 'c' :
9987  SCIP_CALL( registerBranchingCandidatesCentrality(scip, conshdlr, conss, nconss, sol, nnotify) );
9988  break;
9989 
9990  default :
9991  SCIPerrorMessage("invalid branchscoring selection");
9992  SCIPABORT();
9993  return SCIP_ERROR; /*lint !e527*/
9994  }
9995 
9996  return SCIP_OKAY;
9997 }
9998 
9999 
10000 /** registers a quadratic variable from a violated constraint as branching candidate that has a large absolute value in the (LP) relaxation */
10001 static
10003  SCIP* scip, /**< SCIP data structure */
10004  SCIP_CONS** conss, /**< constraints */
10005  int nconss, /**< number of constraints */
10006  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
10007  SCIP_VAR** brvar /**< buffer to store branching variable */
10008  )
10009 {
10010  SCIP_CONSDATA* consdata;
10011  SCIP_Real val;
10012  SCIP_Real brvarval;
10013  int i;
10014  int c;
10015 
10016  assert(scip != NULL);
10017  assert(conss != NULL || nconss == 0);
10018 
10019  *brvar = NULL;
10020  brvarval = -1.0;
10021 
10022  for( c = 0; c < nconss; ++c )
10023  {
10024  assert(conss != NULL);
10025  consdata = SCIPconsGetData(conss[c]);
10026  assert(consdata != NULL);
10027 
10028  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10029  continue;
10030 
10031  for( i = 0; i < consdata->nquadvars; ++i )
10032  {
10033  /* do not propose fixed variables */
10034  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var)) )
10035  continue;
10036  val = SCIPgetSolVal(scip, sol, consdata->quadvarterms[i].var);
10037  if( ABS(val) > brvarval )
10038  {
10039  brvarval = ABS(val);
10040  *brvar = consdata->quadvarterms[i].var;
10041  }
10042  }
10043  }
10044 
10045  if( *brvar != NULL )
10046  {
10047  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
10048  }
10049 
10050  return SCIP_OKAY;
10051 }
10052 
10053 /** replaces violated quadratic constraints where all quadratic variables are fixed by linear constraints */
10054 static
10056  SCIP* scip, /**< SCIP data structure */
10057  SCIP_CONS** conss, /**< constraints */
10058  int nconss, /**< number of constraints */
10059  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
10060  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
10061  SCIP_Bool* infeasible /**< whether we detected infeasibility */
10062  )
10063 {
10064  SCIP_CONS* cons;
10065  SCIP_CONSDATA* consdata;
10066  SCIP_RESULT checkresult;
10067  SCIP_VAR* var;
10068  SCIP_Bool tightened;
10069  SCIP_Real constant;
10070  SCIP_Real val1;
10071  SCIP_Real val2;
10072  int i;
10073  int c;
10074 
10075  assert(scip != NULL);
10076  assert(conss != NULL || nconss == 0);
10077  assert(addedcons != NULL);
10078  assert(reduceddom != NULL);
10079  assert(infeasible != NULL);
10080 
10081  *addedcons = FALSE;
10082  *reduceddom = FALSE;
10083  *infeasible = FALSE;
10084 
10085  for( c = 0; c < nconss; ++c )
10086  {
10087  assert(conss != NULL);
10088  consdata = SCIPconsGetData(conss[c]);
10089  assert(consdata != NULL);
10090 
10091  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
10092  continue;
10093 
10094  constant = 0.0;
10095 
10096  for( i = 0; i < consdata->nquadvars; ++i )
10097  {
10098  var = consdata->quadvarterms[i].var;
10099 
10100  /* variables should be fixed if constraint is violated */
10101  assert(SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)));
10102 
10103  val1 = (SCIPvarGetUbLocal(var) + SCIPvarGetLbLocal(var)) / 2.0;
10104  constant += (consdata->quadvarterms[i].lincoef + consdata->quadvarterms[i].sqrcoef * val1) * val1;
10105 
10106  SCIPdebugMessage("<%s>: [%.20g, %.20g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
10107 
10108  /* if variable is not fixed w.r.t. absolute eps yet, then try to fix it
10109  * (SCIPfixVar() doesn't allow for small tightenings, so tighten lower and upper bound separately)
10110  */
10111  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10112  {
10113  SCIP_CALL( SCIPtightenVarLb(scip, var, val1, TRUE, infeasible, &tightened) );
10114  if( *infeasible )
10115  {
10116  SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(var));
10117  return SCIP_OKAY;
10118  }
10119  if( tightened )
10120  {
10121  SCIPdebugMsg(scip, "Tightened lower bound of almost fixed variable <%s>.\n", SCIPvarGetName(var));
10122  *reduceddom = TRUE;
10123  }
10124 
10125  SCIP_CALL( SCIPtightenVarUb(scip, var, val1, TRUE, infeasible, &tightened) );
10126  if( *infeasible )
10127  {
10128  SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(var));
10129  return SCIP_OKAY;
10130  }
10131  if( tightened )
10132  {
10133  SCIPdebugMsg(scip, "Tightened upper bound of almost fixed variable <%s>.\n", SCIPvarGetName(var));
10134  *reduceddom = TRUE;
10135  }
10136  }
10137  }
10138 
10139  /* if some quadratic variable was fixed now, then restart node (next enfo round) */
10140  if( *reduceddom )
10141  return SCIP_OKAY;
10142 
10143  for( i = 0; i < consdata->nbilinterms; ++i )
10144  {
10145  val1 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var1) + SCIPvarGetLbLocal(consdata->bilinterms[i].var1)) / 2.0;
10146  val2 = (SCIPvarGetUbLocal(consdata->bilinterms[i].var2) + SCIPvarGetLbLocal(consdata->bilinterms[i].var2)) / 2.0;
10147  constant += consdata->bilinterms[i].coef * val1 * val2;
10148  }
10149 
10150  /* check if we have a bound change */
10151  if ( consdata->nlinvars == 1 )
10152  {
10153  SCIP_Real coef;
10154  SCIP_Real lhs;
10155  SCIP_Real rhs;
10156 
10157  coef = *consdata->lincoefs;
10158  var = *consdata->linvars;
10159 
10160  assert( ! SCIPisZero(scip, coef) );
10161 
10162  /* compute lhs/rhs, divide already by |coef| */
10163  if ( SCIPisInfinity(scip, -consdata->lhs) )
10164  lhs = -SCIPinfinity(scip);
10165  else
10166  lhs = (consdata->lhs - constant) / REALABS(coef);
10167 
10168  if ( SCIPisInfinity(scip, consdata->rhs) )
10169  rhs = SCIPinfinity(scip);
10170  else
10171  rhs = (consdata->rhs - constant) / REALABS(coef);
10172 
10173  SCIPdebugMsg(scip, "Linear constraint with one variable: %.20g <= %g <%s> <= %.20g\n", lhs, coef > 0.0 ? 1.0 : -1.0, SCIPvarGetName(var), rhs);
10174 
10175  SCIPdebugMessage("<%s>: [%.20g, %.20g]\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
10176 
10177  if ( coef < 0.0 )
10178  {
10179  /* swap lhs and rhs, with negated sign */
10180  SCIP_Real h;
10181  h = rhs;
10182  rhs = -lhs;
10183  lhs = -h;
10184  }
10185  SCIPdebugMsg(scip, "Linear constraint is a bound: %.20g <= <%s> <= %.20g\n", lhs, SCIPvarGetName(var), rhs);
10186 
10187  if( SCIPisInfinity(scip, -rhs) || SCIPisInfinity(scip, lhs) )
10188  {
10189  SCIPdebugMsg(scip, "node will marked as infeasible since lb/ub of %s is +/-infinity\n",
10190  SCIPvarGetName(var));
10191 
10192  *infeasible = TRUE;
10193  return SCIP_OKAY;
10194  }
10195 
10196  if ( ! SCIPisInfinity(scip, -lhs) )
10197  {
10198  SCIP_CALL( SCIPtightenVarLb(scip, var, lhs, TRUE, infeasible, &tightened) );
10199  if ( *infeasible )
10200  {
10201  SCIPdebugMsg(scip, "Lower bound leads to infeasibility.\n");
10202  return SCIP_OKAY;
10203  }
10204  if ( tightened )
10205  {
10206  SCIPdebugMsg(scip, "Lower bound changed.\n");
10207  *reduceddom = TRUE;
10208  return SCIP_OKAY;
10209  }
10210  }
10211 
10212  if ( ! SCIPisInfinity(scip, rhs) )
10213  {
10214  SCIP_CALL( SCIPtightenVarUb(scip, var, rhs, TRUE, infeasible, &tightened) );
10215  if ( *infeasible )
10216  {
10217  SCIPdebugMsg(scip, "Upper bound leads to infeasibility.\n");
10218  return SCIP_OKAY;
10219  }
10220  if ( tightened )
10221  {
10222  SCIPdebugMsg(scip, "Upper bound changed.\n");
10223  *reduceddom = TRUE;
10224  return SCIP_OKAY;
10225  }
10226  }
10227  }
10228  else
10229  {
10230  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
10231  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
10232  (SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : (consdata->lhs - constant)),
10233  (SCIPisInfinity(scip, consdata->rhs) ? SCIPinfinity(scip) : (consdata->rhs - constant)),
10234  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
10235  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
10236  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
10237  SCIPconsIsStickingAtNode(conss[c])) );
10238 
10239  SCIPdebugMsg(scip, "replace quadratic constraint <%s> by linear constraint after all quadratic vars have been fixed\n", SCIPconsGetName(conss[c]) );
10240  SCIPdebugPrintCons(scip, cons, NULL);
10241 
10242  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
10243 
10244  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
10245  {
10246  SCIPdebugMsg(scip, "linear constraint is feasible and LP optimal, thus do not add\n");
10247  }
10248  else
10249  {
10250  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
10251  *addedcons = TRUE;
10252  }
10253  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
10254  }
10255  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
10256  }
10257 
10258  return SCIP_OKAY;
10259 }
10260 
10261 /** tightens a lower bound on a variable and checks the result */
10262 static
10264  SCIP* scip, /**< SCIP data structure */
10265  SCIP_CONS* cons, /**< constraint where we currently propagate */
10266  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10267  SCIP_VAR* var, /**< variable which domain we might reduce */
10268  SCIP_Real bnd, /**< new lower bound for variable */
10269  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
10270  int* nchgbds /**< counter to increase if a bound was tightened */
10271  )
10272 {
10273  SCIP_Bool infeas;
10274  SCIP_Bool tightened;
10275 
10276  assert(scip != NULL);
10277  assert(cons != NULL);
10278  assert(intervalinfty > 0.0);
10279  assert(bnd > -intervalinfty);
10280  assert(var != NULL);
10281  assert(result != NULL);
10282  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10283  assert(nchgbds != NULL);
10284 
10285  /* new bound is no improvement */
10286  if( SCIPisHugeValue(scip, -bnd) || SCIPisLE(scip, bnd, SCIPvarGetLbLocal(var)) )
10287  return SCIP_OKAY;
10288 
10289  if( SCIPisInfinity(scip, bnd) )
10290  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
10291  *result = SCIP_CUTOFF;
10292  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10293  return SCIP_OKAY;
10294  }
10295 
10296  /* new lower bound is very low (between -intervalinfty and -SCIPinfinity()) */
10297  if( SCIPisInfinity(scip, -bnd) )
10298  return SCIP_OKAY;
10299 
10300  bnd = SCIPadjustedVarLb(scip, var, bnd);
10301  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
10302  if( infeas )
10303  {
10304  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n",
10305  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
10306  *result = SCIP_CUTOFF;
10307  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10308  return SCIP_OKAY;
10309  }
10310  if( tightened )
10311  {
10312  SCIPdebugMsg(scip, "%s tightened lower bound of variable <%s> in constraint <%s> to %g\n",
10313  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
10314  ++*nchgbds;
10315  *result = SCIP_REDUCEDDOM;
10316  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10317  }
10318 
10319  return SCIP_OKAY;
10320 }
10321 
10322 /** tightens an upper bound on a variable and checks the result */
10323 static
10325  SCIP* scip, /**< SCIP data structure */
10326  SCIP_CONS* cons, /**< constraint where we currently propagate */
10327  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10328  SCIP_VAR* var, /**< variable which domain we might reduce */
10329  SCIP_Real bnd, /**< new upper bound for variable */
10330  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
10331  int* nchgbds /**< counter to increase if a bound was tightened */
10332  )
10333 {
10334  SCIP_Bool infeas;
10335  SCIP_Bool tightened;
10336 
10337  assert(scip != NULL);
10338  assert(cons != NULL);
10339  assert(intervalinfty > 0.0);
10340  assert(bnd < intervalinfty);
10341  assert(var != NULL);
10342  assert(result != NULL);
10343  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10344  assert(nchgbds != NULL);
10345 
10346  /* new bound is no improvement */
10347  if( SCIPisHugeValue(scip, bnd) || SCIPisGE(scip, bnd, SCIPvarGetUbLocal(var)) )
10348  return SCIP_OKAY;
10349 
10350  if( SCIPisInfinity(scip, -bnd) )
10351  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
10352  *result = SCIP_CUTOFF;
10353  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10354  return SCIP_OKAY;
10355  }
10356 
10357  /* new upper bound is very high (between SCIPinfinity() and intervalinfty) */
10358  if( SCIPisInfinity(scip, bnd) )
10359  return SCIP_OKAY;
10360 
10361  bnd = SCIPadjustedVarUb(scip, var, bnd);
10362  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
10363  if( infeas )
10364  {
10365  SCIPdebugMsg(scip, "%s found constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n",
10366  SCIPinProbing(scip) ? "in probing" : "", SCIPconsGetName(cons), bnd, SCIPvarGetName(var));
10367  *result = SCIP_CUTOFF;
10368  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10369  return SCIP_OKAY;
10370  }
10371  if( tightened )
10372  {
10373  SCIPdebugMsg(scip, "%s tightened upper bound of variable <%s> in constraint <%s> to %g\n",
10374  SCIPinProbing(scip) ? "in probing" : "", SCIPvarGetName(var), SCIPconsGetName(cons), bnd);
10375  ++*nchgbds;
10376  *result = SCIP_REDUCEDDOM;
10377  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10378  }
10379 
10380  return SCIP_OKAY;
10381 }
10382 
10383 /** 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 */
10384 static
10386  SCIP* scip, /**< SCIP data structure */
10387  SCIP_CONS* cons, /**< constraint where we currently propagate */
10388  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10389  SCIP_VAR* var, /**< variable which bounds with might tighten */
10390  SCIP_Real a, /**< coefficient in square term */
10391  SCIP_INTERVAL b, /**< coefficient in linear term */
10392  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10393  SCIP_RESULT* result, /**< result of propagation */
10394  int* nchgbds /**< buffer where to add number of tightened bounds */
10395  )
10396 {
10397  SCIP_INTERVAL newrange;
10398 
10399  assert(scip != NULL);
10400  assert(cons != NULL);
10401  assert(var != NULL);
10402  assert(result != NULL);
10403  assert(nchgbds != NULL);
10404 
10405  /* compute solution of a*x^2 + b*x \in rhs */
10406  if( a == 0.0 && SCIPintervalGetInf(b) == 0.0 && SCIPintervalGetSup(b) == 0.0 )
10407  {
10408  /* relatively easy case: 0.0 \in rhs, thus check if infeasible or just redundant */
10409  if( SCIPintervalGetInf(rhs) > 0.0 || SCIPintervalGetSup(rhs) < 0.0 )
10410  {
10411  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
10412  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10413  *result = SCIP_CUTOFF;
10414  }
10415  return SCIP_OKAY;
10416  }
10417  else
10418  {
10419  SCIP_INTERVAL a_;
10420  SCIP_INTERVAL xbnds;
10421 
10422  SCIPintervalSet(&a_, a);
10423  SCIPintervalSetBounds(&xbnds, -infty2infty(SCIPinfinity(scip), intervalinfty, -SCIPvarGetLbLocal(var)), infty2infty(SCIPinfinity(scip), intervalinfty, SCIPvarGetUbLocal(var))); /*lint !e666*/
10424  SCIPintervalSolveUnivariateQuadExpression(intervalinfty, &newrange, a_, b, rhs, xbnds);
10425  }
10426 
10427  /* SCIPdebugMsg(scip, "%g x^2 + [%g, %g] x in [%g, %g] and x in [%g,%g] -> [%g, %g]\n", a, b.inf, b.sup, rhs.inf, rhs.sup, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), newrange.inf, newrange.sup); */
10428 
10429  if( SCIPisInfinity(scip, SCIPintervalGetInf(newrange)) || SCIPisInfinity(scip, -SCIPintervalGetSup(newrange)) )
10430  {
10431  /* domain outside [-infty, +infty] -> declare node infeasible */
10432  SCIPdebugMsg(scip, "found <%s> infeasible because propagated domain of quadratic variable <%s> is outside of (-infty, +infty)\n",
10433  SCIPconsGetName(cons), SCIPvarGetName(var));
10434  *result = SCIP_CUTOFF;
10435  SCIP_CALL( SCIPresetConsAge(scip, cons) );
10436  return SCIP_OKAY;
10437  }
10438 
10439  if( SCIPintervalIsEmpty(intervalinfty, newrange) )
10440  {
10441  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(var));
10442  *result = SCIP_CUTOFF;
10443  return SCIP_OKAY;
10444  }
10445 
10446  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(newrange)) )
10447  {
10448  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, SCIPintervalGetInf(newrange), result, nchgbds) );
10449  if( *result == SCIP_CUTOFF )
10450  return SCIP_OKAY;
10451  }
10452 
10453  if( !SCIPisInfinity(scip, SCIPintervalGetSup(newrange)) )
10454  {
10455  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, SCIPintervalGetSup(newrange), result, nchgbds) );
10456  if( *result == SCIP_CUTOFF )
10457  return SCIP_OKAY;
10458  }
10459 
10460  return SCIP_OKAY;
10461 }
10462 
10463 /* The new version below computes potentially tighter bounds, but also always adds a small safety area since it is not implemented roundingsafe.
10464  * This may be a reason why it gives worse results on one of two instances.
10465  * Further, I have only very few instances where one can expect a difference.
10466  */
10467 #ifndef PROPBILINNEW
10468 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
10469  *
10470  * @note Domain reductions for y are not deduced.
10471  */
10472 static
10474  SCIP* scip, /**< SCIP data structure */
10475  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
10476  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10477  SCIP_VAR* x, /**< first variable */
10478  SCIP_Real xsqrcoef, /**< square coefficient of x */
10479  SCIP_Real xlincoef, /**< linear coefficient of x */
10480  SCIP_VAR* y, /**< second variable */
10481  SCIP_Real ysqrcoef, /**< square coefficient of y */
10482  SCIP_Real ylincoef, /**< linear coefficient of y */
10483  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
10484  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10485  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
10486  int* nchgbds /**< counter to increment if domain reductions are found */
10487  )
10488 {
10489  SCIP_INTERVAL myrhs;
10490  SCIP_INTERVAL varbnds;
10491  SCIP_INTERVAL lincoef;
10492 
10493  assert(scip != NULL);
10494  assert(cons != NULL);
10495  assert(x != NULL);
10496  assert(y != NULL);
10497  assert(x != y);
10498  assert(result != NULL);
10499  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10500  assert(nchgbds != NULL);
10501  assert(bilincoef != 0.0);
10502 
10503  if( SCIPintervalIsEntire(intervalinfty, rhs) )
10504  return SCIP_OKAY;
10505 
10506  /* try to find domain reductions for x */
10508 
10509  /* put ysqrcoef*y^2 + ylincoef * y into rhs */
10510  if( SCIPintervalGetSup(rhs) >= intervalinfty )
10511  {
10512  /* if rhs is unbounded by above, it is sufficient to get an upper bound on ysqrcoef*y^2 + ylincoef * y */
10513  SCIP_ROUNDMODE roundmode;
10514  SCIP_Real tmp;
10515 
10516  SCIPintervalSet(&lincoef, ylincoef);
10517  tmp = SCIPintervalQuadUpperBound(intervalinfty, ysqrcoef, lincoef, varbnds);
10518  roundmode = SCIPintervalGetRoundingMode();
10520  SCIPintervalSetBounds(&myrhs, SCIPintervalGetInf(rhs) - tmp, intervalinfty);
10521  SCIPintervalSetRoundingMode(roundmode);
10522  }
10523  else if( SCIPintervalGetInf(rhs) <= -intervalinfty )
10524  {
10525  /* if rhs is unbounded by below, it is sufficient to get a lower bound on ysqrcoef*y^2 + ylincoef * y */
10526  SCIP_ROUNDMODE roundmode;
10527  SCIP_Real tmp;
10528 
10529  SCIPintervalSet(&lincoef, -ylincoef);
10530  tmp = -SCIPintervalQuadUpperBound(intervalinfty, -ysqrcoef, lincoef, varbnds);
10531  roundmode = SCIPintervalGetRoundingMode();
10533  SCIPintervalSetBounds(&myrhs, -intervalinfty, SCIPintervalGetSup(rhs) - tmp);
10534  SCIPintervalSetRoundingMode(roundmode);
10535  }
10536  else
10537  {
10538  /* if rhs is bounded, we need both bounds on ysqrcoef*y^2 + ylincoef * y */
10539  SCIP_INTERVAL tmp;
10540 
10541  SCIPintervalSet(&lincoef, ylincoef);
10542  SCIPintervalQuad(intervalinfty, &tmp, ysqrcoef, lincoef, varbnds);
10543  SCIPintervalSub(intervalinfty, &myrhs, rhs, tmp);
10544  }
10545 
10546  /* create equation xsqrcoef * x^2 + (xlincoef + bilincoef * [ylb, yub]) * x \in myrhs */
10547  SCIPintervalMulScalar(intervalinfty, &lincoef, varbnds, bilincoef);
10548  SCIPintervalAddScalar(intervalinfty, &lincoef, lincoef, xlincoef);
10549 
10550  /* propagate bounds on x */
10551  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, x, xsqrcoef, lincoef, myrhs, result, nchgbds) );
10552 
10553  return SCIP_OKAY;
10554 }
10555 #else
10556 /** tries to deduce domain reductions for x in xsqrcoef x^2 + xlincoef x + ysqrcoef y^2 + ylincoef y + bilincoef x y \\in rhs
10557  *
10558  * @note Domain reductions for y are not deduced.
10559  */
10560 static
10562  SCIP* scip, /**< SCIP data structure */
10563  SCIP_CONS* cons, /**< the constraint, where the bilinear term belongs to */
10564  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10565  SCIP_VAR* x, /**< first variable */
10566  SCIP_Real xsqrcoef, /**< square coefficient of x */
10567  SCIP_Real xlincoef, /**< linear coefficient of x */
10568  SCIP_VAR* y, /**< second variable */
10569  SCIP_Real ysqrcoef, /**< square coefficient of y */
10570  SCIP_Real ylincoef, /**< linear coefficient of y */
10571  SCIP_Real bilincoef, /**< bilinear coefficient of x*y */
10572  SCIP_INTERVAL rhs, /**< right hand side of quadratic equation */
10573  SCIP_RESULT* result, /**< pointer to store result of domain propagation */
10574  int* nchgbds /**< counter to increment if domain reductions are found */
10575  )
10576 {
10577  SCIP_INTERVAL xbnds;
10578  SCIP_INTERVAL ybnds;
10579 
10580  assert(scip != NULL);
10581  assert(cons != NULL);
10582  assert(x != NULL);
10583  assert(y != NULL);
10584  assert(x != y);
10585  assert(result != NULL);
10586  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
10587  assert(nchgbds != NULL);
10588  assert(bilincoef != 0.0);
10589 
10590  if( SCIPintervalIsEntire(intervalinfty, rhs) )
10591  return SCIP_OKAY;
10592 
10593  SCIPintervalSetBounds(&xbnds,
10594  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x))), /*lint !e666*/
10595  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)))); /*lint !e666*/
10596  SCIPintervalSetBounds(&ybnds,
10597  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))), /*lint !e666*/
10598  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))); /*lint !e666*/
10599 
10600  /* try to find domain reductions for x */
10601  SCIPintervalSolveBivariateQuadExpressionAllScalar(intervalinfty, &xbnds, xsqrcoef, ysqrcoef, bilincoef, xlincoef, ylincoef, rhs, xbnds, ybnds);
10602 
10603  if( SCIPintervalIsEmpty(intervalinfty, xbnds) )
10604  {
10605  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for quadratic variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(x));
10606  *result = SCIP_CUTOFF;
10607  return SCIP_OKAY;
10608  }
10609 
10610  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(xbnds)) )
10611  {
10612  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, x, SCIPintervalGetInf(xbnds), result, nchgbds) );
10613  if( *result == SCIP_CUTOFF )
10614  return SCIP_OKAY;
10615  }
10616 
10617  if( !SCIPisInfinity(scip, SCIPintervalGetSup(xbnds)) )
10618  {
10619  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, x, SCIPintervalGetSup(xbnds), result, nchgbds) );
10620  if( *result == SCIP_CUTOFF )
10621  return SCIP_OKAY;
10622  }
10623 
10624  return SCIP_OKAY;
10625 }
10626 #endif
10627 
10628 /** computes the minimal and maximal activity for the quadratic part in a constraint data
10629  *
10630  * Only sums up terms that contribute finite values.
10631  * Gives the number of terms that contribute infinite values.
10632  * Only computes those activities where the corresponding side of the constraint is finite.
10633  */
10634 static
10636  SCIP* scip, /**< SCIP data structure */
10637  SCIP_CONSDATA* consdata, /**< constraint data */
10638  SCIP_Real intervalinfty, /**< infinity value used in interval operations */
10639  SCIP_Real* minquadactivity, /**< minimal activity of quadratic variable terms where only terms with finite minimal activity contribute */
10640  SCIP_Real* maxquadactivity, /**< maximal activity of quadratic variable terms where only terms with finite maximal activity contribute */
10641  int* minactivityinf, /**< number of quadratic variables that contribute -infinity to minimal activity */
10642  int* maxactivityinf, /**< number of quadratic variables that contribute +infinity to maximal activity */
10643  SCIP_INTERVAL* quadactcontr /**< contribution of each quadratic variables to quadactivity */
10644  )
10645 { /*lint --e{666}*/
10646  SCIP_ROUNDMODE prevroundmode;
10647  int i;
10648  int j;
10649  int k;
10650  SCIP_INTERVAL tmp;
10651  SCIP_Real bnd;
10652  SCIP_INTERVAL xrng;
10653  SCIP_INTERVAL lincoef;
10654 
10655  assert(scip != NULL);
10656  assert(consdata != NULL);
10657  assert(minquadactivity != NULL);
10658  assert(maxquadactivity != NULL);
10659  assert(minactivityinf != NULL);
10660  assert(maxactivityinf != NULL);
10661  assert(quadactcontr != NULL);
10662 
10663  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
10664  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
10665  */
10666  *minquadactivity = SCIPisInfinity(scip, consdata->rhs) ? -intervalinfty : 0.0;
10667  *maxquadactivity = SCIPisInfinity(scip, -consdata->lhs) ? intervalinfty : 0.0;
10668 
10669  *minactivityinf = 0;
10670  *maxactivityinf = 0;
10671 
10672  if( consdata->nquadvars == 0 )
10673  {
10674  SCIPintervalSet(&consdata->quadactivitybounds, 0.0);
10675  return;
10676  }
10677 
10678  for( i = 0; i < consdata->nquadvars; ++i )
10679  {
10680  /* there should be no quadratic variables fixed at -/+ infinity due to our locks */
10681  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(consdata->quadvarterms[i].var)));
10682  assert(!SCIPisInfinity(scip, -SCIPvarGetUbLocal(consdata->quadvarterms[i].var)));
10683 
10684  SCIPintervalSetBounds(&quadactcontr[i], -intervalinfty, intervalinfty);
10685 
10686  SCIPintervalSetBounds(&xrng,
10687  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))),
10688  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->quadvarterms[i].var), SCIPvarGetUbLocal(consdata->quadvarterms[i].var))));
10689 
10690  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
10691  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
10692  {
10693  k = consdata->quadvarterms[i].adjbilin[j];
10694  if( consdata->bilinterms[k].var1 != consdata->quadvarterms[i].var )
10695  continue; /* handle this term later */
10696 
10697  SCIPintervalSetBounds(&tmp,
10698  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
10699  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
10700  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
10701  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
10702  }
10703 
10704  if( !SCIPisInfinity(scip, -consdata->lhs) )
10705  {
10706  /* compute maximal activity only if there is a finite left hand side */
10707  bnd = SCIPintervalQuadUpperBound(intervalinfty, consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
10708  if( bnd >= intervalinfty )
10709  {
10710  ++*maxactivityinf;
10711  }
10712  else if( SCIPisInfinity(scip, -bnd) )
10713  {
10714  /* if maximal activity is below value for -infinity, let's take -1e10 as upper bound on maximal activity
10715  * @todo Something better?
10716  */
10717  bnd = -sqrt(SCIPinfinity(scip));
10718  *maxquadactivity += bnd;
10719  quadactcontr[i].sup = bnd;
10720  }
10721  else
10722  {
10723  prevroundmode = SCIPintervalGetRoundingMode();
10725  *maxquadactivity += bnd;
10726  SCIPintervalSetRoundingMode(prevroundmode);
10727  quadactcontr[i].sup = bnd;
10728  }
10729  }
10730 
10731  if( !SCIPisInfinity(scip, consdata->rhs) )
10732  {
10733  /* compute minimal activity only if there is a finite right hand side */
10734  SCIPintervalSetBounds(&lincoef, -SCIPintervalGetSup(lincoef), -SCIPintervalGetInf(lincoef));
10735  bnd = -SCIPintervalQuadUpperBound(intervalinfty, -consdata->quadvarterms[i].sqrcoef, lincoef, xrng);
10736 
10737  if( bnd <= -intervalinfty )
10738  {
10739  ++*minactivityinf;
10740  }
10741  else if( SCIPisInfinity(scip, bnd) )
10742  {
10743  /* if minimal activity is above value for infinity, let's take 1e10 as lower bound on minimal activity
10744  * @todo Something better?
10745  */
10746  bnd = sqrt(SCIPinfinity(scip));
10747  *minquadactivity += bnd;
10748  quadactcontr[i].inf = bnd;
10749  }
10750  else
10751  {
10752  prevroundmode = SCIPintervalGetRoundingMode();
10754  *minquadactivity += bnd;
10755  SCIPintervalSetRoundingMode(prevroundmode);
10756  quadactcontr[i].inf = bnd;
10757  }
10758  }
10759  }
10760 
10761  SCIPintervalSetBounds(&consdata->quadactivitybounds,
10762  (*minactivityinf > 0 ? -intervalinfty : *minquadactivity),
10763  (*maxactivityinf > 0 ? intervalinfty : *maxquadactivity));
10764  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
10765 }
10766 
10767 /** propagates bounds on a quadratic constraint */
10768 static
10770  SCIP* scip, /**< SCIP data structure */
10771  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
10772  SCIP_CONS* cons, /**< constraint to process */
10773  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
10774  int* nchgbds, /**< buffer where to add the the number of changed bounds */
10775  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
10776  )
10777 { /*lint --e{666}*/
10778  SCIP_CONSDATA* consdata;
10779  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
10780  SCIP_INTERVAL consactivity; /* activity of linear plus quadratic part */
10781  SCIP_Real intervalinfty; /* infinity used for interval computation */
10782  SCIP_Real minquadactivity; /* lower bound on finite activities of quadratic part */
10783  SCIP_Real maxquadactivity; /* upper bound on finite activities of quadratic part */
10784  int quadminactinf; /* number of quadratic variables that contribute -infinity to minimal activity of quadratic term */
10785  int quadmaxactinf; /* number of quadratic variables that contribute +infinity to maximal activity of quadratic term */
10786  SCIP_INTERVAL* quadactcontr; /* contribution of each quadratic variable term to quadactivity */
10787 
10788  SCIP_VAR* var;
10789  SCIP_INTERVAL rhs; /* right hand side of quadratic equation */
10790  SCIP_INTERVAL tmp;
10791  SCIP_ROUNDMODE roundmode;
10792  SCIP_Real bnd;
10793  int i;
10794 
10795  assert(scip != NULL);
10796  assert(conshdlr != NULL);
10797  assert(cons != NULL);
10798  assert(result != NULL);
10799  assert(nchgbds != NULL);
10800  assert(redundant != NULL);
10801 
10802  consdata = SCIPconsGetData(cons);
10803  assert(consdata != NULL);
10804 
10805  *result = SCIP_DIDNOTRUN;
10806  *redundant = FALSE;
10807 
10808  *result = SCIP_DIDNOTFIND;
10809 
10810  intervalinfty = 1000 * SCIPinfinity(scip) * SCIPinfinity(scip);
10811 
10812  quadactcontr = NULL;
10813  quadminactinf = -1;
10814  quadmaxactinf = -1;
10815 
10816  SCIPdebugMsg(scip, "start domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
10817 
10818  /* make sure we have activity of linear term and that they are consistent */
10819  consdataUpdateLinearActivity(scip, consdata, intervalinfty);
10820  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10821  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10822  assert(consdata->minlinactivityinf >= 0);
10823  assert(consdata->maxlinactivityinf >= 0);
10824 
10825  /* sort quadratic variable terms, in case we need to search for terms occuring in bilinear terms later
10826  * we sort here already, since we rely on a constant variable order during this method
10827  */
10828  if( consdata->nbilinterms > 0 )
10829  {
10830  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
10831  }
10832 
10833  /* compute activity of quad term part, if not up to date
10834  * in that case, we also collect the contribution of each quad var term for later */
10835  if( SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds) )
10836  {
10837  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
10838  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
10839  assert(!SCIPintervalIsEmpty(intervalinfty, consdata->quadactivitybounds));
10840  }
10841 
10842  SCIPdebugMsg(scip, "linear activity: [%g, %g] quadratic activity: [%g, %g]\n",
10843  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
10844  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity),
10845  consdata->quadactivitybounds.inf, consdata->quadactivitybounds.sup);
10846 
10847  /* extend constraint bounds by epsilon to avoid some numerical difficulties */
10848  SCIPintervalSetBounds(&consbounds,
10849  -infty2infty(SCIPinfinity(scip), intervalinfty, -consdata->lhs+SCIPepsilon(scip)),
10850  +infty2infty(SCIPinfinity(scip), intervalinfty, consdata->rhs+SCIPepsilon(scip)));
10851 
10852  /* check redundancy and infeasibility */
10853  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity,
10854  consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity);
10855  SCIPintervalAdd(intervalinfty, &consactivity, consactivity, consdata->quadactivitybounds);
10856  if( SCIPintervalIsSubsetEQ(intervalinfty, consactivity, consbounds) )
10857  {
10858  SCIPdebugMsg(scip, "found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
10859  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
10860  *redundant = TRUE;
10861  goto CLEANUP;
10862  }
10863 
10864  /* was SCIPintervalAreDisjoint(consbounds, consactivity), but that would allow violations up to eps only
10865  * we need to decide feasibility w.r.t. feastol (but still want to propagate w.r.t. eps)
10866  */
10867  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisGT(scip, consdata->lhs-SCIPfeastol(scip), SCIPintervalGetSup(consactivity))) ||
10868  (!SCIPisInfinity(scip, consdata->rhs) && SCIPisLT(scip, consdata->rhs+SCIPfeastol(scip), SCIPintervalGetInf(consactivity))) )
10869  {
10870  SCIPdebugMsg(scip, "found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
10871  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
10872  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
10873  *result = SCIP_CUTOFF;
10874  goto CLEANUP;
10875  }
10876 
10877  /* propagate linear part \in rhs = consbounds - quadactivity (use the one from consdata, since that includes infinities) */
10878  SCIPintervalSub(intervalinfty, &rhs, consbounds, consdata->quadactivitybounds);
10879  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
10880  {
10881  SCIP_Real coef;
10882 
10883  for( i = 0; i < consdata->nlinvars; ++i )
10884  {
10885  coef = consdata->lincoefs[i];
10886  var = consdata->linvars[i];
10887 
10888  /* skip fixed variables
10889  * @todo is that a good or a bad idea?
10890  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
10891  */
10892  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
10893  continue;
10894 
10895  /* due to large variable bounds and large coefficients, it might happen that the activity of the linear part
10896  * exceeds +/-SCIPinfinity() after updating the activities in consdataUpdateLinearActivity{Lb,Ub}Change; in
10897  * order to detect this case we need to check whether the value of consdata->{min,max}linactivity is infinite
10898  * (see #1433)
10899  */
10900  if( coef > 0.0 )
10901  {
10902  if( SCIPintervalGetSup(rhs) < intervalinfty )
10903  {
10904  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
10905  /* try to tighten the upper bound on var x */
10906  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
10907  {
10908  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
10909  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
10910  roundmode = SCIPintervalGetRoundingMode();
10912  bnd = SCIPintervalGetSup(rhs);
10913  bnd -= consdata->minlinactivity;
10914  bnd += coef * SCIPvarGetLbLocal(var);
10915  bnd /= coef;
10916  SCIPintervalSetRoundingMode(roundmode);
10917  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10918  if( *result == SCIP_CUTOFF )
10919  break;
10920  }
10921  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
10922  {
10923  /* x was the variable that made the minimal linear activity equal -infinity, so
10924  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
10925  roundmode = SCIPintervalGetRoundingMode();
10927  bnd = SCIPintervalGetSup(rhs);
10928  bnd -= consdata->minlinactivity;
10929  bnd /= coef;
10930  SCIPintervalSetRoundingMode(roundmode);
10931  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10932  if( *result == SCIP_CUTOFF )
10933  break;
10934  }
10935  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
10936  }
10937 
10938  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10939  {
10940  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10941  /* try to tighten the lower bound on var x */
10942  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
10943  {
10944  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
10945  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
10946  roundmode = SCIPintervalGetRoundingMode();
10948  bnd = SCIPintervalGetInf(rhs);
10949  bnd -= consdata->maxlinactivity;
10950  bnd += coef * SCIPvarGetUbLocal(var);
10951  bnd /= coef;
10952  SCIPintervalSetRoundingMode(roundmode);
10953  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10954  if( *result == SCIP_CUTOFF )
10955  break;
10956  }
10957  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
10958  {
10959  /* x was the variable that made the maximal linear activity equal infinity, so
10960  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
10961  roundmode = SCIPintervalGetRoundingMode();
10963  bnd = SCIPintervalGetInf(rhs);
10964  bnd -= consdata->maxlinactivity;
10965  bnd /= coef;
10966  SCIPintervalSetRoundingMode(roundmode);
10967  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10968  if( *result == SCIP_CUTOFF )
10969  break;
10970  }
10971  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
10972  }
10973  }
10974  else
10975  {
10976  assert(coef < 0.0 );
10977  if( SCIPintervalGetInf(rhs) > -intervalinfty )
10978  {
10979  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
10980  /* try to tighten the upper bound on var x */
10981  if( consdata->maxlinactivityinf == 0 && !SCIPisInfinity(scip, consdata->maxlinactivity) )
10982  {
10983  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
10984  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
10985  roundmode = SCIPintervalGetRoundingMode();
10987  bnd = consdata->maxlinactivity;
10988  bnd += (-coef) * SCIPvarGetLbLocal(var);
10989  bnd -= SCIPintervalGetInf(rhs);
10990  bnd /= (-coef);
10991  SCIPintervalSetRoundingMode(roundmode);
10992  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
10993  if( *result == SCIP_CUTOFF )
10994  break;
10995  }
10996  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
10997  {
10998  /* x was the variable that made the maximal linear activity equal infinity, so
10999  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
11000  roundmode = SCIPintervalGetRoundingMode();
11002  bnd = consdata->maxlinactivity;
11003  bnd -= SCIPintervalGetInf(rhs);
11004  bnd /= (-coef);
11005  SCIPintervalSetRoundingMode(roundmode);
11006  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11007  if( *result == SCIP_CUTOFF )
11008  break;
11009  }
11010  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
11011  }
11012 
11013  if( SCIPintervalGetSup(rhs) < intervalinfty )
11014  {
11015  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
11016  /* try to tighten the lower bound on var x */
11017  if( consdata->minlinactivityinf == 0 && !SCIPisInfinity(scip, -consdata->minlinactivity) )
11018  {
11019  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
11020  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
11021  roundmode = SCIPintervalGetRoundingMode();
11023  bnd = consdata->minlinactivity;
11024  bnd += (-coef) * SCIPvarGetUbLocal(var);
11025  bnd -= SCIPintervalGetSup(rhs);
11026  bnd /= (-coef);
11027  SCIPintervalSetRoundingMode(roundmode);
11028  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11029  if( *result == SCIP_CUTOFF )
11030  break;
11031  }
11032  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
11033  {
11034  /* x was the variable that made the maximal linear activity equal -infinity, so
11035  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
11036  roundmode = SCIPintervalGetRoundingMode();
11038  bnd = consdata->minlinactivity;
11039  bnd -= SCIPintervalGetSup(rhs);
11040  bnd /= (-coef);
11041  SCIPintervalSetRoundingMode(roundmode);
11042  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, intervalinfty, var, bnd, result, nchgbds) );
11043  if( *result == SCIP_CUTOFF )
11044  break;
11045  }
11046  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
11047  }
11048  }
11049  }
11050  if( *result == SCIP_CUTOFF )
11051  goto CLEANUP;
11052  }
11053 
11054  /* propagate quadratic part \in rhs = consbounds - linactivity */
11055  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777 */
11056  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777 */
11057  consdataUpdateLinearActivity(scip, consdata, intervalinfty); /* make sure, activities of linear part did not become invalid by above bound changes, if any */
11058  assert(consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0 || consdata->minlinactivity <= consdata->maxlinactivity);
11059  SCIPintervalSetBounds(&tmp,
11060  (consdata->minlinactivityinf > 0 ? -intervalinfty : consdata->minlinactivity),
11061  (consdata->maxlinactivityinf > 0 ? intervalinfty : consdata->maxlinactivity));
11062  SCIPintervalSub(intervalinfty, &rhs, consbounds, tmp);
11063  if( !SCIPintervalIsEntire(intervalinfty, rhs) )
11064  {
11065  if( consdata->nquadvars == 1 )
11066  {
11067  /* quadratic part is just a*x^2+b*x -> a common case that we treat directly */
11068  SCIP_INTERVAL lincoef; /* linear coefficient of quadratic equation */
11069 
11070  assert(consdata->nbilinterms == 0);
11071 
11072  var = consdata->quadvarterms[0].var;
11073  SCIPintervalSet(&lincoef, consdata->quadvarterms[0].lincoef);
11074 
11075  /* propagate a*x^2 + b*x \in rhs */
11076  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[0].sqrcoef, lincoef, rhs, result, nchgbds) );
11077  }
11078  else if( consdata->nbilinterms == 1 && consdata->nquadvars == 2 )
11079  {
11080  /* quadratic part is just ax*x^2+bx*x + ay*y^2+by*y + c*xy -> a common case that we treat directly */
11081  assert(consdata->bilinterms[0].var1 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var1 == consdata->quadvarterms[1].var);
11082  assert(consdata->bilinterms[0].var2 == consdata->quadvarterms[0].var || consdata->bilinterms[0].var2 == consdata->quadvarterms[1].var);
11083 
11084  /* 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 */
11085  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
11086  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
11087  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
11088  consdata->bilinterms[0].coef,
11089  rhs, result, nchgbds) );
11090  if( *result != SCIP_CUTOFF )
11091  {
11092  /* 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 */
11093  SCIP_CALL( propagateBoundsBilinearTerm(scip, cons, intervalinfty,
11094  consdata->quadvarterms[1].var, consdata->quadvarterms[1].sqrcoef, consdata->quadvarterms[1].lincoef,
11095  consdata->quadvarterms[0].var, consdata->quadvarterms[0].sqrcoef, consdata->quadvarterms[0].lincoef,
11096  consdata->bilinterms[0].coef,
11097  rhs, result, nchgbds) );
11098  }
11099  }
11100  else
11101  {
11102  /* general case */
11103 
11104  /* compute "advanced" information on quad var term activities, if not up-to-date */
11105  if( quadminactinf == -1 )
11106  {
11107  assert(quadactcontr == NULL);
11108  SCIP_CALL( SCIPallocBufferArray(scip, &quadactcontr, consdata->nquadvars) );
11109  propagateBoundsGetQuadActivity(scip, consdata, intervalinfty, &minquadactivity, &maxquadactivity, &quadminactinf, &quadmaxactinf, quadactcontr);
11110  }
11111  assert(quadactcontr != NULL);
11112  assert(quadminactinf >= 0);
11113  assert(quadmaxactinf >= 0);
11114 
11115  /* if the quad activities are not hopelessly unbounded on useful sides, try to deduce domain reductions on quad vars */
11116  if( (SCIPintervalGetSup(rhs) < intervalinfty && quadminactinf <= 1) ||
11117  ( SCIPintervalGetInf(rhs) > -intervalinfty && quadmaxactinf <= 1) )
11118  {
11119  SCIP_INTERVAL lincoef;
11120  SCIP_INTERVAL rhs2;
11121  int j;
11122  int k;
11123 
11124  for( i = 0; i < consdata->nquadvars; ++i )
11125  {
11126  var = consdata->quadvarterms[i].var;
11127 
11128  /* skip fixed variables
11129  * @todo is that a good or a bad idea?
11130  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
11131  */
11132  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
11133  continue;
11134 
11135  /* compute rhs2 such that we can propagate quadvarterm(x_i) \in rhs2 */
11136 
11137  /* setup rhs2.sup = rhs.sup - (quadactivity.inf - quadactcontr[i].inf), if everything were finite
11138  * if only quadactcontr[i].inf is infinite (i.e., the other i are all finite), we just get rhs2.sup = rhs.sup
11139  * otherwise we get rhs2.sup = infinity */
11140  if( SCIPintervalGetSup(rhs) < intervalinfty )
11141  {
11142  if( quadminactinf == 0 || (quadminactinf == 1 && SCIPintervalGetInf(quadactcontr[i]) <= -intervalinfty) )
11143  {
11144  roundmode = SCIPintervalGetRoundingMode();
11146  rhs2.sup = rhs.sup - minquadactivity; /*lint !e644*/
11147  /* if the residual quad min activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
11148  if( quadminactinf == 0 && SCIPintervalGetInf(quadactcontr[i]) != 0.0 )
11149  rhs2.sup += SCIPintervalGetInf(quadactcontr[i]);
11150  SCIPintervalSetRoundingMode(roundmode);
11151  }
11152  else
11153  {
11154  /* there are either >= 2 quad var terms contributing -infinity, or there is one which is not i */
11155  rhs2.sup = intervalinfty;
11156  }
11157  }
11158  else
11159  {
11160  rhs2.sup = intervalinfty;
11161  }
11162 
11163  /* setup rhs2.inf = rhs.inf - (quadactivity.sup - quadactcontr[i].sup), see also above */
11164  if( SCIPintervalGetInf(rhs) > -intervalinfty )
11165  {
11166  if( quadmaxactinf == 0 || (quadmaxactinf == 1 && SCIPintervalGetSup(quadactcontr[i]) >= intervalinfty) )
11167  {
11168  roundmode = SCIPintervalGetRoundingMode();
11170  rhs2.inf = rhs.inf - maxquadactivity; /*lint !e644*/
11171  /* if the residual quad max activity w.r.t. quad var term i is finite and nonzero, so add it to right hand side */
11172  if( quadmaxactinf == 0 && SCIPintervalGetSup(quadactcontr[i]) != 0.0 )
11173  rhs2.inf += SCIPintervalGetSup(quadactcontr[i]);
11174  SCIPintervalSetRoundingMode(roundmode);
11175  }
11176  else
11177  {
11178  /* there are either >= 2 quad var terms contributing infinity, or there is one which is not i */
11179  rhs2.inf = -intervalinfty;
11180  }
11181  }
11182  else
11183  {
11184  rhs2.inf = -intervalinfty;
11185  }
11186  assert(!SCIPintervalIsEmpty(intervalinfty, rhs2));
11187 
11188  /* if rhs2 is entire, then there is nothing we could propagate */
11189  if( SCIPintervalIsEntire(intervalinfty, rhs2) )
11190  continue;
11191 
11192  /* assemble linear coefficient for quad equation a*x^2 + b*x \in rhs2 */
11193  SCIPintervalSet(&lincoef, consdata->quadvarterms[i].lincoef);
11194  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
11195  {
11196  k = consdata->quadvarterms[i].adjbilin[j];
11197 #if 1
11198  if( consdata->bilinterms[k].var1 == var )
11199  {
11200  /* bilinear term k contributes to the activity of quad var term i, so just add bounds to linear coef */
11201  SCIPintervalSetBounds(&tmp,
11202  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11203  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11204  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11205  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11206  }
11207  else
11208  {
11209  /* bilinear term k does not contribute to the activity of quad var term i
11210  * so bounds on term k are contained in rhs2
11211  * if they are finite, we try to remove them from rhs2 and update lincoef instead
11212  * 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
11213  * HOWEVER: when computing rhs2, we may not just have added the bounds for the bilinear term, but for the associated quadratic term
11214  * for this complete term, we used SCIPintervalQuad to compute the bounds
11215  * since we do not want to repeat a call to SCIPintervalQuad for that quadratic term with bilinear term k removed,
11216  * we only remove the bounds for the bilinear term k from rhs2 if the associated quadratic term consists only of this bilinear term,
11217  * i.e., the quadratic term corresponding to var1 should be only var1*var2, but have no square or linear coefs or other bilinear terms
11218  * (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)
11219  */
11220  SCIP_INTERVAL me;
11221  SCIP_INTERVAL bilinbounds;
11222  int otherpos;
11223 
11224  assert(consdata->bilinterms[k].var2 == var);
11225 
11226  assert(consdata->quadvarssorted);
11227  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[k].var1, &otherpos) );
11228  assert(otherpos >= 0);
11229  assert(consdata->quadvarterms[otherpos].var == consdata->bilinterms[k].var1);
11230 
11231  if( (consdata->quadvarterms[otherpos].sqrcoef != 0.0) || consdata->quadvarterms[otherpos].lincoef != 0.0 ||
11232  consdata->quadvarterms[otherpos].nadjbilin > 1 )
11233  continue;
11234 
11235  /* set tmp to bounds of other variable and multiply with bilin coef */
11236  SCIPintervalSetBounds(&tmp,
11237  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))),
11238  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var1), SCIPvarGetUbLocal(consdata->bilinterms[k].var1))));
11239  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11240 
11241  /* set me to bounds of i'th variable */
11243  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11244  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11245 
11246  /* remove me*tmp from rhs2 */
11247 
11248  roundmode = SCIPintervalGetRoundingMode();
11249 
11250  if( rhs2.inf > -intervalinfty )
11251  {
11252  /* need upward rounding for SCIPintervalMulSup */
11254  SCIPintervalMulSup(intervalinfty, &bilinbounds, me, tmp);
11255  /* rhs2.inf += bilinbounds.sup, but we are in upward rounding */
11256  if( bilinbounds.sup < intervalinfty )
11257  rhs2.inf = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.inf) - bilinbounds.sup);
11258  }
11259 
11260  if( rhs2.sup < intervalinfty )
11261  {
11262  /* need downward rounding for SCIPintervalMulInf */
11264  SCIPintervalMulInf(intervalinfty, &bilinbounds, me, tmp);
11265  /* rhs2.sup += bilinbounds.inf, but we are in downward rounding */
11266  if( bilinbounds.inf > -intervalinfty )
11267  rhs2.sup = SCIPintervalNegateReal(SCIPintervalNegateReal(rhs2.sup) - bilinbounds.inf);
11268  }
11269 
11270  SCIPintervalSetRoundingMode(roundmode);
11271 
11272  /* in theory, rhs2 should not be empty here
11273  * what we tried to do here is to remove the contribution of the k'th bilinear term (=bilinbounds) to [minquadactivity,maxquadactivity] from rhs2
11274  * however, quadactivity is computed differently (as x*(a1*y1+...+an*yn)) than bilinbounds (a*ak*yk) and since interval arithmetics do overestimation,
11275  * it can happen that bilinbounds is actually slightly larger than quadactivity, which results in rhs2 being (slightly) empty
11276  * a proper fix could be to compute the quadactivity also as x*a1*y1+...+x*an*yn in propagateBoundsGetQuadAcitivity if sqrcoef=0, but due to taking
11277  * also infinite bounds into account, this complicates the code even further
11278  * instead, I'll just work around this by turning an empty rhs2 into a small non-empty one
11279  */
11280  if( SCIPintervalIsEmpty(intervalinfty, rhs2) )
11281  {
11282  assert(SCIPisSumRelEQ(scip, rhs2.inf, rhs2.sup));
11283  SCIPswapReals(&rhs2.inf, &rhs2.sup);
11284  }
11285 
11286  /* add tmp to lincoef */
11287  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11288  }
11289 #else
11290  if( consdata->bilinterms[k].var1 != var )
11291  continue; /* this term does not contribute to the activity of quad var term i */
11292 
11293  SCIPintervalSetBounds(&tmp,
11294  -infty2infty(SCIPinfinity(scip), intervalinfty, -MIN(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))),
11295  +infty2infty(SCIPinfinity(scip), intervalinfty, MAX(SCIPvarGetLbLocal(consdata->bilinterms[k].var2), SCIPvarGetUbLocal(consdata->bilinterms[k].var2))));
11296  SCIPintervalMulScalar(intervalinfty, &tmp, tmp, consdata->bilinterms[k].coef);
11297  SCIPintervalAdd(intervalinfty, &lincoef, lincoef, tmp);
11298 #endif
11299  }
11300 
11301  /* deduce domain reductions for x_i */
11302  SCIP_CALL( propagateBoundsQuadVar(scip, cons, intervalinfty, var, consdata->quadvarterms[i].sqrcoef, lincoef, rhs2, result, nchgbds) );
11303  if( *result == SCIP_CUTOFF )
11304  goto CLEANUP;
11305  }
11306  }
11307  }
11308  }
11309 
11310  CLEANUP:
11311  SCIPfreeBufferArrayNull(scip, &quadactcontr);
11312 
11313  return SCIP_OKAY;
11314 }
11315 
11316 /** calls domain propagation for a set of constraints */
11317 static
11319  SCIP* scip, /**< SCIP data structure */
11320  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11321  SCIP_CONS** conss, /**< constraints to process */
11322  int nconss, /**< number of constraints */
11323  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
11324  int* nchgbds /**< buffer where to add the the number of changed bounds */
11325  )
11326 {
11327  SCIP_CONSHDLRDATA* conshdlrdata;
11328  SCIP_RESULT propresult;
11329  SCIP_Bool redundant;
11330  int c;
11331  int roundnr;
11332  SCIP_Bool success;
11333  int maxproprounds;
11334 
11335  assert(scip != NULL);
11336  assert(conshdlr != NULL);
11337  assert(conss != NULL || nconss == 0);
11338  assert(result != NULL);
11339  assert(nchgbds != NULL);
11340 
11342 
11343  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11344  assert(conshdlrdata != NULL);
11345 
11346  *result = SCIP_DIDNOTFIND;
11347  roundnr = 0;
11348  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
11349  maxproprounds = conshdlrdata->maxproproundspresolve;
11350  else
11351  maxproprounds = conshdlrdata->maxproprounds;
11352 
11353  do
11354  {
11355  success = FALSE;
11356  ++roundnr;
11357 
11358  SCIPdebugMsg(scip, "starting domain propagation round %d of %d for %d constraints\n", roundnr, maxproprounds, nconss);
11359 
11360  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
11361  {
11362  assert(conss != NULL);
11363  if( !SCIPconsIsEnabled(conss[c]) )
11364  continue;
11365 
11366  if( SCIPconsIsMarkedPropagate(conss[c]) )
11367  {
11368  /* unmark constraint for propagation */
11369  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[c]) );
11370 
11371  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
11372  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
11373  {
11374  *result = propresult;
11375  success = TRUE;
11376  }
11377  if( redundant )
11378  {
11379  SCIPdebugMsg(scip, "deleting constraint <%s> locally\n", SCIPconsGetName(conss[c]));
11380  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
11381  }
11382  }
11383  }
11384  }
11385  while( success && *result != SCIP_CUTOFF && roundnr < maxproprounds );
11386 
11387  return SCIP_OKAY;
11388 }
11389 
11390 /** checks for a linear variable that can be increase or decreased without harming feasibility */
11391 static
11393  SCIP* scip, /**< SCIP data structure */
11394  SCIP_CONSDATA* consdata /**< constraint data */
11395  )
11396 {
11397  int i;
11398  int downlock;
11399  int uplock;
11400 
11401  consdata->linvar_maydecrease = -1;
11402  consdata->linvar_mayincrease = -1;
11403 
11404  /* check for a linear variable that can be increase or decreased without harming feasibility */
11405  for( i = 0; i < consdata->nlinvars; ++i )
11406  {
11407  /* compute locks of i'th linear variable */
11408  assert(consdata->lincoefs[i] != 0.0);
11409  if( consdata->lincoefs[i] > 0.0 )
11410  {
11411  downlock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0; /* lhs <= x -> downlock on x */
11412  uplock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0; /* x <= rhs -> uplock on x */
11413  }
11414  else
11415  {
11416  downlock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0; /* -x <= rhs -> downlock on x */
11417  uplock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0; /* lhs <= -x -> uplock on x */
11418  }
11419 
11420  if( SCIPvarGetNLocksDownType(consdata->linvars[i], SCIP_LOCKTYPE_MODEL) - downlock == 0 )
11421  {
11422  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
11423  /* if we have already one candidate, then take the one where the loss in the objective function is less */
11424  if( (consdata->linvar_maydecrease < 0) ||
11425  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
11426  consdata->linvar_maydecrease = i;
11427  }
11428 
11429  if( SCIPvarGetNLocksUpType(consdata->linvars[i], SCIP_LOCKTYPE_MODEL) - uplock == 0 )
11430  {
11431  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
11432  /* if we have already one candidate, then take the one where the loss in the objective function is less */
11433  if( (consdata->linvar_mayincrease < 0) ||
11434  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
11435  consdata->linvar_mayincrease = i;
11436  }
11437  }
11438 
11439 #ifdef SCIP_DEBUG
11440  if( consdata->linvar_mayincrease >= 0 )
11441  {
11442  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
11443  }
11444  if( consdata->linvar_maydecrease >= 0 )
11445  {
11446  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
11447  }
11448 #endif
11449 }
11450 
11451 /** Given a solution where every quadratic constraint is either feasible or can be made feasible by
11452  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
11453  *
11454  * The method assumes that this is always possible and that not all constraints are feasible already.
11455  */
11456 static
11458  SCIP* scip, /**< SCIP data structure */
11459  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11460  SCIP_CONS** conss, /**< constraints to process */
11461  int nconss, /**< number of constraints */
11462  SCIP_SOL* sol, /**< solution to process */
11463  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
11464  )
11465 {
11466  SCIP_CONSHDLRDATA* conshdlrdata;
11467  SCIP_CONSDATA* consdata;
11468  SCIP_SOL* newsol;
11469  SCIP_VAR* var;
11470  int c;
11471  SCIP_Real viol;
11472  SCIP_Real delta;
11473  SCIP_Real gap;
11474  SCIP_Bool solviolbounds;
11475  SCIP_Bool solchanged;
11476 
11477  assert(scip != NULL);
11478  assert(conshdlr != NULL);
11479  assert(conss != NULL || nconss == 0);
11480  assert(success != NULL);
11481 
11482  *success = FALSE;
11483 
11484  /* don't propose new solutions if not in presolve or solving */
11486  return SCIP_OKAY;
11487 
11488  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11489  assert(conshdlrdata != NULL);
11490 
11491  if( sol != NULL )
11492  {
11493  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
11494  }
11495  else
11496  {
11497  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
11498  }
11499  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
11500  solchanged = FALSE;
11501 
11502  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
11503  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
11504 
11505  for( c = 0; c < nconss; ++c )
11506  {
11507  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
11508  assert(consdata != NULL);
11509 
11510  /* recompute violation of constraint in case newsol is not identical to sol anymore */
11511  if( solchanged )
11512  {
11513  SCIP_CALL( computeViolation(scip, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
11514  assert(!solviolbounds);
11515  }
11516 
11517  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
11518  viol = consdata->lhs - consdata->activity;
11519  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
11520  viol = consdata->rhs - consdata->activity;
11521  else
11522  continue; /* constraint is satisfied */
11523 
11524  assert(viol != 0.0);
11525  if( consdata->linvar_mayincrease >= 0 &&
11526  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
11527  {
11528  /* have variable where increasing makes the constraint less violated */
11529  var = consdata->linvars[consdata->linvar_mayincrease];
11530  /* compute how much we would like to increase var */
11531  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
11532  assert(delta > 0.0);
11533  /* if var has an upper bound, may need to reduce delta */
11534  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
11535  {
11536  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
11537  delta = MIN(MAX(0.0, gap), delta);
11538  }
11539  if( SCIPisPositive(scip, delta) )
11540  {
11541  /* if variable is integral, round delta up so that it will still have an integer value */
11542  if( SCIPvarIsIntegral(var) )
11543  delta = SCIPceil(scip, delta);
11544 
11545  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
11546  /*lint --e{613} */
11547  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
11548 
11549  solchanged = TRUE;
11550 
11551  /* adjust constraint violation, if satisfied go on to next constraint */
11552  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
11553  if( SCIPisZero(scip, viol) )
11554  continue;
11555  }
11556  }
11557 
11558  assert(viol != 0.0);
11559  if( consdata->linvar_maydecrease >= 0 &&
11560  ((viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) || (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
11561  {
11562  /* have variable where decreasing makes constraint less violated */
11563  var = consdata->linvars[consdata->linvar_maydecrease];
11564  /* compute how much we would like to decrease var */
11565  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
11566  assert(delta < 0.0);
11567  /* if var has a lower bound, may need to reduce delta */
11568  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
11569  {
11570  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
11571  delta = MAX(MIN(0.0, gap), delta);
11572  }
11573  if( SCIPisNegative(scip, delta) )
11574  {
11575  /* if variable is integral, round delta down so that it will still have an integer value */
11576  if( SCIPvarIsIntegral(var) )
11577  delta = SCIPfloor(scip, delta);
11578  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
11579  /*lint --e{613} */
11580  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
11581 
11582  solchanged = TRUE;
11583 
11584  /* adjust constraint violation, if satisfied go on to next constraint */
11585  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
11586  if( SCIPisZero(scip, viol) )
11587  continue;
11588  }
11589  }
11590 
11591  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
11592  break;
11593  }
11594 
11595  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
11596  * then pass it to the trysol heuristic
11597  */
11598  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
11599  {
11600  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
11601  assert(solchanged);
11602 
11603  assert(conshdlrdata->trysolheur != NULL);
11604  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
11605 
11606  *success = TRUE;
11607  }
11608 
11609  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
11610 
11611  return SCIP_OKAY;
11612 }
11613 
11614 /** helper function to enforce constraints */
11615 static
11617  SCIP* scip, /**< SCIP data structure */
11618  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
11619  SCIP_CONS** conss, /**< constraints to process */
11620  int nconss, /**< number of constraints */
11621  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
11622  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
11623  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
11624  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
11625  )
11626 {
11627  SCIP_CONSHDLRDATA* conshdlrdata;
11628  SCIP_CONSDATA* consdata;
11629  SCIP_CONS* maxviolcon;
11630  SCIP_Real maxviol;
11631  SCIP_RESULT propresult;
11632  SCIP_RESULT separateresult;
11633  int nchgbds;
11634  int nnotify;
11635  SCIP_Real sepaefficacy;
11636  SCIP_Bool solviolbounds;
11637 
11638  assert(scip != NULL);
11639  assert(conshdlr != NULL);
11640  assert(conss != NULL || nconss == 0);
11641  assert(nconss >= 0);
11642  assert(nusefulconss >= 0);
11643  assert(result != NULL);
11644 
11645  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11646  assert(conshdlrdata != NULL);
11647 
11648  SCIP_CALL( computeViolations(scip, conss, nconss, sol, &solviolbounds, &maxviolcon) );
11649 
11650  if( maxviolcon == NULL )
11651  {
11652  *result = SCIP_FEASIBLE;
11653  return SCIP_OKAY;
11654  }
11655 
11656  *result = SCIP_INFEASIBLE;
11657 
11658  if( solviolbounds )
11659  {
11660  /* if LP solution violates variable bounds, then this should be because a row was added that
11661  * introduced this variable newly to the LP, in which case it gets value 0.0; the row should
11662  * have been added to resolve an infeasibility, so solinfeasible should be TRUE
11663  * see also issue #627
11664  */
11665  assert(solinfeasible);
11666  /* however, if solinfeasible is actually not TRUE, then better cut off the node to avoid that SCIP
11667  * stops because infeasible cannot be resolved */
11668  /*lint --e{774} */
11669  if( !solinfeasible )
11670  *result = SCIP_CUTOFF;
11671  return SCIP_OKAY;
11672  }
11673 
11674  consdata = SCIPconsGetData(maxviolcon);
11675  assert(consdata != NULL);
11676  maxviol = consdata->lhsviol + consdata->rhsviol;
11677  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
11678 
11679  SCIPdebugMsg(scip, "enforcement with max violation %g in cons <%s> for %s solution\n", maxviol, SCIPconsGetName(maxviolcon),
11680  sol == NULL ? "LP" : "relaxation");
11681 
11682  /* if we are above the 100'th enforcement round for this node, something is strange
11683  * (maybe the LP / relaxator does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
11684  * 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
11685  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
11686  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
11687  * we only increment nenforounds until 101 to avoid an overflow
11688  */
11689  if( conshdlrdata->lastenfonode == SCIPgetCurrentNode(scip) )
11690  {
11691  if( conshdlrdata->nenforounds > 100 )
11692  {
11693  if( SCIPisStopped(scip) )
11694  {
11695  SCIP_NODE* child;
11696 
11697  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
11698  *result = SCIP_BRANCHED;
11699 
11700  return SCIP_OKAY;
11701  }
11702  }
11703 
11704  ++conshdlrdata->nenforounds;
11705 
11706  /* cut off the current subtree, if a limit on the enforcement rounds should be applied. At this point, feasible
11707  * solutions might get cut off; the enfolplimit parameter should therefore only be set if SCIP is used as a
11708  * heuristic solver and when the returned result (infeasible, optimal, the gap) can be ignored
11709  */
11710  if( conshdlrdata->enfolplimit != -1 && conshdlrdata->nenforounds > conshdlrdata->enfolplimit )
11711  {
11713  "cut off subtree because enforcement limit was reached; this might lead to incorrect results\n");
11714  *result = SCIP_CUTOFF;
11715  return SCIP_OKAY;
11716  }
11717  }
11718  else
11719  {
11720  conshdlrdata->lastenfonode = SCIPgetCurrentNode(scip);
11721  conshdlrdata->nenforounds = 0;
11722  }
11723 
11724  /* run domain propagation */
11725  nchgbds = 0;
11726  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
11727  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
11728  {
11729  SCIPdebugMsg(scip, "propagation succeeded (%s)\n", propresult == SCIP_CUTOFF ? "cutoff" : "reduceddom");
11730  *result = propresult;
11731  return SCIP_OKAY;
11732  }
11733 
11734  /* we would like a cut that is efficient enough that it is not redundant in the LP (>lpfeastol)
11735  * however, we also don't want very weak cuts, so try to reach at least feastol (=lpfeastol by default, though)
11736  */
11737  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPfeastol(scip), TRUE, &separateresult, &sepaefficacy) );
11738  if( separateresult == SCIP_CUTOFF )
11739  {
11740  SCIPdebugMsg(scip, "separation found cutoff\n");
11741  *result = SCIP_CUTOFF;
11742  return SCIP_OKAY;
11743  }
11744  if( separateresult == SCIP_SEPARATED )
11745  {
11746  SCIPdebugMsg(scip, "separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, SCIPfeastol(scip));
11747  *result = SCIP_SEPARATED;
11748  return SCIP_OKAY;
11749  }
11750 
11751  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
11752  * -> collect variables for branching
11753  */
11754 
11755  SCIPdebugMsg(scip, "separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, SCIPfeastol(scip), maxviol);
11756 
11757  /* find branching candidates */
11758  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, sol, &nnotify) );
11759 
11760  if( nnotify == 0 && !solinfeasible && SCIPfeastol(scip) > SCIPlpfeastol(scip) )
11761  {
11762  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
11763  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPlpfeastol(scip), TRUE, &separateresult, &sepaefficacy) );
11764  if( separateresult == SCIP_CUTOFF )
11765  {
11766  SCIPdebugMsg(scip, "separation found cutoff\n");
11767  *result = SCIP_CUTOFF;
11768  return SCIP_OKAY;
11769  }
11770  if( separateresult == SCIP_SEPARATED )
11771  {
11772  SCIPdebugMsg(scip, "separation fallback succeeded, efficacy = %g\n", sepaefficacy);
11773  *result = SCIP_SEPARATED;
11774  return SCIP_OKAY;
11775  }
11776  }
11777 
11778  if( nnotify == 0 && !solinfeasible )
11779  {
11780  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
11781  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
11782  */
11783  SCIP_VAR* brvar = NULL;
11784  SCIP_CALL( registerLargeRelaxValueVariableForBranching(scip, conss, nconss, sol, &brvar) );
11785  if( brvar == NULL )
11786  {
11787  /* fallback 3: all quadratic variables seem to be fixed -> replace by linear constraint */
11788  SCIP_Bool addedcons;
11789  SCIP_Bool reduceddom;
11790  SCIP_Bool infeasible;
11791 
11792  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
11793  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
11794  * when it enforces the new constraints again and nothing resolves the infeasibility that we declare here
11795  * thus, we only add them if considered violated, and otherwise claim the solution is feasible (but print a
11796  * warning) */
11797  if ( infeasible )
11798  *result = SCIP_CUTOFF;
11799  else if ( addedcons )
11800  *result = SCIP_CONSADDED;
11801  else if ( reduceddom )
11802  *result = SCIP_REDUCEDDOM;
11803  else
11804  {
11805  *result = SCIP_FEASIBLE;
11806  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
11807  assert(!SCIPisInfinity(scip, maxviol));
11808  }
11809  return SCIP_OKAY;
11810  }
11811  else
11812  {
11813  SCIPdebugMsg(scip, "Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
11814  SCIPvarGetName(brvar), SCIPgetSolVal(scip, sol, brvar));
11815  nnotify = 1;
11816  }
11817  }
11818 
11819  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
11820  return SCIP_OKAY;
11821 }
11822 
11823 /** tries to upgrade a nonlinear constraint into a quadratic constraint */
11824 static
11825 SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
11827  SCIP_EXPRGRAPH* exprgraph;
11828  SCIP_EXPRGRAPHNODE* node;
11829  int i;
11830 
11831  assert(nupgdconss != NULL);
11832  assert(upgdconss != NULL);
11833 
11834  *nupgdconss = 0;
11835 
11836  node = SCIPgetExprgraphNodeNonlinear(scip, cons);
11837 
11838  /* no interest in linear constraints */
11839  if( node == NULL )
11840  return SCIP_OKAY;
11841 
11842  /* if a quadratic expression has been simplified, then all children of the node should be variables */
11844  return SCIP_OKAY;
11845 
11846  switch( SCIPexprgraphGetNodeOperator(node) )
11847  {
11848  case SCIP_EXPR_VARIDX:
11849  case SCIP_EXPR_CONST:
11850  case SCIP_EXPR_PLUS:
11851  case SCIP_EXPR_MINUS:
11852  case SCIP_EXPR_SUM:
11853  case SCIP_EXPR_LINEAR:
11854  /* these should not appear as exprgraphnodes after constraint presolving */
11855  return SCIP_OKAY;
11856 
11857  case SCIP_EXPR_DIV:
11858  case SCIP_EXPR_SQRT:
11859  case SCIP_EXPR_REALPOWER:
11860  case SCIP_EXPR_INTPOWER:
11861  case SCIP_EXPR_SIGNPOWER:
11862  case SCIP_EXPR_EXP:
11863  case SCIP_EXPR_LOG:
11864  case SCIP_EXPR_SIN:
11865  case SCIP_EXPR_COS:
11866  case SCIP_EXPR_TAN:
11867  /* case SCIP_EXPR_ERF: */
11868  /* case SCIP_EXPR_ERFI: */
11869  case SCIP_EXPR_MIN:
11870  case SCIP_EXPR_MAX:
11871  case SCIP_EXPR_ABS:
11872  case SCIP_EXPR_SIGN:
11873  case SCIP_EXPR_PRODUCT:
11874  case SCIP_EXPR_POLYNOMIAL:
11875  case SCIP_EXPR_USER:
11876  /* these do not look like an quadratic expression (assuming the expression graph simplifier did run) */
11877  return SCIP_OKAY;
11878 
11879  case SCIP_EXPR_MUL:
11880  case SCIP_EXPR_SQUARE:
11881  case SCIP_EXPR_QUADRATIC:
11882  /* these mean that we have something quadratic */
11883  break;
11884 
11885  case SCIP_EXPR_PARAM:
11886  case SCIP_EXPR_LAST:
11887  default:
11888  SCIPwarningMessage(scip, "unexpected expression operator %d in nonlinear constraint <%s>\n", SCIPexprgraphGetNodeOperator(node), SCIPconsGetName(cons));
11889  return SCIP_OKAY;
11890  }
11891 
11892  /* setup a quadratic constraint */
11893 
11894  if( upgdconsssize < 1 )
11895  {
11896  /* request larger upgdconss array */
11897  *nupgdconss = -1;
11898  return SCIP_OKAY;
11899  }
11900 
11901  *nupgdconss = 1;
11902  SCIP_CALL( SCIPcreateConsQuadratic(scip, &upgdconss[0], SCIPconsGetName(cons),
11904  0, NULL, 0, NULL,
11905  SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
11909  assert(!SCIPconsIsStickingAtNode(cons));
11910 
11911  exprgraph = SCIPgetExprgraphNonlinear(scip, SCIPconsGetHdlr(cons));
11912 
11913  /* add variables from expression tree as "quadratic" variables to quadratic constraint */
11914  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
11915  {
11916  assert(SCIPexprgraphGetNodeChildren(node)[i] != NULL);
11917  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, upgdconss[0], (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[i]), 0.0, 0.0) );
11918  }
11919 
11920  switch( SCIPexprgraphGetNodeOperator(node) )
11921  {
11922  case SCIP_EXPR_MUL:
11923  /* expression is product of two variables, so add bilinear term to constraint */
11924  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
11925 
11926  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
11929  1.0) );
11930 
11931  break;
11932 
11933  case SCIP_EXPR_SQUARE:
11934  /* expression is square of a variable, so change square coefficient of quadratic variable */
11935  assert(SCIPexprgraphGetNodeNChildren(node) == 1);
11936 
11937  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
11939  1.0) );
11940 
11941  break;
11942 
11943  case SCIP_EXPR_QUADRATIC:
11944  {
11945  /* expression is quadratic */
11946  SCIP_QUADELEM* quadelems;
11947  int nquadelems;
11948  SCIP_Real* lincoefs;
11949 
11951  nquadelems = SCIPexprgraphGetNodeQuadraticNQuadElements(node);
11953 
11955 
11956  if( lincoefs != NULL )
11957  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
11958  if( lincoefs[i] != 0.0 )
11959  {
11960  /* linear term */
11961  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, upgdconss[0],
11963  lincoefs[i]) );
11964  }
11965 
11966  for( i = 0; i < nquadelems; ++i )
11967  {
11968  assert(quadelems[i].idx1 < SCIPexprgraphGetNodeNChildren(node));
11969  assert(quadelems[i].idx2 < SCIPexprgraphGetNodeNChildren(node));
11970 
11971  if( quadelems[i].idx1 == quadelems[i].idx2 )
11972  {
11973  /* square term */
11974  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, upgdconss[0],
11975  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
11976  quadelems[i].coef) );
11977  }
11978  else
11979  {
11980  /* bilinear term */
11981  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, upgdconss[0],
11982  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx1]),
11983  (SCIP_VAR*)SCIPexprgraphGetNodeVar(exprgraph, SCIPexprgraphGetNodeChildren(node)[quadelems[i].idx2]),
11984  quadelems[i].coef) );
11985  }
11986  }
11987 
11988  break;
11989  }
11990 
11991  default:
11992  SCIPerrorMessage("you should not be here\n");
11993  return SCIP_ERROR;
11994  } /*lint !e788 */
11995 
11996  return SCIP_OKAY;
11997 }
11998 
11999 /*
12000  * Callback methods of constraint handler
12001  */
12002 
12003 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
12004 static
12005 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyQuadratic)
12006 { /*lint --e{715}*/
12007  assert(scip != NULL);
12008  assert(conshdlr != NULL);
12009  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
12010 
12011  /* call inclusion method of constraint handler */
12013 
12014  *valid = TRUE;
12015 
12016  return SCIP_OKAY;
12017 }
12018 
12019 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
12020 static
12021 SCIP_DECL_CONSFREE(consFreeQuadratic)
12023  SCIP_CONSHDLRDATA* conshdlrdata;
12024  int i;
12025 
12026  assert(scip != NULL);
12027  assert(conshdlr != NULL);
12028 
12029  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12030  assert(conshdlrdata != NULL);
12031 
12032  for( i = 0; i < conshdlrdata->nquadconsupgrades; ++i )
12033  {
12034  assert(conshdlrdata->quadconsupgrades[i] != NULL);
12035  SCIPfreeBlockMemory(scip, &conshdlrdata->quadconsupgrades[i]); /*lint !e866*/
12036  }
12037  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize);
12038  SCIPfreeBlockMemory(scip, &conshdlrdata);
12039 
12040  return SCIP_OKAY;
12041 }
12042 
12043 /** initialization method of constraint handler (called after problem was transformed) */
12044 static
12045 SCIP_DECL_CONSINIT(consInitQuadratic)
12046 { /*lint --e{715} */
12047  SCIP_CONSHDLRDATA* conshdlrdata;
12048 
12049  assert(scip != NULL);
12050  assert(conshdlr != NULL);
12051 
12052  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12053  assert(conshdlrdata != NULL);
12054 
12055  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
12056  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
12057 
12058  return SCIP_OKAY;
12059 }
12060 
12061 
12062 /** deinitialization method of constraint handler (called before transformed problem is freed) */
12063 static
12064 SCIP_DECL_CONSEXIT(consExitQuadratic)
12065 { /*lint --e{715} */
12066  SCIP_CONSHDLRDATA* conshdlrdata;
12067 
12068  assert(scip != NULL);
12069  assert(conshdlr != NULL);
12070 
12071  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12072  assert(conshdlrdata != NULL);
12073 
12074  conshdlrdata->subnlpheur = NULL;
12075  conshdlrdata->trysolheur = NULL;
12076 
12077  return SCIP_OKAY;
12078 }
12079 
12080 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
12081 #if 0
12082 static
12083 SCIP_DECL_CONSINITPRE(consInitpreQuadratic)
12084 { /*lint --e{715}*/
12085  SCIP_CONSHDLRDATA* conshdlrdata;
12086  SCIP_CONSDATA* consdata;
12087  int c;
12088 
12089  assert(scip != NULL);
12090  assert(conshdlr != NULL);
12091  assert(conss != NULL || nconss == 0);
12092 
12093  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12094  assert(conshdlrdata != NULL);
12095 
12096  return SCIP_OKAY;
12097 }
12098 #endif
12099 
12100 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
12101 static
12102 SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
12103 { /*lint --e{715}*/
12104  SCIP_CONSDATA* consdata;
12105  int c;
12106 #ifndef NDEBUG
12107  int i;
12108 #endif
12109 
12110  assert(scip != NULL);
12111  assert(conshdlr != NULL);
12112  assert(conss != NULL || nconss == 0);
12113 
12114  for( c = 0; c < nconss; ++c )
12115  {
12116  assert(conss != NULL);
12117  consdata = SCIPconsGetData(conss[c]);
12118  assert(consdata != NULL);
12119 
12120  if( !consdata->isremovedfixings )
12121  {
12122  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
12123  }
12124 
12125  /* make sure we do not have duplicate bilinear terms, quad var terms, or linear vars */
12126  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12127  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12128  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12129 
12130  assert(consdata->isremovedfixings);
12131  assert(consdata->linvarsmerged);
12132  assert(consdata->quadvarsmerged);
12133  assert(consdata->bilinmerged);
12134 
12135 #ifndef NDEBUG
12136  for( i = 0; i < consdata->nlinvars; ++i )
12137  assert(SCIPvarIsActive(consdata->linvars[i]));
12138 
12139  for( i = 0; i < consdata->nquadvars; ++i )
12140  assert(SCIPvarIsActive(consdata->quadvarterms[i].var));
12141 #endif
12142 
12143  /* tell SCIP that we have something nonlinear */
12144  if( SCIPconsIsAdded(conss[c]) && consdata->nquadvars > 0 )
12145  SCIPenableNLP(scip);
12146  }
12147 
12148  return SCIP_OKAY;
12149 }
12150 
12151 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin)
12152  *
12153  * @note Also called from consEnableQuadratic during solving stage.
12154  */
12155 static
12156 SCIP_DECL_CONSINITSOL(consInitsolQuadratic)
12158  SCIP_CONSHDLRDATA* conshdlrdata;
12159  SCIP_CONSDATA* consdata;
12160  int c;
12161  int i;
12162 
12163  assert(scip != NULL);
12164  assert(conshdlr != NULL);
12165  assert(conss != NULL || nconss == 0);
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  /* check for a linear variable that can be increase or decreased without harming feasibility */
12177  consdataFindUnlockedLinearVar(scip, consdata);
12178 
12179  /* setup lincoefsmin, lincoefsmax */
12180  consdata->lincoefsmin = SCIPinfinity(scip);
12181  consdata->lincoefsmax = 0.0;
12182  for( i = 0; i < consdata->nlinvars; ++i )
12183  {
12184  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666 */
12185  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666 */
12186  }
12187 
12188  /* add nlrow representation to NLP, if NLP had been constructed */
12189  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
12190  {
12191  if( consdata->nlrow == NULL )
12192  {
12193  /* compute curvature for the quadratic constraint if not done yet */
12194  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) );
12195 
12196  SCIP_CALL( createNlRow(scip, conss[c]) );
12197  assert(consdata->nlrow != NULL);
12198  }
12199  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
12200  }
12201 
12202  /* setup sepaquadvars and sepabilinvar2pos */
12203  assert(consdata->sepaquadvars == NULL);
12204  assert(consdata->sepabilinvar2pos == NULL);
12205  if( consdata->nquadvars > 0 )
12206  {
12207  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepaquadvars, consdata->nquadvars) );
12208  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms) );
12209 
12210  /* make sure, quadratic variable terms are sorted */
12211  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
12212 
12213  for( i = 0; i < consdata->nquadvars; ++i )
12214  consdata->sepaquadvars[i] = consdata->quadvarterms[i].var;
12215 
12216  for( i = 0; i < consdata->nbilinterms; ++i )
12217  {
12218  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, consdata->bilinterms[i].var2, &consdata->sepabilinvar2pos[i]) );
12219  }
12220  }
12221 
12222  if( conshdlrdata->checkfactorable )
12223  {
12224  /* check if constraint function is factorable, i.e., can be written as product of two linear functions */
12225  SCIP_CALL( checkFactorable(scip, conss[c]) );
12226  }
12227 
12228  /* compute gauge function using interior points per constraint, only when there are quadratic variables */
12229  if( conshdlrdata->gaugecuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
12230  {
12231  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12232  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12233  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12234  {
12235  SCIP_CALL( computeGauge(scip, conshdlr, conss[c]) );
12236  }
12237  }
12238 
12239  /* compute eigendecomposition for convex quadratics */
12240  if( conshdlrdata->projectedcuts && SCIPgetSubscipDepth(scip) == 0 && consdata->nquadvars > 0 )
12241  {
12242  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12243  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12244  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12245  {
12246  SCIP_CALL( computeED(scip, conshdlr, conss[c]) );
12247  }
12248  }
12249 
12250  /* mark constraint for propagation */
12251  SCIP_CALL( SCIPmarkConsPropagate(scip, conss[c]) );
12252  consdata->ispropagated = FALSE;
12253  }
12254 
12255  if( SCIPgetStage(scip) != SCIP_STAGE_INITSOLVE )
12256  {
12257  /* if called from consEnableQuadratic, then don't do below */
12258  return SCIP_OKAY;
12259  }
12260 
12261  conshdlrdata->newsoleventfilterpos = -1;
12262  if( nconss != 0 && conshdlrdata->linearizeheursol )
12263  {
12264  SCIP_EVENTHDLR* eventhdlr;
12265 
12266  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
12267  assert(eventhdlr != NULL);
12268 
12269  /* @todo Should we catch every new solution or only new *best* solutions */
12270  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
12271  }
12272 
12273  if( nconss != 0 && !SCIPisIpoptAvailableIpopt() && !SCIPisInRestart(scip) )
12274  {
12275  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");
12276  }
12277 
12278  /* reset flags and counters */
12279  conshdlrdata->sepanlp = FALSE;
12280  conshdlrdata->lastenfonode = NULL;
12281  conshdlrdata->nenforounds = 0;
12282 
12283  return SCIP_OKAY;
12284 }
12285 
12286 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed)
12287  *
12288  * @note Also called from consDisableQuadratic during solving stage.
12289  */
12290 static
12291 SCIP_DECL_CONSEXITSOL(consExitsolQuadratic)
12292 { /*lint --e{715}*/
12293  SCIP_CONSHDLRDATA* conshdlrdata;
12294  SCIP_CONSDATA* consdata;
12295  int c;
12296 
12297  assert(scip != NULL);
12298  assert(conshdlr != NULL);
12299  assert(conss != NULL || nconss == 0);
12300 
12301  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12302  assert(conshdlrdata != NULL);
12303 
12304  for( c = 0; c < nconss; ++c )
12305  {
12306  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
12307  assert(consdata != NULL);
12308 
12309  /* free nonlinear row representation */
12310  if( consdata->nlrow != NULL )
12311  {
12312  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
12313  }
12314 
12315  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepaquadvars != NULL || consdata->nquadvars == 0); /*lint !e613 */
12316  assert(!SCIPconsIsEnabled(conss[c]) || consdata->sepabilinvar2pos != NULL || consdata->nquadvars == 0); /*lint !e613 */
12317  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepaquadvars, consdata->nquadvars);
12318  SCIPfreeBlockMemoryArrayNull(scip, &consdata->sepabilinvar2pos, consdata->nbilinterms);
12319 
12320  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorleft, consdata->nquadvars + 1);
12321  SCIPfreeBlockMemoryArrayNull(scip, &consdata->factorright, consdata->nquadvars + 1);
12322 
12323  SCIPfreeBlockMemoryArrayNull(scip, &consdata->interiorpoint, consdata->nquadvars);
12324  SCIPfreeBlockMemoryArrayNull(scip, &consdata->gaugecoefs, consdata->nquadvars);
12325  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvalues, consdata->nquadvars);
12326  SCIPfreeBlockMemoryArrayNull(scip, &consdata->eigenvectors, (int)(consdata->nquadvars*consdata->nquadvars));
12327  SCIPfreeBlockMemoryArrayNull(scip, &consdata->bp, consdata->nquadvars);
12328  }
12329 
12330  if( SCIPgetStage(scip) != SCIP_STAGE_EXITSOLVE )
12331  {
12332  /* if called from consDisableQuadratic, then don't do below */
12333  return SCIP_OKAY;
12334  }
12335 
12336  if( conshdlrdata->newsoleventfilterpos >= 0 )
12337  {
12338  SCIP_EVENTHDLR* eventhdlr;
12339 
12340  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
12341  assert(eventhdlr != NULL);
12342 
12343  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
12344  conshdlrdata->newsoleventfilterpos = -1;
12345  }
12346 
12347  /* free all stored bilinear terms in the constraint handler and constraint data; note that we might not want to
12348  * recollect all bilinear terms and therefore keep them even if consDisableQuadratic is called
12349  */
12350  SCIP_CALL( freeAllBilinearTerms(scip, conshdlrdata, conss, nconss) );
12351 
12352  return SCIP_OKAY;
12353 }
12354 
12355 /** frees specific constraint data */
12356 static
12357 SCIP_DECL_CONSDELETE(consDeleteQuadratic)
12359  assert(scip != NULL);
12360  assert(conshdlr != NULL);
12361  assert(cons != NULL);
12362  assert(consdata != NULL);
12363  assert(SCIPconsGetData(cons) == *consdata);
12364 
12365  SCIP_CALL( consdataFree(scip, consdata) );
12366 
12367  assert(*consdata == NULL);
12368 
12369  return SCIP_OKAY;
12370 }
12371 
12372 /** transforms constraint data into data belonging to the transformed problem */
12373 static
12374 SCIP_DECL_CONSTRANS(consTransQuadratic)
12375 {
12376  SCIP_CONSDATA* sourcedata;
12377  SCIP_CONSDATA* targetdata;
12378  int i;
12379 
12380  sourcedata = SCIPconsGetData(sourcecons);
12381  assert(sourcedata != NULL);
12382 
12383  SCIP_CALL( consdataCreate(scip, &targetdata,
12384  sourcedata->lhs, sourcedata->rhs,
12385  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
12386  sourcedata->nquadvars, sourcedata->quadvarterms,
12387  sourcedata->nbilinterms, sourcedata->bilinterms,
12388  FALSE) );
12389 
12390  for( i = 0; i < targetdata->nlinvars; ++i )
12391  {
12392  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
12393  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
12394  }
12395 
12396  for( i = 0; i < targetdata->nquadvars; ++i )
12397  {
12398  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->quadvarterms[i].var, &targetdata->quadvarterms[i].var) );
12399  SCIP_CALL( SCIPcaptureVar(scip, targetdata->quadvarterms[i].var) );
12400  }
12401 
12402  for( i = 0; i < targetdata->nbilinterms; ++i )
12403  {
12404  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var1, &targetdata->bilinterms[i].var1) );
12405  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->bilinterms[i].var2, &targetdata->bilinterms[i].var2) );
12406 
12407  if( SCIPvarCompare(targetdata->bilinterms[i].var1, targetdata->bilinterms[i].var2) > 0 )
12408  {
12409  SCIP_VAR* tmp;
12410  tmp = targetdata->bilinterms[i].var2;
12411  targetdata->bilinterms[i].var2 = targetdata->bilinterms[i].var1;
12412  targetdata->bilinterms[i].var1 = tmp;
12413  }
12414  }
12415 
12416  /* create target constraint */
12417  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
12418  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
12419  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
12420  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
12421  SCIPconsIsStickingAtNode(sourcecons)) );
12422 
12423  SCIPdebugMsg(scip, "created transformed quadratic constraint ");
12424  SCIPdebugPrintCons(scip, *targetcons, NULL);
12425 
12426  return SCIP_OKAY;
12427 }
12428 
12429 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
12430 static
12431 SCIP_DECL_CONSINITLP(consInitlpQuadratic)
12433  SCIP_CONSHDLRDATA* conshdlrdata;
12434  SCIP_CONSDATA* consdata;
12435  SCIP_VAR* var;
12436  SCIP_ROW* row;
12437  SCIP_Real* x;
12438  int c;
12439  int i;
12440 
12441  assert(scip != NULL);
12442  assert(conshdlr != NULL);
12443  assert(conss != NULL || nconss == 0);
12444 
12445  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12446  assert(conshdlrdata != NULL);
12447 
12448  *infeasible = FALSE;
12449 
12450  for( c = 0; c < nconss && !(*infeasible); ++c )
12451  {
12452  assert(conss[c] != NULL); /*lint !e613 */
12453 
12454  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12455 
12456  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
12457  assert(consdata != NULL);
12458 
12459  row = NULL;
12460 
12461  if( consdata->nquadvars == 0 )
12462  {
12463  /* if we are actually linear, add the constraint as row to the LP */
12464  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
12465  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613 */
12466  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
12467  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12468  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12469  continue;
12470  }
12471 
12472  /* alloc memory for reference point */
12473  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nquadvars) );
12474 
12475  /* for convex parts, add linearizations in 5 points */
12476  if( (consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs)) ||
12477  (consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs)) )
12478  {
12479  SCIP_Real lb;
12480  SCIP_Real ub;
12481  SCIP_Real lambda;
12482  int k;
12483 
12484  for( k = 0; k < 5; ++k )
12485  {
12486  lambda = 0.1 * (k+1); /* lambda = 0.1, 0.2, 0.3, 0.4, 0.5 */
12487  for( i = 0; i < consdata->nquadvars; ++i )
12488  {
12489  var = consdata->quadvarterms[i].var;
12490  lb = SCIPvarGetLbGlobal(var);
12491  ub = SCIPvarGetUbGlobal(var);
12492 
12493  if( ub > -INITLPMAXVARVAL )
12494  lb = MAX(lb, -INITLPMAXVARVAL);
12495  if( lb < INITLPMAXVARVAL )
12496  ub = MIN(ub, INITLPMAXVARVAL);
12497 
12498  /* make bounds finite */
12499  if( SCIPisInfinity(scip, -lb) )
12500  lb = MIN(-10.0, ub - 0.1*REALABS(ub)); /*lint !e666 */
12501  if( SCIPisInfinity(scip, ub) )
12502  ub = MAX( 10.0, lb + 0.1*REALABS(lb)); /*lint !e666 */
12503 
12505  x[i] = lambda * ub + (1.0 - lambda) * lb;
12506  else
12507  x[i] = lambda * lb + (1.0 - lambda) * ub;
12508  }
12509 
12510  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, consdata->isconvex ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT, &row, NULL,
12511  FALSE, -SCIPinfinity(scip)) ); /*lint !e613 */
12512  if( row != NULL )
12513  {
12514  SCIPdebugMsg(scip, "initlp adds row <%s> for lambda = %g of conss <%s>\n", SCIProwGetName(row), lambda, SCIPconsGetName(conss[c])); /*lint !e613 */
12515  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12516 
12517  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12518  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12519  }
12520  }
12521  }
12522 
12523  /* for concave parts, add underestimator w.r.t. at most 2 reference points */
12524  if( !(*infeasible) && ((! consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs))
12525  || (! consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs))) )
12526  {
12527  SCIP_Bool unbounded;
12528  SCIP_Bool possquare;
12529  SCIP_Bool negsquare;
12530  SCIP_Real lb;
12531  SCIP_Real ub;
12532  SCIP_Real lambda;
12533  int k;
12534 
12535  unbounded = FALSE; /* whether there are unbounded variables */
12536  possquare = FALSE; /* whether there is a positive square term */
12537  negsquare = FALSE; /* whether there is a negative square term */
12538  for( k = 0; k < 2; ++k )
12539  {
12540  /* Set reference point to 0 projected on bounds for unbounded variables or in between lower and upper bound
12541  * for bounded variables in the first round, we set it closer to the best bound for one part of the
12542  * variables, in the second closer to the best bound for the other part of the variables.
12543  * Additionally, we use slightly different weights for each variable.
12544  * The reason for the latter is, that for a bilinear term with bounded variables, there are always two linear underestimators
12545  * if the same weight is used for both variables of a product, then rounding and luck decides which underestimator is chosen
12546  * of course, the possible number of cuts is something in the order of 2^nquadvars, and we choose two of them here.
12547  */
12548  for( i = 0; i < consdata->nquadvars; ++i )
12549  {
12550  var = consdata->quadvarterms[i].var;
12551  lb = SCIPvarGetLbGlobal(var);
12552  ub = SCIPvarGetUbGlobal(var);
12553 
12554  if( SCIPisInfinity(scip, -lb) )
12555  {
12556  if( SCIPisInfinity(scip, ub) )
12557  x[i] = 0.0;
12558  else
12559  x[i] = MIN(0.0, ub);
12560  unbounded = TRUE;
12561  }
12562  else
12563  {
12564  if( SCIPisInfinity(scip, ub) )
12565  {
12566  x[i] = MAX(0.0, lb);
12567  unbounded = TRUE;
12568  }
12569  else
12570  {
12571  lambda = 0.4 + 0.2 * ((i+k)%2) + 0.01 * i / (double)consdata->nquadvars;
12572  x[i] = lambda * SCIPvarGetBestBoundLocal(var) + (1.0-lambda) * SCIPvarGetWorstBoundLocal(var);
12573  }
12574  }
12575 
12576  possquare |= consdata->quadvarterms[i].sqrcoef > 0.0; /*lint !e514 */
12577  negsquare |= consdata->quadvarterms[i].sqrcoef < 0.0; /*lint !e514 */
12578  }
12579 
12580  if( !consdata->isconvex && !SCIPisInfinity(scip, consdata->rhs) )
12581  {
12582  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_RIGHT, &row, NULL,
12583  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
12584  if( row != NULL )
12585  {
12586  SCIPdebugMsg(scip, "initlp adds row <%s> for rhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
12587  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12588 
12589  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12590  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12591  }
12592  }
12593  if( !(*infeasible) && !consdata->isconcave && !SCIPisInfinity(scip, -consdata->lhs) )
12594  {
12595  SCIP_CALL( generateCut(scip, conshdlr, conss[c], x, NULL, SCIP_SIDETYPE_LEFT, &row, NULL,
12596  conshdlrdata->checkcurvature, -SCIPinfinity(scip)) ); /*lint !e613 */
12597  if( row != NULL )
12598  {
12599  SCIPdebugMsg(scip, "initlp adds row <%s> for lhs of conss <%s>, round %d\n", SCIProwGetName(row), SCIPconsGetName(conss[c]), k); /*lint !e613 */
12600  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
12601 
12602  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
12603  SCIP_CALL( SCIPreleaseRow (scip, &row) );
12604  }
12605  }
12606 
12607  /* if there are unbounded variables, then there is typically only at most one possible underestimator, so don't try another round
12608  * 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 */
12609  if( unbounded ||
12610  (consdata->nbilinterms == 0 && (!possquare || SCIPisInfinity(scip, consdata->rhs))) ||
12611  (consdata->nbilinterms == 0 && (!negsquare || SCIPisInfinity(scip, -consdata->lhs))) )
12612  break;
12613  }
12614  }
12615 
12616  SCIPfreeBufferArray(scip, &x);
12617  }
12618 
12619  /* store all bilinear terms into constraint handler data; this code is not in initsolve because the sub-NLP
12620  * heuristic triggers this callback and should not collect all bilinear terms
12621  */
12622  SCIP_CALL( storeAllBilinearTerms(scip, conshdlrdata, conss, nconss) );
12623 
12624  return SCIP_OKAY;
12625 }
12626 
12627 /** separation method of constraint handler for LP solutions */
12628 static
12629 SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
12630 {
12631  SCIP_CONSHDLRDATA* conshdlrdata;
12632  SCIP_Bool solviolbounds;
12633  SCIP_CONS* maxviolcon;
12634 
12635  assert(scip != NULL);
12636  assert(conshdlr != NULL);
12637  assert(conss != NULL || nconss == 0);
12638  assert(result != NULL);
12639 
12640  *result = SCIP_DIDNOTFIND;
12641 
12642  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12643  assert(conshdlrdata != NULL);
12644 
12645  SCIP_CALL( computeViolations(scip, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
12646 
12647  /* don't try to separate solutions that violate variable bounds */
12648  if( solviolbounds )
12649  return SCIP_OKAY;
12650 
12651  /* if nothing violated, then nothing to separate */
12652  if( maxviolcon == NULL )
12653  return SCIP_OKAY;
12654 
12655  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
12656  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
12657  */
12658  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
12659  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) ||
12660  (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
12661  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
12662  {
12663  SCIP_CONSDATA* consdata;
12664  SCIP_NLPSOLSTAT solstat;
12665  SCIP_Bool solvednlp;
12666  int c;
12667 
12668  solstat = SCIPgetNLPSolstat(scip);
12669  solvednlp = FALSE;
12670  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
12671  {
12672  /* NLP is not solved yet, so we might want to do this
12673  * but first check whether there is a violated constraint side which corresponds to a convex function
12674  */
12675  for( c = 0; c < nconss; ++c )
12676  {
12677  assert(conss[c] != NULL); /*lint !e613 */
12678 
12679  consdata = SCIPconsGetData(conss[c]); /*lint !e613 */
12680  assert(consdata != NULL);
12681 
12682  /* skip feasible constraints */
12683  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12684  continue;
12685 
12686  /* make sure curvature has been checked */
12687  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkcurvature) ); /*lint !e613 */
12688 
12689  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && consdata->isconvex) ||
12690  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && consdata->isconcave) )
12691  break;
12692  }
12693 
12694  if( c < nconss )
12695  {
12696  /* try to solve NLP and update solstat */
12697 
12698  /* ensure linear conss are in NLP */
12699  if( conshdlrdata->subnlpheur != NULL )
12700  {
12701  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
12702  }
12703 
12704  /* set LP solution as starting values, if available */
12706  {
12708  }
12709 
12710  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
12711  SCIP_CALL( SCIPsolveNLP(scip) );
12712 
12713  solstat = SCIPgetNLPSolstat(scip);
12714  SCIPdebugMsg(scip, "solved NLP relax, solution status: %d\n", solstat);
12715 
12716  solvednlp = TRUE;
12717  }
12718  }
12719 
12720  conshdlrdata->sepanlp = TRUE;
12721 
12722  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
12723  {
12724  SCIPdebugMsg(scip, "NLP relaxation is globally infeasible, thus can cutoff node\n");
12725  *result = SCIP_CUTOFF;
12726  return SCIP_OKAY;
12727  }
12728 
12729  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
12730  {
12731  /* if we have feasible NLP solution, generate linearization cuts there */
12732  SCIP_Bool lpsolseparated;
12733  SCIP_SOL* nlpsol;
12734 
12735  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
12736  assert(nlpsol != NULL);
12737 
12738  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
12739  if( solvednlp && conshdlrdata->trysolheur != NULL )
12740  {
12741  int nfracvars;
12742 
12743  nfracvars = 0;
12744  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
12745  {
12746  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
12747  }
12748 
12749  if( nfracvars == 0 )
12750  {
12751  SCIPdebugMsg(scip, "pass solution with obj. value %g to trysol\n", SCIPgetSolOrigObj(scip, nlpsol));
12752  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
12753  }
12754  }
12755 
12756  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, SCIPgetSepaMinEfficacy(scip)) );
12757 
12758  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
12759 
12760  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
12761  if( lpsolseparated )
12762  {
12763  SCIPdebugMsg(scip, "linearization cuts separate LP solution\n");
12764  *result = SCIP_SEPARATED;
12765 
12766  return SCIP_OKAY;
12767  }
12768  }
12769  }
12770  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
12771  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
12772  */
12773 
12774  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
12775 
12776  return SCIP_OKAY;
12777 }
12778 
12779 /** separation method of constraint handler for arbitrary primal solutions */
12780 static
12781 SCIP_DECL_CONSSEPASOL(consSepasolQuadratic)
12783  SCIP_Bool solviolbounds;
12784  SCIP_CONS* maxviolcon;
12785 
12786  assert(scip != NULL);
12787  assert(conshdlr != NULL);
12788  assert(conss != NULL || nconss == 0);
12789  assert(sol != NULL);
12790  assert(result != NULL);
12791 
12792  *result = SCIP_DIDNOTFIND;
12793 
12794  SCIP_CALL( computeViolations(scip, conss, nconss, sol, &solviolbounds, &maxviolcon) );
12795 
12796  /* don't separate solution that are outside variable bounds */
12797  if( solviolbounds )
12798  return SCIP_OKAY;
12799 
12800  /* if nothing violated, then nothing to separate */
12801  if( maxviolcon == NULL )
12802  return SCIP_OKAY;
12803 
12804  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
12805 
12806  return SCIP_OKAY;
12807 }
12808 
12809 /** constraint enforcing method of constraint handler for LP solutions */
12810 static
12811 SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
12812 { /*lint --e{715}*/
12813  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
12814 
12815  return SCIP_OKAY;
12816 }
12817 
12818 /** constraint enforcing method of constraint handler for relaxation solutions */
12819 static
12820 SCIP_DECL_CONSENFORELAX(consEnforelaxQuadratic)
12821 { /*lint --e{715}*/
12822  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
12823 
12824  return SCIP_OKAY;
12825 }
12826 
12827 /** constraint enforcing method of constraint handler for pseudo solutions */
12828 static
12829 SCIP_DECL_CONSENFOPS(consEnfopsQuadratic)
12830 { /*lint --e{715}*/
12831  SCIP_Bool solviolbounds;
12832  SCIP_CONS* maxviolcon;
12833  SCIP_CONSDATA* consdata;
12834  SCIP_RESULT propresult;
12835  SCIP_VAR* var;
12836  int c;
12837  int i;
12838  int nchgbds;
12839  int nnotify;
12840 
12841  assert(scip != NULL);
12842  assert(conss != NULL || nconss == 0);
12843 
12844  SCIP_CALL( computeViolations(scip, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
12845 
12846  /* pseudo solutions should be within bounds by definition */
12847  assert(!solviolbounds);
12848 
12849  if( maxviolcon == NULL )
12850  {
12851  *result = SCIP_FEASIBLE;
12852  return SCIP_OKAY;
12853  }
12854 
12855  *result = SCIP_INFEASIBLE;
12856 
12857  SCIPdebugMsg(scip, "enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcon));
12858 
12859  /* run domain propagation */
12860  nchgbds = 0;
12861  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &nchgbds) );
12862  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
12863  {
12864  *result = propresult;
12865  return SCIP_OKAY;
12866  }
12867 
12868  /* we are not feasible and we cannot proof that the whole node is infeasible
12869  * -> collect all variables in violated constraints for branching
12870  */
12871  nnotify = 0;
12872  for( c = 0; c < nconss; ++c )
12873  {
12874  assert(conss != NULL);
12875  consdata = SCIPconsGetData(conss[c]);
12876  assert(consdata != NULL);
12877 
12878  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
12879  continue;
12880 
12881  for( i = 0; i < consdata->nlinvars; ++i )
12882  {
12883  var = consdata->linvars[i];
12884  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
12885  {
12886  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
12887  ++nnotify;
12888  }
12889  }
12890 
12891  for( i = 0; i < consdata->nquadvars; ++i )
12892  {
12893  var = consdata->quadvarterms[i].var;
12894  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
12895  {
12896  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
12897  ++nnotify;
12898  }
12899  }
12900  }
12901 
12902  if( nnotify == 0 )
12903  {
12904  SCIP_Bool addedcons;
12905  SCIP_Bool reduceddom;
12906  SCIP_Bool infeasible;
12907 
12908  /* if no branching candidate found, then all variables are almost fixed
12909  * calling replaceByLinearConstraints() should lead to fix all almost-fixed quadratic variables, and possibly replace some quad. conss by linear ones
12910  */
12911  SCIP_CALL( replaceByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
12912  if( addedcons )
12913  {
12914  *result = SCIP_CONSADDED;
12915  return SCIP_OKAY;
12916  }
12917  if( reduceddom )
12918  {
12919  *result = SCIP_REDUCEDDOM;
12920  return SCIP_OKAY;
12921  }
12922  if( infeasible )
12923  {
12924  *result = SCIP_CUTOFF;
12925  return SCIP_OKAY;
12926  }
12927 
12928  SCIPdebugMsg(scip, "All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
12929  *result = SCIP_SOLVELP;
12930  }
12931 
12932  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
12933  return SCIP_OKAY;
12934 }
12935 
12936 /** domain propagation method of constraint handler */
12937 static
12938 SCIP_DECL_CONSPROP(consPropQuadratic)
12940  int nchgbds;
12941 
12942  assert(scip != NULL);
12943  assert(conshdlr != NULL);
12944  assert(conss != NULL || nconss == 0);
12945  assert(result != NULL);
12946 
12947  nchgbds = 0;
12948  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nmarkedconss, result, &nchgbds) );
12949 
12950  return SCIP_OKAY;
12951 } /*lint !e715 */
12952 
12953 /** presolving method of constraint handler */
12954 static
12955 SCIP_DECL_CONSPRESOL(consPresolQuadratic)
12956 { /*lint --e{715,788}*/
12957  SCIP_CONSHDLRDATA* conshdlrdata;
12958  SCIP_CONSDATA* consdata;
12959  SCIP_RESULT solveresult;
12960  SCIP_Bool redundant;
12961  SCIP_Bool havechange;
12962  SCIP_Bool doreformulations;
12963  int c;
12964  int i;
12965 
12966  assert(scip != NULL);
12967  assert(conshdlr != NULL);
12968  assert(conss != NULL || nconss == 0);
12969  assert(result != NULL);
12970 
12971  *result = SCIP_DIDNOTFIND;
12972 
12973  /* if other presolvers did not find enough changes for another presolving round and we are in exhaustive presolving,
12974  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
12975  * otherwise, we wait with these
12976  */
12977  doreformulations = ((presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0) && SCIPisPresolveFinished(scip);
12978  SCIPdebugMsg(scip, "presolving will %swait with reformulation\n", doreformulations ? "not " : "");
12979 
12980  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12981  assert(conshdlrdata != NULL);
12982 
12983  for( c = 0; c < nconss; ++c )
12984  {
12985  assert(conss != NULL);
12986  consdata = SCIPconsGetData(conss[c]);
12987  assert(consdata != NULL);
12988 
12989  SCIPdebugMsg(scip, "process constraint <%s>\n", SCIPconsGetName(conss[c]));
12990  SCIPdebugPrintCons(scip, conss[c], NULL);
12991 
12992  if( !consdata->initialmerge )
12993  {
12994  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
12995  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
12996  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
12997  consdata->initialmerge = TRUE;
12998  }
12999 
13000  havechange = FALSE;
13001 #ifdef CHECKIMPLINBILINEAR
13002  if( consdata->isimpladded && (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
13003  {
13004  int nbilinremoved;
13005  SCIP_CALL( presolveApplyImplications(scip, conss[c], &nbilinremoved) );
13006  if( nbilinremoved > 0 )
13007  {
13008  *nchgcoefs += nbilinremoved;
13009  havechange = TRUE;
13010  *result = SCIP_SUCCESS;
13011  }
13012  assert(!consdata->isimpladded);
13013  }
13014 #endif
13015  /* 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
13016  * we want to do this before (multi)aggregated variables are replaced, since that may change structure, e.g., introduce bilinear terms
13017  */
13018  if( !consdata->ispresolved || !consdata->ispropagated || nnewchgvartypes > 0 )
13019  {
13020  SCIP_Bool upgraded;
13021 
13022  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
13023  if( upgraded )
13024  {
13025  *result = SCIP_SUCCESS;
13026  continue;
13027  }
13028  }
13029 
13030  if( !consdata->isremovedfixings )
13031  {
13032  SCIP_CALL( removeFixedVariables(scip, conss[c]) );
13033  assert(consdata->isremovedfixings);
13034  havechange = TRUE;
13035  }
13036 
13037  /* try to "solve" the constraint, e.g., reduce to a variable aggregation */
13038  SCIP_CALL( presolveSolve(scip, conss[c], &solveresult, &redundant, naggrvars) );
13039  if( solveresult == SCIP_CUTOFF )
13040  {
13041  SCIPdebugMsg(scip, "solving constraint <%s> says problem is infeasible in presolve\n", SCIPconsGetName(conss[c]));
13042  *result = SCIP_CUTOFF;
13043  return SCIP_OKAY;
13044  }
13045  if( redundant )
13046  {
13047  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13048  ++*ndelconss;
13049  *result = SCIP_SUCCESS;
13050  break;
13051  }
13052  if( solveresult == SCIP_SUCCESS )
13053  {
13054  *result = SCIP_SUCCESS;
13055  havechange = TRUE;
13056  }
13057 
13058  /* @todo divide constraint by gcd of coefficients if all are integral */
13059 
13060  if( doreformulations )
13061  {
13062  int naddconss_old;
13063 
13064  naddconss_old = *naddconss;
13065 
13066  SCIP_CALL( presolveTryAddAND(scip, conshdlr, conss[c], naddconss) );
13067  assert(*naddconss >= naddconss_old);
13068 
13069  if( *naddconss == naddconss_old )
13070  {
13071  /* user not so empathic about AND, or we don't have products of two binaries, so try this more general reformulation */
13072  SCIP_CALL( presolveTryAddLinearReform(scip, conshdlr, conss[c], naddconss) );
13073  assert(*naddconss >= naddconss_old);
13074  }
13075 
13076  if( conshdlrdata->maxdisaggrsize > 1 )
13077  {
13078  /* try disaggregation, if enabled */
13079  SCIP_CALL( presolveDisaggregate(scip, conshdlr, conss[c], naddconss) );
13080  }
13081 
13082  if( *naddconss > naddconss_old )
13083  {
13084  /* if something happened, report success and cleanup constraint */
13085  *result = SCIP_SUCCESS;
13086  havechange = TRUE;
13087  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
13088  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
13089  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
13090  }
13091  }
13092 
13093  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
13094  {
13095  /* all variables fixed or removed, constraint function is 0.0 now */
13096  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
13097  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
13098  { /* left hand side positive or right hand side negative */
13099  SCIPdebugMsg(scip, "constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
13100  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13101  ++*ndelconss;
13102  *result = SCIP_CUTOFF;
13103  return SCIP_OKAY;
13104  }
13105 
13106  /* left and right hand side are consistent */
13107  SCIPdebugMsg(scip, "constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
13108  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13109  ++*ndelconss;
13110  *result = SCIP_SUCCESS;
13111  continue;
13112  }
13113 
13114  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 && !consdata->ispropagated )
13115  {
13116  /* try domain propagation if there were bound changes or constraint has changed (in which case, processVarEvents may have set ispropagated to false) */
13117  SCIP_RESULT propresult;
13118  int roundnr;
13119 
13120  roundnr = 0;
13121  do
13122  {
13123  ++roundnr;
13124 
13125  SCIPdebugMsg(scip, "starting domain propagation round %d of %d\n", roundnr, conshdlrdata->maxproproundspresolve);
13126 
13127  if( !consdata->ispropagated )
13128  {
13129  consdata->ispropagated = TRUE;
13130 
13131  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
13132 
13133  if( propresult == SCIP_CUTOFF )
13134  {
13135  SCIPdebugMsg(scip, "propagation on constraint <%s> says problem is infeasible in presolve\n",
13136  SCIPconsGetName(conss[c]));
13137  *result = SCIP_CUTOFF;
13138  return SCIP_OKAY;
13139  }
13140 
13141  /* delete constraint if found redundant by bound tightening */
13142  if( redundant )
13143  {
13144  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
13145  ++*ndelconss;
13146  *result = SCIP_SUCCESS;
13147  break;
13148  }
13149 
13150  if( propresult == SCIP_REDUCEDDOM )
13151  {
13152  *result = SCIP_SUCCESS;
13153  havechange = TRUE;
13154  }
13155  }
13156  }
13157  while( !consdata->ispropagated && roundnr < conshdlrdata->maxproproundspresolve );
13158 
13159  if( redundant )
13160  continue;
13161  }
13162 
13163  /* check if we have a single linear continuous variable that we can make implicit integer */
13164  if( (nnewchgvartypes != 0 || havechange || !consdata->ispresolved)
13165  && (SCIPisEQ(scip, consdata->lhs, consdata->rhs) && SCIPisIntegral(scip, consdata->lhs)) )
13166  {
13167  int ncontvar;
13168  SCIP_VAR* candidate;
13169  SCIP_Bool fail;
13170 
13171  fail = FALSE;
13172  candidate = NULL;
13173  ncontvar = 0;
13174 
13175  for( i = 0; !fail && i < consdata->nlinvars; ++i )
13176  {
13177  if( !SCIPisIntegral(scip, consdata->lincoefs[i]) )
13178  {
13179  fail = TRUE;
13180  }
13181  else if( SCIPvarGetType(consdata->linvars[i]) == SCIP_VARTYPE_CONTINUOUS )
13182  {
13183  if( ncontvar > 0 ) /* now at 2nd continuous variable */
13184  fail = TRUE;
13185  else if( SCIPisEQ(scip, ABS(consdata->lincoefs[i]), 1.0) )
13186  candidate = consdata->linvars[i];
13187  ++ncontvar;
13188  }
13189  }
13190  for( i = 0; !fail && i < consdata->nquadvars; ++i )
13191  fail = SCIPvarGetType(consdata->quadvarterms[i].var) == SCIP_VARTYPE_CONTINUOUS ||
13192  !SCIPisIntegral(scip, consdata->quadvarterms[i].lincoef) ||
13193  !SCIPisIntegral(scip, consdata->quadvarterms[i].sqrcoef);
13194  for( i = 0; !fail && i < consdata->nbilinterms; ++i )
13195  fail = !SCIPisIntegral(scip, consdata->bilinterms[i].coef);
13196 
13197  if( !fail && candidate != NULL )
13198  {
13199  SCIP_Bool infeasible;
13200 
13201  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n", SCIPvarGetName(candidate), SCIPconsGetName(conss[c]));
13202 
13203  SCIP_CALL( SCIPchgVarType(scip, candidate, SCIP_VARTYPE_IMPLINT, &infeasible) );
13204  if( infeasible )
13205  {
13206  SCIPdebugMsg(scip, "infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(candidate));
13207  *result = SCIP_CUTOFF;
13208 
13209  return SCIP_OKAY;
13210  }
13211 
13212  ++(*nchgvartypes);
13213  *result = SCIP_SUCCESS;
13214  havechange = TRUE;
13215  }
13216  }
13217 
13218  /* call upgrade methods again if constraint has been changed */
13219  if( havechange )
13220  {
13221  SCIP_Bool upgraded;
13222 
13223  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss, presoltiming) );
13224  if( upgraded )
13225  {
13226  *result = SCIP_SUCCESS;
13227  continue;
13228  }
13229  }
13230 
13231  /* fix quadratic variables with proper square coefficients contained in a single quadratic constraint to their
13232  * upper or lower bounds
13233  */
13234  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && conshdlrdata->checkquadvarlocks != 'd'
13235  && SCIPisPresolveFinished(scip) )
13236  {
13237  SCIP_CONS* cons;
13238  SCIP_VAR* vars[2];
13239  SCIP_BOUNDTYPE boundtypes[2];
13240  SCIP_Real bounds[2];
13241  char name[SCIP_MAXSTRLEN];
13242 
13243  /* merge variables in order to get correct locks for quadratic variables */
13244  if( !consdata->initialmerge )
13245  {
13246  SCIP_CALL( mergeAndCleanBilinearTerms(scip, conss[c]) );
13247  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, conss[c]) );
13248  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
13249  consdata->initialmerge = TRUE;
13250  }
13251 
13252  for( i = 0; i < consdata->nquadvars; ++i )
13253  {
13254  if( hasQuadvarHpProperty(scip, consdata, i) )
13255  {
13256  SCIP_VAR* var;
13257 
13258  var = consdata->quadvarterms[i].var;
13259  assert(var != NULL);
13260 
13261  /* try to change the variable type to binary */
13262  if( conshdlrdata->checkquadvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
13263  {
13264  SCIP_Bool infeasible;
13265 
13266  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
13267  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, &infeasible) );
13268 
13269  if( infeasible )
13270  {
13271  SCIPdebugMsg(scip, "detect infeasibility after changing variable <%s> to binary type\n", SCIPvarGetName(var));
13272  *result = SCIP_CUTOFF;
13273  return SCIP_OKAY;
13274  }
13275  }
13276  /* add bound disjunction constraint if bounds of variable are finite */
13277  else if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
13278  {
13279  vars[0] = var;
13280  vars[1] = var;
13281  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
13282  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
13283  bounds[0] = SCIPvarGetUbGlobal(var);
13284  bounds[1] = SCIPvarGetLbGlobal(var);
13285 
13286  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
13287 
13288  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
13289  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &cons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
13290  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
13291 
13292  SCIP_CALL( SCIPaddCons(scip, cons) );
13293  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
13294  }
13295 
13296  *result = SCIP_SUCCESS;
13297  }
13298  }
13299  }
13300 
13301  consdata->ispresolved = TRUE;
13302  }
13303 
13304  return SCIP_OKAY;
13305 }
13306 
13307 /** variable rounding lock method of constraint handler */
13308 static
13309 SCIP_DECL_CONSLOCK(consLockQuadratic)
13310 { /*lint --e{715}*/
13311  SCIP_CONSDATA* consdata;
13312  SCIP_Bool haslb;
13313  SCIP_Bool hasub;
13314  int i;
13315 
13316  assert(scip != NULL);
13317  assert(cons != NULL);
13318  assert(locktype == SCIP_LOCKTYPE_MODEL);
13319 
13320  consdata = SCIPconsGetData(cons);
13321  assert(consdata != NULL);
13322 
13323  haslb = !SCIPisInfinity(scip, -consdata->lhs);
13324  hasub = !SCIPisInfinity(scip, consdata->rhs);
13325 
13326  for( i = 0; i < consdata->nlinvars; ++i )
13327  {
13328  if( consdata->lincoefs[i] > 0 )
13329  {
13330  if( haslb )
13331  {
13332  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlockspos, nlocksneg) );
13333  }
13334  if( hasub )
13335  {
13336  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlocksneg, nlockspos) );
13337  }
13338  }
13339  else
13340  {
13341  if( haslb )
13342  {
13343  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlocksneg, nlockspos) );
13344  }
13345  if( hasub )
13346  {
13347  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlockspos, nlocksneg) );
13348  }
13349  }
13350  }
13351 
13352  for( i = 0; i < consdata->nquadvars; ++i )
13353  {
13354  /* @todo try to be more clever, but variable locks that depend on the bounds of other variables are not trival to maintain */
13355  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->quadvarterms[i].var, SCIP_LOCKTYPE_MODEL, nlockspos+nlocksneg,
13356  nlockspos+nlocksneg) );
13357  }
13358 
13359  return SCIP_OKAY;
13360 }
13361 
13362 /** constraint enabling notification method of constraint handler */
13363 static
13364 SCIP_DECL_CONSENABLE(consEnableQuadratic)
13366  SCIP_CONSHDLRDATA* conshdlrdata;
13367 
13368  assert(scip != NULL);
13369  assert(conshdlr != NULL);
13370  assert(cons != NULL);
13371  assert(SCIPconsIsTransformed(cons));
13372  assert(SCIPconsIsActive(cons));
13373 
13374  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13375  assert(conshdlrdata != NULL);
13376 
13377  SCIPdebugMsg(scip, "enable cons <%s>\n", SCIPconsGetName(cons));
13378 
13379  if( SCIPgetStage(scip) >= SCIP_STAGE_EXITPRESOLVE )
13380  {
13381  /* merge duplicate bilinear terms, move quad terms that are linear to linear vars */
13382  SCIP_CALL( mergeAndCleanBilinearTerms(scip, cons) );
13383  SCIP_CALL( mergeAndCleanQuadVarTerms(scip, cons) );
13384  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
13385  }
13386 
13387  /* catch variable events */
13388  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
13389 
13390  /* initialize solving data */
13391  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
13392  {
13393  SCIP_CALL( consInitsolQuadratic(scip, conshdlr, &cons, 1) );
13394  }
13395 
13396  return SCIP_OKAY;
13397 }
13398 
13399 /** constraint disabling notification method of constraint handler */
13400 static
13401 SCIP_DECL_CONSDISABLE(consDisableQuadratic)
13402 { /*lint --e{715}*/
13403  SCIP_CONSHDLRDATA* conshdlrdata;
13404 
13405  assert(scip != NULL);
13406  assert(conshdlr != NULL);
13407  assert(cons != NULL);
13408  assert(SCIPconsIsTransformed(cons));
13409 
13410  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13411  assert(conshdlrdata != NULL);
13412 
13413  SCIPdebugMsg(scip, "disable cons <%s>\n", SCIPconsGetName(cons));
13414 
13415  /* free solving data */
13416  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
13417  {
13418  SCIP_CALL( consExitsolQuadratic(scip, conshdlr, &cons, 1, FALSE) );
13419  }
13420 
13421  /* drop variable events */
13422  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
13423 
13424  return SCIP_OKAY;
13425 }
13426 
13427 /** constraint display method of constraint handler */
13428 static
13429 SCIP_DECL_CONSPRINT(consPrintQuadratic)
13430 { /*lint --e{715}*/
13431  SCIP_CONSDATA* consdata;
13432 
13433  assert(scip != NULL);
13434  assert(cons != NULL);
13435 
13436  consdata = SCIPconsGetData(cons);
13437  assert(consdata != NULL);
13438 
13439  /* print left hand side for ranged rows */
13440  if( !SCIPisInfinity(scip, -consdata->lhs)
13441  && !SCIPisInfinity(scip, consdata->rhs)
13442  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
13443  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
13444 
13445  /* print coefficients and variables */
13446  if( consdata->nlinvars == 0 && consdata->nquadvars == 0 )
13447  {
13448  SCIPinfoMessage(scip, file, "0 ");
13449  }
13450  else
13451  {
13452  SCIP_VAR*** monomialvars;
13453  SCIP_Real** monomialexps;
13454  SCIP_Real* monomialcoefs;
13455  int* monomialnvars;
13456  int nmonomials;
13457  int monomialssize;
13458  int j;
13459 
13460  monomialssize = consdata->nlinvars + 2 * consdata->nquadvars + consdata->nbilinterms;
13461  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, monomialssize) );
13462  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps, monomialssize) );
13463  SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, monomialssize) );
13464  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, monomialssize) );
13465 
13466  nmonomials = 0;
13467  for( j = 0; j < consdata->nlinvars; ++j )
13468  {
13469  assert(nmonomials < monomialssize);
13470 
13471  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13472 
13473  monomialvars[nmonomials][0] = consdata->linvars[j];
13474  monomialexps[nmonomials] = NULL;
13475  monomialcoefs[nmonomials] = consdata->lincoefs[j];
13476  monomialnvars[nmonomials] = 1;
13477  ++nmonomials;
13478  }
13479 
13480  for( j = 0; j < consdata->nquadvars; ++j )
13481  {
13482  if( consdata->quadvarterms[j].lincoef != 0.0 )
13483  {
13484  assert(nmonomials < monomialssize);
13485 
13486  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13487 
13488  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
13489  monomialexps[nmonomials] = NULL;
13490  monomialcoefs[nmonomials] = consdata->quadvarterms[j].lincoef;
13491  monomialnvars[nmonomials] = 1;
13492  ++nmonomials;
13493  }
13494 
13495  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
13496  {
13497  assert(nmonomials < monomialssize);
13498 
13499  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 1) ); /*lint !e866 */
13500  SCIP_CALL( SCIPallocBufferArray(scip, &monomialexps[nmonomials], 1) ); /*lint !e866 */
13501 
13502  monomialvars[nmonomials][0] = consdata->quadvarterms[j].var;
13503  monomialexps[nmonomials][0] = 2.0;
13504  monomialcoefs[nmonomials] = consdata->quadvarterms[j].sqrcoef;
13505  monomialnvars[nmonomials] = 1;
13506  ++nmonomials;
13507  }
13508  }
13509 
13510  for( j = 0; j < consdata->nbilinterms; ++j )
13511  {
13512  assert(nmonomials < monomialssize);
13513 
13514  SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars[nmonomials], 2) ); /*lint !e866 */
13515 
13516  monomialvars[nmonomials][0] = consdata->bilinterms[j].var1;
13517  monomialvars[nmonomials][1] = consdata->bilinterms[j].var2;
13518  monomialexps[nmonomials] = NULL;
13519  monomialcoefs[nmonomials] = consdata->bilinterms[j].coef;
13520  monomialnvars[nmonomials] = 2;
13521  ++nmonomials;
13522  }
13523 
13524  SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, monomialexps, monomialcoefs, monomialnvars, nmonomials, TRUE) );
13525 
13526  for( j = nmonomials - 1; j >= 0 ; --j )
13527  {
13528  SCIPfreeBufferArrayNull(scip, &monomialexps[j]);
13529  SCIPfreeBufferArray(scip, &monomialvars[j]);
13530  }
13531 
13532  SCIPfreeBufferArray(scip, &monomialnvars);
13533  SCIPfreeBufferArray(scip, &monomialcoefs);
13534  SCIPfreeBufferArray(scip, &monomialexps);
13535  SCIPfreeBufferArray(scip, &monomialvars);
13536  }
13537 
13538  /* print right hand side */
13539  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
13540  {
13541  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
13542  }
13543  else if( !SCIPisInfinity(scip, consdata->rhs) )
13544  {
13545  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
13546  }
13547  else if( !SCIPisInfinity(scip, -consdata->lhs) )
13548  {
13549  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
13550  }
13551  else
13552  {
13553  /* should be ignored by parser */
13554  SCIPinfoMessage(scip, file, " [free]");
13555  }
13556 
13557  return SCIP_OKAY;
13558 }
13559 
13560 /** feasibility check method of constraint handler for integral solutions */
13561 static
13562 SCIP_DECL_CONSCHECK(consCheckQuadratic)
13563 { /*lint --e{715}*/
13564  SCIP_CONSHDLRDATA* conshdlrdata;
13565  SCIP_CONSDATA* consdata;
13566  SCIP_Real maxviol;
13567  int c;
13568  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
13569  SCIP_Bool solviolbounds;
13570 
13571  assert(scip != NULL);
13572  assert(conss != NULL || nconss == 0);
13573  assert(result != NULL);
13574 
13575  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13576  assert(conshdlrdata != NULL);
13577 
13578  *result = SCIP_FEASIBLE;
13579 
13580  maxviol = 0.0;
13581  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
13583  for( c = 0; c < nconss; ++c )
13584  {
13585  assert(conss != NULL);
13586  SCIP_CALL( computeViolation(scip, conss[c], sol, &solviolbounds) );
13587  assert(!solviolbounds); /* see also issue #627 */
13588 
13589  consdata = SCIPconsGetData(conss[c]);
13590  assert(consdata != NULL);
13591 
13592  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
13593  {
13594  *result = SCIP_INFEASIBLE;
13595  if( printreason )
13596  {
13597  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
13598  SCIPinfoMessage(scip, NULL, ";\n");
13599  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
13600  {
13601  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
13602  }
13603  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
13604  {
13605  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
13606  }
13607  }
13608  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
13609  return SCIP_OKAY;
13610  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
13611  maxviol = consdata->lhsviol + consdata->rhsviol;
13612 
13613  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
13614  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
13615  maypropfeasible = FALSE;
13616 
13617  if( maypropfeasible )
13618  {
13619  /* update information on linear variables that may be in- or decreased, if initsolve has not done so yet */
13621  consdataFindUnlockedLinearVar(scip, consdata);
13622 
13623  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
13624  {
13625  /* check if there is a variable which may help to get the left hand side satisfied
13626  * if there is no such var, then we cannot get feasible */
13627  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
13628  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
13629  maypropfeasible = FALSE;
13630  }
13631  else
13632  {
13633  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
13634  /* check if there is a variable which may help to get the right hand side satisfied
13635  * if there is no such var, then we cannot get feasible */
13636  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
13637  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
13638  maypropfeasible = FALSE;
13639  }
13640  }
13641  }
13642  }
13643 
13644  if( *result == SCIP_INFEASIBLE && maypropfeasible )
13645  {
13646  SCIP_Bool success;
13647 
13648  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
13649 
13650  /* do not pass solution to NLP heuristic if we made it feasible this way */
13651  if( success )
13652  return SCIP_OKAY;
13653  }
13654 
13655  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
13656  {
13657  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
13658  }
13659 
13660  return SCIP_OKAY;
13661 }
13662 
13663 /** constraint copying method of constraint handler */
13664 static
13665 SCIP_DECL_CONSCOPY(consCopyQuadratic)
13667  SCIP_CONSDATA* consdata;
13668  SCIP_CONSDATA* targetconsdata;
13669  SCIP_VAR** linvars;
13670  SCIP_QUADVARTERM* quadvarterms;
13671  SCIP_BILINTERM* bilinterms;
13672  int i;
13673  int j;
13674  int k;
13675 
13676  assert(scip != NULL);
13677  assert(cons != NULL);
13678  assert(sourcescip != NULL);
13679  assert(sourceconshdlr != NULL);
13680  assert(sourcecons != NULL);
13681  assert(varmap != NULL);
13682  assert(valid != NULL);
13683 
13684  consdata = SCIPconsGetData(sourcecons);
13685  assert(consdata != NULL);
13686 
13687  linvars = NULL;
13688  quadvarterms = NULL;
13689  bilinterms = NULL;
13690 
13691  *valid = TRUE;
13692 
13693  if( consdata->nlinvars != 0 )
13694  {
13695  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
13696  for( i = 0; i < consdata->nlinvars; ++i )
13697  {
13698  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
13699  assert(!(*valid) || linvars[i] != NULL);
13700 
13701  /* we do not copy, if a variable is missing */
13702  if( !(*valid) )
13703  goto TERMINATE;
13704  }
13705  }
13706 
13707  if( consdata->nbilinterms != 0 )
13708  {
13709  SCIP_CALL( SCIPallocBufferArray(sourcescip, &bilinterms, consdata->nbilinterms) );
13710  }
13711 
13712  if( consdata->nquadvars != 0 )
13713  {
13714  SCIP_CALL( SCIPallocBufferArray(sourcescip, &quadvarterms, consdata->nquadvars) );
13715  for( i = 0; i < consdata->nquadvars; ++i )
13716  {
13717  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->quadvarterms[i].var, &quadvarterms[i].var, varmap, consmap, global, valid) );
13718  assert(!(*valid) || quadvarterms[i].var != NULL);
13719 
13720  /* we do not copy, if a variable is missing */
13721  if( !(*valid) )
13722  goto TERMINATE;
13723 
13724  quadvarterms[i].lincoef = consdata->quadvarterms[i].lincoef;
13725  quadvarterms[i].sqrcoef = consdata->quadvarterms[i].sqrcoef;
13726  quadvarterms[i].eventdata = NULL;
13727  quadvarterms[i].nadjbilin = consdata->quadvarterms[i].nadjbilin;
13728  quadvarterms[i].adjbilin = consdata->quadvarterms[i].adjbilin;
13729 
13730  assert(consdata->nbilinterms != 0 || consdata->quadvarterms[i].nadjbilin == 0);
13731 
13732  for( j = 0; j < consdata->quadvarterms[i].nadjbilin; ++j )
13733  {
13734  assert(bilinterms != NULL);
13735 
13736  k = consdata->quadvarterms[i].adjbilin[j];
13737  assert(consdata->bilinterms[k].var1 != NULL);
13738  assert(consdata->bilinterms[k].var2 != NULL);
13739  if( consdata->bilinterms[k].var1 == consdata->quadvarterms[i].var )
13740  {
13741  assert(consdata->bilinterms[k].var2 != consdata->quadvarterms[i].var);
13742  bilinterms[k].var1 = quadvarterms[i].var;
13743  }
13744  else
13745  {
13746  assert(consdata->bilinterms[k].var2 == consdata->quadvarterms[i].var);
13747  bilinterms[k].var2 = quadvarterms[i].var;
13748  }
13749  bilinterms[k].coef = consdata->bilinterms[k].coef;
13750  }
13751  }
13752  }
13753 
13754  assert(stickingatnode == FALSE);
13755  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name ? name : SCIPconsGetName(sourcecons),
13756  consdata->nlinvars, linvars, consdata->lincoefs,
13757  consdata->nquadvars, quadvarterms,
13758  consdata->nbilinterms, bilinterms,
13759  consdata->lhs, consdata->rhs,
13760  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
13761 
13762  /* copy information on curvature */
13763  targetconsdata = SCIPconsGetData(*cons);
13764  targetconsdata->isconvex = consdata->isconvex;
13765  targetconsdata->isconcave = consdata->isconcave;
13766  targetconsdata->iscurvchecked = consdata->iscurvchecked;
13767 
13768  TERMINATE:
13769  SCIPfreeBufferArrayNull(sourcescip, &quadvarterms);
13770  SCIPfreeBufferArrayNull(sourcescip, &bilinterms);
13771  SCIPfreeBufferArrayNull(sourcescip, &linvars);
13772 
13773  return SCIP_OKAY;
13774 }
13775 
13776 /** constraint parsing method of constraint handler */
13777 static
13778 SCIP_DECL_CONSPARSE(consParseQuadratic)
13779 { /*lint --e{715}*/
13780  SCIP_VAR*** monomialvars;
13781  SCIP_Real** monomialexps;
13782  SCIP_Real* monomialcoefs;
13783  char* endptr;
13784  int* monomialnvars;
13785  int nmonomials;
13786 
13787  SCIP_Real lhs;
13788  SCIP_Real rhs;
13789 
13790  assert(scip != NULL);
13791  assert(success != NULL);
13792  assert(str != NULL);
13793  assert(name != NULL);
13794  assert(cons != NULL);
13795 
13796  /* set left and right hand side to their default values */
13797  lhs = -SCIPinfinity(scip);
13798  rhs = SCIPinfinity(scip);
13799 
13800  (*success) = FALSE;
13801 
13802  /* return of string empty */
13803  if( !*str )
13804  return SCIP_OKAY;
13805 
13806  /* ignore whitespace */
13807  while( isspace((unsigned char)*str) )
13808  ++str;
13809 
13810  /* check for left hand side */
13811  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
13812  {
13813  /* there is a number coming, maybe it is a left-hand-side */
13814  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13815  {
13816  SCIPerrorMessage("error parsing number from <%s>\n", str);
13817  return SCIP_OKAY;
13818  }
13819 
13820  /* ignore whitespace */
13821  while( isspace((unsigned char)*endptr) )
13822  ++endptr;
13823 
13824  if( endptr[0] != '<' || endptr[1] != '=' )
13825  {
13826  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
13827  lhs = -SCIPinfinity(scip);
13828  }
13829  else
13830  {
13831  /* it was indeed a left-hand-side, so continue parsing after it */
13832  str = endptr + 2;
13833 
13834  /* ignore whitespace */
13835  while( isspace((unsigned char)*str) )
13836  ++str;
13837  }
13838  }
13839 
13840  SCIP_CALL( SCIPparseVarsPolynomial(scip, str, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, &nmonomials, &endptr, success) );
13841 
13842  if( *success )
13843  {
13844  /* check for right hand side */
13845  str = endptr;
13846 
13847  /* ignore whitespace */
13848  while( isspace((unsigned char)*str) )
13849  ++str;
13850 
13851  if( *str && str[0] == '<' && str[1] == '=' )
13852  {
13853  /* we seem to get a right-hand-side */
13854  str += 2;
13855 
13856  if( !SCIPstrToRealValue(str, &rhs, &endptr) )
13857  {
13858  SCIPerrorMessage("error parsing right-hand-side from %s\n", str);
13859  *success = FALSE;
13860  }
13861  }
13862  else if( *str && str[0] == '>' && str[1] == '=' )
13863  {
13864  /* we seem to get a left-hand-side */
13865  str += 2;
13866 
13867  /* we should not have a left-hand-side already */
13868  assert(SCIPisInfinity(scip, -lhs));
13869 
13870  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13871  {
13872  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
13873  *success = FALSE;
13874  }
13875  }
13876  else if( *str && str[0] == '=' && str[1] == '=' )
13877  {
13878  /* we seem to get a left- and right-hand-side */
13879  str += 2;
13880 
13881  /* we should not have a left-hand-side already */
13882  assert(SCIPisInfinity(scip, -lhs));
13883 
13884  if( !SCIPstrToRealValue(str, &lhs, &endptr) )
13885  {
13886  SCIPerrorMessage("error parsing left-hand-side from %s\n", str);
13887  *success = FALSE;
13888  }
13889  else
13890  {
13891  rhs = lhs;
13892  }
13893  }
13894  }
13895 
13896  if( *success )
13897  {
13898  int i;
13899 
13900  /* setup constraint */
13901  assert(stickingatnode == FALSE);
13902  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, 0, NULL, NULL,
13903  0, NULL, NULL, NULL, lhs, rhs,
13904  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
13905 
13906  for( i = 0; i < nmonomials; ++i )
13907  {
13908  if( monomialnvars[i] == 0 )
13909  {
13910  /* constant monomial */
13911  SCIPaddConstantQuadratic(scip, *cons, monomialcoefs[i]);
13912  }
13913  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 1.0 )
13914  {
13915  /* linear monomial */
13916  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, *cons, monomialvars[i][0], monomialcoefs[i]) );
13917  }
13918  else if( monomialnvars[i] == 1 && monomialexps[i][0] == 2.0 )
13919  {
13920  /* square monomial */
13921  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, monomialvars[i][0], 0.0, monomialcoefs[i]) );
13922  }
13923  else if( monomialnvars[i] == 2 && monomialexps[i][0] == 1.0 && monomialexps[i][1] == 1.0 )
13924  {
13925  /* bilinear term */
13926  SCIP_VAR* var1;
13927  SCIP_VAR* var2;
13928  int pos;
13929 
13930  var1 = monomialvars[i][0];
13931  var2 = monomialvars[i][1];
13932  if( var1 == var2 )
13933  {
13934  /* actually a square term */
13935  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, monomialcoefs[i]) );
13936  }
13937  else
13938  {
13939  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var1, &pos) );
13940  if( pos == -1 )
13941  {
13942  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var1, 0.0, 0.0) );
13943  }
13944 
13945  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, *cons, var2, &pos) );
13946  if( pos == -1 )
13947  {
13948  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, *cons, var2, 0.0, 0.0) );
13949  }
13950  }
13951 
13952  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, *cons, var1, var2, monomialcoefs[i]) );
13953  }
13954  else
13955  {
13956  SCIPerrorMessage("polynomial in quadratic constraint does not have degree at most 2\n");
13957  *success = FALSE;
13958  SCIP_CALL( SCIPreleaseCons(scip, cons) );
13959  break;
13960  }
13961  }
13962  }
13963 
13964  SCIPfreeParseVarsPolynomialData(scip, &monomialvars, &monomialexps, &monomialcoefs, &monomialnvars, nmonomials);
13965 
13966  return SCIP_OKAY;
13967 }
13968 
13969 /** constraint method of constraint handler which returns the variables (if possible) */
13970 static
13971 SCIP_DECL_CONSGETVARS(consGetVarsQuadratic)
13972 { /*lint --e{715}*/
13973  SCIP_CONSDATA* consdata;
13974 
13975  assert(cons != NULL);
13976  assert(success != NULL);
13977 
13978  consdata = SCIPconsGetData(cons);
13979  assert(consdata != NULL);
13980 
13981  if( varssize < consdata->nlinvars + consdata->nquadvars )
13982  (*success) = FALSE;
13983  else
13984  {
13985  int i;
13986 
13987  assert(vars != NULL);
13988 
13989  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
13990 
13991  for( i = 0; i < consdata->nquadvars; ++i )
13992  vars[consdata->nlinvars+i] = consdata->quadvarterms[i].var;
13993 
13994  (*success) = TRUE;
13995  }
13996 
13997  return SCIP_OKAY;
13998 }
13999 
14000 /** constraint method of constraint handler which returns the number of variables (if possible) */
14001 static
14002 SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
14003 { /*lint --e{715}*/
14004  SCIP_CONSDATA* consdata;
14005 
14006  assert(cons != NULL);
14007  assert(success != NULL);
14008 
14009  consdata = SCIPconsGetData(cons);
14010  assert(consdata != NULL);
14011 
14012  (*nvars) = consdata->nlinvars + consdata->nquadvars;
14013  (*success) = TRUE;
14014 
14015  return SCIP_OKAY;
14016 }
14017 
14018 
14019 /*
14020  * constraint specific interface methods
14021  */
14022 
14023 /** creates the handler for quadratic constraints and includes it in SCIP */
14025  SCIP* scip /**< SCIP data structure */
14026  )
14027 {
14028  SCIP_CONSHDLRDATA* conshdlrdata;
14029  SCIP_CONSHDLR* conshdlr;
14030 
14031  /* create quadratic constraint handler data */
14032  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
14033  BMSclearMemory(conshdlrdata);
14034 
14035  /* include constraint handler */
14038  consEnfolpQuadratic, consEnfopsQuadratic, consCheckQuadratic, consLockQuadratic,
14039  conshdlrdata) );
14040  assert(conshdlr != NULL);
14041 
14042  /* set non-fundamental callbacks via specific setter functions */
14043  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyQuadratic, consCopyQuadratic) );
14044  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteQuadratic) );
14045  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableQuadratic) );
14046  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableQuadratic) );
14047  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitQuadratic) );
14048  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreQuadratic) );
14049  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolQuadratic) );
14050  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeQuadratic) );
14051  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsQuadratic) );
14052  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsQuadratic) );
14053  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitQuadratic) );
14054  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolQuadratic) );
14055  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpQuadratic) );
14056  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseQuadratic) );
14057  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolQuadratic, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
14058  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintQuadratic) );
14059  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropQuadratic, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
14061  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpQuadratic, consSepasolQuadratic, CONSHDLR_SEPAFREQ,
14063  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransQuadratic) );
14064  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxQuadratic) );
14065 
14066  /* add quadratic constraint handler parameters */
14067  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/replacebinaryprod",
14068  "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)",
14069  &conshdlrdata->replacebinaryprodlength, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
14070 
14071  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/empathy4and",
14072  "empathy level for using the AND constraint handler: 0 always avoid using AND; 1 use AND sometimes; 2 use AND as often as possible",
14073  &conshdlrdata->empathy4and, FALSE, 0, 0, 2, NULL, NULL) );
14074 
14075  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreforminitial",
14076  "whether to make non-varbound linear constraints added due to replacing products with binary variables initial",
14077  &conshdlrdata->binreforminitial, TRUE, FALSE, NULL, NULL) );
14078 
14079  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/binreformbinaryonly",
14080  "whether to consider only binary variables when replacing products with binary variables",
14081  &conshdlrdata->binreformbinaryonly, FALSE, TRUE, NULL, NULL) );
14082 
14083  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/binreformmaxcoef",
14084  "limit (as factor on 1/feastol) on coefficients and coef. range in linear constraints created when replacing products with binary variables",
14085  &conshdlrdata->binreformmaxcoef, TRUE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
14086 
14087  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
14088  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
14089  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
14090 
14091  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/mincurvcollectbilinterms",
14092  "minimal curvature of constraints to be considered when returning bilinear terms to other plugins",
14093  &conshdlrdata->mincurvcollectbilinterms, TRUE, 0.8, -SCIPinfinity(scip), SCIPinfinity(scip), NULL, NULL) );
14094 
14095  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
14096  "whether linearizations of convex quadratic constraints should be added to cutpool in a solution found by some heuristic",
14097  &conshdlrdata->linearizeheursol, TRUE, TRUE, NULL, NULL) );
14098 
14099  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkcurvature",
14100  "whether multivariate quadratic functions should be checked for convexity/concavity",
14101  &conshdlrdata->checkcurvature, FALSE, TRUE, NULL, NULL) );
14102 
14103  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkfactorable",
14104  "whether constraint functions should be checked to be factorable",
14105  &conshdlrdata->checkfactorable, TRUE, TRUE, NULL, NULL) );
14106 
14107  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkquadvarlocks",
14108  "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)",
14109  &conshdlrdata->checkquadvarlocks, TRUE, 't', "bdt", NULL, NULL) );
14110 
14111  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
14112  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
14113  &conshdlrdata->linfeasshift, TRUE, TRUE, NULL, NULL) );
14114 
14115  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxdisaggrsize",
14116  "maximum number of created constraints when disaggregating a quadratic constraint (<= 1: off)",
14117  &conshdlrdata->maxdisaggrsize, FALSE, 1, 1, INT_MAX, NULL, NULL) );
14118 
14119  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/disaggrmergemethod",
14120  "strategy how to merge independent blocks to reach maxdisaggrsize limit (keep 'b'iggest blocks and merge others; keep 's'mallest blocks and merge other; merge small blocks into bigger blocks to reach 'm'ean sizes)",
14121  &conshdlrdata->disaggrmergemethod, TRUE, 'm', "bms", NULL, NULL) );
14122 
14123  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
14124  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation during solve",
14125  &conshdlrdata->maxproprounds, TRUE, 1, 0, INT_MAX, NULL, NULL) );
14126 
14127  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproproundspresolve",
14128  "limit on number of propagation rounds for a single constraint within one round of SCIP presolve",
14129  &conshdlrdata->maxproproundspresolve, TRUE, 10, 0, INT_MAX, NULL, NULL) );
14130 
14131  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/enfolplimit",
14132  "maximum number of enforcement rounds before declaring the LP relaxation infeasible (-1: no limit); WARNING: changing this parameter might lead to incorrect results!",
14133  &conshdlrdata->enfolplimit, TRUE, -1, -1, INT_MAX, NULL, NULL) );
14134 
14135  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
14136  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
14137  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
14138 
14139  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
14140  "are cuts added during enforcement removable from the LP in the same node?",
14141  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
14142 
14143  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/gaugecuts",
14144  "should convex quadratics generated strong cuts via gauge function?",
14145  &conshdlrdata->gaugecuts, FALSE, FALSE, NULL, NULL) );
14146 
14147  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/interiorcomputation",
14148  "how the interior point for gauge cuts should be computed: 'a'ny point per constraint, 'm'ost interior per constraint",
14149  &conshdlrdata->interiorcomputation, TRUE, 'a', "am", NULL, NULL) );
14150 
14151  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/projectedcuts",
14152  "should convex quadratics generated strong cuts via projections?",
14153  &conshdlrdata->projectedcuts, FALSE, FALSE, NULL, NULL) );
14154 
14155  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branchscoring",
14156  "which score to give branching candidates: convexification 'g'ap, constraint 'v'iolation, 'c'entrality of variable value in domain",
14157  &conshdlrdata->branchscoring, TRUE, 'g', "cgv", NULL, NULL) );
14158 
14159  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/usebilinineqbranch",
14160  "should linear inequalities be consindered when computing the branching scores for bilinear terms?",
14161  &conshdlrdata->usebilinineqbranch, FALSE, FALSE, NULL, NULL) );
14162 
14163  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minscorebilinterms",
14164  "minimal required score in order to use linear inequalities for tighter bilinear relaxations",
14165  &conshdlrdata->minscorebilinterms, FALSE, 0.01, 0.0, 1.0, NULL, NULL) );
14166 
14167  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinineqmaxseparounds",
14168  "maximum number of separation rounds to use linear inequalities for the bilinear term relaxation in a local node",
14169  &conshdlrdata->bilinineqmaxseparounds, TRUE, 3, 0, INT_MAX, NULL, NULL) );
14170 
14171  conshdlrdata->eventhdlr = NULL;
14172  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->eventhdlr),CONSHDLR_NAME"_boundchange", "signals a bound change to a quadratic constraint",
14173  processVarEvent, NULL) );
14174  assert(conshdlrdata->eventhdlr != NULL);
14175 
14176  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
14177  processNewSolutionEvent, NULL) );
14178 
14179  /* include the quadratic constraint upgrade in the nonlinear constraint handler */
14181 
14182  return SCIP_OKAY;
14183 }
14184 
14185 /** includes a quadratic constraint update method into the quadratic constraint handler */
14187  SCIP* scip, /**< SCIP data structure */
14188  SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), /**< method to call for upgrading quadratic constraint */
14189  int priority, /**< priority of upgrading method */
14190  SCIP_Bool active, /**< should the upgrading method be active by default? */
14191  const char* conshdlrname /**< name of the constraint handler */
14192  )
14193 {
14194  SCIP_CONSHDLR* conshdlr;
14195  SCIP_CONSHDLRDATA* conshdlrdata;
14196  SCIP_QUADCONSUPGRADE* quadconsupgrade;
14197  char paramname[SCIP_MAXSTRLEN];
14198  char paramdesc[SCIP_MAXSTRLEN];
14199  int i;
14200 
14201  assert(quadconsupgd != NULL);
14202  assert(conshdlrname != NULL );
14203 
14204  /* find the quadratic constraint handler */
14205  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14206  if( conshdlr == NULL )
14207  {
14208  SCIPerrorMessage("quadratic constraint handler not found\n");
14209  return SCIP_PLUGINNOTFOUND;
14210  }
14211 
14212  conshdlrdata = SCIPconshdlrGetData(conshdlr);
14213  assert(conshdlrdata != NULL);
14214 
14215  if( !conshdlrdataHasUpgrade(scip, conshdlrdata, quadconsupgd, conshdlrname) )
14216  {
14217  /* create a quadratic constraint upgrade data object */
14218  SCIP_CALL( SCIPallocBlockMemory(scip, &quadconsupgrade) );
14219  quadconsupgrade->quadconsupgd = quadconsupgd;
14220  quadconsupgrade->priority = priority;
14221  quadconsupgrade->active = active;
14222 
14223  /* insert quadratic constraint upgrade method into constraint handler data */
14224  assert(conshdlrdata->nquadconsupgrades <= conshdlrdata->quadconsupgradessize);
14225  if( conshdlrdata->nquadconsupgrades+1 > conshdlrdata->quadconsupgradessize )
14226  {
14227  int newsize;
14228 
14229  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nquadconsupgrades+1);
14230  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->quadconsupgrades, conshdlrdata->quadconsupgradessize, newsize) );
14231  conshdlrdata->quadconsupgradessize = newsize;
14232  }
14233  assert(conshdlrdata->nquadconsupgrades+1 <= conshdlrdata->quadconsupgradessize);
14234 
14235  for( i = conshdlrdata->nquadconsupgrades; i > 0 && conshdlrdata->quadconsupgrades[i-1]->priority < quadconsupgrade->priority; --i )
14236  conshdlrdata->quadconsupgrades[i] = conshdlrdata->quadconsupgrades[i-1];
14237  assert(0 <= i && i <= conshdlrdata->nquadconsupgrades);
14238  conshdlrdata->quadconsupgrades[i] = quadconsupgrade;
14239  conshdlrdata->nquadconsupgrades++;
14240 
14241  /* adds parameter to turn on and off the upgrading step */
14242  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
14243  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable quadratic upgrading for constraint handler <%s>", conshdlrname);
14245  paramname, paramdesc,
14246  &quadconsupgrade->active, FALSE, active, NULL, NULL) );
14247  }
14248 
14249  return SCIP_OKAY;
14250 }
14251 
14252 /** Creates and captures a quadratic constraint.
14253  *
14254  * The constraint should be given in the form
14255  * \f[
14256  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
14257  * \f]
14258  * where \f$x_i = y_j = z_k\f$ is possible.
14259  *
14260  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14261  */
14263  SCIP* scip, /**< SCIP data structure */
14264  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14265  const char* name, /**< name of constraint */
14266  int nlinvars, /**< number of linear terms (n) */
14267  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14268  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14269  int nquadterms, /**< number of quadratic terms (m) */
14270  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
14271  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
14272  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
14273  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
14274  SCIP_Real rhs, /**< right hand side of quadratic equation (u) */
14275  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
14276  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
14277  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
14278  * Usually set to TRUE. */
14279  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
14280  * TRUE for model constraints, FALSE for additional, redundant constraints. */
14281  SCIP_Bool check, /**< should the constraint be checked for feasibility?
14282  * TRUE for model constraints, FALSE for additional, redundant constraints. */
14283  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
14284  * Usually set to TRUE. */
14285  SCIP_Bool local, /**< is constraint only valid locally?
14286  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
14287  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
14288  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
14289  * adds coefficients to this constraint. */
14290  SCIP_Bool dynamic, /**< is constraint subject to aging?
14291  * Usually set to FALSE. Set to TRUE for own cuts which
14292  * are separated as constraints. */
14293  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
14294  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
14295  )
14296 {
14297  SCIP_CONSHDLR* conshdlr;
14298  SCIP_CONSDATA* consdata;
14299  SCIP_HASHMAP* quadvaridxs;
14300  SCIP_Real sqrcoef;
14301  int i;
14302  int var1pos;
14303  int var2pos;
14304 
14305  int nbilinterms;
14306 
14307  assert(linvars != NULL || nlinvars == 0);
14308  assert(lincoefs != NULL || nlinvars == 0);
14309  assert(quadvars1 != NULL || nquadterms == 0);
14310  assert(quadvars2 != NULL || nquadterms == 0);
14311  assert(quadcoefs != NULL || nquadterms == 0);
14312 
14313  assert(modifiable == FALSE); /* we do not support column generation */
14314 
14315  /* find the quadratic constraint handler */
14316  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14317  if( conshdlr == NULL )
14318  {
14319  SCIPerrorMessage("quadratic constraint handler not found\n");
14320  return SCIP_PLUGINNOTFOUND;
14321  }
14322 
14323  /* create constraint data and constraint */
14324  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
14325 
14326  consdata->lhs = lhs;
14327  consdata->rhs = rhs;
14328 
14329  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
14330  local, modifiable, dynamic, removable, FALSE) );
14331 
14332  /* add quadratic variables and remember their indices */
14333  SCIP_CALL( SCIPhashmapCreate(&quadvaridxs, SCIPblkmem(scip), nquadterms) );
14334  nbilinterms = 0;
14335  for( i = 0; i < nquadterms; ++i )
14336  {
14337  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
14338  continue;
14339 
14340  /* if it is actually a square term, remember it's coefficient */
14341  /* cppcheck-suppress nullPointer */
14342  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
14343  sqrcoef = quadcoefs[i]; /*lint !e613 */
14344  else
14345  sqrcoef = 0.0;
14346 
14347  /* add quadvars1[i], if not in there already */
14348  if( !SCIPhashmapExists(quadvaridxs, quadvars1[i]) ) /*lint !e613*/
14349  {
14350  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars1[i], 0.0, sqrcoef) ); /*lint !e613*/
14351  assert(consdata->nquadvars >= 0);
14352  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars1[i]); /*lint !e613*/
14353 
14354  SCIP_CALL( SCIPhashmapInsertInt(quadvaridxs, quadvars1[i], consdata->nquadvars-1) ); /*lint !e613*/
14355  }
14356  else if( !SCIPisZero(scip, sqrcoef) )
14357  {
14358  /* if it's there already, but we got a square coefficient, add it to the previous one */
14359  var1pos = SCIPhashmapGetImageInt(quadvaridxs, quadvars1[i]); /*lint !e613*/
14360  assert(consdata->quadvarterms[var1pos].var == quadvars1[i]); /*lint !e613*/
14361  consdata->quadvarterms[var1pos].sqrcoef += sqrcoef;
14362  }
14363 
14364  /* cppcheck-suppress nullPointer */
14365  if( quadvars1[i] == quadvars2[i] ) /*lint !e613*/
14366  continue;
14367 
14368  /* add quadvars2[i], if not in there already */
14369  if( !SCIPhashmapExists(quadvaridxs, quadvars2[i]) ) /*lint !e613*/
14370  {
14371  assert(sqrcoef == 0.0);
14372  SCIP_CALL( addQuadVarTerm(scip, *cons, quadvars2[i], 0.0, 0.0) ); /*lint !e613*/
14373  assert(consdata->nquadvars >= 0);
14374  assert(consdata->quadvarterms[consdata->nquadvars-1].var == quadvars2[i]); /*lint !e613*/
14375 
14376  SCIP_CALL( SCIPhashmapInsertInt(quadvaridxs, quadvars2[i], consdata->nquadvars-1) ); /*lint !e613*/
14377  }
14378 
14379  ++nbilinterms;
14380  }
14381 
14382  /* add bilinear terms, if we saw any */
14383  if( nbilinterms > 0 )
14384  {
14385  SCIP_CALL( consdataEnsureBilinSize(scip, consdata, nbilinterms) );
14386  for( i = 0; i < nquadterms; ++i )
14387  {
14388  if( SCIPisZero(scip, quadcoefs[i]) ) /*lint !e613*/
14389  continue;
14390 
14391  /* square terms have been taken care of already */
14392  if( quadvars1[i] == quadvars2[i] ) /*lint !e613 */
14393  continue;
14394 
14395  assert(SCIPhashmapExists(quadvaridxs, quadvars1[i])); /*lint !e613*/
14396  assert(SCIPhashmapExists(quadvaridxs, quadvars2[i])); /*lint !e613*/
14397 
14398  var1pos = SCIPhashmapGetImageInt(quadvaridxs, quadvars1[i]); /*lint !e613*/
14399  var2pos = SCIPhashmapGetImageInt(quadvaridxs, quadvars2[i]); /*lint !e613*/
14400 
14401  SCIP_CALL( addBilinearTerm(scip, *cons, var1pos, var2pos, quadcoefs[i]) ); /*lint !e613*/
14402  }
14403  }
14404 
14405  /* add linear variables */
14406  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
14407  for( i = 0; i < nlinvars; ++i )
14408  {
14409  if( SCIPisZero(scip, lincoefs[i]) ) /*lint !e613*/
14410  continue;
14411 
14412  /* if it's a linear coefficient for a quadratic variable, add it there, otherwise add as linear variable */
14413  if( SCIPhashmapExists(quadvaridxs, linvars[i]) ) /*lint !e613*/
14414  {
14415  var1pos = SCIPhashmapGetImageInt(quadvaridxs, linvars[i]); /*lint !e613*/
14416  assert(consdata->quadvarterms[var1pos].var == linvars[i]); /*lint !e613*/
14417  consdata->quadvarterms[var1pos].lincoef += lincoefs[i]; /*lint !e613*/
14418  }
14419  else
14420  {
14421  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) ); /*lint !e613*/
14422  }
14423  }
14424 
14425  SCIPhashmapFree(&quadvaridxs);
14426 
14427  SCIPdebugMsg(scip, "created quadratic constraint ");
14428  SCIPdebugPrintCons(scip, *cons, NULL);
14429 
14430  return SCIP_OKAY;
14431 }
14432 
14433 /** creates and captures a quadratic constraint with all its
14434  * flags set to their default values.
14435  *
14436  * The constraint should be given in the form
14437  * \f[
14438  * \ell \leq \sum_{i=1}^n b_i x_i + \sum_{j=1}^m a_j y_j z_j \leq u,
14439  * \f]
14440  * where \f$x_i = y_j = z_k\f$ is possible.
14441  *
14442  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14443  */
14445  SCIP* scip, /**< SCIP data structure */
14446  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14447  const char* name, /**< name of constraint */
14448  int nlinvars, /**< number of linear terms (n) */
14449  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14450  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14451  int nquadterms, /**< number of quadratic terms (m) */
14452  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms (y_j) */
14453  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms (z_j) */
14454  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms (a_j) */
14455  SCIP_Real lhs, /**< left hand side of quadratic equation (ell) */
14456  SCIP_Real rhs /**< right hand side of quadratic equation (u) */
14457  )
14458 {
14459  SCIP_CALL( SCIPcreateConsQuadratic(scip, cons, name, nlinvars, linvars, lincoefs,
14460  nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
14461  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
14462 
14463  return SCIP_OKAY;
14464 }
14465 
14466 /** Creates and captures a quadratic constraint.
14467  *
14468  * The constraint should be given in the form
14469  * \f[
14470  * \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.
14471  * \f]
14472  *
14473  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14474  */
14476  SCIP* scip, /**< SCIP data structure */
14477  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14478  const char* name, /**< name of constraint */
14479  int nlinvars, /**< number of linear terms (n) */
14480  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14481  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14482  int nquadvarterms, /**< number of quadratic terms (m) */
14483  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
14484  int nbilinterms, /**< number of bilinear terms (p) */
14485  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
14486  SCIP_Real lhs, /**< constraint left hand side (ell) */
14487  SCIP_Real rhs, /**< constraint right hand side (u) */
14488  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
14489  SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
14490  SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
14491  SCIP_Bool check, /**< should the constraint be checked for feasibility? */
14492  SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
14493  SCIP_Bool local, /**< is constraint only valid locally? */
14494  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
14495  SCIP_Bool dynamic, /**< is constraint dynamic? */
14496  SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
14497  )
14498 {
14499  SCIP_CONSHDLR* conshdlr;
14500  SCIP_CONSDATA* consdata;
14501 
14502  assert(modifiable == FALSE); /* we do not support column generation */
14503  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
14504  assert(nquadvarterms == 0 || quadvarterms != NULL);
14505  assert(nbilinterms == 0 || bilinterms != NULL);
14506 
14507  /* find the quadratic constraint handler */
14508  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
14509  if( conshdlr == NULL )
14510  {
14511  SCIPerrorMessage("quadratic constraint handler not found\n");
14512  return SCIP_PLUGINNOTFOUND;
14513  }
14514 
14515  /* create constraint data */
14516  SCIP_CALL( consdataCreate(scip, &consdata, lhs, rhs,
14517  nlinvars, linvars, lincoefs, nquadvarterms, quadvarterms, nbilinterms, bilinterms,
14518  TRUE) );
14519 
14520  /* create constraint */
14521  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
14522  local, modifiable, dynamic, removable, FALSE) );
14523 
14524  return SCIP_OKAY;
14525 }
14526 
14527 /** creates and captures a quadratic constraint in its most basic version, i.e.,
14528  * all constraint flags are set to their default values.
14529  *
14530  * The constraint should be given in the form
14531  * \f[
14532  * \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.
14533  * \f]
14534  *
14535  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
14536  */
14538  SCIP* scip, /**< SCIP data structure */
14539  SCIP_CONS** cons, /**< pointer to hold the created constraint */
14540  const char* name, /**< name of constraint */
14541  int nlinvars, /**< number of linear terms (n) */
14542  SCIP_VAR** linvars, /**< array with variables in linear part (x_i) */
14543  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part (b_i) */
14544  int nquadvarterms, /**< number of quadratic terms (m) */
14545  SCIP_QUADVARTERM* quadvarterms, /**< quadratic variable terms */
14546  int nbilinterms, /**< number of bilinear terms (p) */
14547  SCIP_BILINTERM* bilinterms, /**< bilinear terms */
14548  SCIP_Real lhs, /**< constraint left hand side (ell) */
14549  SCIP_Real rhs /**< constraint right hand side (u) */
14550  )
14551 {
14552  SCIP_CALL( SCIPcreateConsQuadratic2(scip, cons, name, nlinvars, linvars, lincoefs,
14553  nquadvarterms, quadvarterms, nbilinterms, bilinterms, lhs, rhs,
14554  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
14555 
14556  return SCIP_OKAY;
14557 }
14558 
14559 
14560 /** Adds a constant to the constraint function, that is, subtracts a constant from both sides */
14562  SCIP* scip, /**< SCIP data structure */
14563  SCIP_CONS* cons, /**< constraint */
14564  SCIP_Real constant /**< constant to subtract from both sides */
14565  )
14566 {
14567  SCIP_CONSDATA* consdata;
14568 
14569  assert(scip != NULL);
14570  assert(cons != NULL);
14571  assert(!SCIPisInfinity(scip, REALABS(constant)));
14572 
14573  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14574  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14575  {
14576  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14577  SCIPABORT();
14578  }
14579 
14580  consdata = SCIPconsGetData(cons);
14581  assert(consdata != NULL);
14582  assert(consdata->lhs <= consdata->rhs);
14583 
14584  if( !SCIPisInfinity(scip, -consdata->lhs) )
14585  consdata->lhs -= constant;
14586  if( !SCIPisInfinity(scip, consdata->rhs) )
14587  consdata->rhs -= constant;
14588 
14589  if( consdata->lhs > consdata->rhs )
14590  {
14591  assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
14592  consdata->lhs = consdata->rhs;
14593  }
14594 }
14595 
14596 /** Adds a linear variable with coefficient to a quadratic constraint. */
14598  SCIP* scip, /**< SCIP data structure */
14599  SCIP_CONS* cons, /**< constraint */
14600  SCIP_VAR* var, /**< variable */
14601  SCIP_Real coef /**< coefficient of variable */
14602  )
14603 {
14604  assert(scip != NULL);
14605  assert(cons != NULL);
14606  assert(var != NULL);
14607  assert(!SCIPisInfinity(scip, REALABS(coef)));
14608 
14609  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14610  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14611  {
14612  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14613  return SCIP_INVALIDCALL;
14614  }
14615 
14616  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
14617 
14618  return SCIP_OKAY;
14619 }
14620 
14621 /** Adds a quadratic variable with linear and square coefficient to a quadratic constraint. */
14623  SCIP* scip, /**< SCIP data structure */
14624  SCIP_CONS* cons, /**< constraint */
14625  SCIP_VAR* var, /**< variable */
14626  SCIP_Real lincoef, /**< linear coefficient of variable */
14627  SCIP_Real sqrcoef /**< square coefficient of variable */
14628  )
14629 {
14630  assert(scip != NULL);
14631  assert(cons != NULL);
14632  assert(var != NULL);
14633  assert(!SCIPisInfinity(scip, REALABS(lincoef)));
14634  assert(!SCIPisInfinity(scip, REALABS(sqrcoef)));
14635 
14636  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14637  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14638  {
14639  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14640  return SCIP_INVALIDCALL;
14641  }
14642 
14643  SCIP_CALL( addQuadVarTerm(scip, cons, var, lincoef, sqrcoef) );
14644 
14645  return SCIP_OKAY;
14646 }
14647 
14648 /** Adds a linear coefficient for a quadratic variable.
14649  *
14650  * Variable will be added with square coefficient 0.0 if not existing yet.
14651  */
14653  SCIP* scip, /**< SCIP data structure */
14654  SCIP_CONS* cons, /**< constraint */
14655  SCIP_VAR* var, /**< variable */
14656  SCIP_Real coef /**< value to add to linear coefficient of variable */
14657  )
14658 {
14659  SCIP_CONSDATA* consdata;
14660  int pos;
14661 
14662  assert(scip != NULL);
14663  assert(cons != NULL);
14664  assert(var != NULL);
14665  assert(!SCIPisInfinity(scip, REALABS(coef)));
14666 
14667  if( SCIPisZero(scip, coef) )
14668  return SCIP_OKAY;
14669 
14670  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14671  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14672  {
14673  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14674  return SCIP_INVALIDCALL;
14675  }
14676 
14677  consdata = SCIPconsGetData(cons);
14678  assert(consdata != NULL);
14679 
14680  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
14681  if( pos < 0 )
14682  {
14683  SCIP_CALL( addQuadVarTerm(scip, cons, var, coef, 0.0) );
14684  return SCIP_OKAY;
14685  }
14686  assert(pos < consdata->nquadvars);
14687  assert(consdata->quadvarterms[pos].var == var);
14688 
14689  consdata->quadvarterms[pos].lincoef += coef;
14690 
14691  /* update flags and invalid activities */
14692  consdata->ispropagated = FALSE;
14693  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].lincoef);
14694 
14695  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14696  consdata->activity = SCIP_INVALID;
14697 
14698  return SCIP_OKAY;
14699 }
14700 
14701 /** Adds a square coefficient for a quadratic variable.
14702  *
14703  * Variable will be added with linear coefficient 0.0 if not existing yet.
14704  */
14706  SCIP* scip, /**< SCIP data structure */
14707  SCIP_CONS* cons, /**< constraint */
14708  SCIP_VAR* var, /**< variable */
14709  SCIP_Real coef /**< value to add to square coefficient of variable */
14710  )
14711 {
14712  SCIP_CONSDATA* consdata;
14713  int pos;
14714 
14715  assert(scip != NULL);
14716  assert(cons != NULL);
14717  assert(var != NULL);
14718  assert(!SCIPisInfinity(scip, REALABS(coef)));
14719 
14720  if( SCIPisZero(scip, coef) )
14721  return SCIP_OKAY;
14722 
14723  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14724  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14725  {
14726  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14727  return SCIP_INVALIDCALL;
14728  }
14729 
14730  consdata = SCIPconsGetData(cons);
14731  assert(consdata != NULL);
14732 
14733  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var, &pos) );
14734  if( pos < 0 )
14735  {
14736  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
14737  return SCIP_OKAY;
14738  }
14739  assert(pos < consdata->nquadvars);
14740  assert(consdata->quadvarterms[pos].var == var);
14741 
14742  consdata->quadvarterms[pos].sqrcoef += coef;
14743 
14744  /* update flags and invalid activities */
14745  consdata->isconvex = FALSE;
14746  consdata->isconcave = FALSE;
14747  consdata->iscurvchecked = FALSE;
14748  consdata->ispropagated = FALSE;
14749  consdata->ispresolved = consdata->ispresolved && !SCIPisZero(scip, consdata->quadvarterms[pos].sqrcoef);
14750 
14751  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
14752  consdata->activity = SCIP_INVALID;
14753 
14754  return SCIP_OKAY;
14755 }
14756 
14757 /** Adds a bilinear term to a quadratic constraint.
14758  *
14759  * Variables will be added with linear and square coefficient 0.0 if not existing yet.
14760  * If variables are equal, only the square coefficient of the variable is updated.
14761  */
14763  SCIP* scip, /**< SCIP data structure */
14764  SCIP_CONS* cons, /**< constraint */
14765  SCIP_VAR* var1, /**< first variable */
14766  SCIP_VAR* var2, /**< second variable */
14767  SCIP_Real coef /**< coefficient of bilinear term */
14768  )
14769 {
14770  SCIP_CONSDATA* consdata;
14771  int var1pos;
14772  int var2pos;
14773 
14774  assert(scip != NULL);
14775  assert(cons != NULL);
14776  assert(var1 != NULL);
14777  assert(var2 != NULL);
14778  assert(!SCIPisInfinity(scip, REALABS(coef)));
14779 
14780  /* nlrow and solving data (see initsol) may become invalid when changing constraint */
14781  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsEnabled(cons) )
14782  {
14783  SCIPerrorMessage("Cannot modify enabled constraint in solving stage.\n");
14784  return SCIP_INVALIDCALL;
14785  }
14786 
14787  if( var1 == var2 )
14788  {
14789  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, cons, var1, coef) );
14790  return SCIP_OKAY;
14791  }
14792 
14793  consdata = SCIPconsGetData(cons);
14794  assert(consdata != NULL);
14795 
14796  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
14797  if( var1pos < 0 )
14798  {
14799  SCIP_CALL( addQuadVarTerm(scip, cons, var1, 0.0, 0.0) );
14800  var1pos = consdata->nquadvars-1;
14801  }
14802 
14803  if( !consdata->quadvarssorted )
14804  {
14805  SCIP_CALL( consdataSortQuadVarTerms(scip, consdata) );
14806  /* sorting may change the position of var1 */
14807  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var1, &var1pos) );
14808  assert(var1pos >= 0);
14809  }
14810 
14811  assert(consdata->quadvarssorted);
14812  SCIP_CALL( consdataFindQuadVarTerm(scip, consdata, var2, &var2pos) );
14813  if( var2pos < 0 )
14814  {
14815  SCIP_CALL( addQuadVarTerm(scip, cons, var2, 0.0, 0.0) );
14816  var2pos = consdata->nquadvars-1;
14817  }
14818 
14819  assert(consdata->quadvarterms[var1pos].var == var1);
14820  assert(consdata->quadvarterms[var2pos].var == var2);
14821 
14822  SCIP_CALL( addBilinearTerm(scip, cons, var1pos, var2pos, coef) );
14823 
14824  return SCIP_OKAY;
14825 }
14826 
14827 /** Gets the quadratic constraint as a nonlinear row representation. */
14829  SCIP* scip, /**< SCIP data structure */
14830  SCIP_CONS* cons, /**< constraint */
14831  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
14832  )
14833 {
14834  SCIP_CONSDATA* consdata;
14835 
14836  assert(cons != NULL);
14837  assert(nlrow != NULL);
14838 
14839  consdata = SCIPconsGetData(cons);
14840  assert(consdata != NULL);
14841 
14842  if( consdata->nlrow == NULL )
14843  {
14844  SCIP_CALL( createNlRow(scip, cons) );
14845  }
14846  assert(consdata->nlrow != NULL);
14847  *nlrow = consdata->nlrow;
14848 
14849  return SCIP_OKAY;
14850 }
14851 
14852 /** Gets the number of variables in the linear term of a quadratic constraint. */
14854  SCIP* scip, /**< SCIP data structure */
14855  SCIP_CONS* cons /**< constraint */
14856  )
14857 {
14858  assert(cons != NULL);
14859  assert(SCIPconsGetData(cons) != NULL);
14860 
14861  return SCIPconsGetData(cons)->nlinvars;
14862 }
14863 
14864 /** Gets the variables in the linear part of a quadratic constraint.
14865  * Length is given by SCIPgetNLinearVarsQuadratic.
14866  */
14868  SCIP* scip, /**< SCIP data structure */
14869  SCIP_CONS* cons /**< constraint */
14870  )
14871 {
14872  assert(cons != NULL);
14873  assert(SCIPconsGetData(cons) != NULL);
14874 
14875  return SCIPconsGetData(cons)->linvars;
14876 }
14877 
14878 /** Gets the coefficients in the linear part of a quadratic constraint.
14879  * Length is given by SCIPgetNLinearVarsQuadratic.
14880  */
14882  SCIP* scip, /**< SCIP data structure */
14883  SCIP_CONS* cons /**< constraint */
14884  )
14885 {
14886  assert(cons != NULL);
14887  assert(SCIPconsGetData(cons) != NULL);
14888 
14889  return SCIPconsGetData(cons)->lincoefs;
14890 }
14891 
14892 /** Gets the number of quadratic variable terms of a quadratic constraint.
14893  */
14895  SCIP* scip, /**< SCIP data structure */
14896  SCIP_CONS* cons /**< constraint */
14897  )
14898 {
14899  assert(cons != NULL);
14900  assert(SCIPconsGetData(cons) != NULL);
14901 
14902  return SCIPconsGetData(cons)->nquadvars;
14903 }
14904 
14905 /** Gets the quadratic variable terms of a quadratic constraint.
14906  * Length is given by SCIPgetNQuadVarTermsQuadratic.
14907  */
14909  SCIP* scip, /**< SCIP data structure */
14910  SCIP_CONS* cons /**< constraint */
14911  )
14912 {
14913  assert(cons != NULL);
14914  assert(SCIPconsGetData(cons) != NULL);
14915 
14916  return SCIPconsGetData(cons)->quadvarterms;
14917 }
14918 
14919 /** Ensures that quadratic variable terms are sorted. */
14921  SCIP* scip, /**< SCIP data structure */
14922  SCIP_CONS* cons /**< constraint */
14923  )
14924 {
14925  assert(cons != NULL);
14926  assert(SCIPconsGetData(cons) != NULL);
14927 
14929 
14930  return SCIP_OKAY;
14931 }
14932 
14933 /** Finds the position of a quadratic variable term for a given variable.
14934  *
14935  * @note If the quadratic variable terms have not been sorted before, then a search may reorder the current order of the terms.
14936  */
14938  SCIP* scip, /**< SCIP data structure */
14939  SCIP_CONS* cons, /**< constraint */
14940  SCIP_VAR* var, /**< variable to search for */
14941  int* pos /**< buffer to store position of quadvarterm for var, or -1 if not found */
14942  )
14943 {
14944  assert(cons != NULL);
14945  assert(SCIPconsGetData(cons) != NULL);
14946  assert(var != NULL);
14947  assert(pos != NULL);
14948 
14949  SCIP_CALL( consdataFindQuadVarTerm(scip, SCIPconsGetData(cons), var, pos) );
14950 
14951  return SCIP_OKAY;
14952 }
14953 
14954 /** Gets the number of bilinear terms of a quadratic constraint. */
14956  SCIP* scip, /**< SCIP data structure */
14957  SCIP_CONS* cons /**< constraint */
14958  )
14959 {
14960  assert(cons != NULL);
14961  assert(SCIPconsGetData(cons) != NULL);
14962 
14963  return SCIPconsGetData(cons)->nbilinterms;
14964 }
14965 
14966 /** Gets the bilinear terms of a quadratic constraint.
14967  * Length is given by SCIPgetNBilinTermQuadratic.
14968  */
14970  SCIP* scip, /**< SCIP data structure */
14971  SCIP_CONS* cons /**< constraint */
14972  )
14973 {
14974  assert(cons != NULL);
14975  assert(SCIPconsGetData(cons) != NULL);
14976 
14977  return SCIPconsGetData(cons)->bilinterms;
14978 }
14979 
14980 /** Gets the left hand side of a quadratic constraint. */
14982  SCIP* scip, /**< SCIP data structure */
14983  SCIP_CONS* cons /**< constraint */
14984  )
14985 {
14986  assert(cons != NULL);
14987  assert(SCIPconsGetData(cons) != NULL);
14988 
14989  return SCIPconsGetData(cons)->lhs;
14990 }
14991 
14992 /** Gets the right hand side of a quadratic constraint. */
14994  SCIP* scip, /**< SCIP data structure */
14995  SCIP_CONS* cons /**< constraint */
14996  )
14997 {
14998  assert(cons != NULL);
14999  assert(SCIPconsGetData(cons) != NULL);
15000 
15001  return SCIPconsGetData(cons)->rhs;
15002 }
15003 
15004 /** get index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
15006  SCIP* scip, /**< SCIP data structure */
15007  SCIP_CONS* cons /**< constraint */
15008  )
15009 {
15010  SCIP_CONSDATA* consdata;
15011 
15012  assert(cons != NULL);
15013 
15014  consdata = SCIPconsGetData(cons);
15015  assert(consdata != NULL);
15016 
15017  /* check for a linear variable that can be increase or decreased without harming feasibility */
15018  consdataFindUnlockedLinearVar(scip, consdata);
15019 
15020  return consdata->linvar_maydecrease;
15021 }
15022 
15023 /** get index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
15025  SCIP* scip, /**< SCIP data structure */
15026  SCIP_CONS* cons /**< constraint */
15027  )
15028 {
15029  SCIP_CONSDATA* consdata;
15030 
15031  assert(cons != NULL);
15032 
15033  consdata = SCIPconsGetData(cons);
15034  assert(consdata != NULL);
15035 
15036  /* check for a linear variable that can be increase or decreased without harming feasibility */
15037  consdataFindUnlockedLinearVar(scip, consdata);
15038 
15039  return consdata->linvar_mayincrease;
15040 }
15041 
15042 /** Check the quadratic function of a quadratic constraint for its semi-definiteness, if not done yet. */
15044  SCIP* scip, /**< SCIP data structure */
15045  SCIP_CONS* cons /**< constraint */
15046  )
15047 {
15048  assert(cons != NULL);
15049 
15050  SCIP_CALL( checkCurvature(scip, cons, TRUE) );
15051 
15052  return SCIP_OKAY;
15053 }
15054 
15055 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) convex. */
15057  SCIP* scip, /**< SCIP data structure */
15058  SCIP_CONS* cons /**< constraint */
15059  )
15060 {
15061  SCIP_Bool determined;
15062 
15063  assert(cons != NULL);
15064  assert(SCIPconsGetData(cons) != NULL);
15065 
15066  checkCurvatureEasy(scip, cons, &determined, FALSE);
15067  assert(determined);
15068 
15069  return (SCIPconsGetData(cons)->isconvex);
15070 }
15071 
15072 /** Indicates whether the quadratic function of a quadratic constraint is (known to be) concave. */
15074  SCIP* scip, /**< SCIP data structure */
15075  SCIP_CONS* cons /**< constraint */
15076  )
15077 {
15078  SCIP_Bool determined;
15079 
15080  assert(cons != NULL);
15081  assert(SCIPconsGetData(cons) != NULL);
15082 
15083  checkCurvatureEasy(scip, cons, &determined, FALSE);
15084  assert(determined);
15085 
15086  return (SCIPconsGetData(cons)->isconcave);
15087 }
15088 
15089 /** Computes the violation of a constraint by a solution */
15091  SCIP* scip, /**< SCIP data structure */
15092  SCIP_CONS* cons, /**< constraint */
15093  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
15094  SCIP_Real* violation /**< pointer to store violation of constraint */
15095  )
15096 {
15097  SCIP_CONSDATA* consdata;
15098  SCIP_Bool solviolbounds;
15099 
15100  assert(scip != NULL);
15101  assert(cons != NULL);
15102  assert(violation != NULL);
15103 
15104  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15105  /* we don't care here whether the solution violated variable bounds */
15106 
15107  consdata = SCIPconsGetData(cons);
15108  assert(consdata != NULL);
15109 
15110  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
15111 
15112  return SCIP_OKAY;
15113 }
15114 
15115 /** Indicates whether the quadratic constraint is local w.r.t. the current local bounds.
15116  *
15117  * That is, checks whether each variable with a square term is fixed and for each bilinear term at least one variable is fixed.
15118  */
15120  SCIP* scip, /**< SCIP data structure */
15121  SCIP_CONS* cons /**< constraint */
15122  )
15123 {
15124  SCIP_CONSDATA* consdata;
15125  SCIP_VAR* var1;
15126  SCIP_VAR* var2;
15127  int i;
15128 
15129  assert(scip != NULL);
15130  assert(cons != NULL);
15131 
15132  consdata = SCIPconsGetData(cons);
15133  assert(consdata != NULL);
15134 
15135  /* check all square terms */
15136  for( i = 0; i < consdata->nquadvars; ++i )
15137  {
15138  if( consdata->quadvarterms[i].sqrcoef == 0.0 )
15139  continue;
15140 
15141  var1 = consdata->quadvarterms[i].var;
15142  assert(var1 != NULL);
15143 
15144  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) )
15145  return FALSE;
15146  }
15147 
15148  for( i = 0; i < consdata->nbilinterms; ++i )
15149  {
15150  var1 = consdata->bilinterms[i].var1;
15151  var2 = consdata->bilinterms[i].var2;
15152 
15153  assert(var1 != NULL);
15154  assert(var2 != NULL);
15155 
15156  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var1), SCIPvarGetUbLocal(var1)) &&
15157  ! SCIPisRelEQ(scip, SCIPvarGetLbLocal(var2), SCIPvarGetUbLocal(var2)) )
15158  return FALSE;
15159  }
15160 
15161  return TRUE;
15162 }
15163 
15164 /** Adds the constraint to an NLPI problem. */
15166  SCIP* scip, /**< SCIP data structure */
15167  SCIP_CONS* cons, /**< constraint */
15168  SCIP_NLPI* nlpi, /**< interface to NLP solver */
15169  SCIP_NLPIPROBLEM* nlpiprob, /**< NLPI problem where to add constraint */
15170  SCIP_HASHMAP* scipvar2nlpivar, /**< mapping from SCIP variables to variable indices in NLPI */
15171  SCIP_Bool names /**< whether to pass constraint names to NLPI */
15172  )
15173 {
15174  SCIP_CONSDATA* consdata;
15175  int nlininds;
15176  int* lininds;
15177  SCIP_Real* linvals;
15178  int nquadelems;
15179  SCIP_QUADELEM* quadelems;
15180  SCIP_VAR* othervar;
15181  const char* name;
15182  int j;
15183  int l;
15184  int lincnt;
15185  int quadcnt;
15186  int idx1;
15187  int idx2;
15188 
15189  assert(scip != NULL);
15190  assert(cons != NULL);
15191  assert(nlpi != NULL);
15192  assert(nlpiprob != NULL);
15193  assert(scipvar2nlpivar != NULL);
15194 
15195  consdata = SCIPconsGetData(cons);
15196  assert(consdata != NULL);
15197 
15198  /* count nonzeros in quadratic part */
15199  nlininds = consdata->nlinvars;
15200  nquadelems = consdata->nbilinterms;
15201  for( j = 0; j < consdata->nquadvars; ++j )
15202  {
15203  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
15204  ++nquadelems;
15205  if( consdata->quadvarterms[j].lincoef != 0.0 )
15206  ++nlininds;
15207  }
15208 
15209  /* setup linear part */
15210  lininds = NULL;
15211  linvals = NULL;
15212  lincnt = 0;
15213  if( nlininds > 0 )
15214  {
15215  SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlininds) );
15216  SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlininds) );
15217 
15218  for( j = 0; j < consdata->nlinvars; ++j )
15219  {
15220  linvals[j] = consdata->lincoefs[j];
15221  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->linvars[j]));
15222  lininds[j] = SCIPhashmapGetImageInt(scipvar2nlpivar, consdata->linvars[j]);
15223  }
15224 
15225  lincnt = consdata->nlinvars;
15226  }
15227 
15228  /* setup quadratic part */
15229  quadelems = NULL;
15230  if( nquadelems > 0 )
15231  {
15232  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nquadelems) );
15233  }
15234  quadcnt = 0;
15235 
15236  for( j = 0; j < consdata->nquadvars; ++j )
15237  {
15238  assert(SCIPhashmapExists(scipvar2nlpivar, consdata->quadvarterms[j].var));
15239  idx1 = SCIPhashmapGetImageInt(scipvar2nlpivar, consdata->quadvarterms[j].var);
15240  if( consdata->quadvarterms[j].lincoef != 0.0 )
15241  {
15242  assert(lininds != NULL);
15243  assert(linvals != NULL);
15244  /* coverity[var_deref_op] */
15245  lininds[lincnt] = idx1;
15246  linvals[lincnt] = consdata->quadvarterms[j].lincoef;
15247  ++lincnt;
15248  }
15249 
15250  if( consdata->quadvarterms[j].sqrcoef != 0.0 )
15251  {
15252  assert(quadcnt < nquadelems);
15253  assert(quadelems != NULL);
15254  /* coverity[var_deref_op] */
15255  quadelems[quadcnt].idx1 = idx1;
15256  quadelems[quadcnt].idx2 = idx1;
15257  quadelems[quadcnt].coef = consdata->quadvarterms[j].sqrcoef;
15258  ++quadcnt;
15259  }
15260 
15261  for( l = 0; l < consdata->quadvarterms[j].nadjbilin; ++l )
15262  {
15263  othervar = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].var2;
15264  /* if othervar is on position 2, then we process this bilinear term later (or it was processed already) */
15265  if( othervar == consdata->quadvarterms[j].var )
15266  continue;
15267 
15268  assert(quadcnt < nquadelems);
15269  assert(quadelems != NULL);
15270  assert(SCIPhashmapExists(scipvar2nlpivar, othervar));
15271  idx2 = SCIPhashmapGetImageInt(scipvar2nlpivar, othervar);
15272  /* coverity[var_deref_op] */
15273  quadelems[quadcnt].idx1 = MIN(idx1, idx2);
15274  quadelems[quadcnt].idx2 = MAX(idx1, idx2);
15275  quadelems[quadcnt].coef = consdata->bilinterms[consdata->quadvarterms[j].adjbilin[l]].coef;
15276  ++quadcnt;
15277  }
15278  }
15279 
15280  assert(quadcnt == nquadelems);
15281  assert(lincnt == nlininds);
15282 
15283  name = names ? SCIPconsGetName(cons) : NULL;
15284 
15285  SCIP_CALL( SCIPnlpiAddConstraints(nlpi, nlpiprob, 1,
15286  &consdata->lhs, &consdata->rhs,
15287  &nlininds, &lininds, &linvals ,
15288  &nquadelems, &quadelems,
15289  NULL, NULL, &name) );
15290 
15291  SCIPfreeBufferArrayNull(scip, &quadelems);
15292  SCIPfreeBufferArrayNull(scip, &lininds);
15293  SCIPfreeBufferArrayNull(scip, &linvals);
15294 
15295  return SCIP_OKAY;
15296 }
15297 
15298 
15299 /** sets the left hand side of a quadratic constraint
15300  *
15301  * @note This method may only be called during problem creation stage for an original constraint.
15302  */
15304  SCIP* scip, /**< SCIP data structure */
15305  SCIP_CONS* cons, /**< constraint data */
15306  SCIP_Real lhs /**< new left hand side */
15307  )
15308 {
15309  SCIP_CONSDATA* consdata;
15310 
15311  assert(scip != NULL);
15312  assert(cons != NULL);
15313  assert(!SCIPisInfinity(scip, lhs));
15314 
15315  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15316  {
15317  SCIPerrorMessage("constraint is not quadratic\n");
15318  return SCIP_INVALIDDATA;
15319  }
15320 
15321  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
15322  {
15323  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
15324  return SCIP_INVALIDDATA;
15325  }
15326 
15327  consdata = SCIPconsGetData(cons);
15328  assert(consdata != NULL);
15329  assert(!SCIPisInfinity(scip, consdata->lhs));
15330 
15331  /* adjust value to not be smaller than -inf */
15332  if( SCIPisInfinity(scip, -lhs) )
15333  lhs = -SCIPinfinity(scip);
15334 
15335  /* check for lhs <= rhs */
15336  if( !SCIPisLE(scip, lhs, consdata->rhs) )
15337  return SCIP_INVALIDDATA;
15338 
15339  consdata->lhs = lhs;
15340 
15341  return SCIP_OKAY;
15342 }
15343 
15344 /** sets the right hand side of a quadratic constraint
15345  *
15346  * @note This method may only be called during problem creation stage for an original constraint.
15347  */
15349  SCIP* scip, /**< SCIP data structure */
15350  SCIP_CONS* cons, /**< constraint data */
15351  SCIP_Real rhs /**< new right hand side */
15352  )
15353 {
15354  SCIP_CONSDATA* consdata;
15355 
15356  assert(scip != NULL);
15357  assert(cons != NULL);
15358  assert(!SCIPisInfinity(scip, -rhs));
15359 
15360  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15361  {
15362  SCIPerrorMessage("constraint is not quadratic\n");
15363  return SCIP_INVALIDDATA;
15364  }
15365 
15366  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) )
15367  {
15368  SCIPerrorMessage("method may only be called during problem creation stage for original constraints\n");
15369  return SCIP_INVALIDDATA;
15370  }
15371 
15372  consdata = SCIPconsGetData(cons);
15373  assert(consdata != NULL);
15374  assert(!SCIPisInfinity(scip, -consdata->rhs));
15375 
15376  /* adjust value to not be greater than inf */
15377  if( SCIPisInfinity(scip, rhs) )
15378  rhs = SCIPinfinity(scip);
15379 
15380  /* check for lhs <= rhs */
15381  if( !SCIPisLE(scip, consdata->lhs, rhs) )
15382  return SCIP_INVALIDDATA;
15383 
15384  consdata->rhs = rhs;
15385 
15386  return SCIP_OKAY;
15387 }
15388 
15389 /** gets the feasibility of the quadratic constraint in the given solution */
15391  SCIP* scip, /**< SCIP data structure */
15392  SCIP_CONS* cons, /**< constraint data */
15393  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
15394  SCIP_Real* feasibility /**< pointer to store the feasibility */
15395  )
15396 {
15397  SCIP_CONSDATA* consdata;
15398  SCIP_Bool solviolbounds;
15399 
15400  assert(scip != NULL);
15401  assert(cons != NULL);
15402  assert(feasibility != NULL);
15403 
15404  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15405  {
15406  SCIPerrorMessage("constraint is not quadratic\n");
15407  SCIPABORT();
15408  }
15409 
15410  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15411 
15412  consdata = SCIPconsGetData(cons);
15413  assert(consdata != NULL);
15414 
15415  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
15416  *feasibility = SCIPinfinity(scip);
15417  else if( SCIPisInfinity(scip, -consdata->lhs) )
15418  *feasibility = (consdata->rhs - consdata->activity);
15419  else if( SCIPisInfinity(scip, consdata->rhs) )
15420  *feasibility = (consdata->activity - consdata->lhs);
15421  else
15422  {
15423  assert(!SCIPisInfinity(scip, -consdata->rhs));
15424  assert(!SCIPisInfinity(scip, consdata->lhs));
15425  *feasibility = MIN( consdata->rhs - consdata->activity, consdata->activity - consdata->lhs );
15426  }
15427 
15428  return SCIP_OKAY;
15429 }
15430 
15431 /** gets the activity of the quadratic constraint in the given solution */
15433  SCIP* scip, /**< SCIP data structure */
15434  SCIP_CONS* cons, /**< constraint data */
15435  SCIP_SOL* sol, /**< solution, or NULL to use current node's solution */
15436  SCIP_Real* activity /**< pointer to store the activity */
15437  )
15438 {
15439  SCIP_CONSDATA* consdata;
15440  SCIP_Bool solviolbounds;
15441 
15442  assert(scip != NULL);
15443  assert(cons != NULL);
15444  assert(activity != NULL);
15445 
15446  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15447  {
15448  SCIPerrorMessage("constraint is not quadratic\n");
15449  SCIPABORT();
15450  }
15451 
15452  SCIP_CALL( computeViolation(scip, cons, sol, &solviolbounds) );
15453 
15454  consdata = SCIPconsGetData(cons);
15455  assert(consdata != NULL);
15456 
15457  *activity = consdata->activity;
15458 
15459  return SCIP_OKAY;
15460 }
15461 
15462 /** changes the linear coefficient value for a given quadratic variable in a quadratic constraint data; if not
15463  * available, it adds it
15464  *
15465  * @note this is only allowed for original constraints and variables in problem creation stage
15466  */
15468  SCIP* scip, /**< SCIP data structure */
15469  SCIP_CONS* cons, /**< constraint data */
15470  SCIP_VAR* var, /**< quadratic variable */
15471  SCIP_Real coef /**< new coefficient */
15472  )
15473 {
15474  SCIP_CONSDATA* consdata;
15475  SCIP_Bool found;
15476  int i;
15477 
15478  assert(scip != NULL);
15479  assert(cons != NULL);
15480  assert(var != NULL);
15481 
15482  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15483  {
15484  SCIPerrorMessage("constraint is not quadratic\n");
15485  return SCIP_INVALIDDATA;
15486  }
15487 
15488  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
15489  {
15490  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15491  return SCIP_INVALIDDATA;
15492  }
15493 
15494  consdata = SCIPconsGetData(cons);
15495  assert(consdata != NULL);
15496 
15497  /* check all quadratic variables */
15498  found = FALSE;
15499  for( i = 0; i < consdata->nquadvars; ++i )
15500  {
15501  if( var == consdata->quadvarterms[i].var )
15502  {
15503  if( found || SCIPisZero(scip, coef) )
15504  {
15505  consdata->quadvarterms[i].lincoef = 0.0;
15506 
15507  /* remember to merge quadratic variable terms */
15508  consdata->quadvarsmerged = FALSE;
15509  }
15510  else
15511  consdata->quadvarterms[i].lincoef = coef;
15512 
15513  found = TRUE;
15514  }
15515  }
15516 
15517  /* check all linear variables */
15518  i = 0;
15519  while( i < consdata->nlinvars )
15520  {
15521  if( var == consdata->linvars[i] )
15522  {
15523  if( found || SCIPisZero(scip, coef) )
15524  {
15525  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
15526 
15527  /* decrease i by one since otherwise we would skip the coefficient which has been switched to position i */
15528  i--;
15529  }
15530  else
15531  {
15532  SCIP_CALL( chgLinearCoefPos(scip, cons, i, coef) );
15533  }
15534 
15535  found = TRUE;
15536  }
15537  i++;
15538  }
15539 
15540  /* add linear term if necessary */
15541  if( !found && !SCIPisZero(scip, coef) )
15542  {
15543  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
15544  }
15545 
15546  consdata->ispropagated = FALSE;
15547  consdata->ispresolved = FALSE;
15548 
15549  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15550  consdata->activity = SCIP_INVALID;
15551 
15552  return SCIP_OKAY;
15553 }
15554 
15555 /** changes the square coefficient value for a given quadratic variable in a quadratic constraint data; if not
15556  * available, it adds it
15557  *
15558  * @note this is only allowed for original constraints and variables in problem creation stage
15559  */
15561  SCIP* scip, /**< SCIP data structure */
15562  SCIP_CONS* cons, /**< constraint data */
15563  SCIP_VAR* var, /**< quadratic variable */
15564  SCIP_Real coef /**< new coefficient */
15565  )
15566 {
15567  SCIP_CONSDATA* consdata;
15568  SCIP_Bool found;
15569  int i;
15570 
15571  assert(scip != NULL);
15572  assert(cons != NULL);
15573  assert(var != NULL);
15574  assert(!SCIPisInfinity(scip, REALABS(coef)));
15575 
15576  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15577  {
15578  SCIPerrorMessage("constraint is not quadratic\n");
15579  return SCIP_INVALIDDATA;
15580  }
15581 
15582  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
15583  {
15584  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15585  return SCIP_INVALIDDATA;
15586  }
15587 
15588  consdata = SCIPconsGetData(cons);
15589  assert(consdata != NULL);
15590 
15591  /* find the quadratic variable and change its quadratic coefficient */
15592  found = FALSE;
15593  for( i = 0; i < consdata->nquadvars; ++i )
15594  {
15595  if( var == consdata->quadvarterms[i].var )
15596  {
15597  consdata->quadvarterms[i].sqrcoef = (found || SCIPisZero(scip, coef)) ? 0.0 : coef;
15598  found = TRUE;
15599  }
15600  }
15601 
15602  /* add bilinear term if necessary */
15603  if( !found && !SCIPisZero(scip, coef) )
15604  {
15605  SCIP_CALL( addQuadVarTerm(scip, cons, var, 0.0, coef) );
15606  }
15607 
15608  /* update flags and invalidate activities */
15609  consdata->isconvex = FALSE;
15610  consdata->isconcave = FALSE;
15611  consdata->iscurvchecked = FALSE;
15612  consdata->ispropagated = FALSE;
15613  consdata->ispresolved = FALSE;
15614 
15615  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15616  consdata->activity = SCIP_INVALID;
15617 
15618  /* remember to merge quadratic variable terms */
15619  consdata->quadvarsmerged = FALSE;
15620 
15621  return SCIP_OKAY;
15622 }
15623 
15624 /** changes the bilinear coefficient value for a given quadratic variable in a quadratic constraint data; if not
15625  * available, it adds it
15626  *
15627  * @note this is only allowed for original constraints and variables in problem creation stage
15628  */
15630  SCIP* scip, /**< SCIP data structure */
15631  SCIP_CONS* cons, /**< constraint */
15632  SCIP_VAR* var1, /**< first variable */
15633  SCIP_VAR* var2, /**< second variable */
15634  SCIP_Real coef /**< coefficient of bilinear term */
15635  )
15636 {
15637  SCIP_CONSDATA* consdata;
15638  SCIP_Bool found;
15639  int i;
15640 
15641  assert(scip != NULL);
15642  assert(cons != NULL);
15643  assert(var1 != NULL);
15644  assert(var2 != NULL);
15645  assert(!SCIPisInfinity(scip, REALABS(coef)));
15646 
15647  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
15648  {
15649  SCIPerrorMessage("constraint is not quadratic\n");
15650  return SCIP_INVALIDDATA;
15651  }
15652 
15653  if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var1) || !SCIPvarIsOriginal(var2) )
15654  {
15655  SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
15656  return SCIP_INVALIDDATA;
15657  }
15658 
15659  if( var1 == var2 )
15660  {
15661  SCIP_CALL( SCIPchgSquareCoefQuadratic(scip, cons, var1, coef) );
15662  return SCIP_OKAY;
15663  }
15664 
15665  consdata = SCIPconsGetData(cons);
15666  assert(consdata != NULL);
15667 
15668  /* search array of bilinear terms */
15669  found = FALSE;
15670  for( i = 0; i < consdata->nbilinterms; ++i )
15671  {
15672  if( (consdata->bilinterms[i].var1 == var1 && consdata->bilinterms[i].var2 == var2) ||
15673  (consdata->bilinterms[i].var1 == var2 && consdata->bilinterms[i].var2 == var1) )
15674  {
15675  if( found || SCIPisZero(scip, coef) )
15676  {
15677  consdata->bilinterms[i].coef = 0.0;
15678 
15679  /* remember to merge bilinear terms */
15680  consdata->bilinmerged = FALSE;
15681  }
15682  else
15683  consdata->bilinterms[i].coef = coef;
15684  found = TRUE;
15685  }
15686  }
15687 
15688  /* add bilinear term if necessary */
15689  if( !found )
15690  {
15691  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, cons, var1, var2, coef) );
15692  }
15693 
15694  /* update flags and invalidate activities */
15695  consdata->isconvex = FALSE;
15696  consdata->isconcave = FALSE;
15697  consdata->iscurvchecked = FALSE;
15698  consdata->ispropagated = FALSE;
15699  consdata->ispresolved = FALSE;
15700 
15701  SCIPintervalSetEmpty(&consdata->quadactivitybounds);
15702  consdata->activity = SCIP_INVALID;
15703 
15704  return SCIP_OKAY;
15705 }
15706 
15707 /** returns the total number of bilinear terms that are contained in all quadratic constraints */
15709  SCIP* scip /**< SCIP data structure */
15710  )
15711 {
15712  SCIP_CONSHDLRDATA* conshdlrdata;
15713  SCIP_CONSHDLR* conshdlr;
15714 
15715  assert(scip != NULL);
15716 
15717  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15718 
15719  if( conshdlr == NULL )
15720  return 0;
15721 
15722  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15723  assert(conshdlrdata != NULL);
15724 
15725  return conshdlrdata->nbilinterms;
15726 }
15727 
15728 /** returns all bilinear terms that are contained in all quadratic constraints */
15730  SCIP* scip, /**< SCIP data structure */
15731  SCIP_VAR** RESTRICT x, /**< array to store first variable of each bilinear term */
15732  SCIP_VAR** RESTRICT y, /**< array to second variable of each bilinear term */
15733  int* RESTRICT nbilinterms, /**< buffer to store the total number of bilinear terms */
15734  int* RESTRICT nunderests, /**< array to store the total number of constraints that require to underestimate a bilinear term */
15735  int* RESTRICT noverests, /**< array to store the total number of constraints that require to overestimate a bilinear term */
15736  SCIP_Real* maxnonconvexity /**< largest absolute value of nonconvex eigenvalues of all quadratic constraints containing a bilinear term */
15737  )
15738 {
15739  SCIP_CONSHDLRDATA* conshdlrdata;
15740  SCIP_CONSHDLR* conshdlr;
15741  int i;
15742 
15743  assert(scip != NULL);
15744  assert(x != NULL);
15745  assert(y != NULL);
15746  assert(nbilinterms != NULL);
15747  assert(nunderests != NULL);
15748  assert(noverests!= NULL);
15749  assert(maxnonconvexity != NULL);
15750 
15751  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15752 
15753  if( conshdlr == NULL )
15754  {
15755  *nbilinterms = 0;
15756  return SCIP_OKAY;
15757  }
15758 
15759  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15760  assert(conshdlrdata != NULL);
15761 
15762  for( i = 0; i < conshdlrdata->nbilinterms; ++i )
15763  {
15764  x[i] = conshdlrdata->bilinestimators[i].x;
15765  y[i] = conshdlrdata->bilinestimators[i].y;
15766  nunderests[i] = conshdlrdata->bilinestimators[i].nunderest;
15767  noverests[i] = conshdlrdata->bilinestimators[i].noverest;
15768  maxnonconvexity[i] = conshdlrdata->bilinestimators[i].maxnonconvexity;
15769  }
15770 
15771  *nbilinterms = conshdlrdata->nbilinterms;
15772 
15773  return SCIP_OKAY;
15774 }
15775 
15776 /** helper function to compute the violation of an inequality of the form xcoef * x <= ycoef * y + constant for two
15777  * corner points of the domain [lbx,ubx]x[lby,uby]
15778  */
15779 static
15780 void getIneqViol(
15781  SCIP_VAR* x, /**< first variable */
15782  SCIP_VAR* y, /**< second variable */
15783  SCIP_Real xcoef, /**< x-coefficient */
15784  SCIP_Real ycoef, /**< y-coefficient */
15785  SCIP_Real constant, /**< constant */
15786  SCIP_Real* viol1, /**< buffer to store the violation of the first corner point */
15787  SCIP_Real* viol2 /**< buffer to store the violation of the second corner point */
15788  )
15789 {
15790  SCIP_Real norm;
15791 
15792  assert(viol1 != NULL);
15793  assert(viol2 != NULL);
15794 
15795  norm = SQRT(SQR(xcoef) + SQR(ycoef));
15796 
15797  /* inequality can be used for underestimating xy if and only if xcoef * ycoef > 0 */
15798  if( xcoef * ycoef >= 0 )
15799  {
15800  /* violation for top-left and bottom-right corner */
15801  *viol1 = MAX(0, (xcoef * SCIPvarGetLbLocal(x) - ycoef * SCIPvarGetUbLocal(y) - constant) / norm); /*lint !e666*/
15802  *viol2 = MAX(0, (xcoef * SCIPvarGetUbLocal(x) - ycoef * SCIPvarGetLbLocal(y) - constant) / norm); /*lint !e666*/
15803  }
15804  else
15805  {
15806  /* violation for top-right and bottom-left corner */
15807  *viol1 = MAX(0, (xcoef * SCIPvarGetUbLocal(x) - ycoef * SCIPvarGetUbLocal(y) - constant) / norm); /*lint !e666*/
15808  *viol2 = MAX(0, (xcoef * SCIPvarGetLbLocal(x) - ycoef * SCIPvarGetLbLocal(y) - constant) / norm); /*lint !e666*/
15809  }
15810 
15811  return;
15812 }
15813 
15814 /** adds a globally valid inequality of the form xcoef x <= ycoef y + constant for a bilinear term (x,y)
15815  *
15816  * @note the indices of bilinear terms match with the entries of bilinear terms returned by SCIPgetAllBilinearTermsQuadratic
15817  */
15819  SCIP* scip, /**< SCIP data structure */
15820  SCIP_VAR* x, /**< first variable */
15821  SCIP_VAR* y, /**< second variable */
15822  int idx, /**< index of the bilinear term */
15823  SCIP_Real xcoef, /**< x coefficient */
15824  SCIP_Real ycoef, /**< y coefficient */
15825  SCIP_Real constant, /**< constant part */
15826  SCIP_Bool* success /**< buffer to store whether inequality has been accepted */
15827  )
15828 {
15829  SCIP_CONSHDLRDATA* conshdlrdata;
15830  SCIP_CONSHDLR* conshdlr;
15831  BILINESTIMATOR* bilinest;
15832  SCIP_Real* ineqs;
15833  SCIP_Real viol1 = 0.0;
15834  SCIP_Real viol2 = 0.0;
15835  int* nineqs;
15836  int i;
15837 
15838  assert(scip != NULL);
15839  assert(x != NULL);
15840  assert(y != NULL);
15841  assert(idx >= 0);
15842  assert(xcoef != SCIP_INVALID); /*lint !e777 */
15843  assert(ycoef != SCIP_INVALID); /*lint !e777 */
15844  assert(constant != SCIP_INVALID); /*lint !e777 */
15845  assert(success != NULL);
15846 
15847  *success = FALSE;
15848 
15849  /* ignore inequalities that only yield to a (possible) bound tightening */
15850  if( SCIPisFeasZero(scip, xcoef) || SCIPisFeasZero(scip, ycoef) )
15851  return SCIP_OKAY;
15852 
15853  /* get constraint handler and its data */
15854  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15855  if( conshdlr == NULL )
15856  return SCIP_OKAY;
15857 
15858  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15859  assert(conshdlrdata != NULL);
15860  assert(idx < conshdlrdata->nbilinterms);
15861 
15862  bilinest = &conshdlrdata->bilinestimators[idx];
15863  assert(bilinest != NULL);
15864  assert(bilinest->x == x);
15865  assert(bilinest->y == y);
15866 
15867  SCIPdebugMsg(scip, "add bilinear term inequality: %g %s <= %g %s + %g\n", xcoef, SCIPvarGetName(bilinest->x),
15868  ycoef, SCIPvarGetName(bilinest->y), constant);
15869 
15870  if( xcoef * ycoef > 0.0 )
15871  {
15872  ineqs = bilinest->inequnderest;
15873  nineqs = &bilinest->ninequnderest;
15874  }
15875  else
15876  {
15877  ineqs = bilinest->ineqoverest;
15878  nineqs = &bilinest->nineqoverest;
15879  }
15880 
15881  /* compute violation of the inequality of the important corner points */
15882  getIneqViol(x, y, xcoef, ycoef, constant, &viol1, &viol2);
15883  SCIPdebugMsg(scip, "violations of inequality = (%g,%g)\n", viol1, viol2);
15884 
15885  /* inequality does not cut off one of the important corner points */
15886  if( SCIPisFeasLE(scip, MAX(viol1, viol2), 0.0) )
15887  return SCIP_OKAY;
15888 
15889  /* check whether inequality exists already */
15890  for( i = 0; i < *nineqs; ++i )
15891  {
15892  if( SCIPisFeasEQ(scip, xcoef, ineqs[3*i]) && SCIPisFeasEQ(scip, ycoef, ineqs[3*i+1])
15893  && SCIPisFeasEQ(scip, constant, ineqs[3*i+2]) )
15894  {
15895  SCIPdebugMsg(scip, "inequality already found -> skip\n");
15896  return SCIP_OKAY;
15897  }
15898  }
15899 
15900  /* add inequality if we found less than two so far; otherwise compare the violations to decide which which
15901  * inequality might be replaced
15902  */
15903  if( *nineqs < 2 )
15904  {
15905  ineqs[3*(*nineqs)] = xcoef;
15906  ineqs[3*(*nineqs) + 1] = ycoef;
15907  ineqs[3*(*nineqs) + 2] = constant;
15908  ++(*nineqs);
15909  *success = TRUE;
15910  }
15911  else
15912  {
15913  SCIP_Real viols1[2] = {0.0, 0.0};
15914  SCIP_Real viols2[2] = {0.0, 0.0};
15915  SCIP_Real bestviol;
15916  int pos = -1;
15917 
15918  assert(*nineqs == 2);
15919 
15920  /* compute resulting violations of both corner points when replacing an existing inequality
15921  *
15922  * given the violations (v1,w1), (v2,w2), (v3,w3) we select two inequalities i and j that
15923  * maximize max{vi,vj} + max{wi,wj} this measurement guarantees that select inequalities that
15924  * separate both important corner points
15925  */
15926  getIneqViol(x, y, ineqs[0], ineqs[1], ineqs[2], &viols1[0], &viols2[0]);
15927  getIneqViol(x, y, ineqs[3], ineqs[4], ineqs[5], &viols1[1], &viols2[1]);
15928  bestviol = MAX(viols1[0], viols1[1]) + MAX(viols2[0], viols2[1]);
15929 
15930  for( i = 0; i < 2; ++i )
15931  {
15932  SCIP_Real viol = MAX(viol1, viols1[i]) + MAX(viol2, viols2[i]);
15933  if( SCIPisGT(scip, viol, bestviol) )
15934  {
15935  bestviol = viol;
15936  /* remember inequality that should be replaced */
15937  pos = 1 - i;
15938  }
15939  }
15940 
15941  /* replace inequality at pos when replacing an existing inequality improved the total violation */
15942  if( pos != -1 )
15943  {
15944  assert(pos >= 0 && pos < 2);
15945  ineqs[3*pos] = xcoef;
15946  ineqs[3*pos+1] = ycoef;
15947  ineqs[3*pos+2] = constant;
15948  *success = TRUE;
15949  }
15950  }
15951  SCIPdebugMsg(scip, "accepted inequality? %u\n", *success);
15952 
15953  return SCIP_OKAY;
15954 }
15955 
15956 
15957 /** creates a SCIP_ROWPREP datastructure
15958  *
15959  * Initial cut represents 0 <= 0.
15960  */
15962  SCIP* scip, /**< SCIP data structure */
15963  SCIP_ROWPREP** rowprep, /**< buffer to store pointer to rowprep */
15964  SCIP_SIDETYPE sidetype, /**< whether cut will be or lower-equal or larger-equal type */
15965  SCIP_Bool local /**< whether cut will be valid only locally */
15966  )
15967 {
15968  assert(scip != NULL);
15969  assert(rowprep != NULL);
15970 
15971  SCIP_CALL( SCIPallocBlockMemory(scip, rowprep) );
15972  BMSclearMemory(*rowprep);
15973 
15974  (*rowprep)->sidetype = sidetype;
15975  (*rowprep)->local = local;
15976 
15977  return SCIP_OKAY;
15978 }
15979 
15980 /** frees a SCIP_ROWPREP datastructure */
15981 void SCIPfreeRowprep(
15982  SCIP* scip, /**< SCIP data structure */
15983  SCIP_ROWPREP** rowprep /**< pointer that stores pointer to rowprep */
15984  )
15985 {
15986  assert(scip != NULL);
15987  assert(rowprep != NULL);
15988  assert(*rowprep != NULL);
15989 
15990  SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->vars, (*rowprep)->varssize);
15991  SCIPfreeBlockMemoryArrayNull(scip, &(*rowprep)->coefs, (*rowprep)->varssize);
15992  SCIPfreeBlockMemory(scip, rowprep);
15993 }
15994 
15995 /** creates a copy of a SCIP_ROWPREP datastructure */
15997  SCIP* scip, /**< SCIP data structure */
15998  SCIP_ROWPREP** target, /**< buffer to store pointer of rowprep copy */
15999  SCIP_ROWPREP* source /**< rowprep to copy */
16000  )
16001 {
16002  assert(scip != NULL);
16003  assert(target != NULL);
16004  assert(source != NULL);
16005 
16006  SCIP_CALL( SCIPduplicateBlockMemory(scip, target, source) );
16007  if( source->coefs != NULL )
16008  {
16009  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->coefs, source->coefs, source->varssize) );
16010  }
16011  if( source->vars != NULL )
16012  {
16013  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*target)->vars, source->vars, source->varssize) );
16014  }
16015 
16016  return SCIP_OKAY;
16017 }
16018 
16019 /** ensures that rowprep has space for at least given number of additional terms
16020  *
16021  * Useful when knowing in advance how many terms will be added.
16022  */
16024  SCIP* scip, /**< SCIP data structure */
16025  SCIP_ROWPREP* rowprep, /**< rowprep */
16026  int size /**< number of additional terms for which to alloc space in rowprep */
16027  )
16028 {
16029  int oldsize;
16030 
16031  assert(scip != NULL);
16032  assert(rowprep != NULL);
16033  assert(size >= 0);
16034 
16035  if( rowprep->varssize >= rowprep->nvars + size )
16036  return SCIP_OKAY; /* already enough space left */
16037 
16038  /* realloc vars and coefs array */
16039  oldsize = rowprep->varssize;
16040  rowprep->varssize = SCIPcalcMemGrowSize(scip, rowprep->nvars + size);
16041 
16042  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->vars, oldsize, rowprep->varssize) );
16043  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &rowprep->coefs, oldsize, rowprep->varssize) );
16044 
16045  return SCIP_OKAY;
16046 }
16047 
16048 /** prints a rowprep */
16049 void SCIPprintRowprep(
16050  SCIP* scip, /**< SCIP data structure */
16051  SCIP_ROWPREP* rowprep, /**< rowprep to be printed */
16052  FILE* file /**< file to print to, or NULL for stdout */
16053  )
16054 {
16055  int i;
16056 
16057  assert(scip != NULL);
16058  assert(rowprep != NULL);
16059 
16060  if( *rowprep->name != '\0' )
16061  {
16062  SCIPinfoMessage(scip, file, "[%s](%c) ", rowprep->name, rowprep->local ? 'l' : 'g');
16063  }
16064 
16065  for( i = 0; i < rowprep->nvars; ++i )
16066  {
16067  SCIPinfoMessage(scip, file, "%+.15g*<%s> ", rowprep->coefs[i], SCIPvarGetName(rowprep->vars[i]));
16068  }
16069 
16070  SCIPinfoMessage(scip, file, rowprep->sidetype == SCIP_SIDETYPE_LEFT ? ">= %.15g\n" : "<= %.15g\n", rowprep->side);
16071 }
16072 
16073 /** adds a term coef*var to a rowprep */
16075  SCIP* scip, /**< SCIP data structure */
16076  SCIP_ROWPREP* rowprep, /**< rowprep */
16077  SCIP_VAR* var, /**< variable to add */
16078  SCIP_Real coef /**< coefficient to add */
16079  )
16080 {
16081  assert(scip != NULL);
16082  assert(rowprep != NULL);
16083  assert(var != NULL);
16084 
16085  if( coef == 0.0 )
16086  return SCIP_OKAY;
16087 
16088  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, 1) );
16089  assert(rowprep->varssize > rowprep->nvars);
16090 
16091  rowprep->vars[rowprep->nvars] = var;
16092  rowprep->coefs[rowprep->nvars] = coef;
16093  ++rowprep->nvars;
16094 
16095  return SCIP_OKAY;
16096 }
16097 
16098 /** adds several terms coef*var to a rowprep */
16100  SCIP* scip, /**< SCIP data structure */
16101  SCIP_ROWPREP* rowprep, /**< rowprep */
16102  int nvars, /**< number of terms to add */
16103  SCIP_VAR** vars, /**< variables to add */
16104  SCIP_Real* coefs /**< coefficients to add */
16105  )
16106 {
16107  assert(scip != NULL);
16108  assert(rowprep != NULL);
16109  assert(vars != NULL || nvars == 0);
16110  assert(coefs != NULL || nvars == 0);
16111 
16112  if( nvars == 0 )
16113  return SCIP_OKAY;
16114 
16115  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nvars) );
16116  assert(rowprep->varssize >= rowprep->nvars + nvars);
16117 
16118  /*lint --e{866} */
16119  BMScopyMemoryArray(rowprep->vars + rowprep->nvars, vars, nvars);
16120  BMScopyMemoryArray(rowprep->coefs + rowprep->nvars, coefs, nvars);
16121  rowprep->nvars += nvars;
16122 
16123  return SCIP_OKAY;
16124 }
16125 
16126 #ifdef NDEBUG
16127 #undef SCIPaddRowprepSide
16128 #undef SCIPaddRowprepConstant
16129 #endif
16130 
16131 /** adds constant value to side of rowprep */
16132 void SCIPaddRowprepSide(
16133  SCIP_ROWPREP* rowprep, /**< rowprep */
16134  SCIP_Real side /**< constant value to be added to side */
16135  )
16136 {
16137  assert(rowprep != NULL);
16138 
16139  rowprep->side += side;
16140 }
16141 
16142 /** adds constant term to rowprep
16143  *
16144  * Substracts constant from side.
16145  */
16147  SCIP_ROWPREP* rowprep, /**< rowprep */
16148  SCIP_Real constant /**< constant value to be added */
16149  )
16150 {
16151  assert(rowprep != NULL);
16152 
16153  SCIPaddRowprepSide(rowprep, -constant);
16154 }
16155 
16156 /** computes violation of cut in a given solution */
16158  SCIP* scip, /**< SCIP data structure */
16159  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
16160  SCIP_SOL* sol /**< solution or NULL for LP solution */
16161  )
16162 {
16163  SCIP_Real activity;
16164  int i;
16165 
16166  activity = 0.0;
16167  for( i = 0; i < rowprep->nvars; ++i )
16168  {
16169  /* Loose variable have the best bound as LP solution value.
16170  * HOWEVER, they become column variables when they are added to a row (via SCIPaddVarsToRow below).
16171  * When this happens, their LP solution value changes to 0.0!
16172  * So when calculating the row activity for an LP solution, we treat loose variable as if they were already column variables.
16173  */
16174  if( sol != NULL || SCIPvarGetStatus(rowprep->vars[i]) != SCIP_VARSTATUS_LOOSE )
16175  activity += rowprep->coefs[i] * SCIPgetSolVal(scip, sol, rowprep->vars[i]);
16176  }
16177 
16178  if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16179  /* cut is activity <= side -> violation is activity - side, if positive */
16180  return MAX(activity - rowprep->side, 0.0);
16181  else
16182  /* cut is activity >= side -> violation is side - activity, if positive */
16183  return MAX(rowprep->side - activity, 0.0);
16184 }
16185 
16186 /** Merge terms that use same variable and eliminate zero coefficients.
16187  *
16188  * Terms are sorted by variable (@see SCIPvarComp) after return.
16189  */
16191  SCIP* scip, /**< SCIP data structure */
16192  SCIP_ROWPREP* rowprep /**< rowprep to be cleaned up */
16193  )
16194 {
16195  int i;
16196  int j;
16197 
16198  assert(scip != NULL);
16199  assert(rowprep != NULL);
16200 
16201  if( rowprep->nvars <= 1 )
16202  return;
16203 
16204  /* sort terms by variable index */
16205  SCIPsortPtrReal((void**)rowprep->vars, rowprep->coefs, SCIPvarComp, rowprep->nvars);
16206 
16207  /* merge terms with same variable, drop 0 coefficients */
16208  i = 0;
16209  j = 1;
16210  while( j < rowprep->nvars )
16211  {
16212  if( rowprep->vars[i] == rowprep->vars[j] )
16213  {
16214  /* merge term j into term i */
16215  rowprep->coefs[i] += rowprep->coefs[j];
16216  ++j;
16217  continue;
16218  }
16219 
16220  if( rowprep->coefs[i] == 0.0 )
16221  {
16222  /* move term j to position i */
16223  rowprep->coefs[i] = rowprep->coefs[j];
16224  rowprep->vars[i] = rowprep->vars[j];
16225  ++j;
16226  continue;
16227  }
16228 
16229  /* move term j to position i+1 and move on */
16230  if( j != i+1 )
16231  {
16232  rowprep->vars[i+1] = rowprep->vars[j];
16233  rowprep->coefs[i+1] = rowprep->coefs[j];
16234  }
16235  ++i;
16236  ++j;
16237  }
16238 
16239  /* remaining term can have coef zero -> forget about it */
16240  if( rowprep->coefs[i] == 0.0 )
16241  --i;
16242 
16243  /* i points to last term */
16244  rowprep->nvars = i+1;
16245 }
16246 
16247 /** sort cut terms by absolute value of coefficients, from largest to smallest */
16248 static
16250  SCIP* scip, /**< SCIP data structure */
16251  SCIP_ROWPREP* rowprep /**< rowprep to be sorted */
16252  )
16253 {
16254  int i;
16255 
16256  assert(scip != NULL);
16257  assert(rowprep != NULL);
16258 
16259  /* special treatment for cuts with few variables */
16260  switch( rowprep->nvars )
16261  {
16262  case 0:
16263  case 1:
16264  break;
16265 
16266  case 2:
16267  {
16268  if( REALABS(rowprep->coefs[0]) < REALABS(rowprep->coefs[1]) )
16269  {
16270  SCIP_Real tmp1;
16271  SCIP_VAR* tmp2;
16272 
16273  tmp1 = rowprep->coefs[0];
16274  rowprep->coefs[0] = rowprep->coefs[1];
16275  rowprep->coefs[1] = tmp1;
16276 
16277  tmp2 = rowprep->vars[0];
16278  rowprep->vars[0] = rowprep->vars[1];
16279  rowprep->vars[1] = tmp2;
16280  }
16281  break;
16282  }
16283 
16284  default :
16285  {
16286  SCIP_Real* abscoefs;
16287 
16288  SCIP_CALL( SCIPallocBufferArray(scip, &abscoefs, rowprep->nvars) );
16289  for( i = 0; i < rowprep->nvars; ++i )
16290  abscoefs[i] = REALABS(rowprep->coefs[i]);
16291  SCIPsortDownRealRealPtr(abscoefs, rowprep->coefs, (void**)rowprep->vars, rowprep->nvars);
16292  SCIPfreeBufferArray(scip, &abscoefs);
16293  }
16294  }
16295 
16296  /* forget about coefs that are exactly zero (unlikely to have some) */
16297  while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
16298  --rowprep->nvars;
16299 
16300  return SCIP_OKAY;
16301 }
16302 
16303 /** try to improve coef range by aggregating cut with variable bounds
16304  *
16305  * Assumes terms have been sorted by rowprepCleanupSortTerms().
16306  */
16307 static
16309  SCIP* scip, /**< SCIP data structure */
16310  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16311  SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
16312  SCIP_Real maxcoefrange /**< maximal allowed coefficients range */
16313  )
16314 {
16315  SCIP_VAR* var;
16316  SCIP_Real lb;
16317  SCIP_Real ub;
16318  SCIP_Real ref;
16319  SCIP_Real coef;
16320  SCIP_Real mincoef;
16321  SCIP_Real maxcoef;
16322  SCIP_Real loss[2];
16323  int maxcoefidx;
16324  int pos;
16325 
16326  maxcoefidx = 0;
16327  if( rowprep->nvars > 0 )
16328  {
16329  maxcoef = REALABS(rowprep->coefs[0]);
16330  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16331  }
16332  else
16333  mincoef = maxcoef = 1.0;
16334 
16335  /* eliminate minimal or maximal coefs as long as coef range is too large
16336  * this is likely going to eliminate coefs that are within eps of 0.0
16337  * if not, then we do so after scaling (or should we enforce this here?)
16338  */
16339  while( maxcoef / mincoef > maxcoefrange )
16340  {
16341  SCIPdebugMsg(scip, "cut coefficients have very large range: mincoef = %g maxcoef = %g\n", mincoef, maxcoef);
16342 
16343  /* max/min can only be > 1 if there is more than one var
16344  * we need this below for updating the max/min coef after eliminating a term
16345  */
16346  assert(rowprep->nvars > 1);
16347 
16348  /* try to reduce coef range by aggregating with variable bounds
16349  * that is, eliminate a term like a*x from a*x + ... <= side by adding -a*x <= -a*lb(x)
16350  * with ref(x) the reference point we try to eliminate, this would weaken the cut by a*(lb(x)-ref(x))
16351  *
16352  * we consider eliminating either the term with maximal or the one with minimal coefficient,
16353  * taking the one that leads to the least weakening of the cut
16354  *
16355  * TODO (suggested by @bzfserra, see !496):
16356  * - Also one could think of not completely removing the coefficient but do an aggregation that makes the coefficient look better. For instance:
16357  * say you have $`a x + 0.1 y \leq r`$ and $`y`$ has only an upper bound, $`y \leq b`$,
16358  * then you can't really remove $`y`$. However, you could aggregate it with $`0.9 \cdot (y \leq b)`$ to get
16359  * $`a x + y \leq r + 0.9 b`$, which has better numerics (and hopefully still cuts the point... actually, if for the point you want to separate, $`y^* = b`$, then the violation is the same)
16360  */
16361 
16362  for( pos = 0; pos < 2; ++pos )
16363  {
16364  var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
16365  coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
16366  lb = SCIPvarGetLbLocal(var);
16367  ub = SCIPvarGetUbLocal(var);
16368  ref = SCIPgetSolVal(scip, sol, var);
16369  assert(coef != 0.0);
16370 
16371  /* make sure reference point is something reasonable within the bounds, preferable the value from the solution */
16372  if( SCIPisInfinity(scip, REALABS(ref)) )
16373  ref = 0.0;
16374  ref = MAX(lb, MIN(ub, ref));
16375 
16376  /* check whether we can eliminate coef*var from rowprep and how much we would loose w.r.t. ref(x) */
16377  if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
16378  {
16379  /* we would need to aggregate with -coef*var <= -coef*lb(x) */
16380  if( SCIPisInfinity(scip, -lb) )
16381  loss[pos] = SCIP_INVALID;
16382  else
16383  loss[pos] = REALABS(coef) * (ref - lb);
16384  }
16385  else
16386  {
16387  assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
16388  /* we would need to aggregate with -coef*var >= -coef*ub(x) */
16389  if( SCIPisInfinity(scip, ub) )
16390  loss[pos] = SCIP_INVALID;
16391  else
16392  loss[pos] = REALABS(coef) * (ub - ref);
16393  }
16394  assert(loss[pos] >= 0.0); /* assuming SCIP_INVALID >= 0 */
16395 
16396  SCIPdebugMsg(scip, "aggregating %g*<%s> %c= ... with <%s>[%g] %c= %g looses %g\n",
16397  coef, SCIPvarGetName(var), rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? '<' : '>',
16398  SCIPvarGetName(var), ref,
16399  ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? '>' : '<',
16400  ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) ? lb : ub, loss[pos]);
16401  }
16402 
16403  /*lint --e{777} */
16404  if( loss[0] == SCIP_INVALID && loss[1] == SCIP_INVALID )
16405  break; /* cannot eliminate coefficient */
16406 
16407  /* select position with smaller loss */
16408  pos = (loss[1] == SCIP_INVALID || loss[1] > loss[0]) ? 0 : 1;
16409 
16410  /* now do the actual elimination */
16411  var = rowprep->vars[pos ? rowprep->nvars-1 : maxcoefidx];
16412  coef = rowprep->coefs[pos ? rowprep->nvars-1 : maxcoefidx];
16413 
16414  /* eliminate coef*var from rowprep: increase side */
16415  if( ((coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT)) )
16416  {
16417  /* we aggregate with -coef*var <= -coef*lb(x) */
16418  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
16419  SCIPaddRowprepConstant(rowprep, coef * SCIPvarGetLbLocal(var));
16420  rowprep->local |= SCIPisGT(scip, SCIPvarGetLbLocal(var), SCIPvarGetLbGlobal(var));
16421  }
16422  else
16423  {
16424  assert((coef < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT));
16425  /* we aggregate with -coef*var >= -coef*ub(x) */
16426  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
16427  SCIPaddRowprepConstant(rowprep, coef * SCIPvarGetUbLocal(var));
16428  rowprep->local |= SCIPisLT(scip, SCIPvarGetUbLocal(var), SCIPvarGetUbGlobal(var));
16429  }
16430 
16431  /* eliminate coef*var from rowprep: remove coef */
16432  if( pos == 0 )
16433  {
16434  /* set first term to zero */
16435  rowprep->coefs[maxcoefidx] = 0.0;
16436 
16437  /* update index */
16438  ++maxcoefidx;
16439 
16440  /* update maxcoef */
16441  maxcoef = REALABS(rowprep->coefs[maxcoefidx]);
16442  }
16443  else
16444  {
16445  /* forget last term */
16446  --rowprep->nvars;
16447 
16448  /* update mincoef */
16449  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16450  }
16451  }
16452 
16453  /* if maximal coefs were removed, then there are now 0's in the beginning of the coefs array
16454  * -> move all remaining coefs and vars up front
16455  */
16456  if( maxcoefidx > 0 )
16457  {
16458  int i;
16459  for( i = maxcoefidx; i < rowprep->nvars; ++i )
16460  {
16461  rowprep->vars[i-maxcoefidx] = rowprep->vars[i];
16462  rowprep->coefs[i-maxcoefidx] = rowprep->coefs[i];
16463  }
16464  rowprep->nvars -= maxcoefidx;
16465  }
16466 }
16467 
16468 
16469 /** scales up rowprep if it seems useful */
16470 static
16472  SCIP* scip, /**< SCIP data structure */
16473  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16474  SCIP_Real* viol, /**< violation of cut in sol (input and output) */
16475  SCIP_Real minviol /**< minimal violation we try to achieve */
16476  )
16477 {
16478  SCIP_Real scalefactor;
16479  SCIP_Real mincoef;
16480  SCIP_Real maxcoef;
16481 
16482  assert(scip != NULL);
16483  assert(rowprep != NULL);
16484  assert(viol != NULL);
16485 
16486  /* if violation is very small than better don't scale up */
16487  if( *viol < ROWPREP_SCALEUP_VIOLNONZERO )
16488  return;
16489 
16490  /* if violation is already above minviol, then nothing to do */
16491  if( *viol >= minviol )
16492  return;
16493 
16494  /* if violation is sufficiently positive (>10*eps), but has not reached minviol,
16495  * then consider scaling up to reach approx MINVIOLFACTOR*minviol
16496  */
16497  scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
16498 
16499  /* scale by approx. scalefactor, if minimal coef is not so large yet and maximal coef and rhs don't get huge by doing so (or have been so before) */
16500  mincoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[rowprep->nvars-1]) : 1.0;
16501  maxcoef = rowprep->nvars > 0 ? REALABS(rowprep->coefs[0]) : 1.0;
16502  if( mincoef < ROWPREP_SCALEUP_MAXMINCOEF && scalefactor * maxcoef < ROWPREP_SCALEUP_MAXMAXCOEF && scalefactor * REALABS(rowprep->side) < ROWPREP_SCALEUP_MAXSIDE )
16503  {
16504  int scaleexp;
16505 
16506  /* SCIPinfoMessage(scip, NULL, "scale up by ~%g, viol=%g: ", scalefactor, myviol);
16507  SCIPprintRowprep(scip, rowprep, NULL); */
16508 
16509  /* SCIPscaleRowprep returns the actually applied scale factor */
16510  scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
16511  *viol = ldexp(*viol, scaleexp);
16512 
16513  /* SCIPinfoMessage(scip, NULL, "scaled up by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
16514  SCIPprintRowprep(scip, rowprep, NULL); */
16515  }
16516 }
16517 
16518 /** scales down rowprep if it improves coefs and keeps rowprep violated */
16519 static
16521  SCIP* scip, /**< SCIP data structure */
16522  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16523  SCIP_Real* viol, /**< violation of cut in sol (input and output) */
16524  SCIP_Real minviol /**< minimal violation we try to keep */
16525  )
16526 {
16527  SCIP_Real scalefactor;
16528 
16529  /* if maxcoef < ROWPREP_SCALEDOWN_MINMAXCOEF (or no terms), then don't consider scaling down */
16530  if( rowprep->nvars == 0 || REALABS(rowprep->coefs[0]) < ROWPREP_SCALEDOWN_MINMAXCOEF )
16531  return;
16532 
16533  /* consider scaling down so that maxcoef ~ 10 */
16534  scalefactor = 10.0 / REALABS(rowprep->coefs[0]);
16535 
16536  /* if minimal violation would be lost by scaling down, then increase scalefactor such that minviol is still reached */
16537  if( *viol > minviol && scalefactor * *viol < minviol )
16538  {
16539  assert(minviol > 0.0); /* since viol >= 0, the if-condition should ensure that minviol > 0 */
16540  assert(*viol > 0.0); /* since minviol > 0, the if-condition ensures viol > 0 */
16541  scalefactor = ROWPREP_SCALEUP_MINVIOLFACTOR * minviol / *viol;
16542  }
16543 
16544  /* scale by approx. scalefactor if scaling down and minimal coef does not get too small
16545  * myviol < minviol (-> scalefactor > 1) or mincoef < feastol before scaling is possible, in which case we also don't scale down
16546  */
16547  if( scalefactor < 1.0 && scalefactor * REALABS(rowprep->coefs[rowprep->nvars-1]) > ROWPREP_SCALEDOWN_MINCOEF )
16548  {
16549  int scaleexp;
16550 
16551  /* SCIPinfoMessage(scip, NULL, "scale down by ~%g, viol=%g: ", scalefactor, myviol);
16552  SCIPprintRowprep(scip, rowprep, NULL); */
16553 
16554  scaleexp = SCIPscaleRowprep(rowprep, scalefactor);
16555  *viol = ldexp(*viol, scaleexp);
16556 
16557  /* SCIPinfoMessage(scip, NULL, "scaled down by %g, viol=%g: ", ldexp(1.0, scaleexp), myviol);
16558  SCIPprintRowprep(scip, rowprep, NULL); */
16559  }
16560 }
16561 
16562 /** rounds almost integral coefs to integrals, thereby trying to relax the cut */
16563 static
16565  SCIP* scip, /**< SCIP data structure */
16566  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16567  SCIP_Real* viol /**< violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
16568  )
16569 {
16570  SCIP_Real coef;
16571  SCIP_Real roundcoef;
16572  int i;
16573 
16574  assert(scip != NULL);
16575  assert(rowprep != NULL);
16576  assert(viol != NULL);
16577 
16578  /* Coefficients smaller than epsilon are rounded to 0.0 when added to row and
16579  * coefficients very close to integral values are rounded to integers when added to LP.
16580  * Both cases can be problematic if variable value is very large (bad numerics).
16581  * Thus, we anticipate by rounding coef here, but also modify constant so that cut is still valid (if possible),
16582  * i.e., bound coef[i]*x by round(coef[i])*x + (coef[i]-round(coef[i])) * bound(x).
16583  * Or in other words, we aggregate with the variable bound.
16584  *
16585  * If the required bound of x is not finite, then only round coef (introduces an error).
16586  * @TODO If only the opposite bound is available, then one could move the coefficient
16587  * away from the closest integer so that the SCIP_ROW won't try to round it.
16588  */
16589  for( i = 0; i < rowprep->nvars; ++i )
16590  {
16591  coef = rowprep->coefs[i];
16592  roundcoef = SCIPround(scip, coef);
16593  if( coef != roundcoef && SCIPisEQ(scip, coef, roundcoef) ) /*lint !e777*/
16594  {
16595  SCIP_Real xbnd;
16596  SCIP_VAR* var;
16597 
16598  var = rowprep->vars[i];
16599  if( rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16600  if( rowprep->local )
16601  xbnd = coef > roundcoef ? SCIPvarGetLbLocal(var) : SCIPvarGetUbLocal(var);
16602  else
16603  xbnd = coef > roundcoef ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
16604  else
16605  if( rowprep->local )
16606  xbnd = coef > roundcoef ? SCIPvarGetUbLocal(var) : SCIPvarGetLbLocal(var);
16607  else
16608  xbnd = coef > roundcoef ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
16609 
16610  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
16611  {
16612  /* if there is a bound, then relax row side so rounding coef will not introduce an error */
16613  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g and add constant %g\n",
16614  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef, (coef-roundcoef) * xbnd);
16615  SCIPaddRowprepConstant(rowprep, (coef-roundcoef) * xbnd);
16616  }
16617  else
16618  {
16619  /* if there is no bound, then we make the coef integral, too, even though this will introduce an error
16620  * however, SCIP_ROW would do this anyway, but doing this here might eliminate some epsilon coefs (so they don't determine mincoef below)
16621  * and helps to get a more accurate row violation value
16622  */
16623  SCIPdebugMsg(scip, "var <%s> [%g,%g] has almost integral coef %.20g, round coefficient to %g without relaxing side (!)\n",
16624  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), coef, roundcoef);
16625  }
16626  rowprep->coefs[i] = roundcoef;
16627  *viol = SCIP_INVALID;
16628  }
16629  }
16630 
16631  /* forget about coefs that became exactly zero by the above step */
16632  while( rowprep->nvars > 0 && rowprep->coefs[rowprep->nvars-1] == 0.0 )
16633  --rowprep->nvars;
16634 }
16635 
16636 /** relaxes almost zero side */
16637 static
16638 void rowprepCleanupSide(
16639  SCIP* scip, /**< SCIP data structure */
16640  SCIP_ROWPREP* rowprep, /**< rowprep to be improve */
16641  SCIP_Real* viol /**< violation of cut in sol (input), set to SCIP_INVALID if some coef changed */
16642  )
16643 {
16644  /* SCIP_ROW handling will replace a side close to 0 by 0.0, even if that makes the row more restrictive
16645  * we thus relax the side here so that it will either be 0 now or will not be rounded to 0 later
16646  */
16647  if( !SCIPisZero(scip, rowprep->side) )
16648  return;
16649 
16650  if( rowprep->side > 0.0 && rowprep->sidetype == SCIP_SIDETYPE_RIGHT )
16651  rowprep->side = 1.1*SCIPepsilon(scip);
16652  else if( rowprep->side < 0.0 && rowprep->sidetype == SCIP_SIDETYPE_LEFT )
16653  rowprep->side = -1.1*SCIPepsilon(scip);
16654  else
16655  rowprep->side = 0.0;
16656 
16657  *viol = SCIP_INVALID;
16658 }
16659 
16660 /* Cleans up and attempts to improve rowprep
16661  *
16662  * Drops small or large coefficients if coefrange is too large, if this can be done by relaxing the cut.
16663  * Scales coefficients and side up to reach minimal violation, if possible.
16664  * Scaling is omitted if violation is very small (ROWPREP_SCALEUP_VIOLNONZERO) or
16665  * maximal coefficient would become huge (ROWPREP_SCALEUP_MAXMAXCOEF).
16666  * Scales coefficients and side down if they are large and if the minimal violation is still reached.
16667  * Rounds coefficients close to integral values to integrals, if this can be done by relaxing the cut.
16668  * Rounds side within epsilon of 0 to 0.0 or +/-1.1*epsilon, whichever relaxes the cut least.
16669  *
16670  * After return, the terms in the rowprep will be sorted by absolute value of coefficient, in decreasing order.
16671  */
16673  SCIP* scip, /**< SCIP data structure */
16674  SCIP_ROWPREP* rowprep, /**< rowprep to be cleaned */
16675  SCIP_SOL* sol, /**< solution that we try to cut off, or NULL for LP solution */
16676  SCIP_Real maxcoefrange, /**< maximal allowed coefficients range */
16677  SCIP_Real minviol, /**< minimal absolute violation the row should achieve (w.r.t. sol) */
16678  SCIP_Real* coefrange, /**< buffer to store coefrange of cleaned up cut, or NULL if not of interest */
16679  SCIP_Real* viol /**< buffer to store absolute violation of cleaned up cut in sol, or NULL if not of interest */
16680  )
16681 {
16682  SCIP_Real myviol;
16683 #ifdef SCIP_DEBUG
16684  SCIP_Real mincoef = 1.0;
16685  SCIP_Real maxcoef = 1.0;
16686 #endif
16687 
16688  assert(maxcoefrange > 1.0); /* not much interesting otherwise */
16689 
16690  /* sort term by absolute value of coef. */
16691  SCIP_CALL( rowprepCleanupSortTerms(scip, rowprep) );
16692 
16693 #ifdef SCIP_DEBUG
16694  if( rowprep->nvars > 0 )
16695  {
16696  maxcoef = REALABS(rowprep->coefs[0]);
16697  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16698  }
16699 
16700  SCIPinfoMessage(scip, NULL, "starting cleanup, coefrange %g: ", maxcoef/mincoef);
16701  SCIPprintRowprep(scip, rowprep, NULL);
16702 #endif
16703 
16704  /* improve coefficient range by aggregating out variables */
16705  rowprepCleanupImproveCoefrange(scip, rowprep, sol, maxcoefrange);
16706 
16707  /* get current violation in sol */
16708  myviol = SCIPgetRowprepViolation(scip, rowprep, sol);
16709  assert(myviol >= 0.0);
16710 
16711 #ifdef SCIP_DEBUG
16712  if( rowprep->nvars > 0 )
16713  {
16714  maxcoef = REALABS(rowprep->coefs[0]);
16715  mincoef = REALABS(rowprep->coefs[rowprep->nvars-1]);
16716  }
16717 
16718  SCIPinfoMessage(scip, NULL, "improved coefrange to %g, viol %g: ", maxcoef / mincoef, myviol);
16719  SCIPprintRowprep(scip, rowprep, NULL);
16720 #endif
16721 
16722  /* if there is interest in achieving some minimal violation, then possibly scale up to increase violation, updates myviol */
16723  if( minviol > 0.0 )
16724  {
16725  /* first, try to achieve scip's minefficacy (typically 1e-4) */
16726  if( SCIPgetSepaMinEfficacy(scip) > minviol )
16727  rowprepCleanupScaleup(scip, rowprep, &myviol, SCIPgetSepaMinEfficacy(scip));
16728  /* in case scip minefficacy could not be reached or was smaller than minviol, try with the given minviol */
16729  rowprepCleanupScaleup(scip, rowprep, &myviol, minviol);
16730  }
16731 
16732  /* scale down to improve numerics, updates myviol */
16733  rowprepCleanupScaledown(scip, rowprep, &myviol, MAX(SCIPgetSepaMinEfficacy(scip), minviol)); /*lint !e666*/
16734 
16735 #ifdef SCIP_DEBUG
16736  SCIPinfoMessage(scip, NULL, "applied scaling, viol %g: ", myviol);
16737  SCIPprintRowprep(scip, rowprep, NULL);
16738 #endif
16739 
16740  /* turn almost-integral coefs to integral values, may set myviol to SCIP_INVALID */
16741  rowprepCleanupIntegralCoefs(scip, rowprep, &myviol);
16742 
16743  /* relax almost-zero side, may set myviol to SCIP_INVALID */
16744  rowprepCleanupSide(scip, rowprep, &myviol);
16745 
16746 #ifdef SCIP_DEBUG
16747  SCIPinfoMessage(scip, NULL, "adjusted almost-integral coefs and sides, viol %g: ", myviol);
16748  SCIPprintRowprep(scip, rowprep, NULL);
16749 #endif
16750 
16751  /* compute final coefrange, if requested by caller */
16752  if( coefrange != NULL )
16753  {
16754  if( rowprep->nvars > 0 )
16755  *coefrange = REALABS(rowprep->coefs[0]) / REALABS(rowprep->coefs[rowprep->nvars-1]);
16756  else
16757  *coefrange = 1.0;
16758  }
16759 
16760  /* If we updated myviol correctly, then it should coincide with freshly computed violation.
16761  * I leave this assert off for now, since getting the tolerance in the EQ correctly is not trivial. We recompute viol below anyway.
16762  */
16763  /* assert(myviol == SCIP_INVALID || SCIPisEQ(scip, myviol, SCIPgetRowprepViolation(scip, rowprep, sol))); */
16764 
16765  /* compute final violation, if requested by caller */
16766  if( viol != NULL ) /*lint --e{777} */
16767  *viol = myviol == SCIP_INVALID ? SCIPgetRowprepViolation(scip, rowprep, sol) : myviol;
16768 
16769  return SCIP_OKAY;
16770 }
16771 
16772 /** scales a rowprep
16773  *
16774  * @return Exponent of actually applied scaling factor, if written as 2^x.
16775  */
16776 int SCIPscaleRowprep(
16777  SCIP_ROWPREP* rowprep, /**< rowprep to be scaled */
16778  SCIP_Real factor /**< suggested scale factor */
16779  )
16780 {
16781  double v;
16782  int expon;
16783  int i;
16784 
16785  assert(rowprep != NULL);
16786  assert(factor > 0.0);
16787 
16788  /* write factor as v*2^expon with v in [0.5,1) */
16789  v = frexp(factor, &expon);
16790  /* adjust to v'*2^expon with v' in (0.5,1] by v'=v if v > 0.5, v'=1 if v=0.5 */
16791  if( v == 0.5 )
16792  --expon;
16793 
16794  /* multiply each coefficient by 2^expon */
16795  for( i = 0; i < rowprep->nvars; ++i )
16796  rowprep->coefs[i] = ldexp(rowprep->coefs[i], expon);
16797 
16798  /* multiply side by 2^expon */
16799  rowprep->side = ldexp(rowprep->side, expon);
16800 
16801  return expon;
16802 }
16803 
16804 /** generates a SCIP_ROW from a rowprep */
16806  SCIP* scip, /**< SCIP data structure */
16807  SCIP_ROW** row, /**< buffer to store pointer to new row */
16808  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
16809  SCIP_CONSHDLR* conshdlr /**< constraint handler */
16810  )
16811 {
16812  assert(scip != NULL);
16813  assert(row != NULL);
16814  assert(rowprep != NULL);
16815 
16816  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, conshdlr, rowprep->name,
16817  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
16818  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
16819  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
16820 
16821  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
16822 
16823  return SCIP_OKAY;
16824 }
16825 
16826 /** generates a SCIP_ROW from a rowprep */
16828  SCIP* scip, /**< SCIP data structure */
16829  SCIP_ROW** row, /**< buffer to store pointer to new row */
16830  SCIP_ROWPREP* rowprep, /**< rowprep to be turned into a row */
16831  SCIP_SEPA* sepa /**< separator */
16832  )
16833 {
16834  assert(scip != NULL);
16835  assert(row != NULL);
16836  assert(rowprep != NULL);
16837 
16838  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, rowprep->name,
16839  rowprep->sidetype == SCIP_SIDETYPE_LEFT ? rowprep->side : -SCIPinfinity(scip),
16840  rowprep->sidetype == SCIP_SIDETYPE_RIGHT ? rowprep->side : SCIPinfinity(scip),
16841  rowprep->local && (SCIPgetDepth(scip) > 0), FALSE, TRUE) );
16842 
16843  SCIP_CALL( SCIPaddVarsToRow(scip, *row, rowprep->nvars, rowprep->vars, rowprep->coefs) );
16844 
16845  return SCIP_OKAY;
16846 }
SCIP_RETCODE SCIPaddLinearCoefsToNlRow(SCIP *scip, SCIP_NLROW *nlrow, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_nlp.c:1465
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static void rowprepCleanupImproveCoefrange(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefrange)
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:116
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_prob.c:2134
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)
SCIP_Bool SCIPisIpoptAvailableIpopt(void)
#define ROWPREP_SCALEUP_VIOLNONZERO
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:105
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:17443
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_cons.c:640
static volatile int nterms
Definition: interrupt.c:37
void * SCIPhashmapEntryGetImage(SCIP_HASHMAPENTRY *entry)
Definition: misc.c:3387
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)
static SCIP_RETCODE freeAllBilinearTerms(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss)
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)
#define NULL
Definition: def.h:246
#define ROWPREP_SCALEDOWN_MINCOEF
static void consdataMoveLinearVar(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8173
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:99
static SCIP_RETCODE consdataSortBilinTerms(SCIP *scip, SCIP_CONSDATA *consdata)
primal heuristic that tries a given solution
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:284
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_var.c:5119
SCIP_VAR * var2
static void rowprepCleanupScaleup(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol, SCIP_Real minviol)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for SCIP parameter handling
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3176
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:158
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:411
#define MAXDNOM
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
#define GAUGESCALE
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8335
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17136
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip_sol.c:1367
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_cons.c:663
public methods for branch and bound tree
#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)
Constraint handler for variable bound constraints .
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetNAllBilinearTermsQuadratic(SCIP *scip)
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)
public methods for memory management
#define ROWPREP_SCALEDOWN_MINMAXCOEF
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:422
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:954
SCIP_RETCODE SCIPchgRhsQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_Real rhs)
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12973
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:132
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17344
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_cons.c:893
static SCIP_DECL_SORTINDCOMP(quadVarTermComp)
#define SCIP_MAXSTRLEN
Definition: def.h:267
static SCIP_RETCODE replaceQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_VAR *var, SCIP_Real coef, SCIP_Real offset)
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3233
#define SCIP_DECL_CONSINITPRE(x)
Definition: type_cons.h:141
#define CONSHDLR_DELAYPROP
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition: var.c:16931
SCIP_VAR * var1
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPaddRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep, int nvars, SCIP_VAR **vars, SCIP_Real *coefs)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:385
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:103
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1826
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_prob.c:2895
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:210
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17124
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16880
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefrange, SCIP_Real minviol, SCIP_Real *coefrange, SCIP_Real *viol)
#define CONSHDLR_PROPFREQ
SCIP_Real inequnderest[6]
#define SQR(x)
Definition: def.h:198
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisSumRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define INTERIOR_EPS
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17400
static SCIP_DECL_CONSSEPALP(consSepalpQuadratic)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
internal methods for NLPI solver interfaces
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
public solving methods
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool local
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:8505
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_event.c:172
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip_nlp.c:667
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17018
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1442
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_var.c:1251
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16910
static SCIP_RETCODE addQuadVarTerm(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
#define RESTRICT
Definition: def.h:258
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPnlpiGetSolution(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_Real **primalvalues, SCIP_Real **consdualvalues, SCIP_Real **varlbdualvalues, SCIP_Real **varubdualvalues, SCIP_Real *objval)
Definition: nlpi.c:537
SCIP_Real SCIPvarGetBestBoundLocal(SCIP_VAR *var)
Definition: var.c:17430
SCIP_Real SCIPdualfeastol(SCIP *scip)
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)
static SCIP_DECL_NONLINCONSUPGD(nonlinconsUpgdQuadratic)
#define CONSHDLR_MAXPREROUNDS
SCIP_RETCODE SCIPchgLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
SCIP_SIDETYPE sidetype
static SCIP_DECL_CONSEXITPRE(consExitpreQuadratic)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4563
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16959
#define FALSE
Definition: def.h:72
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:4581
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2891
#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 storeAllBilinearTerms(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss)
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
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10561
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip_copy.c:2354
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_cons.c:243
SCIP_Real * SCIPgetLinearCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPinfinity(SCIP *scip)
#define CONSHDLR_SEPAPRIORITY
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10253
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:71
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:2056
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPsolveNLP(SCIP *scip)
Definition: scip_nlp.c:644
static SCIP_RETCODE generateCutConvex(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8355
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3009
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:8385
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)
void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
public methods for problem variables
static GRAPHNODE ** active
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:9868
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5235
static SCIP_RETCODE removeBilinearTermsPos(SCIP *scip, SCIP_CONS *cons, int nterms, int *termposs)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:114
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)
#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_cons.c:297
SCIP_Real SCIPselectSimpleValue(SCIP_Real lb, SCIP_Real ub, SCIP_Longint maxdnom)
Definition: misc.c:9368
static SCIP_RETCODE presolveTryAddAND(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip_event.c:302
Constraint handler for AND constraints, .
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_var.c:394
static SCIP_RETCODE mergeAndCleanBilinearTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
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_sol.c:419
static SCIP_DECL_CONSENFOLP(consEnfolpQuadratic)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:142
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:4549
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:16941
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:97
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
public methods for SCIP variables
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:8345
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:108
void SCIPcomputeBilinEnvelope2(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 xcoef1, SCIP_Real ycoef1, SCIP_Real constant1, SCIP_Real xcoef2, SCIP_Real ycoef2, SCIP_Real constant2, SCIP_Real *RESTRICT lincoefx, SCIP_Real *RESTRICT lincoefy, SCIP_Real *RESTRICT linconstant, SCIP_Bool *RESTRICT success)
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:686
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_message.c:203
#define SCIPdebugMsgPrint
Definition: scip_message.h:89
#define ROWPREP_SCALEUP_MAXMAXCOEF
#define SCIPdebugMsg
Definition: scip_message.h:88
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_param.c:155
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real intervalinfty)
public methods for separator plugins
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:870
SCIP_Real SCIPgetLhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** x
Definition: circlepacking.c:54
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8137
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:279
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2224
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_cons.c:1011
SCIP_Real SCIPepsilon(SCIP *scip)
static SCIP_RETCODE lockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPaddLinearVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
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)
public methods for numerical tolerances
static SCIP_RETCODE unlockQuadraticVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
SCIP_Bool SCIPisRelGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetNQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsOriginal(SCIP_CONS *cons)
Definition: cons.c:8375
int SCIPnlrowGetNQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3323
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)
public methods for expressions, expression trees, expression graphs, and related stuff ...
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:104
public methods for querying solving statistics
SCIP_Bool SCIPisRelLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE generateCutNonConvex(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
const char * SCIPgetProbName(SCIP *scip)
Definition: scip_prob.c:1123
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3240
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4198
static SCIP_RETCODE registerBranchingCandidatesGap(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, int *nnotify)
SCIP_RETCODE SCIPaddBilinearIneqQuadratic(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, int idx, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Bool *success)
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPnlpiSolve(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:497
public methods for the branch-and-bound tree
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:242
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13033
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_var.c:8082
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17354
void SCIPcomputeBilinEnvelope1(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 xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Real *RESTRICT lincoefx, SCIP_Real *RESTRICT lincoefy, SCIP_Real *RESTRICT linconstant, SCIP_Bool *RESTRICT success)
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:506
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:111
SCIP_Bool SCIPisConcaveQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real coef
Definition: type_expr.h:104
public methods for managing constraints
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:127
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
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:1198
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip_sol.c:667
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:647
SCIP_Bool SCIPconsIsLocked(SCIP_CONS *cons)
Definition: cons.c:8415
SCIP_VAR ** SCIPnlrowGetQuadVars(SCIP_NLROW *nlrow)
Definition: nlp.c:3286
static SCIP_RETCODE presolveTryAddLinearReform(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
static SCIP_RETCODE 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_ROWPREP *rowprep, SCIP_Bool *success)
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1774
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:409
SCIP_RETCODE SCIPaddLinearConsToNlpHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_Bool addcombconss, SCIP_Bool addcontconss)
Definition: heur_subnlp.c:2417
static SCIP_DECL_CONSEXIT(consExitQuadratic)
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1254
struct SCIP_QuadVarEventData SCIP_QUADVAREVENTDATA
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_Bool SCIPisRelGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static void getIneqViol(SCIP_VAR *x, SCIP_VAR *y, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Real *viol1, SCIP_Real *viol2)
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)
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:328
SCIP_RETCODE SCIPfindQuadVarTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, int *pos)
SCIP_RETCODE SCIPensureRowprepSize(SCIP *scip, SCIP_ROWPREP *rowprep, int size)
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:5008
#define SCIPerrorMessage
Definition: pub_message.h:45
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4191
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2822
interval arithmetics for provable bounds
static SCIP_RETCODE removeFixedVariables(SCIP *scip, SCIP_CONS *cons)
int SCIPhashmapGetNEntries(SCIP_HASHMAP *hashmap)
Definition: misc.c:3358
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_RETCODE SCIPgetAllBilinearTermsQuadratic(SCIP *scip, SCIP_VAR **RESTRICT x, SCIP_VAR **RESTRICT y, int *RESTRICT nbilinterms, int *RESTRICT nunderests, int *RESTRICT noverests, SCIP_Real *maxnonconvexity)
SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol)
SCIP_HASHMAPENTRY * SCIPhashmapGetEntry(SCIP_HASHMAP *hashmap, int entryidx)
Definition: misc.c:3366
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPaddConsLocal(SCIP *scip, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip_prob.c:3446
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:535
SCIP_VAR ** vars
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:69
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3527
public methods for event handler plugins and event handlers
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
public methods for nonlinear functions
#define COPYSIGN
Definition: def.h:237
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *solviolbounds)
static SCIP_DECL_CONSDELETE(consDeleteQuadratic)
static SCIP_DECL_CONSPARSE(consParseQuadratic)
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17068
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1350
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss, SCIP_PRESOLTIMING presoltiming)
static SCIP_RETCODE presolveDisaggregateMarkComponent(SCIP *scip, SCIP_CONSDATA *consdata, int quadvaridx, SCIP_HASHMAP *var2component, int componentnr, int *componentsize)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1796
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_mem.h:143
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:128
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_cons.c:2149
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
void SCIPhashmapEntrySetImage(SCIP_HASHMAPENTRY *entry, void *image)
Definition: misc.c:3417
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4374
static SCIP_DECL_CONSCHECK(consCheckQuadratic)
#define MAX3(x, y, z)
Definition: def.h:220
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8076
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8295
#define SCIP_EVENTTYPE_IMPLADDED
Definition: type_event.h:71
static SCIP_DECL_CONSPRESOL(consPresolQuadratic)
void SCIPaddRowprepSide(SCIP_ROWPREP *rowprep, SCIP_Real side)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16730
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:434
static SCIP_DECL_CONSTRANS(consTransQuadratic)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2925
constraint handler for quadratic constraints
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4211
SCIP_RETCODE SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
#define CONSHDLR_CHECKPRIORITY
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:2028
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:2553
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1540
int SCIPgetNNlpis(SCIP *scip)
Definition: scip_nlp.c:206
#define REALABS(x)
Definition: def.h:181
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_nlp.c:612
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_branch.c:959
SCIP_QUADELEM * SCIPnlrowGetQuadElems(SCIP_NLROW *nlrow)
Definition: nlp.c:3333
public methods for problem copies
public methods for primal CIP solutions
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition: scip_sepa.c:376
#define SCIP_CALL(x)
Definition: def.h:358
unsigned int SCIP_PRESOLTIMING
Definition: type_timing.h:52
#define CONSHDLR_ENFOPRIORITY
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17148
SCIP_VAR * h
Definition: circlepacking.c:59
SCIP_Real sup
Definition: intervalarith.h:40
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16969
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:296
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8315
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:294
static void rowprepCleanupScaledown(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol, SCIP_Real minviol)
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:279
static SCIP_RETCODE rowprepCleanupSortTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:51
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:16905
SCIP_NLPSOLSTAT SCIPnlpiGetSolstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:511
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
public methods for primal heuristic plugins and divesets
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:105
SCIP_Bool SCIPhasPrimalRay(SCIP *scip)
Definition: scip_sol.c:3556
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)
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4593
public methods for constraint handler plugins and constraints
public methods for NLP management
static SCIP_RETCODE consdataEnsureAdjBilinSize(SCIP *scip, SCIP_QUADVARTERM *quadvarterm, int num)
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
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:13136
SCIP_RETCODE SCIPgetViolationQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
SCIP_Bool SCIPvarIsOriginal(SCIP_VAR *var)
Definition: var.c:16859
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_mem.h:130
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:16915
public data structures and miscellaneous methods
SCIP_BOUNDTYPE * SCIPvarGetImplTypes(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17654
#define CONSHDLR_NEEDSCONS
static unsigned int nextPowerOf2(unsigned int v)
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1018
static SCIP_DECL_CONSINITLP(consInitlpQuadratic)
SCIP_Real side
#define SCIP_Bool
Definition: def.h:69
static SCIP_DECL_CONSFREE(consFreeQuadratic)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:354
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:226
static SCIP_RETCODE presolveDisaggregate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int *naddconss)
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14637
static void rowprepCleanupIntegralCoefs(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol)
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds)
#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:995
static SCIP_RETCODE computeGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons)
static SCIP_RETCODE generateCutFactorable(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
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_lp.c:1336
SCIP_Real SCIPgetLhsNonlinear(SCIP *scip, SCIP_CONS *cons)
#define NONLINCONSUPGD_PRIORITY
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:715
SCIP_RETCODE SCIPnlpiSetIntPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, int ival)
Definition: nlpi.c:636
SCIP_Real SCIPlpfeastol(SCIP *scip)
constraint handler for nonlinear constraints
int SCIPvarGetNImpls(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17622
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_cons.c:2550
void SCIPmergeRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10354
SCIP_NLPTERMSTAT SCIPnlpiGetTermstat(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem)
Definition: nlpi.c:523
static SCIP_RETCODE sortAllBilinTerms(SCIP *scip, SCIP_BILINTERM *bilinterms, int nbilinterms, SCIP_CONS **bilinconss, int *bilinposs)
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_cut.c:405
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8096
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11428
#define MIN(x, y)
Definition: def.h:216
methods for debugging
public methods for LP management
static SCIP_RETCODE generateCutLTI(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE violside, SCIP_Real *ref, SCIP_SOL *sol, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1365
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip_cons.c:801
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:388
public methods for cuts and aggregation rows
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1034
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8275
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8245
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17192
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:468
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_var.c:104
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:654
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:123
#define ROWPREP_SCALEUP_MAXSIDE
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4289
static SCIP_Real getInteriority(SCIP *scip, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refy)
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1493
#define infty2infty(infty1, infty2, val)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:847
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
Constraint handler for linear constraints in their most general form, .
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip_cut.c:251
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17112
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real * SCIPvarGetImplBounds(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17668
#define CONSHDLR_NAME
#define BMSclearMemory(ptr)
Definition: memory.h:118
#define SCIP_EVENTTYPE_GBDCHANGED
Definition: type_event.h:103
static SCIP_Bool consdataCheckBilinTermsSort(SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONSHDLR *conshdlr)
char name[SCIP_MAXSTRLEN]
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip_cons.c:778
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13065
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2089
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_probing.c:152
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)
public methods for the LP relaxation, rows and columns
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13148
#define ROWPREP_SCALEUP_MINVIOLFACTOR
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2044
SCIP_RETCODE SCIPcheckCurvatureQuadratic(SCIP *scip, SCIP_CONS *cons)
public methods for nonlinear relaxations
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7377
void SCIPenableNLP(SCIP *scip)
Definition: scip_nlp.c:269
SCIP_Bool SCIPinDive(SCIP *scip)
Definition: scip_lp.c:2662
static SCIP_RETCODE registerLargeRelaxValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_VAR **brvar)
methods for sorting joint arrays of various types
SCIP_QUADVAREVENTDATA * eventdata
SCIP_Bool SCIPconsIsLockedType(SCIP_CONS *cons, SCIP_LOCKTYPE locktype)
Definition: cons.c:8469
SCIP_VAR ** SCIPvarGetImplVars(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17639
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_cons.c:578
#define SQRT(x)
Definition: def.h:199
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:95
public methods for branching rule plugins and branching
SCIP_VAR ** b
Definition: circlepacking.c:56
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1474
int SCIPgetLinvarMayIncreaseQuadratic(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
public methods for managing events
static SCIP_RETCODE addBilinearTerm(SCIP *scip, SCIP_CONS *cons, int var1pos, int var2pos, SCIP_Real coef)
general public methods
#define MAX(x, y)
Definition: def.h:215
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:447
static void consdataMoveQuadVarTerm(SCIP_CONSDATA *consdata, int oldpos, int newpos)
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5317
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPcopyRowprep(SCIP *scip, SCIP_ROWPREP **target, SCIP_ROWPREP *source)
static SCIP_RETCODE consdataCreateEmpty(SCIP *scip, SCIP_CONSDATA **consdata)
static SCIP_DECL_CONSGETNVARS(consGetNVarsQuadratic)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
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_param.c:239
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16729
int SCIPgetNLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
public methods for solutions
void SCIPfreeParseVarsPolynomialData(SCIP *scip, SCIP_VAR ****monomialvars, SCIP_Real ***monomialexps, SCIP_Real **monomialcoefs, int **monomialnvars, int nmonomials)
Definition: scip_var.c:1161
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_copy.c:737
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1724
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8106
#define CONSHDLR_DESC
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip_cons.c:458
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_cons.c:482
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
public methods for the probing mode
static void rowprepCleanupSide(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real *viol)
static SCIP_DECL_CONSCOPY(consCopyQuadratic)
static SCIP_DECL_CONSINIT(consInitQuadratic)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1187
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
void SCIPintervalSetRoundingModeUpwards(void)
type definitions for expressions and expression trees
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_cons.c:602
public methods for message output
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)
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:322
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1916
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:1174
SCIP_VAR * a
Definition: circlepacking.c:57
int SCIPscaleRowprep(SCIP_ROWPREP *rowprep, SCIP_Real factor)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
void SCIPsortDownRealRealPtr(SCIP_Real *realarray1, SCIP_Real *realarray2, void **ptrarray, int len)
SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
Definition: scip_nlp.c:787
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16849
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_var.c:8287
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1217
#define SCIP_Real
Definition: def.h:157
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8325
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_lp.c:1633
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_general.c:738
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:916
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_VAR ** y
Definition: circlepacking.c:55
SCIP_Bool SCIPhaveVarsCommonClique(SCIP *scip, SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: scip_var.c:7567
static SCIP_RETCODE computeReferencePointGauge(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *refsol, SCIP_Real *ref, SCIP_Bool *success)
public methods for message handling
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8265
static SCIP_RETCODE checkFactorable(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12983
#define SCIP_INVALID
Definition: def.h:177
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8255
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_lp.c:2099
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:142
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:17456
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1239
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:278
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16895
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_var.c:809
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)
SCIP_Real ineqoverest[6]
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:50
static SCIP_DECL_EVENTEXEC(processVarEvent)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17410
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:117
static SCIP_RETCODE addLinearCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE presolveDisaggregateMergeComponents(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_HASHMAP *var2component, int nvars, int *ncomponents, int *componentssize)
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16872
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2451
SCIP_Bool SCIPconsIsMarkedPropagate(SCIP_CONS *cons)
Definition: cons.c:8285
#define CONSHDLR_PROP_TIMING
#define SCIP_DECL_QUADCONSUPGD(x)
static SCIP_DECL_CONSPROP(consPropQuadratic)
SCIP_Real * coefs
SCIP_NLPI ** SCIPgetNlpis(SCIP *scip)
Definition: scip_nlp.c:193
static SCIP_RETCODE delQuadVarTermPos(SCIP *scip, SCIP_CONS *cons, int pos)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
static SCIP_DECL_CONSPRINT(consPrintQuadratic)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:119
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
public methods for primal heuristics
#define ROWPREP_SCALEUP_MAXMINCOEF
#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_nlp.c:1242
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:13172
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3098
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
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_cons.c:530
SCIP_Longint SCIPgetNLPs(SCIP *scip)
#define SCIPABORT()
Definition: def.h:330
static void updateBilinearRelaxation(SCIP *scip, SCIP_VAR *RESTRICT x, SCIP_VAR *RESTRICT y, SCIP_Real bilincoef, SCIP_SIDETYPE violside, SCIP_Real refx, SCIP_Real refy, SCIP_Real *RESTRICT ineqs, int nineqs, SCIP_Real mccormickval, SCIP_Real *RESTRICT bestcoefx, SCIP_Real *RESTRICT bestcoefy, SCIP_Real *RESTRICT bestconst, SCIP_Real *RESTRICT bestval, SCIP_Bool *success)
public methods for global and local (sub)problems
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16921
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:8690
SCIP_RETCODE SCIPgetRowprepRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_SEPA *sepa)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1410
static SCIP_RETCODE mergeAndCleanQuadVarTerms(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisInRestart(SCIP *scip)
Definition: scip_solve.c:3571
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1259
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_param.c:211
#define SCIPduplicateBlockMemory(scip, ptr, source)
Definition: scip_mem.h:109
SCIP_Bool SCIPisRelLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
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)
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *solviolbounds, SCIP_CONS **maxviolcon)
#define ABS(x)
Definition: def.h:211
SCIP_Bool SCIPisConvexQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetPrimalRayVal(SCIP *scip, SCIP_VAR *var)
Definition: scip_sol.c:3574
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_param.c:129
static SCIP_RETCODE processCut(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Real efficacy, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_Real *bestefficacy, SCIP_RESULT *result)
int SCIPgetNSepaRounds(SCIP *scip)
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONS *cons, int linvarpos)
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17017
void SCIPaddSquareLinearization(SCIP *scip, SCIP_Real sqrcoef, SCIP_Real refpoint, SCIP_Bool isint, SCIP_Real *lincoef, SCIP_Real *linconstant, SCIP_Bool *success)
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:134
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:134
SCIP_RETCODE SCIPnlpiSetRealPar(SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *problem, SCIP_NLPPARAM type, SCIP_Real dval)
Definition: nlpi.c:671
void SCIPaddRowprepConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:343
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)
memory allocation routines
enum SCIP_SideType SCIP_SIDETYPE
Definition: type_lp.h:58
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13160