Scippy

SCIP

Solving Constraint Integer Programs

nlhdlr_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-2022 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 nlhdlr_quadratic.c
17  * @ingroup DEFPLUGINS_NLHDLR
18  * @brief nonlinear handler to handle quadratic expressions
19  * @author Felipe Serrano
20  * @author Antonia Chmiela
21  *
22  * Some definitions:
23  * - a `BILINEXPRTERM` is a product of two expressions
24  * - a `QUADEXPRTERM` stores an expression `expr` that is known to appear in a nonlinear, quadratic term, that is
25  * `expr^2` or `expr*other_expr`. It stores its `sqrcoef` (that can be 0), its linear coef and all the bilinear expression
26  * terms in which expr appears.
27  */
28 
29 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
30 
31 /* #define DEBUG_INTERSECTIONCUT */
32 /* #define INTERCUT_MOREDEBUG */
33 /* #define INTERCUTS_VERBOSE */
34 
35 #ifdef INTERCUTS_VERBOSE
36 #define INTER_LOG
37 #endif
38 
39 #ifdef INTER_LOG
40 #define INTERLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
41 #else
42 #define INTERLOG(x)
43 #endif
44 
45 #include <string.h>
46 
47 #include "scip/cons_nonlinear.h"
48 #include "scip/pub_nlhdlr.h"
49 #include "scip/nlhdlr_quadratic.h"
50 #include "scip/expr_pow.h"
51 #include "scip/expr_sum.h"
52 #include "scip/expr_var.h"
53 #include "scip/expr_product.h"
54 #include "scip/pub_misc_rowprep.h"
55 
56 /* fundamental nonlinear handler properties */
57 #define NLHDLR_NAME "quadratic"
58 #define NLHDLR_DESC "handler for quadratic expressions"
59 #define NLHDLR_DETECTPRIORITY 1
60 #define NLHDLR_ENFOPRIORITY 100
61 
62 /* properties of the quadratic nlhdlr statistics table */
63 #define TABLE_NAME_QUADRATIC "nlhdlr_quadratic"
64 #define TABLE_DESC_QUADRATIC "quadratic nlhdlr statistics table"
65 #define TABLE_POSITION_QUADRATIC 14700 /**< the position of the statistics table */
66 #define TABLE_EARLIEST_STAGE_QUADRATIC SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
67 
68 /* some default values */
69 #define INTERCUTS_MINVIOL 1e-4
70 #define DEFAULT_USEINTERCUTS FALSE
71 #define DEFAULT_USESTRENGTH FALSE
72 #define DEFAULT_USEBOUNDS FALSE
73 #define BINSEARCH_MAXITERS 120
74 #define DEFAULT_NCUTSROOT 20
75 #define DEFAULT_NCUTS 2
76 
77 /*
78  * Data structures
79  */
80 
81 /** nonlinear handler expression data */
82 struct SCIP_NlhdlrExprData
83 {
84  SCIP_EXPR* qexpr; /**< quadratic expression (stored here again for convenient access) */
85 
86  SCIP_EXPRCURV curvature; /**< curvature of the quadratic representation of the expression */
87 
88  SCIP_INTERVAL linactivity; /**< activity of linear part */
89 
90  /* activities of quadratic parts as defined in nlhdlrIntevalQuadratic */
91  SCIP_Real minquadfiniteact; /**< minimum activity of quadratic part where only terms with finite min
92  activity contribute */
93  SCIP_Real maxquadfiniteact; /**< maximum activity of quadratic part where only terms with finite max
94  activity contribute */
95  int nneginfinityquadact;/**< number of quadratic terms contributing -infinity to activity */
96  int nposinfinityquadact;/**< number of quadratic terms contributing +infinity to activity */
97  SCIP_INTERVAL* quadactivities; /**< activity of each quadratic term as defined in nlhdlrIntevalQuadratic */
98  SCIP_INTERVAL quadactivity; /**< activity of quadratic part (sum of quadactivities) */
99  SCIP_Longint activitiestag; /**< value of activities tag when activities were computed */
100 
101  SCIP_CONS* cons; /**< if expr is the root of constraint cons, store cons; otherwise NULL */
102  SCIP_Bool separating; /**< whether we are using the nlhdlr also for separation */
103  SCIP_Bool origvars; /**< whether the quad expr in qexpr is in original (non-aux) variables */
104 
105  int ncutsadded; /**< number of intersection cuts added for this quadratic */
106 };
107 
108 /** nonlinear handler data */
109 struct SCIP_NlhdlrData
110 {
111  int ncutsgenerated; /**< total number of cuts that where generated by separateQuadratic */
112  int ncutsadded; /**< total number of cuts that where generated by separateQuadratic and actually added */
113  SCIP_Longint lastnodenumber; /**< number of last node for which cuts were (allowed to be) generated */
114  int lastncuts; /**< number of cuts already generated */
115 
116  /* parameter */
117  SCIP_Bool useintersectioncuts; /**< whether to use intersection cuts for quadratic constraints or not */
118  SCIP_Bool usestrengthening; /**< whether the strengthening should be used */
119  SCIP_Bool useboundsasrays; /**< use bounds of variables in quadratic as rays for intersection cuts */
120  int ncutslimit; /**< limit for number of cuts generated consecutively */
121  int ncutslimitroot; /**< limit for number of cuts generated at root node */
122  int maxrank; /**< maximal rank a slackvar can have */
123  SCIP_Real mincutviolation; /**< minimal cut violation the generated cuts must fulfill to be added to the LP */
124  SCIP_Real minviolation; /**< minimal violation the constraint must fulfill such that a cut can be generated */
125  int atwhichnodes; /**< determines at which nodes cut is used (if it's -1, it's used only at the root node,
126  if it's n >= 0, it's used at every multiple of n) */
127  int nstrengthlimit; /**< limit for number of rays we do the strengthening for */
128  SCIP_Real cutcoefsum; /**< sum of average cutcoefs of a cut */
129  SCIP_Bool ignorebadrayrestriction; /**< should cut be generated even with bad numerics when restricting to ray? */
130  SCIP_Bool ignorehighre; /**< should cut be added even when range / efficacy is large? */
131 
132  /* statistics */
133  int ncouldimprovedcoef; /**< number of times a coefficient could improve but didn't because of numerics */
134  int nbadrayrestriction; /**< number of times a cut was aborted because of numerics when restricting to ray */
135  int nbadnonbasic; /**< number of times a cut was aborted because the nonbasic row was not nonbasic enough */
136  int nhighre; /**< number of times a cut was not added because range / efficacy was too large */
137  int nphinonneg; /**< number of times a cut was aborted because phi is nonnegative at 0 */
138  int nstrengthenings; /**< number of successful strengthenings */
139  int nboundcuts; /**< number of successful bound cuts */
140  SCIP_Real ncalls; /**< number of calls to separation */
141  SCIP_Real densitysum; /**< sum of density of cuts */
142 };
143 
144 /* structure to store rays. note that for a given ray, the entries in raysidx are sorted. */
145 struct Rays
146 {
147  SCIP_Real* rays; /**< coefficients of rays */
148  int* raysidx; /**< to which var the coef belongs; vars are [quadvars, linvars, auxvar] */
149  int* raysbegin; /**< positions of rays: coefs of i-th ray [raybegin[i], raybegin[i+1]) */
150  int* lpposray; /**< lp pos of var associated with the ray;
151  >= 0 -> lppos of var; < 0 -> var is row -lpposray -1 */
152 
153  int rayssize; /**< size of rays and rays idx */
154  int nrays; /**< size of raysbegin is nrays + 1; size of lpposray */
155 };
156 typedef struct Rays RAYS;
157 
158 
159 /*
160  * Callback methods of the table
161  */
162 
163 /** output method of statistics table to output file stream 'file' */
164 static
165 SCIP_DECL_TABLEOUTPUT(tableOutputQuadratic)
166 { /*lint --e{715}*/
167  SCIP_NLHDLR* nlhdlr;
168  SCIP_NLHDLRDATA* nlhdlrdata;
169  SCIP_CONSHDLR* conshdlr;
170 
171  conshdlr = SCIPfindConshdlr(scip, "nonlinear");
172  assert(conshdlr != NULL);
173  nlhdlr = SCIPfindNlhdlrNonlinear(conshdlr, NLHDLR_NAME);
174  assert(nlhdlr != NULL);
175  nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
176  assert(nlhdlrdata);
177 
178  /* print statistics */
179  SCIPinfoMessage(scip, file, "Quadratic Nlhdlr : %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s %10s \n", "GenCuts", "AddCuts", "CouldImpr", "NLargeRE",
180  "AbrtBadRay", "AbrtPosPhi", "AbrtNonBas", "NStrength", "AveCutcoef", "AveDensity", "AveBCutsFrac");
181  SCIPinfoMessage(scip, file, " %-17s:", "Quadratic Nlhdlr");
182  SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->ncutsgenerated);
183  SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->ncutsadded);
184  SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->ncouldimprovedcoef);
185  SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nhighre);
186  SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nbadrayrestriction);
187  SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nphinonneg);
188  SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nbadnonbasic);
189  SCIPinfoMessage(scip, file, " %10d", nlhdlrdata->nstrengthenings);
190  SCIPinfoMessage(scip, file, " %10g", nlhdlrdata->nstrengthenings > 0 ? nlhdlrdata->cutcoefsum / nlhdlrdata->nstrengthenings : 0.0);
191  SCIPinfoMessage(scip, file, " %10g", nlhdlrdata->ncutsadded > 0 ? nlhdlrdata->densitysum / nlhdlrdata->ncutsadded : 0.0);
192  SCIPinfoMessage(scip, file, " %10g", nlhdlrdata->ncalls > 0 ? nlhdlrdata->nboundcuts / nlhdlrdata->ncalls : 0.0);
193  SCIPinfoMessage(scip, file, "\n");
194 
195  return SCIP_OKAY;
196 }
197 
198 
199 /*
200  * static methods
201  */
202 
203 /** adds cutcoef * (col - col*) to rowprep */
204 static
206  SCIP* scip, /**< SCIP data structure */
207  SCIP_ROWPREP* rowprep, /**< rowprep to store intersection cut */
208  SCIP_SOL* sol, /**< solution to separate */
209  SCIP_Real cutcoef, /**< cut coefficient */
210  SCIP_COL* col /**< column to add to rowprep */
211  )
212 {
213  assert(col != NULL);
214 
215 #ifdef DEBUG_INTERCUTS_NUMERICS
216  SCIPinfoMessage(scip, NULL, "adding col %s to cut. %g <= col <= %g\n", SCIPvarGetName(SCIPcolGetVar(col)),
218  SCIPinfoMessage(scip, NULL, "col is active at %s. Value %.15f\n", SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_LOWER ? "lower bound" :
219  "upper bound" , SCIPcolGetPrimsol(col));
220 #endif
221 
222  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPcolGetVar(col), cutcoef) );
223  SCIProwprepAddConstant(rowprep, -cutcoef * SCIPgetSolVal(scip, sol, SCIPcolGetVar(col)) );
224 
225  return SCIP_OKAY;
226 }
227 
228 /** adds cutcoef * (slack - slack*) to rowprep
229  *
230  * row is lhs &le; <coefs, vars> + constant &le; rhs, thus slack is defined by
231  * slack + <coefs.vars> + constant = side
232  *
233  * If row (slack) is at upper, it means that <coefs,vars*> + constant = rhs, and so
234  * slack* = side - rhs --> slack - slack* = rhs - <coefs, vars> - constant.
235  *
236  * If row (slack) is at lower, then <coefs,vars*> + constant = lhs, and so
237  * slack* = side - lhs --> slack - slack* = lhs - <coefs, vars> - constant.
238  */
239 static
241  SCIP* scip, /**< SCIP data structure */
242  SCIP_ROWPREP* rowprep, /**< rowprep to store intersection cut */
243  SCIP_Real cutcoef, /**< cut coefficient */
244  SCIP_ROW* row, /**< row, whose slack we are ading to rowprep */
245  SCIP_Bool* success /**< if the row is nonbasic enough */
246  )
247 {
248  int i;
249  SCIP_COL** rowcols;
250  SCIP_Real* rowcoefs;
251  int nnonz;
252 
253  assert(row != NULL);
254 
255  rowcols = SCIProwGetCols(row);
256  rowcoefs = SCIProwGetVals(row);
257  nnonz = SCIProwGetNLPNonz(row);
258 
259 #ifdef DEBUG_INTERCUTS_NUMERICS
260  SCIPinfoMessage(scip, NULL, "adding slack var row_%d to cut. %g <= row <= %g\n", SCIProwGetLPPos(row), SCIProwGetLhs(row), SCIProwGetRhs(row));
261  SCIPinfoMessage(scip, NULL, "row is active at %s = %.15f Activity %.15f\n", SCIProwGetBasisStatus(row) == SCIP_BASESTAT_LOWER ? "lhs" :
263  SCIPgetRowActivity(scip, row));
264 #endif
265 
267  {
268  assert(!SCIPisInfinity(scip, -SCIProwGetLhs(row)));
269  if( ! SCIPisFeasEQ(scip, SCIProwGetLhs(row), SCIPgetRowActivity(scip, row)) )
270  {
271  *success = FALSE;
272  return SCIP_OKAY;
273  }
274 
275  SCIProwprepAddConstant(rowprep, SCIProwGetLhs(row) * cutcoef);
276  }
277  else
278  {
279  assert(!SCIPisInfinity(scip, SCIProwGetRhs(row)));
280  if( ! SCIPisFeasEQ(scip, SCIProwGetRhs(row), SCIPgetRowActivity(scip, row)) )
281  {
282  *success = FALSE;
283  return SCIP_OKAY;
284  }
285 
286  SCIProwprepAddConstant(rowprep, SCIProwGetRhs(row) * cutcoef);
287  }
288 
289  for( i = 0; i < nnonz; i++ )
290  {
291  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPcolGetVar(rowcols[i]), -rowcoefs[i] * cutcoef) );
292  }
293 
294  SCIProwprepAddConstant(rowprep, -SCIProwGetConstant(row) * cutcoef);
295 
296  return SCIP_OKAY;
297 }
298 
299 /** constructs map between lp position of a basic variable and its row in the tableau */
300 static
302  SCIP* scip, /**< SCIP data structure */
303  int* map /**< buffer to store the map */
304  )
305 {
306  int* basisind;
307  int nrows;
308  int i;
309 
310  nrows = SCIPgetNLPRows(scip);
311  SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) );
312 
313  SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) );
314  for( i = 0; i < nrows; ++i )
315  {
316  if( basisind[i] >= 0 )
317  map[basisind[i]] = i;
318  }
319 
320  SCIPfreeBufferArray(scip, &basisind);
321 
322  return SCIP_OKAY;
323 }
324 
325 /** counts the number of basic variables in the quadratic expr */
326 static
328  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
329  SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
330  SCIP_Bool* nozerostat /**< whether there is no variable with basis status zero */
331  )
332 {
333  SCIP_EXPR* qexpr;
334  SCIP_EXPR** linexprs;
335  SCIP_COL* col;
336  int i;
337  int nbasicvars = 0;
338  int nquadexprs;
339  int nlinexprs;
340 
341  *nozerostat = TRUE;
342 
343  qexpr = nlhdlrexprdata->qexpr;
344  SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, NULL, NULL, NULL);
345 
346  /* loop over quadratic vars */
347  for( i = 0; i < nquadexprs; ++i )
348  {
349  SCIP_EXPR* expr;
350 
351  SCIPexprGetQuadraticQuadTerm(qexpr, i, &expr, NULL, NULL, NULL, NULL, NULL);
352 
355  nbasicvars += 1;
356  else if( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_ZERO )
357  {
358  *nozerostat = FALSE;
359  return 0;
360  }
361  }
362 
363  /* loop over linear vars */
364  for( i = 0; i < nlinexprs; ++i )
365  {
366  col = SCIPvarGetCol(SCIPgetExprAuxVarNonlinear(linexprs[i]));
368  nbasicvars += 1;
369  else if( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_ZERO )
370  {
371  *nozerostat = FALSE;
372  return 0;
373  }
374  }
375 
376  /* finally consider the aux var (if it exists) */
377  if( auxvar != NULL )
378  {
379  col = SCIPvarGetCol(auxvar);
381  nbasicvars += 1;
382  else if( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_ZERO )
383  {
384  *nozerostat = FALSE;
385  return 0;
386  }
387  }
388 
389  return nbasicvars;
390 }
391 
392 /** stores the row of the tableau where `col` is basic
393  *
394  * In general, we will have
395  *
396  * basicvar1 = tableaurow var1
397  * basicvar2 = tableaurow var2
398  * ...
399  * basicvarn = tableaurow varn
400  *
401  * However, we want to store the the tableau row by columns. Thus, we need to know which of the basic vars `col` is.
402  *
403  * Note we only store the entries of the nonbasic variables
404  */
405 static
407  SCIP* scip, /**< SCIP data structure */
408  SCIP_COL* col, /**< basic columns to store its tableau row */
409  int* basicvarpos2tableaurow,/**< map between basic var and its tableau row */
410  int nbasiccol, /**< which basic var this is */
411  int raylength, /**< the length of a ray (the total number of basic vars) */
412  SCIP_Real* binvrow, /**< buffer to store row of Binv */
413  SCIP_Real* binvarow, /**< buffer to store row of Binv A */
414  SCIP_Real* tableaurows /**< pointer to store the tableau rows */
415  )
416 {
417  int nrows;
418  int ncols;
419  int lppos;
420  int i;
421  SCIP_COL** cols;
422  SCIP_ROW** rows;
423  int nray;
424 
425  assert(nbasiccol < raylength);
426  assert(col != NULL);
427  assert(binvrow != NULL);
428  assert(binvarow != NULL);
429  assert(tableaurows != NULL);
430  assert(basicvarpos2tableaurow != NULL);
432 
433  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
434  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
435 
436  lppos = SCIPcolGetLPPos(col);
437 
438  assert(basicvarpos2tableaurow[lppos] >= 0);
439 
440  SCIP_CALL( SCIPgetLPBInvRow(scip, basicvarpos2tableaurow[lppos], binvrow, NULL, NULL) );
441  SCIP_CALL( SCIPgetLPBInvARow(scip, basicvarpos2tableaurow[lppos], binvrow, binvarow, NULL, NULL) );
442 
443  nray = 0;
444  for( i = 0; i < ncols; ++i )
446  {
447  tableaurows[nbasiccol + nray * raylength] = binvarow[i];
448  nray++;
449  }
450  for( ; i < ncols + nrows; ++i )
451  if( SCIProwGetBasisStatus(rows[i - ncols]) != SCIP_BASESTAT_BASIC )
452  {
453  tableaurows[nbasiccol + nray * raylength] = binvrow[i - ncols];
454  nray++;
455  }
456 
457  return SCIP_OKAY;
458 }
459 
460 /** stores the rows of the tableau corresponding to the basic variables in the quadratic expression
461  *
462  * Also return a map storing to which var the entry of a ray corresponds, i.e., if the tableau is
463  *
464  * basicvar_1 = ray1_1 nonbasicvar_1 + ...
465  * basicvar_2 = ray1_2 nonbasicvar_1 + ...
466  * ...
467  * basicvar_n = ray1_n nonbasicvar_1 + ...
468  *
469  * The map maps k to the position of basicvar_k in the variables of the constraint assuming the variables are sorted as
470  * [quadratic vars, linear vars, auxvar].
471  */
472 static
474  SCIP* scip, /**< SCIP data structure */
475  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
476  int raylength, /**< length of a ray of the tableau */
477  SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
478  SCIP_Real* tableaurows, /**< buffer to store the tableau rows */
479  int* rayentry2conspos /**< buffer to store the map */
480  )
481 {
482  SCIP_EXPR* qexpr;
483  SCIP_EXPR** linexprs;
484  SCIP_Real* binvarow;
485  SCIP_Real* binvrow;
486  SCIP_COL* col;
487  int* basicvarpos2tableaurow; /* map between basic var and its tableau row */
488  int nrayentries;
489  int nquadexprs;
490  int nlinexprs;
491  int nrows;
492  int ncols;
493  int i;
494 
495  nrows = SCIPgetNLPRows(scip);
496  ncols = SCIPgetNLPCols(scip);
497 
498  SCIP_CALL( SCIPallocBufferArray(scip, &basicvarpos2tableaurow, ncols) );
499  SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) );
500  SCIP_CALL( SCIPallocBufferArray(scip, &binvarow, ncols) );
501 
502  for( i = 0; i < ncols; ++i )
503  basicvarpos2tableaurow[i] = -1;
504  SCIP_CALL( constructBasicVars2TableauRowMap(scip, basicvarpos2tableaurow) );
505 
506  qexpr = nlhdlrexprdata->qexpr;
507  SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, NULL, NULL, NULL);
508 
509  /* entries of quadratic basic vars */
510  nrayentries = 0;
511  for( i = 0; i < nquadexprs; ++i )
512  {
513  SCIP_EXPR* expr;
514  SCIPexprGetQuadraticQuadTerm(qexpr, i, &expr, NULL, NULL, NULL, NULL, NULL);
515 
518  {
519  SCIP_CALL( storeDenseTableauRow(scip, col, basicvarpos2tableaurow, nrayentries, raylength, binvrow, binvarow,
520  tableaurows) );
521 
522  rayentry2conspos[nrayentries] = i;
523  nrayentries++;
524  }
525  }
526  /* entries of linear vars */
527  for( i = 0; i < nlinexprs; ++i )
528  {
529  col = SCIPvarGetCol(SCIPgetExprAuxVarNonlinear(linexprs[i]));
531  {
532  SCIP_CALL( storeDenseTableauRow(scip, col, basicvarpos2tableaurow, nrayentries, raylength, binvrow, binvarow,
533  tableaurows) );
534 
535  rayentry2conspos[nrayentries] = nquadexprs + i;
536  nrayentries++;
537  }
538  }
539  /* entry of aux var (if it exists) */
540  if( auxvar != NULL )
541  {
542  col = SCIPvarGetCol(auxvar);
544  {
545  SCIP_CALL( storeDenseTableauRow(scip, col, basicvarpos2tableaurow, nrayentries, raylength, binvrow, binvarow,
546  tableaurows) );
547 
548  rayentry2conspos[nrayentries] = nquadexprs + nlinexprs;
549  nrayentries++;
550  }
551  }
552  assert(nrayentries == raylength);
553 
554 #ifdef DEBUG_INTERSECTIONCUT
555  for( i = 0; i < ncols; ++i )
556  {
557  SCIPinfoMessage(scip, NULL, "%d column of tableau is: ",i);
558  for( int j = 0; j < raylength; ++j )
559  SCIPinfoMessage(scip, NULL, "%g ", tableaurows[i * raylength + j]);
560  SCIPinfoMessage(scip, NULL, "\n");
561  }
562 #endif
563 
564  SCIPfreeBufferArray(scip, &binvarow);
565  SCIPfreeBufferArray(scip, &binvrow);
566  SCIPfreeBufferArray(scip, &basicvarpos2tableaurow);
567 
568  return SCIP_OKAY;
569 }
570 
571 /** initializes rays data structure */
572 static
574  SCIP* scip, /**< SCIP data structure */
575  RAYS** rays /**< rays data structure */
576  )
577 {
578  SCIP_CALL( SCIPallocBuffer(scip, rays) );
579  BMSclearMemory(*rays);
580 
581  SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->rays, SCIPgetNLPCols(scip)) );
582  SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->raysidx, SCIPgetNLPCols(scip)) );
583 
584  /* overestimate raysbegin and lpposray */
585  SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->raysbegin, SCIPgetNLPCols(scip) + SCIPgetNLPRows(scip) + 1) );
586  SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->lpposray, SCIPgetNLPCols(scip) + SCIPgetNLPRows(scip)) );
587  (*rays)->raysbegin[0] = 0;
588 
589  (*rays)->rayssize = SCIPgetNLPCols(scip);
590 
591  return SCIP_OKAY;
592 }
593 
594 /** initializes rays data structure for bound rays */
595 static
597  SCIP* scip, /**< SCIP data structure */
598  RAYS** rays, /**< rays data structure */
599  int size /**< number of rays to allocate */
600  )
601 {
602  SCIP_CALL( SCIPallocBuffer(scip, rays) );
603  BMSclearMemory(*rays);
604 
605  SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->rays, size) );
606  SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->raysidx, size) );
607 
608  /* overestimate raysbegin and lpposray */
609  SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->raysbegin, size + 1) );
610  SCIP_CALL( SCIPallocBufferArray(scip, &(*rays)->lpposray, size) );
611  (*rays)->raysbegin[0] = 0;
612 
613  (*rays)->rayssize = size;
614 
615  return SCIP_OKAY;
616 }
617 
618 /** frees rays data structure */
619 static
620 void freeRays(
621  SCIP* scip, /**< SCIP data structure */
622  RAYS** rays /**< rays data structure */
623  )
624 {
625  if( *rays == NULL )
626  return;
627 
628  SCIPfreeBufferArray(scip, &(*rays)->lpposray);
629  SCIPfreeBufferArray(scip, &(*rays)->raysbegin);
630  SCIPfreeBufferArray(scip, &(*rays)->raysidx);
631  SCIPfreeBufferArray(scip, &(*rays)->rays);
632 
633  SCIPfreeBuffer(scip, rays);
634 }
635 
636 /** inserts entry to rays data structure; checks and resizes if more space is needed */
637 static
639  SCIP* scip, /**< SCIP data structure */
640  RAYS* rays, /**< rays data structure */
641  SCIP_Real coef, /**< coefficient to insert */
642  int coefidx, /**< index of coefficient (conspos of var it corresponds to) */
643  int coefpos /**< where to insert coefficient */
644  )
645 {
646  /* check for size */
647  if( rays->rayssize <= coefpos + 1 )
648  {
649  int newsize;
650 
651  newsize = SCIPcalcMemGrowSize(scip, coefpos + 1);
652  SCIP_CALL( SCIPreallocBufferArray(scip, &(rays->rays), newsize) );
653  SCIP_CALL( SCIPreallocBufferArray(scip, &(rays->raysidx), newsize) );
654  rays->rayssize = newsize;
655  }
656 
657  /* insert entry */
658  rays->rays[coefpos] = coef;
659  rays->raysidx[coefpos] = coefidx;
660 
661  return SCIP_OKAY;
662 }
663 
664 /** constructs map between the lppos of a variables and its position in the constraint assuming the constraint variables
665  * are sorted as [quad vars, lin vars, aux var (if it exists)]
666  *
667  * If a variable doesn't appear in the constraint, then its position is -1.
668  */
669 static
671  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
672  SCIP_VAR* auxvar, /**< aux var of the expr */
673  int* map /**< buffer to store the mapping */
674  )
675 {
676  SCIP_EXPR* qexpr;
677  SCIP_EXPR** linexprs;
678  int nquadexprs;
679  int nlinexprs;
680  int lppos;
681  int i;
682 
683  qexpr = nlhdlrexprdata->qexpr;
684  SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, NULL, NULL, NULL);
685 
686  /* set pos of quadratic vars */
687  for( i = 0; i < nquadexprs; ++i )
688  {
689  SCIP_EXPR* expr;
690  SCIPexprGetQuadraticQuadTerm(qexpr, i, &expr, NULL, NULL, NULL, NULL, NULL);
691 
693  map[lppos] = i;
694  }
695  /* set pos of lin vars */
696  for( i = 0; i < nlinexprs; ++i )
697  {
699  map[lppos] = nquadexprs + i;
700  }
701  /* set pos of aux var (if it exists) */
702  if( auxvar != NULL )
703  {
704  lppos = SCIPcolGetLPPos(SCIPvarGetCol(auxvar));
705  map[lppos] = nquadexprs + nlinexprs;
706  }
707 
708  return;
709 }
710 
711 /** inserts entries of factor * nray-th column of densetableaucols into rays data structure */
712 static
714  SCIP* scip, /**< SCIP data structure */
715  RAYS* rays, /**< rays data structure */
716  SCIP_Real* densetableaucols, /**< column of the tableau in dense format */
717  int* rayentry2conspos, /**< map between rayentry and conspos of associated var */
718  int raylength, /**< length of a tableau column */
719  int nray, /**< which tableau column to insert */
720  int conspos, /**< conspos of ray's nonbasic var in the cons; -1 if not in the cons */
721  SCIP_Real factor, /**< factor to multiply each tableau col */
722  int* nnonz, /**< position to start adding the ray in rays and buffer to store nnonz */
723  SCIP_Bool* success /**< we can't separate if there is a nonzero ray with basis status ZERO */
724  )
725 {
726  int i;
727 
728  *success = TRUE;
729 
730  for( i = 0; i < raylength; ++i )
731  {
732  SCIP_Real coef;
733 
734  /* we have a nonzero ray with base stat zero -> can't generate cut */
735  if( factor == 0.0 && ! SCIPisZero(scip, densetableaucols[nray * raylength + i]) )
736  {
737  *success = FALSE;
738  return SCIP_OKAY;
739  }
740 
741  coef = factor * densetableaucols[nray * raylength + i];
742 
743  /* this might be a source of numerical issues
744  * TODO: in case of problems, an idea would be to scale the ray entries; compute the cut coef and scale it back down
745  * another idea would be to check against a smaller epsilion.
746  * The problem is that if the cut coefficient is 1/t where lpsol + t*ray intersects the S-free set.
747  * Now if t is super big, then a super small coefficient would have had an impact...
748  */
749  if( SCIPisZero(scip, coef) )
750  continue;
751 
752  /* check if nonbasic var entry should come before this one */
753  if( conspos > -1 && conspos < rayentry2conspos[i] )
754  {
755  /* add nonbasic entry */
756  assert(factor != 0.0);
757 
758 #ifdef DEBUG_INTERSECTIONCUT
759  SCIPinfoMessage(scip, NULL, "ray belongs to nonbasic var pos %d in cons\n", conspos);
760 #endif
761 
762  SCIP_CALL( insertRayEntry(scip, rays, -factor, conspos, *nnonz) );
763  (*nnonz)++;
764 
765  /* we are done with nonbasic entry */
766  conspos = -1;
767  }
768 
769  SCIP_CALL( insertRayEntry(scip, rays, coef, rayentry2conspos[i], *nnonz) );
770  (*nnonz)++;
771  }
772 
773  /* if nonbasic entry was not added and should still be added, then it should go at the end */
774  if( conspos > -1 )
775  {
776  /* add nonbasic entry */
777  assert(factor != 0.0);
778 
779 #ifdef DEBUG_INTERSECTIONCUT
780  SCIPinfoMessage(scip, NULL, "ray belongs to nonbasic var pos %d in cons\n", conspos);
781 #endif
782 
783  SCIP_CALL( insertRayEntry(scip, rays, -factor, conspos, *nnonz) );
784  (*nnonz)++;
785  }
786 
787  /* finished ray entry; store its end */
788  rays->raysbegin[rays->nrays + 1] = *nnonz;
789 
790 #ifdef DEBUG_INTERSECTIONCUT
791  SCIPinfoMessage(scip, NULL, "entries of ray %d are between [%d, %d):\n", rays->nrays, rays->raysbegin[rays->nrays], *nnonz);
792  for( i = rays->raysbegin[rays->nrays]; i < *nnonz; ++i )
793  SCIPinfoMessage(scip, NULL, "(%d, %g), ", rays->raysidx[i], rays->rays[i]);
794  SCIPinfoMessage(scip, NULL, "\n");
795 #endif
796 
797  return SCIP_OKAY;
798 }
799 
800 /** stores rays in sparse form
801  *
802  * The first rays correspond to the nonbasic variables
803  * and the last rays to the nonbasic slack variables.
804  *
805  * More details: The LP tableau is of the form
806  *
807  * basicvar_1 = ray1_1 nonbasicvar_1 + ... + raym_1 nonbasicvar_m
808  * basicvar_2 = ray1_2 nonbasicvar_1 + ... + raym_2 nonbasicvar_m
809  * ...
810  * basicvar_n = ray1_n nonbasicvar_1 + ... + raym_n nonbasicvar_m
811  * nonbasicvar_1 = 1.0 nonbasicvar_1 + ... + 0.0 nonbasicvar_m
812  * ...
813  * nonbasicvar_m = 0.0 nonbasicvar_1 + ... + 1.0 nonbasicvar_m
814  *
815  * so rayk = (rayk_1, ... rayk_n, e_k)
816  * We store the entries of the rays associated to the variables present in the quadratic expr.
817  * We do not store zero rays.
818  *
819  * Also, we store the rays as if every nonbasic variable was at lower (so that all rays moves to infinity)
820  * Since the tableau is:
821  *
822  * basicvar + Binv L (nonbasic_lower - lb) + Binv U (nonbasic_upper - ub) = basicvar_sol
823  *
824  * then:
825  *
826  * basicvar = basicvar_sol - Binv L (nonbasic_lower - lb) + Binv U (ub - nonbasic_upper)
827  *
828  * and so the entries of the rays associated with the basic variables are:
829  * rays_basicvars = [-BinvL, BinvU].
830  *
831  * So we flip the sign of the rays associated to nonbasic vars at lower.
832  * In constrast, the nonbasic part of the ray has a 1.0 for nonbasic at lower and a -1.0 for nonbasic at upper, i.e.
833  * nonbasic_lower = lb + 1.0(nonbasic_lower - lb) and
834  * nonbasic_upper = ub - 1.0(ub - nonbasic_upper)
835  */
836 static
838  SCIP* scip, /**< SCIP data structure */
839  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
840  SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
841  RAYS** raysptr, /**< buffer to store rays datastructure */
842  SCIP_Bool* success /**< we can't separate if there is a var with basis status ZERO */
843  )
844 {
845  SCIP_Real* densetableaucols;
846  SCIP_COL** cols;
847  SCIP_ROW** rows;
848  RAYS* rays;
849  int* rayentry2conspos;
850  int* lppos2conspos;
851  int nnonbasic;
852  int nrows;
853  int ncols;
854  int nnonz;
855  int raylength;
856  int i;
857 
858  nrows = SCIPgetNLPRows(scip);
859  ncols = SCIPgetNLPCols(scip);
860 
861  *success = TRUE;
862 
863  raylength = countBasicVars(nlhdlrexprdata, auxvar, success);
864  if( ! *success )
865  {
866  SCIPdebugMsg(scip, "failed to store sparse rays: there is a var with base status zero\n");
867  return SCIP_OKAY;
868  }
869 
870  SCIP_CALL( SCIPallocBufferArray(scip, &densetableaucols, raylength * (ncols + nrows)) );
871  SCIP_CALL( SCIPallocBufferArray(scip, &rayentry2conspos, raylength) );
872 
873  /* construct dense tableau and map between ray entries and position of corresponding var in quad cons */
874  SCIP_CALL( storeDenseTableauRowsByColumns(scip, nlhdlrexprdata, raylength, auxvar,
875  densetableaucols, rayentry2conspos) );
876 
877  /* build rays sparsely now */
878  SCIP_CALL( SCIPallocBufferArray(scip, &lppos2conspos, ncols) );
879  for( i = 0; i < ncols; ++i )
880  lppos2conspos[i] = -1;
881 
882  constructLPPos2ConsPosMap(nlhdlrexprdata, auxvar, lppos2conspos);
883 
884  /* store sparse rays */
885  SCIP_CALL( createRays(scip, raysptr) );
886  rays = *raysptr;
887 
888  nnonz = 0;
889  nnonbasic = 0;
890 
891  /* go through nonbasic variables */
892  cols = SCIPgetLPCols(scip);
893  for( i = 0; i < ncols; ++i )
894  {
895  int oldnnonz = nnonz;
896  SCIP_COL* col;
897  SCIP_Real factor;
898 
899  col = cols[i];
900 
901  /* set factor to store basic entries of ray as = [-BinvL, BinvU] */
903  factor = -1.0;
904  else if( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_UPPER )
905  factor = 1.0;
906  else if( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_ZERO )
907  factor = 0.0;
908  else
909  continue;
910 
911  SCIP_CALL( insertRayEntries(scip, rays, densetableaucols, rayentry2conspos, raylength, nnonbasic,
912  lppos2conspos[SCIPcolGetLPPos(col)], factor, &nnonz, success) );
913 
914 #ifdef DEBUG_INTERSECTIONCUT
915  SCIPinfoMessage(scip, NULL, "looked at ray of var %s with basestat %d, it has %d nonzeros\n-----------------\n",
916  SCIPvarGetName(SCIPcolGetVar(col)), SCIPcolGetBasisStatus(col), nnonz - oldnnonz);
917 #endif
918  if( ! (*success) )
919  {
920 #ifdef DEBUG_INTERSECTIONCUT
921  SCIPdebugMsg(scip, "nonzero ray associated with variable <%s> has base status zero -> abort storing rays\n",
923 #endif
924  goto CLEANUP;
925  }
926 
927  /* if ray is non zero remember who it belongs to */
928  assert(oldnnonz <= nnonz);
929  if( oldnnonz < nnonz )
930  {
931  rays->lpposray[rays->nrays] = SCIPcolGetLPPos(col);
932  (rays->nrays)++;
933  }
934  nnonbasic++;
935  }
936 
937  /* go through nonbasic slack variables */
938  rows = SCIPgetLPRows(scip);
939  for( i = 0; i < nrows; ++i )
940  {
941  int oldnnonz = nnonz;
942  SCIP_ROW* row;
943  SCIP_Real factor;
944 
945  row = rows[i];
946 
947  /* set factor to store basic entries of ray as = [-BinvL, BinvU]; basic status of rows are flipped! See lpi.h! */
950  factor = 1.0;
951  else if( SCIProwGetBasisStatus(row) == SCIP_BASESTAT_UPPER )
952  factor =-1.0;
953  else
954  continue;
955 
956  SCIP_CALL( insertRayEntries(scip, rays, densetableaucols, rayentry2conspos, raylength, nnonbasic, -1, factor,
957  &nnonz, success) );
958  assert(*success);
959 
960  /* if ray is non zero remember who it belongs to */
961 #ifdef DEBUG_INTERSECTIONCUT
962  SCIPinfoMessage(scip, NULL, "looked at ray of row %d, it has %d nonzeros\n-----------------\n", i, nnonz - oldnnonz);
963 #endif
964  assert(oldnnonz <= nnonz);
965  if( oldnnonz < nnonz )
966  {
967  rays->lpposray[rays->nrays] = -SCIProwGetLPPos(row) - 1;
968  (rays->nrays)++;
969  }
970  nnonbasic++;
971  }
972 
973 CLEANUP:
974  SCIPfreeBufferArray(scip, &lppos2conspos);
975  SCIPfreeBufferArray(scip, &rayentry2conspos);
976  SCIPfreeBufferArray(scip, &densetableaucols);
977 
978  if( ! *success )
979  {
980  freeRays(scip, &rays);
981  }
982 
983  return SCIP_OKAY;
984 }
985 
986 /* TODO: which function this comment belongs to? */
987 /* this function determines how the maximal S-free set is going to look like
988  *
989  * There are 4 possibilities: after writing the quadratic constraint
990  * \f$q(z) \leq 0\f$
991  * as
992  * \f$\Vert x(z)\Vert^2 - \Vert y\Vert^2 + w(z) + kappa \leq 0\f$,
993  * the cases are determined according to the following:
994  * - Case 1: w = 0 and kappa = 0
995  * - Case 2: w = 0 and kappa > 0
996  * - Case 3: w = 0 and kappa < 0
997  * - Case 4: w != 0
998  */
999 
1000 /** compute quantities for intersection cuts
1001  *
1002  * Assume the quadratic is stored as
1003  * \f[ q(z) = z_q^T Q z_q + b_q^T z_q + b_l z_l + c - z_a \f]
1004  * where:
1005  * - \f$z_q\f$ are the quadratic vars
1006  * - \f$z_l\f$ are the linear vars
1007  * - \f$z_a\f$ is the aux var if it exists
1008  *
1009  * We can rewrite it as
1010  * \f[ \Vert x(z)\Vert^2 - \Vert y\Vert^2 + w(z) + \kappa \leq 0. \f]
1011  * To do this transformation and later to compute the actual cut we need to compute and store some quantities.
1012  * Let
1013  * - \f$I_0\f$, \f$I_+\f$, and \f$I_-\f$ be the index set of zero, positive, and negative eigenvalues, respectively
1014  * - \f$v_i\f$ be the i-th eigenvector of \f$Q\f$
1015  * - \f$zlp\f$ be the lp value of the variables \f$z\f$
1016  *
1017  * The quantities we need are:
1018  * - \f$vb_i = v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$
1019  * - \f$vzlp_i = v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$
1020  * - \f$\kappa = c - 1/4 \sum_{i \in I_+ \cup I_-} (v_i^T b_q)^2 / eigval_i\f$
1021  * - \f$w(z) = (\sum_{i \in I_0} v_i^T b_q v_i^T) z_q + b_l^T z_l - z_a\f$
1022  * - \f$w(zlp)\f$
1023  *
1024  * @return \f$\kappa\f$ and the vector \f$\sum_{i \in I_0} v_i^T b_q v_i^T\f$
1025  *
1026  * @note if the constraint is q(z) &le; rhs, then the constant when writing the constraint as quad &le; 0 is c - rhs.
1027  * @note if the quadratic constraint we are separating is q(z) &ge; lhs, then we multiply by -1.
1028  * In practice, what changes is
1029  * - the sign of the eigenvalues
1030  * - the sign of \f$b_q\f$ and \f$b_l\f$
1031  * - the sign of the coefficient of the auxvar (if it exists)
1032  * - the constant of the quadratic written as quad &le; 0 is lhs - c
1033  * @note The eigenvectors _do not_ change sign!
1034  */
1035 static
1037  SCIP* scip, /**< SCIP data structure */
1038  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1039  SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
1040  SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
1041  SCIP_SOL* sol, /**< solution to separate */
1042  SCIP_Real* vb, /**< buffer to store \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
1043  SCIP_Real* vzlp, /**< buffer to store \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
1044  SCIP_Real* wcoefs, /**< buffer to store the coefs of quad vars of w */
1045  SCIP_Real* wzlp, /**< pointer to store the value of w at zlp */
1046  SCIP_Real* kappa /**< pointer to store the value of kappa */
1047  )
1048 {
1049  SCIP_EXPR* qexpr;
1050  SCIP_EXPR** linexprs;
1051  SCIP_Real* eigenvectors;
1052  SCIP_Real* eigenvalues;
1053  SCIP_Real* lincoefs;
1054  SCIP_Real constant; /* constant of the quadratic when written as <= 0 */
1055  int nquadexprs;
1056  int nlinexprs;
1057  int i;
1058  int j;
1059 
1060  assert(sidefactor == 1.0 || sidefactor == -1.0);
1061  assert(nlhdlrexprdata->cons != NULL || auxvar != NULL );
1062 
1063  qexpr = nlhdlrexprdata->qexpr;
1064  SCIPexprGetQuadraticData(qexpr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, NULL, &eigenvalues,
1065  &eigenvectors);
1066 
1067  assert( eigenvalues != NULL );
1068 
1069  /* first get constant of quadratic when written as quad <= 0 */
1070  if( nlhdlrexprdata->cons != NULL )
1071  constant = (sidefactor == 1.0) ? constant - SCIPgetRhsNonlinear(nlhdlrexprdata->cons) :
1072  SCIPgetLhsNonlinear(nlhdlrexprdata->cons) - constant;
1073  else
1074  constant = (sidefactor * constant);
1075 
1076  *kappa = 0.0;
1077  *wzlp = 0.0;
1078  BMSclearMemoryArray(wcoefs, nquadexprs);
1079 
1080  for( i = 0; i < nquadexprs; ++i )
1081  {
1082  SCIP_Real vdotb;
1083  SCIP_Real vdotzlp;
1084  int offset;
1085 
1086  offset = i * nquadexprs;
1087 
1088  /* compute v_i^T b and v_i^T zlp */
1089  vdotb = 0;
1090  vdotzlp = 0;
1091  for( j = 0; j < nquadexprs; ++j )
1092  {
1093  SCIP_EXPR* expr;
1094  SCIP_Real lincoef;
1095 
1096  SCIPexprGetQuadraticQuadTerm(qexpr, j, &expr, &lincoef, NULL, NULL, NULL, NULL);
1097 
1098  vdotb += (sidefactor * lincoef) * eigenvectors[offset + j];
1099 #ifdef INTERCUT_MOREDEBUG
1100  printf("vdotb: offset %d, eigenvector %d = %g, lincoef quad %g\n", offset, j,
1101  eigenvectors[offset + j], lincoef);
1102 #endif
1103  vdotzlp += SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr)) * eigenvectors[offset + j];
1104  }
1105  vb[i] = vdotb;
1106  vzlp[i] = vdotzlp;
1107 
1108  if( ! SCIPisZero(scip, eigenvalues[i]) )
1109  {
1110  /* nonzero eigenvalue: compute kappa */
1111  *kappa += SQR(vdotb) / (sidefactor * eigenvalues[i]);
1112  }
1113  else
1114  {
1115  /* compute coefficients of w and compute w at zlp */
1116  for( j = 0; j < nquadexprs; ++j )
1117  wcoefs[j] += vdotb * eigenvectors[offset + j];
1118 
1119  *wzlp += vdotb * vdotzlp;
1120  }
1121  }
1122 
1123  /* finish kappa computation */
1124  *kappa *= -0.25;
1125  *kappa += constant;
1126 
1127  /* finish w(zlp) computation: linear part (including auxvar, if applicable) */
1128  for( i = 0; i < nlinexprs; ++i )
1129  {
1130  *wzlp += (sidefactor * lincoefs[i]) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
1131  }
1132  if( auxvar != NULL )
1133  {
1134  *wzlp += (sidefactor * -1.0) * SCIPgetSolVal(scip, sol, auxvar);
1135  }
1136 
1137 #ifdef DEBUG_INTERSECTIONCUT
1138  SCIPinfoMessage(scip, NULL, "Computed common quantities needed for intercuts:\n");
1139  SCIPinfoMessage(scip, NULL, " kappa = %g\n quad part w = ", *kappa);
1140  for( i = 0; i < nquadexprs; ++i )
1141  {
1142  SCIPinfoMessage(scip, NULL, "%g ", wcoefs[i]);
1143  }
1144  SCIPinfoMessage(scip, NULL, "\n");
1145 #endif
1146  return SCIP_OKAY;
1147 }
1148 
1149 /** computes eigenvec^T ray */
1150 static
1152  SCIP_Real* eigenvec, /**< eigenvector */
1153  int nquadvars, /**< number of quadratic vars (length of eigenvec) */
1154  SCIP_Real* raycoefs, /**< coefficients of ray */
1155  int* rayidx, /**< index of consvar the ray coef is associated to */
1156  int raynnonz /**< length of raycoefs and rayidx */
1157  )
1158 {
1159  SCIP_Real retval;
1160  int i;
1161 
1162  retval = 0.0;
1163  for( i = 0; i < raynnonz; ++i )
1164  {
1165  /* rays are sorted; the first entries correspond to the quad vars, so we stop after first nonquad var entry */
1166  if( rayidx[i] >= nquadvars )
1167  break;
1168 
1169  retval += eigenvec[rayidx[i]] * raycoefs[i];
1170  }
1171 
1172  return retval;
1173 }
1174 
1175 /** computes linear part of evaluation of w(ray): \f$b_l^T ray_l - ray_a\f$
1176  *
1177  * @note we can know whether the auxiliary variable appears by the entries of the ray
1178  */
1179 static
1181  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1182  SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
1183  SCIP_Real* raycoefs, /**< coefficients of ray */
1184  int* rayidx, /**< ray coef[i] affects var at pos rayidx[i] in consvar */
1185  int raynnonz /**< length of raycoefs and rayidx */
1186  )
1187 {
1188  SCIP_EXPR* qexpr;
1189  SCIP_Real* lincoefs;
1190  SCIP_Real retval;
1191  int nquadexprs;
1192  int nlinexprs;
1193 
1194  int i;
1195  int start;
1196 
1197 #ifdef INTERCUT_MOREDEBUG
1198  printf("Computing w(ray) \n");
1199 #endif
1200  retval = 0.0;
1201  start = raynnonz - 1;
1202 
1203  qexpr = nlhdlrexprdata->qexpr;
1204  SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, NULL, &lincoefs, &nquadexprs, NULL, NULL, NULL);
1205 
1206  /* process ray entry associated to the auxvar if it applies */
1207  if( rayidx[raynnonz - 1] == nquadexprs + nlinexprs )
1208  {
1209 #ifdef INTERCUT_MOREDEBUG
1210  printf("wray auxvar term %g \n", (sidefactor * -1.0) * raycoefs[raynnonz - 1]);
1211 #endif
1212  retval += (sidefactor * -1.0) * raycoefs[raynnonz - 1];
1213  start--;
1214  }
1215 
1216  /* process the rest of the entries */
1217  for( i = start; i >= 0; --i )
1218  {
1219  /* rays are sorted; last entries correspond to the lin vars, so we stop after first quad var entry */
1220  if( rayidx[i] < nquadexprs )
1221  break;
1222 
1223 #ifdef INTERCUT_MOREDEBUG
1224  printf("wray var in pos %d term %g:: lincoef %g raycoef %g\n", rayidx[i], (sidefactor *
1225  lincoefs[rayidx[i] - nquadexprs]) * raycoefs[i], lincoefs[rayidx[i] - nquadexprs] ,raycoefs[i]);
1226 #endif
1227  retval += (sidefactor * lincoefs[rayidx[i] - nquadexprs]) * raycoefs[i] ;
1228  }
1229 
1230  return retval;
1231 }
1232 
1233 /** calculate coefficients of restriction of the function to given ray.
1234  *
1235  * The restriction of the function representing the maximal S-free set to zlp + t * ray has the form
1236  * SQRT(A t^2 + B t + C) - (D t + E) for cases 1, 2, and 3.
1237  * For case 4 it is a piecewise defined function and each piece is of the aforementioned form.
1238  *
1239  * This function computes the coefficients A, B, C, D, E for the given ray.
1240  * In case 4, it computes the coefficients for both pieces, in addition to coefficients needed to evaluate the condition
1241  * in the piecewise definition of the function.
1242  *
1243  * The parameter iscase4 tells the function if it is case 4 or not.
1244  */
1245 static
1247  SCIP* scip, /**< SCIP data structure */
1248  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1249  SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
1250  SCIP_Bool iscase4, /**< whether we are in case 4 */
1251  SCIP_Real* raycoefs, /**< coefficients of ray */
1252  int* rayidx, /**< index of consvar the ray coef is associated to */
1253  int raynnonz, /**< length of raycoefs and rayidx */
1254  SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
1255  SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
1256  SCIP_Real* wcoefs, /**< coefficients of w for the qud vars or NULL if w is 0 */
1257  SCIP_Real wzlp, /**< value of w at zlp */
1258  SCIP_Real kappa, /**< value of kappa */
1259  SCIP_Real* coefs1234a, /**< buffer to store A, B, C, D, and E of cases 1, 2, 3, or 4a */
1260  SCIP_Real* coefs4b, /**< buffer to store A, B, C, D, and E of case 4b (or NULL if not needed) */
1261  SCIP_Real* coefscondition, /**< buffer to store data to evaluate condition to decide case 4a or 4b */
1262  SCIP_Bool* success /**< did we successfully compute the coefficients? */
1263  )
1264 {
1265  SCIP_EXPR* qexpr;
1266  int nquadexprs;
1267  SCIP_Real* eigenvectors;
1268  SCIP_Real* eigenvalues;
1269  SCIP_Real* a;
1270  SCIP_Real* b;
1271  SCIP_Real* c;
1272  SCIP_Real* d;
1273  SCIP_Real* e;
1274  SCIP_Real wray;
1275  int i;
1276 
1277  *success = TRUE;
1278 
1279  qexpr = nlhdlrexprdata->qexpr;
1280  SCIPexprGetQuadraticData(qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, &eigenvalues, &eigenvectors);
1281 
1282 #ifdef DEBUG_INTERSECTIONCUT
1283  SCIPinfoMessage(scip, NULL, "\n############################################\n");
1284  SCIPinfoMessage(scip, NULL, "Restricting to ray:\n");
1285  for( i = 0; i < raynnonz; ++i )
1286  {
1287  SCIPinfoMessage(scip, NULL, "(%d, %g), ", rayidx[i], raycoefs[i]);
1288  }
1289  SCIPinfoMessage(scip, NULL, "\n");
1290 #endif
1291 
1292  assert(coefs1234a != NULL);
1293 
1294  /* set all coefficients to zero */
1295  memset(coefs1234a, 0, 5 * sizeof(SCIP_Real));
1296  if( iscase4 )
1297  {
1298  assert(coefs4b != NULL);
1299  assert(coefscondition != NULL);
1300  assert(wcoefs != NULL);
1301 
1302  memset(coefs4b, 0, 5 * sizeof(SCIP_Real));
1303  memset(coefscondition, 0, 3 * sizeof(SCIP_Real));
1304  }
1305 
1306  a = coefs1234a;
1307  b = coefs1234a + 1;
1308  c = coefs1234a + 2;
1309  d = coefs1234a + 3;
1310  e = coefs1234a + 4;
1311  wray = 0;
1312 
1313  for( i = 0; i < nquadexprs; ++i )
1314  {
1315  SCIP_Real dot = 0.0;
1316  SCIP_Real vdotray;
1317 
1318  if( SCIPisZero(scip, eigenvalues[i]) )
1319  {
1320  if( wcoefs == NULL )
1321  continue;
1322  }
1323  else
1324  {
1325  dot = vzlp[i] + vb[i] / (2.0 * (sidefactor * eigenvalues[i]));
1326  }
1327  vdotray = computeEigenvecDotRay(&eigenvectors[i * nquadexprs], nquadexprs, raycoefs, rayidx, raynnonz);
1328 
1329  if( SCIPisZero(scip, eigenvalues[i]) )
1330  {
1331  /* zero eigenvalue (and wcoefs not null) -> case 4: compute w(r) */
1332  assert(wcoefs != NULL);
1333  wray += vb[i] * vdotray;
1334 #ifdef INTERCUT_MOREDEBUG
1335  printf(" wray += %g, vb[i] %g and vdotray %g\n", vb[i] * vdotray,vb[i],vdotray);
1336 #endif
1337  }
1338  else if( sidefactor * eigenvalues[i] > 0 )
1339  {
1340  /* positive eigenvalue: compute common part of D and E */
1341  *d += (sidefactor * eigenvalues[i]) * dot * vdotray;
1342  *e += (sidefactor * eigenvalues[i]) * SQR( dot );
1343 
1344 #ifdef INTERCUT_MOREDEBUG
1345  printf("Positive eigenvalue: computing D: v^T ray %g, v^T( zlp + b/theta ) %g and theta %g \n", vdotray, dot, (sidefactor * eigenvalues[i]));
1346 #endif
1347  }
1348  else
1349  {
1350  /* negative eigenvalue: compute common part of A, B, and C */
1351  *a -= (sidefactor * eigenvalues[i]) * SQR( vdotray );
1352  *b -= 2.0 * (sidefactor * eigenvalues[i]) * dot * vdotray;
1353  *c -= (sidefactor * eigenvalues[i]) * SQR( dot );
1354 
1355 #ifdef INTERCUT_MOREDEBUG
1356  printf("Negative eigenvalue: computing A: v^T ray %g, and theta %g \n", vdotray, (sidefactor * eigenvalues[i]));
1357 #endif
1358  }
1359  }
1360 
1361  if( ! iscase4 )
1362  {
1363  /* We are in one of the first 3 cases */
1364  *e += MAX(kappa, 0.0);
1365  *c -= MIN(kappa, 0.0);
1366 
1367  /* finish computation of D and E */
1368  assert(*e > 0);
1369  *e = SQRT( *e );
1370  *d /= *e;
1371 
1372  /* some sanity checks only applicable to these cases (more at the end) */
1373  assert(*c >= 0);
1374 
1375  /* In theory, the function at 0 must be negative. Because of bad numerics this might not always hold, so we abort
1376  * the generation of the cut in this case.
1377  */
1378  if( SQRT( *c ) - *e >= 0 )
1379  {
1380  /* check if it's really a numerical problem */
1381  assert(SQRT( *c ) > 10e+15 || *e > 10e+15 || SQRT( *c ) - *e < 10e+9);
1382 
1383  INTERLOG(printf("Bad numerics: phi(0) >= 0\n"); )
1384  *success = FALSE;
1385  return SCIP_OKAY;
1386  }
1387  }
1388  else
1389  {
1390  SCIP_Real norm;
1391  SCIP_Real xextra;
1392  SCIP_Real yextra;
1393 
1394  norm = SQRT( 1 + SQR( kappa ) );
1395  xextra = wzlp + kappa + norm;
1396  yextra = wzlp + kappa - norm;
1397 
1398  /* finish computing w(ray), the linear part is missing */
1399  wray += computeWRayLinear(nlhdlrexprdata, sidefactor, raycoefs, rayidx, raynnonz);
1400 
1401  /*
1402  * coefficients of case 4b
1403  */
1404  /* at this point E is \|x(zlp)\|^2, so we can finish A, B, and C */
1405  coefs4b[0] = (*a) * (*e);
1406  coefs4b[1] = (*b) * (*e);
1407  coefs4b[2] = (*c) * (*e);
1408 
1409  /* finish D and E */
1410  coefs4b[3] = *d;
1411  coefs4b[4] = (*e) + xextra / 2.0;
1412 
1413  /* when \|x(zlp)\|^2 is too large, we can divide everything by \|x(zlp)\| */
1414  if( *e > 100 )
1415  {
1416  coefs4b[0] = (*a);
1417  coefs4b[1] = (*b);
1418  coefs4b[2] = (*c);
1419 
1420  /* finish D and E */
1421  coefs4b[3] = *d / SQRT( *e );
1422  coefs4b[4] = SQRT( *e ) + (xextra / (2.0 * SQRT( *e )));
1423  }
1424 
1425  /*
1426  * coefficients of case 4a
1427  */
1428  /* finish A, B, and C */
1429  *a += SQR( wray ) / (4.0 * norm);
1430  *b += 2.0 * yextra * (wray) / (4.0 * norm);
1431  *c += SQR( yextra ) / (4.0 * norm);
1432 
1433  /* finish D and E */
1434  *e += SQR( xextra ) / (4.0 * norm);
1435  *e = SQRT( *e );
1436 
1437  *d += xextra * (wray) / (4.0 * norm);
1438  *d /= *e;
1439 
1440  /*
1441  * coefficients of condition: stores -numerator of x_{r+1}/ norm xhat, w(ray), and numerator of y_{s+1} at zlp
1442  *
1443  */
1444  /* at this point E is \| \hat{x} (zlp)\| */
1445  coefscondition[0] = - xextra / (*e);
1446  coefscondition[1] = wray;
1447  coefscondition[2] = yextra;
1448  }
1449 
1450 #ifdef DEBUG_INTERSECTIONCUT
1451  if( ! iscase4 )
1452  {
1453  SCIPinfoMessage(scip, NULL, "Restriction yields case 1,2 or 3: a,b,c,d,e %g %g %g %g %g\n", coefs1234a[0], coefs1234a[1], coefs1234a[2],
1454  coefs1234a[3], coefs1234a[4]);
1455  }
1456  else
1457  {
1458  SCIPinfoMessage(scip, NULL, "Restriction yields\n Case 4a: a,b,c,d,e %g %g %g %g %g\n", coefs1234a[0],
1459  coefs1234a[1], coefs1234a[2], coefs1234a[3], coefs1234a[4]);
1460  SCIPinfoMessage(scip, NULL, " Case 4b: a,b,c,d,e %g %g %g %g %g\n", coefs4b[0], coefs4b[1], coefs4b[2],
1461  coefs4b[3], coefs4b[4]);
1462  SCIPinfoMessage(scip, NULL, " Condition: xextra/e, wray, yextra %g %g %g g\n", coefscondition[0],
1463  coefscondition[1], coefscondition[2]);
1464  }
1465 #endif
1466 
1467  /* some sanity check applicable to all cases */
1468  assert(*a >= 0); /* the function inside the root is convex */
1469  assert(*c >= 0); /* radicand at zero */
1470 
1471  if( iscase4 )
1472  {
1473  assert(coefs4b[0] >= 0); /* the function inside the root is convex */
1474  assert(coefs4b[2] >= 0); /* radicand at zero */
1475  }
1476  /*assert(4.0 * (*a) * (*c) >= SQR( *b ) ); *//* the function is defined everywhere, so minimum of radicand must be nonnegative */
1477 
1478  return SCIP_OKAY;
1479 }
1480 
1481 /** returns phi(zlp + t * ray) = SQRT(A t^2 + B t + C) - (D t + E) */
1482 static
1484  SCIP_Real t, /**< argument of phi restricted to ray */
1485  SCIP_Real a, /**< value of A */
1486  SCIP_Real b, /**< value of B */
1487  SCIP_Real c, /**< value of C */
1488  SCIP_Real d, /**< value of D */
1489  SCIP_Real e /**< value of E */
1490  )
1491 {
1492 #ifdef INTERCUTS_DBLDBL
1493  SCIP_Real QUAD(lin);
1494  SCIP_Real QUAD(disc);
1495  SCIP_Real QUAD(tmp);
1496  SCIP_Real QUAD(root);
1497 
1498  /* d * t + e */
1499  SCIPquadprecProdDD(lin, d, t);
1500  SCIPquadprecSumQD(lin, lin, e);
1501 
1502  /* a * t * t */
1503  SCIPquadprecSquareD(disc, t);
1504  SCIPquadprecProdQD(disc, disc, a);
1505 
1506  /* b * t */
1507  SCIPquadprecProdDD(tmp, b, t);
1508 
1509  /* a * t * t + b * t */
1510  SCIPquadprecSumQQ(disc, disc, tmp);
1511 
1512  /* a * t * t + b * t + c */
1513  SCIPquadprecSumQD(disc, disc, c);
1514 
1515  /* sqrt(above): can't take sqrt of 0! */
1516  if( QUAD_TO_DBL(disc) == 0 )
1517  {
1518  QUAD_ASSIGN(root, 0.0);
1519  }
1520  else
1521  {
1522  SCIPquadprecSqrtQ(root, disc);
1523  }
1524 
1525  /* final result */
1526  QUAD_SCALE(lin, -1.0);
1527  SCIPquadprecSumQQ(tmp, root, lin);
1528 
1529  assert(t != 1e20 || QUAD_TO_DBL(tmp) <= 0);
1530 
1531  return QUAD_TO_DBL(tmp);
1532 #else
1533  return SQRT( a * t * t + b * t + c ) - ( d * t + e );
1534 #endif
1535 }
1536 
1537 /** checks whether case 4a applies
1538  *
1539  * The condition for being in case 4a is
1540  * \f[ -\lambda_{r+1} \Vert \hat y(zlp + tsol\, ray)\Vert + \hat y_{s+1}(zlp + tsol\, ray) \leq 0\f]
1541  *
1542  * This reduces to
1543  * \f[ -num(\hat x_{r+1}(zlp)) \sqrt{A t^2 + B t + C} / E + w(ray) \cdot t + num(\hat y_{s+1}(zlp)) \leq 0\f]
1544  * where num is the numerator.
1545  */
1546 static
1548  SCIP_Real tsol, /**< t in the above formula */
1549  SCIP_Real* coefs4a, /**< coefficients A, B, C, D, and E of case 4a */
1550  SCIP_Real* coefscondition /**< extra coefficients needed for the evaluation of the condition:
1551  * \f$num(\hat x_{r+1}(zlp)) / E\f$; \f$w(ray)\f$; \f$num(\hat y_{s+1}(zlp))\f$ */
1552  )
1553 {
1554  return (coefscondition[0] * SQRT( coefs4a[0] * SQR( tsol ) + coefs4a[1] * tsol + coefs4a[2] ) + coefscondition[1] *
1555  tsol + coefscondition[2]) <= 0.0;
1556 }
1557 
1558 /** helper function of computeRoot: we want phi to be &le; 0 */
1559 static
1561  SCIP* scip, /**< SCIP data structure */
1562  SCIP_Real a, /**< value of A */
1563  SCIP_Real b, /**< value of B */
1564  SCIP_Real c, /**< value of C */
1565  SCIP_Real d, /**< value of D */
1566  SCIP_Real e, /**< value of E */
1567  SCIP_Real* sol /**< buffer to store solution; also gives initial point */
1568  )
1569 {
1570  SCIP_Real lb = 0.0;
1571  SCIP_Real ub = *sol;
1572  SCIP_Real curr;
1573  int i;
1574 
1575  for( i = 0; i < BINSEARCH_MAXITERS; ++i )
1576  {
1577  SCIP_Real phival;
1578 
1579  curr = (lb + ub) / 2.0;
1580  phival = evalPhiAtRay(curr, a, b, c, d, e);
1581 #ifdef INTERCUT_MOREDEBUG
1582  printf("%d: lb,ub %.10f, %.10f. curr = %g -> phi at curr %g -> phi at lb %g \n", i, lb, ub, curr, phival, evalPhiAtRay(lb, a, b, c, d, e));
1583 #endif
1584 
1585  if( phival <= 0.0 )
1586  {
1587  lb = curr;
1588  if( SCIPisFeasZero(scip, phival) || SCIPisFeasEQ(scip, ub, lb) )
1589  break;
1590  }
1591  else
1592  ub = curr;
1593  }
1594 
1595  *sol = lb;
1596 }
1597 
1598 /** finds smallest positive root phi by finding the smallest positive root of
1599  * (A - D^2) t^2 + (B - 2 D*E) t + (C - E^2) = 0
1600  *
1601  * However, we are conservative and want a solution such that phi is negative, but close to 0.
1602  * Thus, we correct the result with a binary search.
1603  */
1604 static
1606  SCIP* scip, /**< SCIP data structure */
1607  SCIP_Real* coefs /**< value of A */
1608  )
1609 {
1610  SCIP_Real sol;
1611  SCIP_INTERVAL bounds;
1612  SCIP_INTERVAL result;
1613  SCIP_Real a = coefs[0];
1614  SCIP_Real b = coefs[1];
1615  SCIP_Real c = coefs[2];
1616  SCIP_Real d = coefs[3];
1617  SCIP_Real e = coefs[4];
1618 
1619  /* there is an intersection point if and only if SQRT(A) > D: here we are beliving in math, this might cause
1620  * numerical issues
1621  */
1622  if( SQRT( a ) <= d )
1623  {
1624  sol = SCIPinfinity(scip);
1625  return sol;
1626  }
1627 
1628  SCIPintervalSetBounds(&bounds, 0.0, SCIPinfinity(scip));
1629 
1630  /* SCIPintervalSolveUnivariateQuadExpressionPositiveAllScalar finds all x such that a x^2 + b x >= c and x in bounds.
1631  * it is known that if tsol is the root we are looking for, then gamma(zlp + t * ray) <= 0 between 0 and tsol, thus
1632  * tsol is the smallest t such that (A - D^2) t^2 + (B - 2 D*E) t + (C - E^2) >= 0
1633  */
1635  e, -(c - e * e), bounds);
1636 
1637  /* it can still be empty because of our infinity, I guess... */
1639 
1640 #ifdef INTERCUT_MOREDEBUG
1641  {
1642  SCIP_Real binsol;
1643  binsol = SCIPinfinity(scip);
1644  doBinarySearch(scip, a, b, c, d, e, &binsol);
1645  printf("got root %g: with binsearch get %g\n", sol, binsol);
1646  }
1647 #endif
1648 
1649  /* check that solution is acceptable, ideally it should be <= 0, however when it is positive, we trigger a binary
1650  * search to make it negative. This binary search might return a solution point that is not at accurately 0 as the
1651  * one obtained from the function above. Thus, it might fail to satisfy the condition of case 4b in some cases, e.g.,
1652  * ex8_3_1, bchoco05, etc
1653  */
1654  if( evalPhiAtRay(sol, a, b, c, d, e) <= 1e-10 )
1655  {
1656 #ifdef INTERCUT_MOREDEBUG
1657  printf("interval solution returned %g -> phival = %g, believe it\n", sol, evalPhiAtRay(sol, a, b, c, d, e));
1658  printf("don't do bin search\n");
1659 #endif
1660  return sol;
1661  }
1662  else
1663  {
1664  /* perform a binary search to make it negative: this might correct a wrong infinity (e.g. crudeoil_lee1_05) */
1665 #ifdef INTERCUT_MOREDEBUG
1666  printf("do bin search because phival is %g\n", evalPhiAtRay(sol, a, b, c, d, e));
1667 #endif
1668  doBinarySearch(scip, a, b, c, d, e, &sol);
1669  }
1670 
1671  return sol;
1672 }
1673 
1674 /** The maximal S-free set is \f$\gamma(z) \leq 0\f$; we find the intersection point of the ray `ray` starting from zlp with the
1675  * boundary of the S-free set.
1676  * That is, we find \f$t \geq 0\f$ such that \f$\gamma(zlp + t \cdot \text{ray}) = 0\f$.
1677  *
1678  * In cases 1,2, and 3, gamma is of the form
1679  * \f[ \gamma(zlp + t \cdot \text{ray}) = \sqrt{A t^2 + B t + C} - (D t + E) \f]
1680  *
1681  * In the case 4 gamma is of the form
1682  * \f[ \gamma(zlp + t \cdot \text{ray}) =
1683  * \begin{cases}
1684  * \sqrt{A t^2 + B t + C} - (D t + E), & \text{if some condition holds}, \\
1685  * \sqrt{A' t^2 + B' t + C'} - (D' t + E'), & \text{otherwise.}
1686  * \end{cases}
1687  * \f]
1688  *
1689  * It can be shown (given the special properties of \f$\gamma\f$) that the smallest positive root of each function of the form
1690  * \f$\sqrt{a t^2 + b t + c} - (d t + e)\f$
1691  * is the same as the smallest positive root of the quadratic equation:
1692  * \f{align}{
1693  * & \sqrt{a t^2 + b t + c} - (d t + e)) (\sqrt{a t^2 + b t + c} + (d t + e)) = 0 \\ \Leftrightarrow
1694  * & (a - d^2) t^2 + (b - 2 d\,e) t + (c - e^2) = 0
1695  * \f}
1696  *
1697  * So, in cases 1, 2, and 3, this function just returns the solution of the above equation.
1698  * In case 4, it first solves the equation assuming we are in the first piece.
1699  * If there is no solution, then the second piece can't have a solution (first piece &ge; second piece for all t)
1700  * Then we check if the solution satisfies the condition.
1701  * If it doesn't then we solve the equation for the second piece.
1702  * If it has a solution, then it _has_ to be the solution.
1703  */
1704 static
1706  SCIP* scip, /**< SCIP data structure */
1707  SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
1708  SCIP_Bool iscase4, /**< whether we are in case 4 or not */
1709  SCIP_Real* coefs1234a, /**< values of A, B, C, D, and E of cases 1, 2, 3, or 4a */
1710  SCIP_Real* coefs4b, /**< values of A, B, C, D, and E of case 4b */
1711  SCIP_Real* coefscondition /**< values needed to evaluate condition of case 4 */
1712  )
1713 {
1714  SCIP_Real sol1234a;
1715  SCIP_Real sol4b;
1716 
1717  assert(coefs1234a != NULL);
1718 
1719 #ifdef DEBUG_INTERSECTIONCUT
1720  SCIPinfoMessage(scip, NULL, "Computing intersection point for case 4? %d\n", iscase4);
1721 #endif
1722  if( ! iscase4 )
1723  return computeRoot(scip, coefs1234a);
1724 
1725  assert(coefs4b != NULL);
1726  assert(coefscondition != NULL);
1727 
1728  /* compute solution of first piece */
1729 #ifdef DEBUG_INTERSECTIONCUT
1730  SCIPinfoMessage(scip, NULL, "Compute root in 4a\n");
1731 #endif
1732  sol1234a = computeRoot(scip, coefs1234a);
1733 
1734  /* if there is no solution --> second piece doesn't have solution */
1735  if( SCIPisInfinity(scip, sol1234a) )
1736  {
1737  /* this assert fails on multiplants_mtg5 the problem is that sqrt(A) <= D in 4a but not in 4b,
1738  * now, this is impossible since the phi4a >= phi4b, so actually sqrt(A) is 10e-15 away from
1739  * D in 4b
1740  */
1741  /* assert(SCIPisInfinity(scip, computeRoot(scip, coefs4b))); */
1742  return sol1234a;
1743  }
1744 
1745  /* if solution of 4a is in 4a, then return */
1746  if( isCase4a(sol1234a, coefs1234a, coefscondition) )
1747  return sol1234a;
1748 
1749 #ifdef DEBUG_INTERSECTIONCUT
1750  SCIPinfoMessage(scip, NULL, "Root not in 4a -> Compute root in 4b\n");
1751 #endif
1752 
1753  /* not on 4a --> then the intersection point is whatever 4b says: as phi4a >= phi4b, the solution of phi4b should
1754  * always be larger (but shouldn't be equal at this point given that isCase4a failed, and the condition function
1755  * evaluates to 0 when phi4a == phi4b) than the solution of phi4a; However, because of numerics (or limits in the
1756  * binary search) we can find a slightly smaller solution; thus, we just keep the larger one
1757  */
1758  sol4b = computeRoot(scip, coefs4b);
1759 
1760  /* this assert fails in many instances, e.g. water, because sol4b < sol1234a */
1761  /* assert(SCIPisInfinity(scip, sol4b) || !isCase4a(sol4b, coefs1234a, coefscondition)); */
1762  /* count number of times we could have improved the coefficient by 10% */
1763  if( sol4b < sol1234a && evalPhiAtRay(1.1 * sol1234a, coefs4b[0], coefs4b[1], coefs4b[2], coefs4b[3], coefs4b[4]) <=
1764  0.0 )
1765  nlhdlrdata->ncouldimprovedcoef++;
1766 
1767  return MAX(sol1234a, sol4b);
1768 }
1769 
1770 /** checks if numerics of the coefficients are not too bad */
1771 static
1773  SCIP* scip, /**< SCIP data structure */
1774  SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
1775  SCIP_Real* coefs1234a, /**< coefficients for case 1-3 and 4a */
1776  SCIP_Real* coefs4b, /**< coefficients for case 4b */
1777  SCIP_Bool iscase4 /**< whether we are in case 4 */
1778  )
1779 {
1780  SCIP_Real max;
1781  SCIP_Real min;
1782  int j;
1783 
1784  /* check at phi at 0 is negative (note; this could be checked before restricting to the ray) also, if this
1785  * succeeds for one ray, it should suceed for every ray
1786  */
1787  if( SQRT( coefs1234a[2] ) - coefs1234a[4] >= 0.0 )
1788  {
1789  INTERLOG(printf("Bad numerics: phi(0) >= 0\n"); )
1790  nlhdlrdata->nphinonneg++;
1791  return FALSE;
1792  }
1793 
1794  /* maybe we want to avoid a large dynamism between A, B and C */
1795  if( nlhdlrdata->ignorebadrayrestriction )
1796  {
1797  max = 0.0;
1798  min = SCIPinfinity(scip);
1799  for( j = 0; j < 3; ++j )
1800  {
1801  SCIP_Real absval;
1802 
1803  absval = REALABS(coefs1234a[j]);
1804  if( max < absval )
1805  max = absval;
1806  if( absval != 0.0 && absval < min )
1807  min = absval;
1808  }
1809 
1810  if( SCIPisHugeValue(scip, max / min) )
1811  {
1812  INTERLOG(printf("Bad numerics 1 2 3 or 4a: max(A,B,C)/min(A,B,C) is too large (%g)\n", max / min); )
1813  nlhdlrdata->nbadrayrestriction++;
1814  return FALSE;
1815  }
1816 
1817  if( iscase4 )
1818  {
1819  max = 0.0;
1820  min = SCIPinfinity(scip);
1821  for( j = 0; j < 3; ++j )
1822  {
1823  SCIP_Real absval;
1824 
1825  absval = ABS(coefs4b[j]);
1826  if( max < absval )
1827  max = absval;
1828  if( absval != 0.0 && absval < min )
1829  min = absval;
1830  }
1831 
1832  if( SCIPisHugeValue(scip, max / min) )
1833  {
1834  INTERLOG(printf("Bad numeric 4b: max(A,B,C)/min(A,B,C) is too large (%g)\n", max / min); )
1835  nlhdlrdata->nbadrayrestriction++;
1836  return FALSE;
1837  }
1838  }
1839  }
1840 
1841  return TRUE;
1842 }
1843 
1844 /** computes intersection cut cuts off sol (because solution sol violates the quadratic constraint cons)
1845  * and stores it in rowprep. Here, we don't use any strengthening.
1846  */
1847 static
1849  SCIP* scip, /**< SCIP data structure */
1850  SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
1851  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
1852  RAYS* rays, /**< rays */
1853  SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
1854  SCIP_Bool iscase4, /**< whether we are in case 4 */
1855  SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
1856  SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
1857  SCIP_Real* wcoefs, /**< coefficients of w for the qud vars or NULL if w is 0 */
1858  SCIP_Real wzlp, /**< value of w at zlp */
1859  SCIP_Real kappa, /**< value of kappa */
1860  SCIP_ROWPREP* rowprep, /**< rowprep for the generated cut */
1861  SCIP_Real* interpoints, /**< array to store intersection points for all rays or NULL if nothing
1862  needs to be stored */
1863  SCIP_SOL* sol, /**< solution we want to separate */
1864  SCIP_Bool* success /**< if a cut candidate could be computed */
1865  )
1866 {
1867  SCIP_COL** cols;
1868  SCIP_ROW** rows;
1869  int i;
1870 
1871  cols = SCIPgetLPCols(scip);
1872  rows = SCIPgetLPRows(scip);
1873 
1874  /* for every ray: compute cut coefficient and add var associated to ray into cut */
1875  for( i = 0; i < rays->nrays; ++i )
1876  {
1877  SCIP_Real interpoint;
1878  SCIP_Real cutcoef;
1879  int lppos;
1880  SCIP_Real coefs1234a[5];
1881  SCIP_Real coefs4b[5];
1882  SCIP_Real coefscondition[3];
1883 
1884  /* restrict phi to ray */
1885  SCIP_CALL( computeRestrictionToRay(scip, nlhdlrexprdata, sidefactor, iscase4,
1886  &rays->rays[rays->raysbegin[i]], &rays->raysidx[rays->raysbegin[i]], rays->raysbegin[i + 1] -
1887  rays->raysbegin[i], vb, vzlp, wcoefs, wzlp, kappa, coefs1234a, coefs4b, coefscondition, success) );
1888 
1889  if( ! *success )
1890  return SCIP_OKAY;
1891 
1892  /* if restriction to ray is numerically nasty -> abort cut separation */
1893  *success = areCoefsNumericsGood(scip, nlhdlrdata, coefs1234a, coefs4b, iscase4);
1894 
1895  if( ! *success )
1896  return SCIP_OKAY;
1897 
1898  /* compute intersection point */
1899  interpoint = computeIntersectionPoint(scip, nlhdlrdata, iscase4, coefs1234a, coefs4b, coefscondition);
1900 
1901 #ifdef DEBUG_INTERSECTIONCUT
1902  SCIPinfoMessage(scip, NULL, "interpoint for ray %d is %g\n", i, interpoint);
1903 #endif
1904 
1905  /* store intersection point */
1906  if( interpoints != NULL )
1907  interpoints[i] = interpoint;
1908 
1909  /* compute cut coef */
1910  cutcoef = SCIPisInfinity(scip, interpoint) ? 0.0 : 1.0 / interpoint;
1911 
1912  /* add var to cut: if variable is nonbasic at upper we have to flip sign of cutcoef */
1913  lppos = rays->lpposray[i];
1914  if( lppos < 0 )
1915  {
1916  lppos = -lppos - 1;
1917 
1918  assert(SCIProwGetBasisStatus(rows[lppos]) == SCIP_BASESTAT_LOWER || SCIProwGetBasisStatus(rows[lppos]) ==
1920 
1921  SCIP_CALL( addRowToCut(scip, rowprep, SCIProwGetBasisStatus(rows[lppos]) == SCIP_BASESTAT_UPPER ? cutcoef :
1922  -cutcoef, rows[lppos], success) ); /* rows have flipper base status! */
1923 
1924  if( ! *success )
1925  {
1926  INTERLOG(printf("Bad numeric: now not nonbasic enough\n");)
1927  nlhdlrdata->nbadnonbasic++;
1928  return SCIP_OKAY;
1929  }
1930  }
1931  else
1932  {
1933  if( ! nlhdlrdata->useboundsasrays )
1934  {
1935  assert(SCIPcolGetBasisStatus(cols[lppos]) == SCIP_BASESTAT_UPPER || SCIPcolGetBasisStatus(cols[lppos]) ==
1937  SCIP_CALL( addColToCut(scip, rowprep, sol, SCIPcolGetBasisStatus(cols[lppos]) == SCIP_BASESTAT_UPPER ? -cutcoef :
1938  cutcoef, cols[lppos]) );
1939  }
1940  else
1941  {
1942  SCIP_CALL( addColToCut(scip, rowprep, sol, rays->rays[i] == -1 ? -cutcoef : cutcoef, cols[lppos]) );
1943  }
1944  }
1945  }
1946 
1947  return SCIP_OKAY;
1948 }
1949 
1950 /** combine ray 1 and 2 to obtain new ray coef1 * ray1 - coef2 * ray2 in sparse format */
1951 static
1953  SCIP_Real* raycoefs1, /**< coefficients of ray 1 */
1954  int* rayidx1, /**< index of consvar of the ray 1 coef is associated to */
1955  int raynnonz1, /**< length of raycoefs1 and rayidx1 */
1956  SCIP_Real* raycoefs2, /**< coefficients of ray 2 */
1957  int* rayidx2, /**< index of consvar of the ray 2 coef is associated to */
1958  int raynnonz2, /**< length of raycoefs2 and rayidx2 */
1959  SCIP_Real* newraycoefs, /**< coefficients of combined ray */
1960  int* newrayidx, /**< index of consvar of the combined ray coef is associated to */
1961  int* newraynnonz, /**< pointer to length of newraycoefs and newrayidx */
1962  SCIP_Real coef1, /**< coef of ray 1 */
1963  SCIP_Real coef2 /**< coef of ray 2 */
1964  )
1965 {
1966  int idx1;
1967  int idx2;
1968 
1969  idx1 = 0;
1970  idx2 = 0;
1971  *newraynnonz = 0;
1972 
1973  while( idx1 < raynnonz1 || idx2 < raynnonz2 )
1974  {
1975  /* if the pointers look at different variables (or one already arrieved at the end), only one pointer can move
1976  * on
1977  */
1978  if( idx1 >= raynnonz1 || (idx2 < raynnonz2 && rayidx1[idx1] > rayidx2[idx2]) )
1979  {
1980  /*printf("case 1 \n"); */
1981  newraycoefs[*newraynnonz] = - coef2 * raycoefs2[idx2];
1982  newrayidx[*newraynnonz] = rayidx2[idx2];
1983  ++(*newraynnonz);
1984  ++idx2;
1985  }
1986  else if( idx2 >= raynnonz2 || rayidx1[idx1] < rayidx2[idx2] )
1987  {
1988  /*printf("case 2 \n"); */
1989  newraycoefs[*newraynnonz] = coef1 * raycoefs1[idx1];
1990  newrayidx[*newraynnonz] = rayidx1[idx1];
1991  ++(*newraynnonz);
1992  ++idx1;
1993  }
1994  /* if both pointers look at the same variable, just compute the difference and move both pointers */
1995  else if( rayidx1[idx1] == rayidx2[idx2] )
1996  {
1997  /*printf("case 3 \n"); */
1998  newraycoefs[*newraynnonz] = coef1 * raycoefs1[idx1] - coef2 * raycoefs2[idx2];
1999  newrayidx[*newraynnonz] = rayidx1[idx1];
2000  ++(*newraynnonz);
2001  ++idx1;
2002  ++idx2;
2003  }
2004  }
2005 }
2006 
2007 /** checks if two rays are linearly dependent */
2008 static
2010  SCIP* scip, /**< SCIP data structure */
2011  SCIP_Real* raycoefs1, /**< coefficients of ray 1 */
2012  int* rayidx1, /**< index of consvar of the ray 1 coef is associated to */
2013  int raynnonz1, /**< length of raycoefs1 and rayidx1 */
2014  SCIP_Real* raycoefs2, /**< coefficients of ray 2 */
2015  int* rayidx2, /**< index of consvar of the ray 2 coef is associated to */
2016  int raynnonz2, /**< length of raycoefs2 and rayidx2 */
2017  SCIP_Real* coef /**< pointer to store coef (s.t. r1 = coef * r2) in case rays are
2018  * dependent */
2019  )
2020 {
2021  int i;
2022 
2023  /* cannot be dependent if they have different number of non-zero entries */
2024  if( raynnonz1 != raynnonz2 )
2025  return FALSE;
2026 
2027  *coef = 0.0;
2028 
2029  for( i = 0; i < raynnonz1; ++i )
2030  {
2031  /* cannot be dependent if different variables have non-zero entries */
2032  if( rayidx1[i] != rayidx2[i] ||
2033  (SCIPisZero(scip, raycoefs1[i]) && !SCIPisZero(scip, raycoefs2[i])) ||
2034  (!SCIPisZero(scip, raycoefs1[i]) && SCIPisZero(scip, raycoefs2[i])) )
2035  {
2036  return FALSE;
2037  }
2038 
2039  if( *coef != 0.0 )
2040  {
2041  /* cannot be dependent if the coefs aren't equal for all entries */
2042  if( ! SCIPisEQ(scip, *coef, raycoefs1[i] / raycoefs2[i]) )
2043  {
2044  return FALSE;
2045  }
2046  }
2047  else
2048  *coef = raycoefs1[i] / raycoefs2[i];
2049  }
2050 
2051  return TRUE;
2052 }
2053 
2054 /** checks if the ray alpha * ray_i + (1 - alpha) * ray_j is in the recession cone of the S-free set. To do so,
2055  * we check if phi restricted to the ray has a positive root.
2056  */
2057 static
2059  SCIP* scip, /**< SCIP data structure */
2060  SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
2061  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2062  RAYS* rays, /**< rays */
2063  int j, /**< index of current ray in recession cone */
2064  int i, /**< index of current ray not in recession cone */
2065  SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2066  SCIP_Bool iscase4, /**< whether we are in case 4 */
2067  SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
2068  SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
2069  SCIP_Real* wcoefs, /**< coefficients of w for the quad vars or NULL if w is 0 */
2070  SCIP_Real wzlp, /**< value of w at zlp */
2071  SCIP_Real kappa, /**< value of kappa */
2072  SCIP_Real alpha, /**< coef for combining the two rays */
2073  SCIP_Bool* inreccone, /**< pointer to store whether the ray is in the recession cone or not */
2074  SCIP_Bool* success /**< Did numerical troubles occur? */
2075  )
2076 {
2077  SCIP_Real coefs1234a[5];
2078  SCIP_Real coefs4b[5];
2079  SCIP_Real coefscondition[3];
2080  SCIP_Real interpoint;
2081  SCIP_Real* newraycoefs;
2082  int* newrayidx;
2083  int newraynnonz;
2084 
2085  *inreccone = FALSE;
2086 
2087  /* allocate memory for new ray */
2088  newraynnonz = (rays->raysbegin[i + 1] - rays->raysbegin[i]) + (rays->raysbegin[j + 1] - rays->raysbegin[j]);
2089  SCIP_CALL( SCIPallocBufferArray(scip, &newraycoefs, newraynnonz) );
2090  SCIP_CALL( SCIPallocBufferArray(scip, &newrayidx, newraynnonz) );
2091 
2092  /* build the ray alpha * ray_i + (1 - alpha) * ray_j */
2093  combineRays(&rays->rays[rays->raysbegin[i]], &rays->raysidx[rays->raysbegin[i]], rays->raysbegin[i + 1] -
2094  rays->raysbegin[i], &rays->rays[rays->raysbegin[j]], &rays->raysidx[rays->raysbegin[j]],
2095  rays->raysbegin[j + 1] - rays->raysbegin[j], newraycoefs, newrayidx, &newraynnonz, alpha,
2096  -1 + alpha);
2097 
2098  /* restrict phi to the "new" ray */
2099  SCIP_CALL( computeRestrictionToRay(scip, nlhdlrexprdata, sidefactor, iscase4, newraycoefs, newrayidx,
2100  newraynnonz, vb, vzlp, wcoefs, wzlp, kappa, coefs1234a, coefs4b, coefscondition, success) );
2101 
2102  if( ! *success )
2103  goto CLEANUP;
2104 
2105  /* check if restriction to "new" ray is numerically nasty. If so, treat the corresponding rho as if phi is
2106  * positive
2107  */
2108 
2109  /* compute intersection point */
2110  interpoint = computeIntersectionPoint(scip, nlhdlrdata, iscase4, coefs1234a, coefs4b, coefscondition);
2111 
2112  /* no root exists */
2113  if( SCIPisInfinity(scip, interpoint) )
2114  *inreccone = TRUE;
2115 
2116 CLEANUP:
2117  SCIPfreeBufferArray(scip, &newrayidx);
2118  SCIPfreeBufferArray(scip, &newraycoefs);
2119 
2120  return SCIP_OKAY;
2121 }
2122 
2123 /** finds the smallest negative steplength for the current ray r_idx such that the combination
2124  * of r_idx with all rays not in the recession cone is in the recession cone
2125  */
2126 static
2128  SCIP* scip, /**< SCIP data structure */
2129  SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
2130  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2131  RAYS* rays, /**< rays */
2132  int idx, /**< index of current ray we want to find rho for */
2133  SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2134  SCIP_Bool iscase4, /**< whether we are in case 4 */
2135  SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
2136  SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
2137  SCIP_Real* wcoefs, /**< coefficients of w for the quad vars or NULL if w is 0 */
2138  SCIP_Real wzlp, /**< value of w at zlp */
2139  SCIP_Real kappa, /**< value of kappa */
2140  SCIP_Real* interpoints, /**< array to store intersection points for all rays or NULL if nothing
2141  * needs to be stored */
2142  SCIP_Real* rho, /**< pointer to store the optimal rho */
2143  SCIP_Bool* success /**< could we successfully find the right rho? */
2144  )
2145 {
2146  int i;
2147 
2148  /* go through all rays not in the recession cone and compute the largest negative steplength possible. The
2149  * smallest of them is then the steplength rho we use for the current ray */
2150  *rho = 0.0;
2151  for( i = 0; i < rays->nrays; ++i )
2152  {
2153  SCIP_Real currentrho;
2154  SCIP_Real coef;
2155 
2156  if( SCIPisInfinity(scip, interpoints[i]) )
2157  continue;
2158 
2159  /* if we cannot strengthen enough, we don't strengthen at all */
2160  if( SCIPisInfinity(scip, -*rho) )
2161  {
2162  *rho = -SCIPinfinity(scip);
2163  return SCIP_OKAY;
2164  }
2165 
2166  /* if the rays are linearly independent, we don't need to search for rho */
2167  if( raysAreDependent(scip, &rays->rays[rays->raysbegin[i]], &rays->raysidx[rays->raysbegin[i]],
2168  rays->raysbegin[i + 1] - rays->raysbegin[i], &rays->rays[rays->raysbegin[idx]],
2169  &rays->raysidx[rays->raysbegin[idx]], rays->raysbegin[idx + 1] - rays->raysbegin[idx], &coef) )
2170  {
2171  currentrho = coef * interpoints[i];
2172  }
2173  else
2174  {
2175  /* since the two rays are linearly independent, we need to find the biggest alpha such that
2176  * alpha * ray_i + (1 - alpha) * ray_idx in the recession cone is. For every ray i, we compute
2177  * such a alpha but take the smallest one of them. We use "maxalpha" to keep track of this.
2178  * Since we know that we can only use alpha < maxalpha, we don't need to do the whole binary search
2179  * for every ray i. We only need to search the intervall [0, maxalpha]. Thereby, we start by checking
2180  * if alpha = maxalpha is already feasable */
2181 
2182  SCIP_Bool inreccone;
2183  SCIP_Real alpha;
2184  SCIP_Real lb;
2185  SCIP_Real ub;
2186  int j;
2187 
2188  lb = 0.0;
2189  ub = 1.0;
2190  for( j = 0; j < BINSEARCH_MAXITERS; ++j )
2191  {
2192  alpha = (lb + ub) / 2.0;
2193 
2194  if( SCIPisZero(scip, alpha) )
2195  {
2196  alpha = 0.0;
2197  break;
2198  }
2199 
2200  SCIP_CALL( rayInRecessionCone(scip, nlhdlrdata, nlhdlrexprdata, rays, idx, i, sidefactor, iscase4, vb,
2201  vzlp, wcoefs, wzlp, kappa, alpha, &inreccone, success) );
2202 
2203  if( ! *success )
2204  return SCIP_OKAY;
2205 
2206  /* no root exists */
2207  if( inreccone )
2208  {
2209  lb = alpha;
2210  if( SCIPisEQ(scip, ub, lb) )
2211  break;
2212  }
2213  else
2214  ub = alpha;
2215  }
2216 
2217  /* now we found the best convex combination which we use to derive the corresponding coef. If alpha = 0, we
2218  * cannot move the ray in the recession cone, i.e. strengthening is not possible */
2219  if( SCIPisZero(scip, alpha) )
2220  {
2221  *rho = -SCIPinfinity(scip);
2222  return SCIP_OKAY;
2223  }
2224  else
2225  currentrho = (alpha - 1) * interpoints[i] / alpha; /*lint !e795*/
2226  }
2227 
2228  if( currentrho < *rho )
2229  *rho = currentrho;
2230 
2231  if( *rho < -10e+06 )
2232  *rho = -SCIPinfinity(scip);
2233 
2234  /* if rho is too small, don't add it */
2235  if( SCIPisZero(scip, *rho) )
2236  *success = FALSE;
2237  }
2238 
2239  return SCIP_OKAY;
2240 }
2241 
2242 /** computes intersection cut using negative edge extension to strengthen rays that do not intersect
2243  * (i.e., rays in the recession cone)
2244  */
2245 static
2247  SCIP* scip, /**< SCIP data structure */
2248  SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
2249  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2250  RAYS* rays, /**< rays */
2251  SCIP_Real sidefactor, /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2252  SCIP_Bool iscase4, /**< whether we are in case 4 */
2253  SCIP_Real* vb, /**< array containing \f$v_i^T b\f$ for \f$i \in I_+ \cup I_-\f$ */
2254  SCIP_Real* vzlp, /**< array containing \f$v_i^T zlp_q\f$ for \f$i \in I_+ \cup I_-\f$ */
2255  SCIP_Real* wcoefs, /**< coefficients of w for the qud vars or NULL if w is 0 */
2256  SCIP_Real wzlp, /**< value of w at zlp */
2257  SCIP_Real kappa, /**< value of kappa */
2258  SCIP_ROWPREP* rowprep, /**< rowprep for the generated cut */
2259  SCIP_SOL* sol, /**< solution to separate */
2260  SCIP_Bool* success, /**< if a cut candidate could be computed */
2261  SCIP_Bool* strengthsuccess /**< if strengthening was successfully applied */
2262  )
2263 {
2264  SCIP_COL** cols;
2265  SCIP_ROW** rows;
2266  SCIP_Real* interpoints;
2267  SCIP_Real avecutcoef;
2268  int counter;
2269  int i;
2270 
2271  *success = TRUE;
2272  *strengthsuccess = FALSE;
2273 
2274  cols = SCIPgetLPCols(scip);
2275  rows = SCIPgetLPRows(scip);
2276 
2277  /* allocate memory for intersection points */
2278  SCIP_CALL( SCIPallocBufferArray(scip, &interpoints, rays->nrays) );
2279 
2280  /* compute all intersection points and store them in interpoints; build not-stregthened intersection cut */
2281  SCIP_CALL( computeIntercut(scip, nlhdlrdata, nlhdlrexprdata, rays, sidefactor, iscase4, vb, vzlp, wcoefs, wzlp, kappa,
2282  rowprep, interpoints, sol, success) );
2283 
2284  if( ! *success )
2285  goto CLEANUP;
2286 
2287  /* keep track of the number of attempted strengthenings and average cutcoef */
2288  counter = 0;
2289  avecutcoef = 0.0;
2290 
2291  /* go through all intersection points that are equal to infinity -> these correspond to the rays which are in the
2292  * recession cone of C, i.e. the rays for which we (possibly) can compute a negative steplength */
2293  for( i = 0; i < rays->nrays; ++i )
2294  {
2295  SCIP_Real rho;
2296  SCIP_Real cutcoef;
2297  int lppos;
2298 
2299  if( !SCIPisInfinity(scip, interpoints[i]) )
2300  continue;
2301 
2302  /* if we reached the limit of strengthenings, we stop */
2303  if( counter >= nlhdlrdata->nstrengthlimit )
2304  break;
2305 
2306  /* compute the smallest rho */
2307  SCIP_CALL( findRho(scip, nlhdlrdata, nlhdlrexprdata, rays, i, sidefactor, iscase4, vb, vzlp, wcoefs, wzlp, kappa,
2308  interpoints, &rho, success));
2309 
2310  /* compute cut coef */
2311  if( ! *success || SCIPisInfinity(scip, -rho) )
2312  cutcoef = 0.0;
2313  else
2314  cutcoef = 1.0 / rho;
2315 
2316  /* track average cut coef */
2317  counter += 1;
2318  avecutcoef += cutcoef;
2319 
2320  if( ! SCIPisZero(scip, cutcoef) )
2321  *strengthsuccess = TRUE;
2322 
2323  /* add var to cut: if variable is nonbasic at upper we have to flip sign of cutcoef */
2324  lppos = rays->lpposray[i];
2325  if( lppos < 0 )
2326  {
2327  lppos = -lppos - 1;
2328 
2329  assert(SCIProwGetBasisStatus(rows[lppos]) == SCIP_BASESTAT_LOWER || SCIProwGetBasisStatus(rows[lppos]) ==
2331 
2332  SCIP_CALL( addRowToCut(scip, rowprep, SCIProwGetBasisStatus(rows[lppos]) == SCIP_BASESTAT_UPPER ? cutcoef :
2333  -cutcoef, rows[lppos], success) ); /* rows have flipper base status! */
2334 
2335  if( ! *success )
2336  {
2337  INTERLOG(printf("Bad numeric: row not nonbasic enough\n");)
2338  nlhdlrdata->nbadnonbasic++;
2339  return SCIP_OKAY;
2340  }
2341  }
2342  else
2343  {
2344  assert(SCIPcolGetBasisStatus(cols[lppos]) == SCIP_BASESTAT_UPPER || SCIPcolGetBasisStatus(cols[lppos]) ==
2346  SCIP_CALL( addColToCut(scip, rowprep, sol, SCIPcolGetBasisStatus(cols[lppos]) == SCIP_BASESTAT_UPPER ? -cutcoef :
2347  cutcoef, cols[lppos]) );
2348  }
2349  }
2350 
2351  if( counter > 0 )
2352  nlhdlrdata->cutcoefsum += avecutcoef / counter;
2353 
2354 CLEANUP:
2355  SCIPfreeBufferArray(scip, &interpoints);
2356 
2357  return SCIP_OKAY;
2358 }
2359 
2360 /** sets variable in solution "vertex" to its nearest bound */
2361 static
2363  SCIP* scip, /**< SCIP data structure */
2364  SCIP_SOL* sol, /**< solution to separate */
2365  SCIP_SOL* vertex, /**< new solution to separate */
2366  SCIP_VAR* var, /**< var we want to find nearest bound to */
2367  SCIP_Real* factor, /**< is vertex for current var at lower or upper? */
2368  SCIP_Bool* success /**< TRUE if no variable is bounded */
2369  )
2370 {
2371  SCIP_Real solval;
2372  SCIP_Real bound;
2373 
2374  solval = SCIPgetSolVal(scip, sol, var);
2375  *success = TRUE;
2376 
2377  /* find nearest bound */
2378  if( SCIPisInfinity(scip, SCIPvarGetLbLocal(var)) && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
2379  {
2380  *success = FALSE;
2381  return SCIP_OKAY;
2382  }
2383  else if( solval - SCIPvarGetLbLocal(var) < SCIPvarGetUbLocal(var) - solval )
2384  {
2385  bound = SCIPvarGetLbLocal(var);
2386  *factor = 1.0;
2387  }
2388  else
2389  {
2390  bound = SCIPvarGetUbLocal(var);
2391  *factor = -1.0;
2392  }
2393 
2394  /* set val to bound in solution */
2395  SCIP_CALL( SCIPsetSolVal(scip, vertex, var, bound) );
2396  return SCIP_OKAY;
2397 }
2398 
2399 /** This function finds vertex (w.r.t. bounds of variables appearing in the quadratic) that is closest to the current
2400  * solution we want to separate.
2401  *
2402  * Furthermore, we store the rays corresponding to the unit vectors, i.e.,
2403  * - if \f$x_i\f$ is at its lower bound in vertex --> \f$r_i = e_i\f$
2404  * - if \f$x_i\f$ is at its upper bound in vertex --> \f$r_i = -e_i\f$
2405  */
2406 static
2408  SCIP* scip, /**< SCIP data structure */
2409  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2410  SCIP_SOL* sol, /**< solution to separate */
2411  SCIP_SOL* vertex, /**< new 'vertex' (w.r.t. bounds) solution to separate */
2412  SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
2413  RAYS** raysptr, /**< pointer to new bound rays */
2414  SCIP_Bool* success /**< TRUE if no variable is unbounded */
2415  )
2416 {
2417  SCIP_EXPR* qexpr;
2418  SCIP_EXPR** linexprs;
2419  RAYS* rays;
2420  int nquadexprs;
2421  int nlinexprs;
2422  int raylength;
2423  int i;
2424 
2425  *success = TRUE;
2426 
2427  qexpr = nlhdlrexprdata->qexpr;
2428  SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, NULL, NULL, NULL);
2429 
2430  raylength = (auxvar == NULL) ? nquadexprs + nlinexprs : nquadexprs + nlinexprs + 1;
2431 
2432  /* create rays */
2433  SCIP_CALL( createBoundRays(scip, raysptr, raylength) );
2434  rays = *raysptr;
2435 
2436  rays->rayssize = raylength;
2437  rays->nrays = raylength;
2438 
2439  /* go through quadratic variables */
2440  for( i = 0; i < nquadexprs; ++i )
2441  {
2442  SCIP_EXPR* expr;
2443  SCIPexprGetQuadraticQuadTerm(qexpr, i, &expr, NULL, NULL, NULL, NULL, NULL);
2444 
2445  rays->raysbegin[i] = i;
2446  rays->raysidx[i] = i;
2448 
2449  SCIP_CALL( setVarToNearestBound(scip, sol, vertex, SCIPgetExprAuxVarNonlinear(expr),
2450  &rays->rays[i], success) );
2451 
2452  if( ! *success )
2453  return SCIP_OKAY;
2454  }
2455 
2456  /* go through linear variables */
2457  for( i = 0; i < nlinexprs; ++i )
2458  {
2459  rays->raysbegin[i + nquadexprs] = i + nquadexprs;
2460  rays->raysidx[i + nquadexprs] = i + nquadexprs;
2461  rays->lpposray[i + nquadexprs] = SCIPcolGetLPPos(SCIPvarGetCol(SCIPgetExprAuxVarNonlinear(linexprs[i])));
2462 
2463  SCIP_CALL( setVarToNearestBound(scip, sol, vertex, SCIPgetExprAuxVarNonlinear(linexprs[i]),
2464  &rays->rays[i + nquadexprs], success) );
2465 
2466  if( ! *success )
2467  return SCIP_OKAY;
2468  }
2469 
2470  /* consider auxvar if it exists */
2471  if( auxvar != NULL )
2472  {
2473  rays->raysbegin[nquadexprs + nlinexprs] = nquadexprs + nlinexprs;
2474  rays->raysidx[nquadexprs + nlinexprs] = nquadexprs + nlinexprs;
2475  rays->lpposray[nquadexprs + nlinexprs] = SCIPcolGetLPPos(SCIPvarGetCol(auxvar));
2476 
2477  SCIP_CALL( setVarToNearestBound(scip, sol, vertex, auxvar, &rays->rays[nquadexprs + nlinexprs], success) );
2478 
2479  if( ! *success )
2480  return SCIP_OKAY;
2481  }
2482 
2483  rays->raysbegin[raylength] = raylength;
2484 
2485  return SCIP_OKAY;
2486 }
2487 
2488 /** checks if the quadratic constraint is violated by sol */
2489 static
2491  SCIP* scip, /**< SCIP data structure */
2492  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2493  SCIP_VAR* auxvar, /**< aux var of expr or NULL if not needed (e.g. separating real cons) */
2494  SCIP_SOL* sol, /**< solution to check feasibility for */
2495  SCIP_Real sidefactor /**< 1.0 if the violated constraint is q &le; rhs, -1.0 otherwise */
2496  )
2497 {
2498  SCIP_EXPR* qexpr;
2499  SCIP_EXPR** linexprs;
2500  SCIP_Real* lincoefs;
2501  SCIP_Real constant;
2502  SCIP_Real val;
2503  int nquadexprs;
2504  int nlinexprs;
2505  int nbilinexprs;
2506  int i;
2507 
2508  qexpr = nlhdlrexprdata->qexpr;
2509  SCIPexprGetQuadraticData(qexpr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs,
2510  &nbilinexprs, NULL, NULL);
2511 
2512  val = 0.0;
2513 
2514  /* go through quadratic terms */
2515  for( i = 0; i < nquadexprs; i++ )
2516  {
2517  SCIP_EXPR* expr;
2518  SCIP_Real quadlincoef;
2519  SCIP_Real sqrcoef;
2520  SCIP_Real solval;
2521 
2522  SCIPexprGetQuadraticQuadTerm(qexpr, i, &expr, &quadlincoef, &sqrcoef, NULL, NULL, NULL);
2523 
2524  solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr));
2525 
2526  /* add square term */
2527  val += sqrcoef * SQR(solval);
2528 
2529  /* add linear term */
2530  val += quadlincoef * solval;
2531  }
2532 
2533  /* go through bilinear terms */
2534  for( i = 0; i < nbilinexprs; i++ )
2535  {
2536  SCIP_EXPR* expr1;
2537  SCIP_EXPR* expr2;
2538  SCIP_Real bilincoef;
2539 
2540  SCIPexprGetQuadraticBilinTerm(qexpr, i, &expr1, &expr2, &bilincoef, NULL, NULL);
2541 
2542  val += bilincoef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1))
2543  * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
2544  }
2545 
2546  /* go through linear terms */
2547  for( i = 0; i < nlinexprs; i++ )
2548  {
2549  val += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
2550  }
2551 
2552  /* add auxvar if exists and get constant */
2553  if( auxvar != NULL )
2554  {
2555  val -= SCIPgetSolVal(scip, sol, auxvar);
2556 
2557  constant = (sidefactor == 1.0) ? constant - SCIPgetRhsNonlinear(nlhdlrexprdata->cons) :
2558  SCIPgetLhsNonlinear(nlhdlrexprdata->cons) - constant;
2559  }
2560  else
2561  constant = (sidefactor * constant);
2562 
2563  val = (sidefactor * val);
2564 
2565  /* now constraint is q(z) <= const */
2566  if( val <= constant )
2567  return FALSE;
2568  else
2569  return TRUE;
2570 }
2571 
2572 /** generates intersection cut that cuts off sol (which violates the quadratic constraint cons) */
2573 static
2575  SCIP* scip, /**< SCIP data structure */
2576  SCIP_EXPR* expr, /**< expr */
2577  SCIP_NLHDLRDATA* nlhdlrdata, /**< nlhdlr data */
2578  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nlhdlr expression data */
2579  SCIP_CONS* cons, /**< violated constraint that contains expr */
2580  SCIP_SOL* sol, /**< solution to separate */
2581  SCIP_ROWPREP* rowprep, /**< rowprep for the generated cut */
2582  SCIP_Bool overestimate, /**< TRUE if viol cons is q(z) &ge; lhs; FALSE if q(z) &le; rhs */
2583  SCIP_Bool* success /**< whether separation was successfull or not */
2584  )
2585 {
2586  SCIP_EXPR* qexpr;
2587  RAYS* rays;
2588  SCIP_VAR* auxvar;
2589  SCIP_Real sidefactor;
2590  SCIP_Real* vb; /* eigenvectors * b */
2591  SCIP_Real* vzlp; /* eigenvectors * lpsol */
2592  SCIP_Real* wcoefs; /* coefficients affecting quadterms in w */
2593  SCIP_Real wzlp; /* w(lpsol) */
2594  SCIP_Real kappa;
2595  SCIP_Bool iscase4;
2596  SCIP_SOL* vertex;
2597  SCIP_SOL* soltoseparate;
2598  int nquadexprs;
2599  int nlinexprs;
2600  int i;
2601 
2602  /* count number of calls */
2603  (nlhdlrdata->ncalls++);
2604 
2605  qexpr = nlhdlrexprdata->qexpr;
2606  SCIPexprGetQuadraticData(qexpr, NULL, &nlinexprs, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
2607 
2608 #ifdef DEBUG_INTERSECTIONCUT
2609  SCIPinfoMessage(scip, NULL, "Generating intersection cut for quadratic expr %p aka", (void*)expr);
2610  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2611  SCIPinfoMessage(scip, NULL, "\n");
2612 #endif
2613 
2614  *success = TRUE;
2615  iscase4 = TRUE;
2616 
2617  /* in nonbasic space cut is >= 1 */
2618  assert(SCIProwprepGetSide(rowprep) == 0.0);
2619  SCIProwprepAddSide(rowprep, 1.0);
2621  assert(SCIProwprepGetSide(rowprep) == 1.0);
2622 
2623  auxvar = (nlhdlrexprdata->cons != cons) ? SCIPgetExprAuxVarNonlinear(expr) : NULL;
2624  sidefactor = overestimate ? -1.0 : 1.0;
2625 
2626  rays = NULL;
2627 
2628  /* check if we use tableau or bounds as rays */
2629  if( ! nlhdlrdata->useboundsasrays )
2630  {
2631  SCIP_CALL( createAndStoreSparseRays(scip, nlhdlrexprdata, auxvar, &rays, success) );
2632 
2633  if( ! *success )
2634  {
2635  INTERLOG(printf("Failed to get rays: there is a var with base status ZERO!\n"); )
2636  return SCIP_OKAY;
2637  }
2638 
2639  soltoseparate = sol;
2640  }
2641  else
2642  {
2643  SCIP_Bool violated;
2644 
2645  if( auxvar != NULL )
2646  {
2647  *success = FALSE;
2648  return SCIP_OKAY;
2649  }
2650 
2651  /* create new solution */
2652  SCIP_CALL( SCIPcreateSol(scip, &vertex, NULL) );
2653 
2654  /* find nearest vertex of the box to separate and compute rays */
2655  SCIP_CALL( findVertexAndGetRays(scip, nlhdlrexprdata, sol, vertex, auxvar, &rays, success) );
2656 
2657  if( ! *success )
2658  {
2659  INTERLOG(printf("Failed to use bounds as rays: variable is unbounded!\n"); )
2660  freeRays(scip, &rays);
2661  SCIP_CALL( SCIPfreeSol(scip, &vertex) );
2662  return SCIP_OKAY;
2663  }
2664 
2665  /* check if vertex is violated */
2666  violated = isQuadConsViolated(scip, nlhdlrexprdata, auxvar, vertex, sidefactor);
2667 
2668  if( ! violated )
2669  {
2670  INTERLOG(printf("Failed to use bounds as rays: nearest vertex is not violated!\n"); )
2671  freeRays(scip, &rays);
2672  SCIP_CALL( SCIPfreeSol(scip, &vertex) );
2673  *success = FALSE;
2674  return SCIP_OKAY;
2675  }
2676 
2677  soltoseparate = vertex;
2678  }
2679 
2680  SCIP_CALL( SCIPallocBufferArray(scip, &vb, nquadexprs) );
2681  SCIP_CALL( SCIPallocBufferArray(scip, &vzlp, nquadexprs) );
2682  SCIP_CALL( SCIPallocBufferArray(scip, &wcoefs, nquadexprs) );
2683 
2684  SCIP_CALL( intercutsComputeCommonQuantities(scip, nlhdlrexprdata, auxvar, sidefactor, soltoseparate, vb, vzlp, wcoefs, &wzlp, &kappa) );
2685 
2686  /* check if we are in case 4 */
2687  if( nlinexprs == 0 && auxvar == NULL )
2688  {
2689  for( i = 0; i < nquadexprs; ++i )
2690  if( wcoefs[i] != 0.0 )
2691  break;
2692 
2693  if( i == nquadexprs )
2694  {
2695  /* from now on wcoefs is going to be NULL --> case 1, 2 or 3 */
2696  SCIPfreeBufferArray(scip, &wcoefs);
2697  iscase4 = FALSE;
2698  }
2699  }
2700 
2701  /* compute (strengthened) intersection cut */
2702  if( nlhdlrdata->usestrengthening )
2703  {
2704  SCIP_Bool strengthsuccess;
2705 
2706  SCIP_CALL( computeStrengthenedIntercut(scip, nlhdlrdata, nlhdlrexprdata, rays, sidefactor, iscase4, vb, vzlp, wcoefs,
2707  wzlp, kappa, rowprep, soltoseparate, success, &strengthsuccess) );
2708 
2709  if( *success && strengthsuccess )
2710  nlhdlrdata->nstrengthenings++;
2711  }
2712  else
2713  {
2714  SCIP_CALL( computeIntercut(scip, nlhdlrdata, nlhdlrexprdata, rays, sidefactor, iscase4, vb, vzlp, wcoefs, wzlp, kappa,
2715  rowprep, NULL, soltoseparate, success) );
2716  }
2717 
2718  SCIPfreeBufferArrayNull(scip, &wcoefs);
2719  SCIPfreeBufferArray(scip, &vzlp);
2720  SCIPfreeBufferArray(scip, &vb);
2721  freeRays(scip, &rays);
2722 
2723  if( nlhdlrdata->useboundsasrays )
2724  {
2725  SCIP_CALL( SCIPfreeSol(scip, &vertex) );
2726  }
2727 
2728  return SCIP_OKAY;
2729 }
2730 
2731 /** returns whether a quadratic form is "propagable"
2732  *
2733  * It is propagable, if a variable (aka child expr) appears at least twice, which is the case if at least two of the following hold:
2734  * - it appears as a linear term (coef*expr)
2735  * - it appears as a square term (coef*expr^2)
2736  * - it appears in a bilinear term
2737  * - it appears in another bilinear term
2738  */
2739 static
2741  SCIP_EXPR* qexpr /**< quadratic representation data */
2742  )
2743 {
2744  int nquadexprs;
2745  int i;
2746 
2747  SCIPexprGetQuadraticData(qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
2748 
2749  for( i = 0; i < nquadexprs; ++i )
2750  {
2751  SCIP_Real lincoef;
2752  SCIP_Real sqrcoef;
2753  int nadjbilin;
2754 
2755  SCIPexprGetQuadraticQuadTerm(qexpr, i, NULL, &lincoef, &sqrcoef, &nadjbilin, NULL, NULL);
2756 
2757  if( (lincoef != 0.0) + (sqrcoef != 0.0) + nadjbilin >= 2 ) /*lint !e514*/ /* actually MIN(2, nadjbilin), but we check >= 2 */
2758  return TRUE;
2759  }
2760 
2761  return FALSE;
2762 }
2763 
2764 /** returns whether a quadratic term is "propagable"
2765  *
2766  * A term is propagable, if its variable (aka child expr) appears at least twice, which is the case if at least two of the following hold:
2767  * - it appears as a linear term (coef*expr)
2768  * - it appears as a square term (coef*expr^2)
2769  * - it appears in a bilinear term
2770  * - it appears in another bilinear term
2771  */
2772 static
2774  SCIP_EXPR* qexpr, /**< quadratic representation data */
2775  int idx /**< index of quadratic term to consider */
2776  )
2777 {
2778  SCIP_Real lincoef;
2779  SCIP_Real sqrcoef;
2780  int nadjbilin;
2781 
2782  SCIPexprGetQuadraticQuadTerm(qexpr, idx, NULL, &lincoef, &sqrcoef, &nadjbilin, NULL, NULL);
2783 
2784  return (lincoef != 0.0) + (sqrcoef != 0.0) + nadjbilin >= 2; /*lint !e514*/ /* actually MIN(2, nadjbilin), but we check >= 2 */
2785 }
2786 
2787 /** solves a quadratic equation \f$ a\, \text{expr}^2 + b\, \text{expr} \in \text{rhs} \f$ (with \f$b\f$ an interval)
2788  * and reduces bounds on `expr` or deduces infeasibility if possible
2789  */
2790 static
2792  SCIP* scip, /**< SCIP data structure */
2793  SCIP_EXPR* expr, /**< expression for which to solve */
2794  SCIP_Real sqrcoef, /**< square coefficient */
2795  SCIP_INTERVAL b, /**< interval acting as linear coefficient */
2796  SCIP_INTERVAL rhs, /**< interval acting as rhs */
2797  SCIP_Bool* infeasible, /**< buffer to store if propagation produced infeasibility */
2798  int* nreductions /**< buffer to store the number of interval reductions */
2799  )
2800 {
2801  SCIP_INTERVAL a;
2802  SCIP_INTERVAL exprbounds;
2803  SCIP_INTERVAL newrange;
2804 
2805  assert(scip != NULL);
2806  assert(expr != NULL);
2807  assert(infeasible != NULL);
2808  assert(nreductions != NULL);
2809 
2810 #ifdef DEBUG_PROP
2811  SCIPinfoMessage(scip, NULL, "Propagating <expr> by solving a <expr>^2 + b <expr> in rhs, where <expr> is: ");
2812  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2813  SCIPinfoMessage(scip, NULL, "\n");
2814  SCIPinfoMessage(scip, NULL, "expr in [%g, %g], a = %g, b = [%g, %g] and rhs = [%g, %g]\n",
2816  SCIPintervalGetSup(SCIPgetExprBoundsNonlinear(scip, expr)), sqrcoef, b.inf, b.sup,
2817  rhs.inf, rhs.sup);
2818 #endif
2819 
2820  exprbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2821  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, exprbounds) )
2822  {
2823  *infeasible = TRUE;
2824  return SCIP_OKAY;
2825  }
2826 
2827  /* compute solution of a*x^2 + b*x in rhs */
2828  SCIPintervalSet(&a, sqrcoef);
2829  SCIPintervalSolveUnivariateQuadExpression(SCIP_INTERVAL_INFINITY, &newrange, a, b, rhs, exprbounds);
2830 
2831 #ifdef DEBUG_PROP
2832  SCIPinfoMessage(scip, NULL, "Solution [%g, %g]\n", newrange.inf, newrange.sup);
2833 #endif
2834 
2835  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, newrange, infeasible, nreductions) );
2836 
2837  return SCIP_OKAY;
2838 }
2839 
2840 /** solves a linear equation \f$ b\, \text{expr} \in \text{rhs} \f$ (with \f$b\f$ a scalar) and reduces bounds on `expr` or deduces infeasibility if possible */
2841 static
2843  SCIP* scip, /**< SCIP data structure */
2844  SCIP_EXPR* expr, /**< expression for which to solve */
2845  SCIP_Real b, /**< linear coefficient */
2846  SCIP_INTERVAL rhs, /**< interval acting as rhs */
2847  SCIP_Bool* infeasible, /**< buffer to store if propagation produced infeasibility */
2848  int* nreductions /**< buffer to store the number of interval reductions */
2849  )
2850 {
2851  SCIP_INTERVAL newrange;
2852 
2853  assert(scip != NULL);
2854  assert(expr != NULL);
2855  assert(infeasible != NULL);
2856  assert(nreductions != NULL);
2857 
2858 #ifdef DEBUG_PROP
2859  SCIPinfoMessage(scip, NULL, "Propagating <expr> by solving %g <expr> in [%g, %g], where <expr> is: ", b, rhs.inf, rhs.sup);
2860  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2861  SCIPinfoMessage(scip, NULL, "\n");
2862 #endif
2863 
2864  /* compute solution of b*x in rhs */
2865  SCIPintervalDivScalar(SCIP_INTERVAL_INFINITY, &newrange, rhs, b);
2866 
2867 #ifdef DEBUG_PROP
2868  SCIPinfoMessage(scip, NULL, "Solution [%g, %g]\n", newrange.inf, newrange.sup);
2869 #endif
2870 
2871  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, newrange, infeasible, nreductions) );
2872 
2873  return SCIP_OKAY;
2874 }
2875 
2876 /** returns max of a/x - c*x for x in {x1, x2} with x1, x2 > 0 */
2877 static
2879  SCIP_Real a, /**< coefficient a */
2880  SCIP_Real c, /**< coefficient c */
2881  SCIP_Real x1, /**< coefficient x1 > 0 */
2882  SCIP_Real x2 /**< coefficient x2 > 0 */
2883  )
2884 {
2885  SCIP_Real cneg;
2886  SCIP_Real cand1;
2887  SCIP_Real cand2;
2888  SCIP_ROUNDMODE roundmode;
2889 
2890  assert(x1 > 0.0);
2891  assert(x2 > 0.0);
2892 
2893  cneg = SCIPintervalNegateReal(c);
2894 
2895  roundmode = SCIPintervalGetRoundingMode();
2897  cand1 = a/x1 + cneg*x1;
2898  cand2 = a/x2 + cneg*x2;
2899  SCIPintervalSetRoundingMode(roundmode);
2900 
2901  return MAX(cand1, cand2);
2902 }
2903 
2904 /** returns max of a/x - c*x for x in dom; it assumes that dom is contained in (0, +inf) */
2905 static
2907  SCIP_Real a, /**< coefficient a */
2908  SCIP_Real c, /**< coefficient c */
2909  SCIP_INTERVAL dom /**< domain of x */
2910  )
2911 {
2912  SCIP_ROUNDMODE roundmode;
2913  SCIP_INTERVAL argmax;
2914  SCIP_Real negunresmax;
2915  SCIP_Real boundarymax;
2916  assert(dom.inf > 0);
2917 
2918  /* if a >= 0, then the function is convex which means the maximum is at one of the boundaries
2919  *
2920  * if c = 0, then the function is monotone which means the maximum is also at one of the boundaries
2921  *
2922  * if a < 0, then the function is concave. The function then has a maximum if and only if there is a point with derivative 0,
2923  * that is, iff -a/x^2 - c = 0 has a solution; i.e. if -a/c >= 0, i.e. (using a<0 and c != 0), c > 0.
2924  * Otherwise (that is, c<0), the maximum is at one of the boundaries.
2925  */
2926  if( a >= 0.0 || c <= 0.0 )
2927  return computeMaxBoundaryForBilinearProp(a, c, dom.inf, dom.sup);
2928 
2929  /* now, the (unrestricted) maximum is at sqrt(-a/c).
2930  * if the argmax is not in the interior of dom then the solution is at a boundary, too
2931  * we check this by computing an interval that contains sqrt(-a/c) first
2932  */
2933  SCIPintervalSet(&argmax, -a);
2934  SCIPintervalDivScalar(SCIP_INTERVAL_INFINITY, &argmax, argmax, c);
2936 
2937  /* if the interval containing sqrt(-a/c) does not intersect with the interior of dom, then
2938  * the (restricted) maximum is at a boundary (we could even say at which boundary, but that doesn't save much)
2939  */
2940  if( argmax.sup <= dom.inf || argmax.inf >= dom.sup )
2941  return computeMaxBoundaryForBilinearProp(a, c, dom.inf, dom.sup);
2942 
2943  /* the maximum at sqrt(-a/c) is -2*sqrt(-a*c), so we compute an upper bound for that by computing a lower bound for 2*sqrt(-a*c) */
2944  roundmode = SCIPintervalGetRoundingMode();
2946  negunresmax = 2.0*SCIPnextafter(sqrt(SCIPintervalNegateReal(a)*c), 0.0);
2947  SCIPintervalSetRoundingMode(roundmode);
2948 
2949  /* if the interval containing sqrt(-a/c) is contained in dom, then we can return -negunresmax */
2950  if( argmax.inf >= dom.inf && argmax.sup <= dom.sup )
2951  return -negunresmax;
2952 
2953  /* now what is left is the case where we cannot say for sure whether sqrt(-a/c) is contained in dom or not
2954  * so we are conservative and return the max of both cases, i.e.,
2955  * the max of the upper bounds on -2*sqrt(-a*c), a/dom.inf-c*dom.inf, a/dom.sup-c*dom.sup.
2956  */
2957  boundarymax = computeMaxBoundaryForBilinearProp(a, c, dom.inf, dom.sup);
2958  return MAX(boundarymax, -negunresmax);
2959 }
2960 
2961 /** computes the range of rhs/x - coef * x for x in exprdom; this is used for the propagation of bilinear terms
2962  *
2963  * If 0 is in the exprdom, we set range to \f$\mathbb{R}\f$ (even though this is not quite correct, it is correct for the
2964  * intended use of the function).
2965  * TODO: maybe check before calling it whether 0 is in the domain and then just avoid calling it
2966  *
2967  * If rhs is [A,B] and x > 0, then we want the min of A/x - coef*x and max of B/x - coef*x for x in [exprdom].
2968  * If rhs is [A,B] and x < 0, then we want the min of B/x - coef*x and max of A/x - coef*x for x in [exprdom].
2969  * However, this is the same as min of -B/x + coef*x and max of -A/x + coef*x for x in -[exprdom].
2970  * Thus, we can always reduce to x > 0 by multiplying [exprdom], rhs, and coef by -1.
2971  */
2972 static
2974  SCIP_INTERVAL exprdom, /**< expression for which to solve */
2975  SCIP_Real coef, /**< expression for which to solve */
2976  SCIP_INTERVAL rhs, /**< rhs used for computation */
2977  SCIP_INTERVAL* range /**< storage for the resulting range */
2978  )
2979 {
2980  SCIP_Real max;
2981  SCIP_Real min;
2982 
2983  if( exprdom.inf <= 0.0 && 0.0 <= exprdom.sup )
2984  {
2986  return;
2987  }
2988 
2989  /* reduce to positive case */
2990  if( exprdom.sup < 0 )
2991  {
2992  SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &exprdom, exprdom, -1.0);
2994  coef *= -1.0;
2995  }
2996  assert(exprdom.inf > 0.0);
2997 
2998  /* compute maximum and minimum */
2999  max = computeMaxForBilinearProp(rhs.sup, coef, exprdom);
3000  min = -computeMaxForBilinearProp(-rhs.inf, -coef, exprdom);
3001 
3002  /* set interval */
3003  SCIPintervalSetBounds(range, min, max);
3004 }
3005 
3006 /** reverse propagates coef_i expr_i + constant in rhs */
3007 static
3009  SCIP* scip, /**< SCIP data structure */
3010  SCIP_EXPR** linexprs, /**< linear expressions */
3011  int nlinexprs, /**< number of linear expressions */
3012  SCIP_Real* lincoefs, /**< coefficients of linear expressions */
3013  SCIP_Real constant, /**< constant */
3014  SCIP_INTERVAL rhs, /**< rhs */
3015  SCIP_Bool* infeasible, /**< buffer to store whether an exps' bounds were propagated to an empty interval */
3016  int* nreductions /**< buffer to store the number of interval reductions of all exprs */
3017  )
3018 {
3019  SCIP_INTERVAL* oldboundslin;
3020  SCIP_INTERVAL* newboundslin;
3021  int i;
3022 
3023  if( nlinexprs == 0 )
3024  return SCIP_OKAY;
3025 
3026  SCIP_CALL( SCIPallocBufferArray(scip, &oldboundslin, nlinexprs) );
3027  SCIP_CALL( SCIPallocBufferArray(scip, &newboundslin, nlinexprs) );
3028 
3029  for( i = 0; i < nlinexprs; ++i )
3030  oldboundslin[i] = SCIPexprGetActivity(linexprs[i]); /* TODO use SCIPgetExprBoundsNonlinear(scip, linexprs[i]) ? */
3031 
3032  *nreductions = SCIPintervalPropagateWeightedSum(SCIP_INTERVAL_INFINITY, nlinexprs,
3033  oldboundslin, lincoefs, constant, rhs, newboundslin, infeasible);
3034 
3035  if( *nreductions > 0 && !*infeasible )
3036  {
3037  /* SCIP is more conservative with what constitutes a reduction than interval arithmetic so we follow SCIP */
3038  *nreductions = 0;
3039  for( i = 0; i < nlinexprs && ! (*infeasible); ++i )
3040  {
3041  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, linexprs[i], newboundslin[i], infeasible, nreductions) );
3042  }
3043  }
3044 
3045  SCIPfreeBufferArray(scip, &newboundslin);
3046  SCIPfreeBufferArray(scip, &oldboundslin);
3047 
3048  return SCIP_OKAY;
3049 }
3050 
3051 
3052 /*
3053  * Callback methods of nonlinear handler
3054  */
3055 
3056 /** callback to free expression specific data */
3057 static
3058 SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeexprdataQuadratic)
3059 { /*lint --e{715}*/
3060  assert(nlhdlrexprdata != NULL);
3061  assert(*nlhdlrexprdata != NULL);
3062 
3063  if( (*nlhdlrexprdata)->quadactivities != NULL )
3064  {
3065  int nquadexprs;
3066  SCIPexprGetQuadraticData((*nlhdlrexprdata)->qexpr, NULL, NULL, NULL, NULL, &nquadexprs, NULL, NULL, NULL);
3067  SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->quadactivities, nquadexprs);
3068  }
3069 
3070  SCIPfreeBlockMemory(scip, nlhdlrexprdata);
3071 
3072  return SCIP_OKAY;
3073 }
3074 
3075 /** callback to detect structure in expression tree
3076  *
3077  * A term is quadratic if
3078  * - it is a product expression of two expressions, or
3079  * - it is power expression of an expression with exponent 2.0.
3080  *
3081  * We define a _propagable_ quadratic expression as a quadratic expression whose termwise propagation does not yield the
3082  * best propagation. In other words, is a quadratic expression that suffers from the dependency problem.
3083  *
3084  * Specifically, a propagable quadratic expression is a sum expression such that there is at least one expr that appears
3085  * at least twice (because of simplification, this means it appears in a quadratic terms and somewhere else).
3086  * For example: \f$x^2 + y^2\f$ is not a propagable quadratic expression; \f$x^2 + x\f$ is a propagable quadratic expression;
3087  * \f$x^2 + x y\f$ is also a propagable quadratic expression
3088  *
3089  * Furthermore, we distinguish between propagable and non-propagable terms. A term is propagable if any of the expressions
3090  * involved in it appear somewhere else. For example, \f$xy + z^2 + z\f$ is a propagable quadratic, the term \f$xy\f$ is
3091  * non-propagable, and \f$z^2\f$ is propagable. For propagation, non-propagable terms are handled as if they were linear
3092  * terms, that is, we do not use the activity of \f$x\f$ and \f$y\f$ to compute the activity of \f$xy\f$ but rather we use directly
3093  * the activity of \f$xy\f$. Similarly, we do not backward propagate to \f$x\f$ and \f$y\f$ (the product expr handler will do this),
3094  * but we backward propagate to \f$x*y\f$. More technically, we register \f$xy\f$ for its activity usage, rather than\f$x\f$ and \f$y\f$.
3095  *
3096  * For propagation, we store the quadratic in our data structure in the following way: We count how often a variable
3097  * appears. Then, a bilinear product expr_i * expr_j is stored as expr_i * expr_j if # expr_i appears > # expr_j
3098  * appears. When # expr_i appears = # expr_j appears, it then it will be stored as expr_i * expr_j if and only if
3099  * expr_i < expr_j, where '<' is the expression order (see \ref EXPR_ORDER "Ordering Rules" in \ref scip_expr.h).
3100  * Heuristically, this should be useful for propagation. The intuition is that by factoring out the variable that
3101  * appears most often we should be able to take care of the dependency problem better.
3102  *
3103  * Simple convex quadratics like \f$x^2 + y^2\f$ are ignored since the default nlhdlr will take care of them.
3104  *
3105  * @note The expression needs to be simplified (in particular, it is assumed to be sorted).
3106  * @note Common subexpressions are also assumed to have been identified, the hashing will fail otherwise!
3107  *
3108  * Sorted implies that:
3109  * - expr < expr^2: bases are the same, but exponent 1 < 2
3110  * - expr < expr * other_expr: u*v < w holds if and only if v < w (OR8), but here w = u < v, since expr comes before
3111  * other_expr in the product
3112  * - expr < other_expr * expr: u*v < w holds if and only if v < w (OR8), but here v = w
3113  *
3114  * Thus, if we see somebody twice, it is a propagable quadratic.
3115  *
3116  * It also implies that
3117  * - expr^2 < expr * other_expr
3118  * - other_expr * expr < expr^2
3119  *
3120  * It also implies that x^-2 < x^-1, but since, so far, we do not interpret x^-2 as (x^-1)^2, it is not a problem.
3121  */
3122 static
3123 SCIP_DECL_NLHDLRDETECT(nlhdlrDetectQuadratic)
3124 { /*lint --e{715,774}*/
3125  SCIP_NLHDLREXPRDATA* nlexprdata;
3126  SCIP_NLHDLRDATA* nlhdlrdata;
3127  SCIP_Real* eigenvalues;
3128  SCIP_Bool isquadratic;
3129  SCIP_Bool propagable;
3130 
3131  assert(scip != NULL);
3132  assert(nlhdlr != NULL);
3133  assert(expr != NULL);
3134  assert(enforcing != NULL);
3135  assert(participating != NULL);
3136  assert(nlhdlrexprdata != NULL);
3137 
3138  nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
3139  assert(nlhdlrdata != NULL);
3140 
3141  /* don't check if all enforcement methods are already ensured */
3142  if( (*enforcing & SCIP_NLHDLR_METHOD_ALL) == SCIP_NLHDLR_METHOD_ALL )
3143  return SCIP_OKAY;
3144 
3145  /* if it is not a sum of at least two terms, it is not interesting */
3146  /* TODO: constraints of the form l<= x*y <= r ? */
3147  if( ! SCIPisExprSum(scip, expr) || SCIPexprGetNChildren(expr) < 2 )
3148  return SCIP_OKAY;
3149 
3150  /* If we are in a subSCIP we don't want to separate intersection cuts */
3151  if( SCIPgetSubscipDepth(scip) > 0 )
3152  nlhdlrdata->useintersectioncuts = FALSE;
3153 
3154 #ifdef SCIP_DEBUG
3155  SCIPinfoMessage(scip, NULL, "Nlhdlr quadratic detecting expr %p aka ", (void*)expr);
3156  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
3157  SCIPinfoMessage(scip, NULL, "\n");
3158  SCIPinfoMessage(scip, NULL, "Have to enforce %d\n", *enforcing);
3159 #endif
3160 
3161  /* check whether expression is quadratic (a sum with at least one square or bilinear term) */
3162  SCIP_CALL( SCIPcheckExprQuadratic(scip, expr, &isquadratic) );
3163 
3164  /* not quadratic -> nothing for us */
3165  if( !isquadratic )
3166  {
3167  SCIPdebugMsg(scip, "expr %p is not quadratic -> abort detect\n", (void*)expr);
3168  return SCIP_OKAY;
3169  }
3170 
3171  propagable = isPropagable(expr);
3172 
3173  /* if we are not propagable and are in presolving, return */
3174  if( !propagable && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING )
3175  {
3176  SCIPdebugMsg(scip, "expr %p is not propagable and in presolving -> abort detect\n", (void*)expr);
3177  return SCIP_OKAY;
3178  }
3179 
3180  /* if we do not use intersection cuts and are not propagable, then we do not want to handle it at all;
3181  * if not propagable, then we need to check the curvature to decide if we want to generate intersection cuts
3182  */
3183  if( !propagable && !nlhdlrdata->useintersectioncuts )
3184  {
3185  SCIPdebugMsg(scip, "expr %p is not propagable -> abort detect\n", (void*)expr);
3186  return SCIP_OKAY;
3187  }
3188 
3189  /* store quadratic in nlhdlrexprdata */
3190  SCIP_CALL( SCIPallocClearBlockMemory(scip, nlhdlrexprdata) );
3191  nlexprdata = *nlhdlrexprdata;
3192  nlexprdata->qexpr = expr;
3193  nlexprdata->cons = cons;
3194 
3195 #ifdef DEBUG_DETECT
3196  SCIPinfoMessage(scip, NULL, "Nlhdlr quadratic detected:\n");
3197  SCIP_CALL( SCIPprintExprQuadratic(scip, conshdlr, qexpr) );
3198 #endif
3199 
3200  /* every propagable quadratic expression will be handled since we can propagate */
3201  if( propagable )
3202  {
3203  SCIP_EXPR** linexprs;
3204  int nlinexprs;
3205  int nquadexprs;
3206  int nbilin;
3207  int i;
3208 
3209  *participating |= SCIP_NLHDLR_METHOD_ACTIVITY;
3210  *enforcing |= SCIP_NLHDLR_METHOD_ACTIVITY;
3211 
3212  SCIPexprGetQuadraticData(expr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, &nbilin, NULL, NULL);
3213  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &nlexprdata->quadactivities, nquadexprs) );
3214 
3215  /* notify children of quadratic that we will need their activity for propagation */
3216  for( i = 0; i < nlinexprs; ++i )
3218 
3219  for( i = 0; i < nquadexprs; ++i )
3220  {
3221  SCIP_EXPR* argexpr;
3222  if( isPropagableTerm(expr, i) )
3223  {
3224  SCIPexprGetQuadraticQuadTerm(expr, i, &argexpr, NULL, NULL, &nbilin, NULL, NULL);
3226 
3227 #ifdef DEBUG_DETECT
3228  SCIPinfoMessage(scip, NULL, "quadterm %d propagable, using %p, unbounded=%d\n", i, (void*)argexpr, nbilin >
3230 #endif
3231  }
3232  else
3233  {
3234  /* non-propagable quadratic is either a single square term or a single bilinear term
3235  * we should make use nlhdlrs in pow or product for this term, so we register usage of the square or product
3236  * expr instead of argexpr
3237  */
3238  SCIP_EXPR* sqrexpr;
3239  int* adjbilin;
3240 
3241  SCIPexprGetQuadraticQuadTerm(expr, i, &argexpr, NULL, NULL, &nbilin, &adjbilin, &sqrexpr);
3242 
3243  if( sqrexpr != NULL )
3244  {
3246  assert(nbilin == 0);
3247 
3248 #ifdef DEBUG_DETECT
3249  SCIPinfoMessage(scip, NULL, "quadterm %d non-propagable square, using %p\n", i, (void*)sqrexpr);
3250 #endif
3251  }
3252  else
3253  {
3254  /* we have expr1 * other_expr or other_expr * expr1; know that expr1 is non propagable, but to decide if
3255  * we want the bounds of expr1 or of the product expr1 * other_expr (or other_expr * expr1), we have to
3256  * decide whether other_expr is also non propagable; due to the way we sort bilinear terms (by
3257  * frequency), we can deduce that other_expr doesn't appear anywhere else (i.e. is non propagable) if the
3258  * product is of the form expr1 * other_expr; however, if we see other_expr * expr1 we need to find
3259  * other_expr and check whether it is propagable
3260  */
3261  SCIP_EXPR* expr1;
3262  SCIP_EXPR* prodexpr;
3263 
3264  assert(nbilin == 1);
3265  SCIPexprGetQuadraticBilinTerm(expr, adjbilin[0], &expr1, NULL, NULL, NULL, &prodexpr);
3266 
3267  if( expr1 == argexpr )
3268  {
3270 
3271 #ifdef DEBUG_DETECT
3272  SCIPinfoMessage(scip, NULL, "quadterm %d non-propagable product, using %p\n", i, (void*)prodexpr);
3273 #endif
3274  }
3275  else
3276  {
3277  int j;
3278  /* check if other_expr is propagable in which case we need the bounds of expr1; otherwise we just need
3279  * the bounds of the product and this will be (or was) registered when the loop takes us to the
3280  * quadexpr other_expr.
3281  * TODO this should be done faster, maybe store pos1 in bilinexprterm or store quadexprterm's in bilinexprterm
3282  */
3283  for( j = 0; j < nquadexprs; ++j )
3284  {
3285  SCIP_EXPR* exprj;
3286  SCIPexprGetQuadraticQuadTerm(expr, j, &exprj, NULL, NULL, NULL, NULL, NULL);
3287  if( expr1 == exprj )
3288  {
3289  if( isPropagableTerm(expr, j) )
3290  {
3292 #ifdef DEBUG_DETECT
3293  SCIPinfoMessage(scip, NULL, "quadterm %d non-propagable alien product, using %p\n", i, (void*)argexpr);
3294 #endif
3295  }
3296  break;
3297  }
3298  }
3299  }
3300  }
3301  }
3302  }
3303  }
3304 
3305  /* check if we are going to separate or not */
3306  nlexprdata->curvature = SCIP_EXPRCURV_UNKNOWN;
3307 
3308  /* for now, we do not care about separation if it is not required */
3309  if( (*enforcing & SCIP_NLHDLR_METHOD_SEPABOTH) == SCIP_NLHDLR_METHOD_SEPABOTH )
3310  {
3311  /* if nobody can do anything, remove data */
3312  if( *participating == SCIP_NLHDLR_METHOD_NONE ) /*lint !e845*/
3313  {
3314  SCIP_CALL( nlhdlrFreeexprdataQuadratic(scip, nlhdlr, expr, nlhdlrexprdata) );
3315  }
3316  else
3317  {
3318  SCIPdebugMsg(scip, "expr %p is quadratic and propagable -> propagate\n", (void*)expr);
3319  }
3320  return SCIP_OKAY;
3321  }
3322 
3323  assert(SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE); /* separation should only be required in (init)solving stage */
3324 
3325  /* check if we can do something more: check curvature of quadratic function stored in nlexprdata
3326  * this is currently only used to decide whether we want to separate, so it can be skipped if in presolve
3327  */
3328  SCIPdebugMsg(scip, "checking curvature of expr %p\n", (void*)expr);
3329  SCIP_CALL( SCIPcomputeExprQuadraticCurvature(scip, expr, &nlexprdata->curvature, NULL, nlhdlrdata->useintersectioncuts) );
3330 
3331  /* get eigenvalues to be able to check whether they were computed */
3332  SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, NULL, NULL, &eigenvalues, NULL);
3333 
3334  /* if we use intersection cuts then we can handle any non-convex quadratic */
3335  if( nlhdlrdata->useintersectioncuts && eigenvalues != NULL && (*enforcing & SCIP_NLHDLR_METHOD_SEPABELOW) ==
3336  FALSE && nlexprdata->curvature != SCIP_EXPRCURV_CONVEX )
3337  {
3338  *participating |= SCIP_NLHDLR_METHOD_SEPABELOW;
3339  }
3340 
3341  if( nlhdlrdata->useintersectioncuts && eigenvalues != NULL && (*enforcing & SCIP_NLHDLR_METHOD_SEPAABOVE) == FALSE &&
3342  nlexprdata->curvature != SCIP_EXPRCURV_CONCAVE )
3343  {
3344  *participating |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3345  }
3346 
3347  /* if nobody can do anything, remove data */
3348  if( *participating == SCIP_NLHDLR_METHOD_NONE ) /*lint !e845*/
3349  {
3350  SCIP_CALL( nlhdlrFreeexprdataQuadratic(scip, nlhdlr, expr, nlhdlrexprdata) );
3351  return SCIP_OKAY;
3352  }
3353 
3354  /* we only need auxiliary variables if we are going to separate */
3355  if( *participating & SCIP_NLHDLR_METHOD_SEPABOTH )
3356  {
3357  SCIP_EXPR** linexprs;
3358  int nquadexprs;
3359  int nlinexprs;
3360  int i;
3361 
3362  SCIPexprGetQuadraticData(expr, NULL, &nlinexprs, &linexprs, NULL, &nquadexprs, NULL, NULL, NULL);
3363 
3364  for( i = 0; i < nlinexprs; ++i ) /* expressions appearing linearly */
3365  {
3367  }
3368  for( i = 0; i < nquadexprs; ++i ) /* expressions appearing quadratically */
3369  {
3370  SCIP_EXPR* quadexpr;
3371  SCIPexprGetQuadraticQuadTerm(expr, i, &quadexpr, NULL, NULL, NULL, NULL, NULL);
3373  }
3374 
3375  SCIPdebugMsg(scip, "expr %p is quadratic and propagable -> propagate and separate\n", (void*)expr);
3376 
3377  nlexprdata->separating = TRUE;
3378  }
3379  else
3380  {
3381  SCIPdebugMsg(scip, "expr %p is quadratic and propagable -> propagate only\n", (void*)expr);
3382  }
3383 
3385  {
3386  SCIPexprSetCurvature(expr, nlexprdata->curvature);
3387  SCIPdebugMsg(scip, "expr is %s in the original variables\n", nlexprdata->curvature == SCIP_EXPRCURV_CONCAVE ? "concave" : "convex");
3388  nlexprdata->origvars = TRUE;
3389  }
3390 
3391  return SCIP_OKAY;
3392 }
3393 
3394 /** nonlinear handler auxiliary evaluation callback */
3395 static
3396 SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxQuadratic)
3397 { /*lint --e{715}*/
3398  int i;
3399  int nlinexprs;
3400  int nquadexprs;
3401  int nbilinexprs;
3402  SCIP_Real constant;
3403  SCIP_Real* lincoefs;
3404  SCIP_EXPR** linexprs;
3405 
3406  assert(scip != NULL);
3407  assert(expr != NULL);
3408  assert(auxvalue != NULL);
3409  assert(nlhdlrexprdata->separating);
3410  assert(nlhdlrexprdata->qexpr == expr);
3411 
3412  /* if the quadratic is in the original variable we can just evaluate the expression */
3413  if( nlhdlrexprdata->origvars )
3414  {
3415  *auxvalue = SCIPexprGetEvalValue(expr);
3416  return SCIP_OKAY;
3417  }
3418 
3419  /* TODO there was a
3420  *auxvalue = SCIPevalExprQuadratic(scip, nlhdlrexprdata->qexpr, sol);
3421  here; any reason why not using this anymore?
3422  */
3423 
3424  SCIPexprGetQuadraticData(expr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
3425 
3426  *auxvalue = constant;
3427 
3428  for( i = 0; i < nlinexprs; ++i ) /* linear exprs */
3429  *auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
3430 
3431  for( i = 0; i < nquadexprs; ++i ) /* quadratic terms */
3432  {
3433  SCIP_Real solval;
3434  SCIP_Real lincoef;
3435  SCIP_Real sqrcoef;
3436  SCIP_EXPR* qexpr;
3437 
3438  SCIPexprGetQuadraticQuadTerm(expr, i, &qexpr, &lincoef, &sqrcoef, NULL, NULL, NULL);
3439 
3440  solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(qexpr));
3441  *auxvalue += (lincoef + sqrcoef * solval) * solval;
3442  }
3443 
3444  for( i = 0; i < nbilinexprs; ++i ) /* bilinear terms */
3445  {
3446  SCIP_EXPR* expr1;
3447  SCIP_EXPR* expr2;
3448  SCIP_Real coef;
3449 
3450  SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
3451 
3452  *auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol,
3454  }
3455 
3456  return SCIP_OKAY;
3457 }
3458 
3459 /** nonlinear handler enforcement callback */
3460 static
3461 SCIP_DECL_NLHDLRENFO(nlhdlrEnfoQuadratic)
3462 { /*lint --e{715}*/
3463  SCIP_NLHDLRDATA* nlhdlrdata;
3464  SCIP_ROWPREP* rowprep;
3465  SCIP_Bool success = FALSE;
3466  SCIP_NODE* node;
3467  int depth;
3468  SCIP_Longint nodenumber;
3469  SCIP_Real* eigenvalues;
3470  SCIP_Real violation;
3471 
3472  assert(nlhdlrexprdata != NULL);
3473  assert(nlhdlrexprdata->qexpr == expr);
3474 
3475  INTERLOG(printf("Starting interesection cuts!\n");)
3476 
3477  nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
3478  assert(nlhdlrdata != NULL);
3479 
3480  assert(result != NULL);
3481  *result = SCIP_DIDNOTRUN;
3482 
3483  /* estimate should take care of convex quadratics */
3484  if( ( overestimate && nlhdlrexprdata->curvature == SCIP_EXPRCURV_CONCAVE) ||
3485  (!overestimate && nlhdlrexprdata->curvature == SCIP_EXPRCURV_CONVEX) )
3486  {
3487  INTERLOG(printf("Convex, no need of interesection cuts!\n");)
3488  return SCIP_OKAY;
3489  }
3490 
3491  /* nothing to do if we can't use intersection cuts */
3492  if( ! nlhdlrdata->useintersectioncuts )
3493  {
3494  INTERLOG(printf("We don't use intersection cuts!\n");)
3495  return SCIP_OKAY;
3496  }
3497 
3498  /* right now can use interesction cuts only if a basic LP solution is at hand; TODO: in principle we can do something
3499  * even if it is not optimal
3500  */
3502  {
3503  INTERLOG(printf("LP solutoin not good!\n");)
3504  return SCIP_OKAY;
3505  }
3506 
3507  /* only separate at selected nodes */
3508  node = SCIPgetCurrentNode(scip);
3509  depth = SCIPnodeGetDepth(node);
3510  if( (nlhdlrdata->atwhichnodes == -1 && depth != 0) || (nlhdlrdata->atwhichnodes != -1 && depth % nlhdlrdata->atwhichnodes != 0) )
3511  {
3512  INTERLOG(printf("Don't separate at this node\n");)
3513  return SCIP_OKAY;
3514  }
3515 
3516  /* do not add more than ncutslimitroot cuts in root node and ncutslimit cuts in the non-root nodes */
3517  nodenumber = SCIPnodeGetNumber(node);
3518  if( nlhdlrdata->lastnodenumber != nodenumber )
3519  {
3520  nlhdlrdata->lastnodenumber = nodenumber;
3521  nlhdlrdata->lastncuts = nlhdlrdata->ncutsadded;
3522  }
3523  /*else if( (depth > 0 && nlhdlrdata->ncutsadded - nlhdlrdata->lastncuts >= nlhdlrdata->ncutslimit) || (depth == 0 &&
3524  nlhdlrdata->ncutsadded - nlhdlrdata->lastncuts >= nlhdlrdata->ncutslimitroot)) */
3525  /* allow the addition of a certain number of cuts per quadratic */
3526  if( (depth > 0 && nlhdlrexprdata->ncutsadded >= nlhdlrdata->ncutslimit) || (depth == 0 &&
3527  nlhdlrexprdata->ncutsadded >= nlhdlrdata->ncutslimitroot) )
3528  {
3529  INTERLOG(printf("Too many cuts added already\n");)
3530  return SCIP_OKAY;
3531  }
3532 
3533  /* can't separate if we do not have an eigendecomposition */
3534  SCIPexprGetQuadraticData(expr, NULL, NULL, NULL, NULL, NULL, NULL, &eigenvalues, NULL);
3535  if( eigenvalues == NULL )
3536  {
3537  INTERLOG(printf("No known eigenvalues!\n");)
3538  return SCIP_OKAY;
3539  }
3540 
3541  /* if constraint is not sufficiently violated -> do nothing */
3542  if( cons != nlhdlrexprdata->cons )
3543  {
3544  /* constraint is w.r.t auxvar */
3545  violation = auxvalue - SCIPgetSolVal(scip, NULL, SCIPgetExprAuxVarNonlinear(expr));
3546  violation = ABS( violation );
3547  }
3548  else
3549  /* quadratic is a constraint */
3550  violation = MAX( SCIPgetLhsNonlinear(nlhdlrexprdata->cons) - auxvalue, auxvalue -
3551  SCIPgetRhsNonlinear(nlhdlrexprdata->cons)); /*lint !e666*/
3552 
3553  if( violation < nlhdlrdata->minviolation )
3554  {
3555  INTERLOG(printf("Violation %g is just too small\n", violation); )
3556  return SCIP_OKAY;
3557  }
3558 
3559  /* we can't build an intersection cut when the expr is the root of some constraint and also a subexpression of
3560  * another constraint because we initialize data differently TODO: how differently? */
3561  /* TODO: I don't think this is needed */
3562  if( nlhdlrexprdata->cons != NULL && cons != nlhdlrexprdata->cons )
3563  {
3564  INTERLOG(printf("WARNING!! expr is root of one constraint and subexpr of another!\n"); )
3565  return SCIP_OKAY;
3566  }
3567 
3568  /* if we are the root of a constraint and we are feasible w.r.t our auxiliary variables, that is, auxvalue is
3569  * actually feasible for the sides of the constraint, then do not separate
3570  */
3571  if( cons == nlhdlrexprdata->cons && ((overestimate && (SCIPgetLhsNonlinear(cons)) - auxvalue < SCIPfeastol(scip)) ||
3572  (! overestimate && (auxvalue - SCIPgetRhsNonlinear(cons) < SCIPfeastol(scip)))) )
3573  {
3574  INTERLOG(printf("We are actually feasible for the sides of the constraint\n"); )
3575  return SCIP_OKAY;
3576  }
3577 
3578 #ifdef DEBUG_INTERSECTIONCUT
3579  SCIPinfoMessage(scip, NULL, "Build intersection cut for \n");
3580  if( cons == nlhdlrexprdata->cons )
3581  {
3582  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
3583  SCIPinfoMessage(scip, NULL, "\n");
3584  }
3585  else
3586  {
3587  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
3589  }
3590  SCIPinfoMessage(scip, NULL, "We need to %sestimate\n", overestimate ? "over" : "under" );
3591  SCIPinfoMessage(scip, NULL, "LP sol: \n");
3593 #endif
3594  *result = SCIP_DIDNOTFIND;
3595 
3596  /* cut (in the nonbasic space) is of the form alpha^T x >= 1 */
3598  INTERLOG(printf("Generating inter cut\n"); )
3599 
3600  SCIP_CALL( generateIntercut(scip, expr, nlhdlrdata, nlhdlrexprdata, cons, sol, rowprep, overestimate, &success) );
3601  INTERLOG(if( !success) printf("Generation failed\n"); )
3602 
3603  /* we generated something, let us see if it survives the clean up */
3604  if( success )
3605  {
3606  assert(sol == NULL);
3607  nlhdlrdata->ncutsgenerated += 1;
3608  nlhdlrexprdata->ncutsadded += 1;
3609 
3610  /* merge coefficients that belong to same variable */
3611  SCIPmergeRowprepTerms(scip, rowprep);
3612 
3613  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, nlhdlrdata->mincutviolation, &violation, &success) );
3614  INTERLOG(if( !success) printf("Clean up failed\n"); )
3615  }
3616 
3617  /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
3618  if( success )
3619  {
3620  SCIP_ROW* row;
3621  SCIP_Bool infeasible;
3622 
3623  /* count number of bound cuts */
3624  if( nlhdlrdata->useboundsasrays )
3625  nlhdlrdata->nboundcuts += 1;
3626 
3627  (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "%s_intersection_quadratic%p_lp%" SCIP_LONGINT_FORMAT,
3628  overestimate ? "over" : "under",
3629  (void*)expr,
3630  SCIPgetNLPs(scip));
3631 
3632  SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
3633 
3634  /*printf("## New cut\n");
3635  printf(" -> found maxquad-free cut <%s>: act=%f, lhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n\n",
3636  SCIProwGetName(row), SCIPgetRowLPActivity(scip, row), SCIProwGetLhs(row), SCIProwGetNorm(row),
3637  SCIPgetCutEfficacy(scip, NULL, row),
3638  SCIPgetRowMinCoef(scip, row), SCIPgetRowMaxCoef(scip, row),
3639  SCIPgetRowMaxCoef(scip, row)/SCIPgetRowMinCoef(scip, row)); */
3640 
3641  /* intersection cuts can be numerically nasty; we do some extra numerical checks here */
3642  /*printf("SCIP DEPTH %d got a cut with violation %g, efficacy %g and r/e %g\n", SCIPgetSubscipDepth(scip),
3643  * violation, SCIPgetCutEfficacy(scip, NULL, row), SCIPgetRowMaxCoef(scip, row) / SCIPgetRowMinCoef(scip, row) /
3644  * SCIPgetCutEfficacy(scip, NULL, row));
3645  */
3646  assert(SCIPgetCutEfficacy(scip, NULL, row) > 0.0);
3647  if( ! nlhdlrdata->ignorehighre || SCIPgetRowMaxCoef(scip, row) / SCIPgetRowMinCoef(scip, row) / SCIPgetCutEfficacy(scip, NULL, row) < 1e9 )
3648  {
3649 #ifdef SCIP_DEBUG
3650  SCIPdebugMsg(scip, "adding cut ");
3651  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
3652 #endif
3653 
3654  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
3655 
3656  if( infeasible )
3657  {
3658  *result = SCIP_CUTOFF;
3659  }
3660  else
3661  {
3662  *result = SCIP_SEPARATED;
3663  nlhdlrdata->ncutsadded += 1;
3664  nlhdlrdata->densitysum += (SCIP_Real) SCIProwprepGetNVars(rowprep) / (SCIP_Real) SCIPgetNVars(scip);
3665  }
3666  }
3667  else
3668  {
3669  nlhdlrdata->nhighre++;
3670  }
3671  SCIP_CALL( SCIPreleaseRow(scip, &row) );
3672  }
3673 
3674  SCIPfreeRowprep(scip, &rowprep);
3675 
3676  return SCIP_OKAY;
3677 }
3678 
3679 /** nonlinear handler forward propagation callback
3680  *
3681  * This method should solve the problem
3682  * <pre>
3683  * max/min quad expression over box constraints
3684  * </pre>
3685  * However, this problem is difficult so we are satisfied with a proxy.
3686  * Interval arithmetic suffices when no variable appears twice, however this is seldom the case, so we try
3687  * to take care of the dependency problem to some extent:
3688  * Let \f$P_l = \{i : \text{expr}_l \text{expr}_i \,\text{is a bilinear expr}\}\f$.
3689  * 1. partition the quadratic expression as sum of quadratic functions \f$\sum_l q_l\f$
3690  * where \f$q_l = a_l \text{expr}_l^2 + c_l \text{expr}_l + \sum_{i \in P_l} b_{il} \text{expr}_i \text{expr}_l\f$
3691  * 2. build interval quadratic functions, i.e., \f$a x^2 + b x\f$ where \f$b\f$ is an interval, i.e.,
3692  * \f$a_l \text{expr}_l^2 + [\sum_{i \in P_l} b_{il} \text{expr}_i + c_l] \text{expr}_l\f$
3693  * 3. compute \f$\min/\max \{ a x^2 + b x : x \in [x] \}\f$ for each interval quadratic, i.e.,
3694  * \f$\min/\max a_l \text{expr}_l^2 + \text{expr}_l [\sum_{i \in P_l} b_{il} \text{expr}_i + c_l] : \text{expr}_l \in [\text{expr}_l]\f$
3695  *
3696  * Notes:
3697  * 1. The \f$l\f$-th quadratic expr (expressions that appear quadratically) is associated with \f$q_l\f$.
3698  * 2. `nlhdlrdata->quadactivities[l]` is the activity of \f$q_l\f$ as computed in the description above.
3699  * 3. The \f$q_l\f$ of a quadratic term might be empty, in which case `nlhdlrdata->quadactivities[l]` is [0,0].\n
3700  * For example, consider \f$x^2 + xy\f$. There are two quadratic expressions, \f$x\f$ and \f$y\f$.
3701  * The \f$q\f$ associated to \f$x\f$ is \f$x^2 + xy\f$, while the \f$q\f$ associated to \f$y\f$ is empty.
3702  * Thus, `nlhdlrdata->quadactivities[1]` is [0,0] in this case.
3703  * The logic is to avoid considering the term \f$xy\f$ twice.
3704  *
3705  * @note The order matters! If \f$\text{expr}_i\, \text{expr}_l\f$ is a term in the quadratic, then \f$i\f$ is *not* in \f$P_l\f$
3706  */
3707 static
3708 SCIP_DECL_NLHDLRINTEVAL(nlhdlrIntevalQuadratic)
3709 { /*lint --e{715}*/
3710  SCIP_EXPR** linexprs;
3711  SCIP_Real* lincoefs;
3712  SCIP_Real constant;
3713  int nquadexprs;
3714  int nlinexprs;
3715 
3716  assert(scip != NULL);
3717  assert(expr != NULL);
3718 
3719  assert(nlhdlrexprdata != NULL);
3720  assert(nlhdlrexprdata->quadactivities != NULL);
3721  assert(nlhdlrexprdata->qexpr == expr);
3722 
3723  SCIPdebugMsg(scip, "Interval evaluation of quadratic expr\n");
3724 
3725  SCIPexprGetQuadraticData(expr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, NULL, NULL, NULL);
3726 
3727  /*
3728  * compute activity of linear part, if some linear term has changed
3729  */
3730  {
3731  int i;
3732 
3733  SCIPdebugMsg(scip, "Computing activity of linear part\n");
3734 
3735  SCIPintervalSet(&nlhdlrexprdata->linactivity, constant);
3736  for( i = 0; i < nlinexprs; ++i )
3737  {
3738  SCIP_INTERVAL linterminterval;
3739 
3740  linterminterval = SCIPexprGetActivity(linexprs[i]);
3741  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, linterminterval) )
3742  {
3743  SCIPdebugMsg(scip, "Activity of linear part is empty due to child %d\n", i);
3744  SCIPintervalSetEmpty(interval);
3745  return SCIP_OKAY;
3746  }
3747  SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &linterminterval, linterminterval, lincoefs[i]);
3748  SCIPintervalAdd(SCIP_INTERVAL_INFINITY, &nlhdlrexprdata->linactivity, nlhdlrexprdata->linactivity, linterminterval);
3749  }
3750 
3751  SCIPdebugMsg(scip, "Activity of linear part is [%g, %g]\n", nlhdlrexprdata->linactivity.inf,
3752  nlhdlrexprdata->linactivity.sup);
3753  }
3754 
3755  /*
3756  * compute activity of quadratic part
3757  */
3758  {
3759  int i;
3760 
3761  SCIPdebugMsg(scip, "Computing activity of quadratic part\n");
3762 
3763  nlhdlrexprdata->nneginfinityquadact = 0;
3764  nlhdlrexprdata->nposinfinityquadact = 0;
3765  nlhdlrexprdata->minquadfiniteact = 0.0;
3766  nlhdlrexprdata->maxquadfiniteact = 0.0;
3767  SCIPintervalSet(&nlhdlrexprdata->quadactivity, 0.0);
3768 
3769  for( i = 0; i < nquadexprs; ++i )
3770  {
3771  SCIP_Real quadlb;
3772  SCIP_Real quadub;
3773  SCIP_EXPR* qexpr;
3774  SCIP_Real lincoef;
3775  SCIP_Real sqrcoef;
3776  int nadjbilin;
3777  int* adjbilin;
3778  SCIP_EXPR* sqrexpr;
3779 
3780  SCIPexprGetQuadraticQuadTerm(expr, i, &qexpr, &lincoef, &sqrcoef, &nadjbilin, &adjbilin, &sqrexpr);
3781 
3782  if( !isPropagableTerm(expr, i) )
3783  {
3784  /* term is not propagable, i.e., the exprs involved in term only appear once; thus use the activity of the
3785  * quadratic term directly and not the activity of the exprs involed in the term. See also documentation of
3786  * DETECT
3787  */
3788  SCIP_INTERVAL tmp;
3789 
3790  assert(lincoef == 0.0);
3791 
3792  if( sqrcoef != 0.0 )
3793  {
3794  assert(sqrexpr != NULL);
3795  assert(nadjbilin == 0);
3796 
3797  tmp = SCIPexprGetActivity(sqrexpr);
3799  {
3800  SCIPintervalSetEmpty(interval);
3801  return SCIP_OKAY;
3802  }
3803 
3804  SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &tmp, tmp, sqrcoef);
3805  quadlb = tmp.inf;
3806  quadub = tmp.sup;
3807 
3808 #ifdef DEBUG_PROP
3809  SCIPinfoMessage(scip, NULL, "Computing activity for quadratic term %g <expr>, where <expr> is: ", sqrcoef);
3810  SCIP_CALL( SCIPprintExpr(scip, sqrexpr, NULL) );
3811 #endif
3812  }
3813  else
3814  {
3815  SCIP_EXPR* expr1;
3816  SCIP_EXPR* prodexpr;
3817  SCIP_Real prodcoef;
3818 
3819  assert(nadjbilin == 1);
3820  SCIPexprGetQuadraticBilinTerm(expr, adjbilin[0], &expr1, NULL, &prodcoef, NULL, &prodexpr);
3821 
3822  if( expr1 == qexpr )
3823  {
3824  /* the quadratic expression expr1 appears only as expr1 * expr2, so its 'q' is expr1 * expr2 */
3825  tmp = SCIPexprGetActivity(prodexpr);
3827  {
3828  SCIPintervalSetEmpty(interval);
3829  return SCIP_OKAY;
3830  }
3831 
3832  SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &tmp, tmp, prodcoef);
3833  quadlb = tmp.inf;
3834  quadub = tmp.sup;
3835 
3836 #ifdef DEBUG_PROP
3837  SCIPinfoMessage(scip, NULL, "Computing activity for quadratic term %g <expr>, where <expr> is: ", prodcoef);
3838  SCIP_CALL( SCIPprintExpr(scip, prodexpr, NULL) );
3839 #endif
3840  }
3841  else
3842  {
3843  /* the quadratic expression expr1 appears as expr2 * expr1, thus its 'q' is empty, see also the Notes
3844  * in the documentation of the function
3845  */
3846  SCIPintervalSet(&nlhdlrexprdata->quadactivities[i], 0.0);
3847  continue;
3848  }
3849  }
3850  }
3851  else
3852  {
3853  int j;
3854  SCIP_INTERVAL b;
3855 
3856  SCIPexprGetQuadraticQuadTerm(expr, i, &qexpr, &lincoef, &sqrcoef, &nadjbilin, &adjbilin, NULL);
3857 
3859  {
3860  SCIPintervalSetEmpty(interval);
3861  return SCIP_OKAY;
3862  }
3863 
3864  /* b = [c_l] */
3865  SCIPintervalSet(&b, lincoef);
3866 #ifdef DEBUG_PROP
3867  SCIPinfoMessage(scip, NULL, "b := %g\n", lincoef);
3868 #endif
3869  for( j = 0; j < nadjbilin; ++j )
3870  {
3871  SCIP_INTERVAL bterm;
3872  SCIP_EXPR* expr1;
3873  SCIP_EXPR* expr2;
3874  SCIP_Real bilincoef;
3875 
3876  SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &expr1, &expr2, &bilincoef, NULL, NULL);
3877 
3878  if( expr1 != qexpr )
3879  continue;
3880 
3881  bterm = SCIPexprGetActivity(expr2);
3883  {
3884  SCIPintervalSetEmpty(interval);
3885  return SCIP_OKAY;
3886  }
3887 
3888  /* b += [b_jl * expr_j] for j \in P_l */
3889  SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &bterm, bterm, bilincoef);
3890  SCIPintervalAdd(SCIP_INTERVAL_INFINITY, &b, b, bterm);
3891 
3892 #ifdef DEBUG_PROP
3893  SCIPinfoMessage(scip, NULL, "b += %g * [expr2], where <expr2> is: ", bilincoef);
3894  SCIP_CALL( SCIPprintExpr(scip, expr2, NULL) );
3895  SCIPinfoMessage(scip, NULL, " [%g,%g]\n", SCIPexprGetActivity(expr2).inf, SCIPexprGetActivity(expr2).sup);
3896 #endif
3897  }
3898 
3899  /* TODO: under which assumptions do we know that we just need to compute min or max? its probably the locks that give some information here */
3901  SCIPexprGetActivity(qexpr));
3902 
3903  /* TODO: implement SCIPintervalQuadLowerBound */
3904  {
3905  SCIP_INTERVAL minusb;
3907 
3908  quadlb = -SCIPintervalQuadUpperBound(SCIP_INTERVAL_INFINITY, -sqrcoef, minusb,
3909  SCIPexprGetActivity(qexpr));
3910  }
3911 
3912 #ifdef DEBUG_PROP
3913  SCIPinfoMessage(scip, NULL, "Computing activity for quadratic term %g <expr>^2 + [%g,%g] <expr>, where <expr> is: ", sqrcoef, b.inf, b.sup);
3914  SCIP_CALL( SCIPprintExpr(scip, qexpr, NULL) );
3915 #endif
3916  }
3917 #ifdef DEBUG_PROP
3918  SCIPinfoMessage(scip, NULL, " -> [%g, %g]\n", quadlb, quadub);
3919 #endif
3920 
3921  SCIPintervalSetBounds(&nlhdlrexprdata->quadactivities[i], quadlb, quadub);
3922  SCIPintervalAdd(SCIP_INTERVAL_INFINITY, &nlhdlrexprdata->quadactivity, nlhdlrexprdata->quadactivity, nlhdlrexprdata->quadactivities[i]);
3923 
3924  /* get number of +/-infinity contributions and compute finite activity */
3925  if( quadlb <= -SCIP_INTERVAL_INFINITY )
3926  nlhdlrexprdata->nneginfinityquadact++;
3927  else
3928  {
3929  SCIP_ROUNDMODE roundmode;
3930 
3931  roundmode = SCIPintervalGetRoundingMode();
3933 
3934  nlhdlrexprdata->minquadfiniteact += quadlb;
3935 
3936  SCIPintervalSetRoundingMode(roundmode);
3937  }
3938  if( quadub >= SCIP_INTERVAL_INFINITY )
3939  nlhdlrexprdata->nposinfinityquadact++;
3940  else
3941  {
3942  SCIP_ROUNDMODE roundmode;
3943 
3944  roundmode = SCIPintervalGetRoundingMode();
3946 
3947  nlhdlrexprdata->maxquadfiniteact += quadub;
3948 
3949  SCIPintervalSetRoundingMode(roundmode);
3950  }
3951  }
3952 
3953  SCIPdebugMsg(scip, "Activity of quadratic part is [%g, %g]\n", nlhdlrexprdata->quadactivity.inf, nlhdlrexprdata->quadactivity.sup);
3954  }
3955 
3956  /* interval evaluation is linear activity + quadactivity */
3957  SCIPintervalAdd(SCIP_INTERVAL_INFINITY, interval, nlhdlrexprdata->linactivity, nlhdlrexprdata->quadactivity);
3958 
3959  nlhdlrexprdata->activitiestag = SCIPgetCurBoundsTagNonlinear(SCIPfindConshdlr(scip, "nonlinear"));
3960 
3961  return SCIP_OKAY;
3962 }
3963 
3964 /** nonlinear handler reverse propagation callback
3965  *
3966  * @note the implemented technique is a proxy for solving the problem min/max{ x_i : quad expr in [quad expr] }
3967  * and as such can be improved.
3968  */
3969 static
3970 SCIP_DECL_NLHDLRREVERSEPROP(nlhdlrReversepropQuadratic)
3971 { /*lint --e{715}*/
3972  SCIP_EXPR** linexprs;
3973  SCIP_EXPR** bilinexprs; /* TODO: should this be stored in the nlhdlr expr data? */
3974  SCIP_Real* bilincoefs;
3975  SCIP_Real* lincoefs;
3976  SCIP_Real constant;
3977  int nquadexprs;
3978  int nlinexprs;
3979 
3980  SCIP_INTERVAL rhs;
3981  SCIP_INTERVAL quadactivity;
3982  int i;
3983 
3984  SCIPdebugMsg(scip, "Reverse propagation of quadratic expr given bounds = [%g,%g]\n", bounds.inf, bounds.sup);
3985 
3986  assert(scip != NULL);
3987  assert(expr != NULL);
3988  assert(infeasible != NULL);
3989  assert(nreductions != NULL);
3990  assert(nlhdlrexprdata != NULL);
3991  assert(nlhdlrexprdata->quadactivities != NULL);
3992  assert(nlhdlrexprdata->qexpr == expr);
3993 
3994  *nreductions = 0;
3995 
3996  /* not possible to conclude finite bounds if the interval of the expression is [-inf,inf] */
3998  {
3999  SCIPdebugMsg(scip, "expr's range is R -> cannot reverse propagate\n");
4000  return SCIP_OKAY;
4001  }
4002 
4003  /* ensure that partial activities as stored in nlhdlrexprdata are uptodate
4004  * if the activity stored in expr is more recent than the partial activities stored in this nlhdlrexprdata,
4005  * then we should reevaluate the partial activities
4006  */
4007  if( SCIPexprGetActivityTag(expr) > nlhdlrexprdata->activitiestag )
4008  {
4009  SCIP_CALL( nlhdlrIntevalQuadratic(scip, nlhdlr, expr, nlhdlrexprdata, &quadactivity, NULL, NULL) );
4010  }
4011 
4012  SCIPexprGetQuadraticData(expr, &constant, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, NULL, NULL, NULL);
4013 
4014  /* propagate linear part in rhs = expr's interval - quadratic activity; first, reconstruct the quadratic activity */
4015  SCIPintervalSetBounds(&quadactivity,
4016  nlhdlrexprdata->nneginfinityquadact > 0 ? -SCIP_INTERVAL_INFINITY : nlhdlrexprdata->minquadfiniteact,
4017  nlhdlrexprdata->nposinfinityquadact > 0 ? SCIP_INTERVAL_INFINITY : nlhdlrexprdata->maxquadfiniteact);
4018 
4019  SCIPintervalSub(SCIP_INTERVAL_INFINITY, &rhs, bounds, quadactivity);
4020 
4021  SCIP_CALL( reversePropagateLinearExpr(scip, linexprs, nlinexprs, lincoefs, constant, rhs, infeasible, nreductions) );
4022 
4023  /* stop if we find infeasibility */
4024  if( *infeasible )
4025  return SCIP_OKAY;
4026 
4027  /* propagate quadratic part in expr's interval - linear activity, where linear activity was computed in INTEVAL.
4028  * The idea is basically to write interval quadratics for each expr and then solve for expr.
4029  *
4030  * One way of achieving this is:
4031  * - for each expression expr_i, write the quadratic expression as a_i expr^2_i + expr_i ( \sum_{j \in J_i} b_ij
4032  * expr_j + c_i ) + quadratic expression in expr_k for k \neq i
4033  * - compute the interval b = [\sum_{j \in J_i} b_ij expr_j + c_i], where J_i are all the indices j such that the
4034  * bilinear expression expr_i expr_j appears
4035  * - use some technique (like the one in nlhdlrIntevalQuadratic), to evaluate the activity of rest_i = [quadratic
4036  * expression in expr_k for k \neq i].
4037  * - solve a_i expr_i^2 + b expr_i \in rhs_i := [expr activity] - rest_i
4038  *
4039  * However, this might be expensive, especially computing rest_i. Hence, we implement a simpler version.
4040  * - we use the same partition as in nlhdlrIntevalQuadratic for the bilinear terms. This way, b = [\sum_{j \in P_i}
4041  * b_ij expr_j + c_i], where P_i is the set of indices j such that expr_i * expr_j appears in that order
4042  * - we evaluate the activity of rest_i as sum_{k \neq i} [\min q_k, \max q_k] where q_k = a_k expr_k^2 + [\sum_{j
4043  * \in P_k} b_jk expr_j + c_k] expr_k. The intervals [\min q_k, \max q_k] were already computed in
4044  * nlhdlrIntevalQuadratic, so we just reuse them.
4045  *
4046  * A downside of the above is that we might not deduce any bounds for variables that appear less often. For example,
4047  * consider x^2 + x * y + x * z + y * z + z. This quadratic gets partitioned as (x^2 + x*y + x*z) + (z*y + z). The
4048  * first parenthesis is interpreted as a function of x, while the second one as a function of z.
4049  * To also get bounds on y, after reverse propagating x in x^2 + x*y + x*z \in rhs, we rewrite this as y + z \in rhs/x -
4050  * x and propagate the y + z).
4051  * In general, after reverse propagating expr_i, we consider
4052  * \sum_{j \in J_i} b_ij expr_j in ([expr activity] - quadratic expression in expr_k for k \neq i - c_i) / expr_i - a_i expr_i,
4053  * compute an interval for the right hand side (see computeRangeForBilinearProp) and use that to propagate the
4054  * linear sum on the left hand side.
4055  *
4056  * Note: this last step generalizes a technique that appeared in the classic cons_quadratic.
4057  * The idea of that technique was to borrow a bilinear term expr_k expr_l when propagating expr_l and the quadratic
4058  * function for expr_k was simple enough.
4059  * Since in P_l we only consider the indices of expressions that appear multiplying expr_l as _second_ factor, we
4060  * would lose the bilinear terms expr_k * expr_l, which contributes to the dependency problem.
4061  * The problem is that the contribution of b_kl * expr_k * expr_l to rest_i is not just [b_kl * expr_k * expr_l], but
4062  * rather quadactivities[k] (= max/min of a_k expr_k^2 + expr_k * [c_k + sum_i \in P_k b_ki expr_i]).
4063  * Thus, we _cannot_ just substract [b_kl * expr_k * expr_l] from rest_i.
4064  * But, if expr_k only appears as expr_k * expr_l, then quadactivities[k] = [b_kl * expr_k * expr_l]. So this
4065  * case was handled in old cons_quadratic.
4066  *
4067  *
4068  * TODO: handle simple cases
4069  * TODO: identify early when there is nothing to be gain
4070  */
4071  SCIPintervalSub(SCIP_INTERVAL_INFINITY, &rhs, bounds, nlhdlrexprdata->linactivity);
4072  SCIP_CALL( SCIPallocBufferArray(scip, &bilinexprs, nquadexprs) );
4073  SCIP_CALL( SCIPallocBufferArray(scip, &bilincoefs, nquadexprs) );
4074 
4075  for( i = 0; i < nquadexprs; ++i )
4076  {
4077  SCIP_INTERVAL rhs_i;
4078  SCIP_INTERVAL rest_i;
4079  SCIP_EXPR* qexpr;
4080  SCIP_Real lincoef;
4081  SCIP_Real sqrcoef;
4082  int nadjbilin;
4083  int* adjbilin;
4084  SCIP_EXPR* sqrexpr;
4085 
4086  SCIPexprGetQuadraticQuadTerm(expr, i, &qexpr, &lincoef, &sqrcoef, &nadjbilin, &adjbilin, &sqrexpr);
4087 
4088  /* rhs_i = rhs - rest_i.
4089  * to compute rest_i = [\sum_{k \neq i} q_k] we just have to substract
4090  * the activity of q_i from quadactivity; however, care must be taken about infinities;
4091  * if [q_i].sup = +infinity and there is = 1 contributing +infinity -> rest_i.sup = maxquadfiniteact
4092  * if [q_i].sup = +infinity and there is > 1 contributing +infinity -> rest_i.sup = +infinity
4093  * if [q_i].sup = finite and there is > 0 contributing +infinity -> rest_i.sup = +infinity
4094  * if [q_i].sup = finite and there is = 0 contributing +infinity -> rest_i.sup = maxquadfiniteact - [q_i].sup
4095  *
4096  * the same holds when replacing sup with inf, + with - and max(quadfiniteact) with min(...)
4097  */
4098  /* compute rest_i.sup */
4099  if( SCIPintervalGetSup(nlhdlrexprdata->quadactivities[i]) < SCIP_INTERVAL_INFINITY &&
4100  nlhdlrexprdata->nposinfinityquadact == 0 )
4101  {
4102  SCIP_ROUNDMODE roundmode;
4103 
4104  roundmode = SCIPintervalGetRoundingMode();
4106  rest_i.sup = nlhdlrexprdata->maxquadfiniteact - SCIPintervalGetSup(nlhdlrexprdata->quadactivities[i]);
4107 
4108  SCIPintervalSetRoundingMode(roundmode);
4109  }
4110  else if( SCIPintervalGetSup(nlhdlrexprdata->quadactivities[i]) >= SCIP_INTERVAL_INFINITY &&
4111  nlhdlrexprdata->nposinfinityquadact == 1 )
4112  rest_i.sup = nlhdlrexprdata->maxquadfiniteact;
4113  else
4114  rest_i.sup = SCIP_INTERVAL_INFINITY;
4115 
4116  /* compute rest_i.inf */
4117  if( SCIPintervalGetInf(nlhdlrexprdata->quadactivities[i]) > -SCIP_INTERVAL_INFINITY &&
4118  nlhdlrexprdata->nneginfinityquadact == 0 )
4119  {
4120  SCIP_ROUNDMODE roundmode;
4121 
4122  roundmode = SCIPintervalGetRoundingMode();
4124  rest_i.inf = nlhdlrexprdata->minquadfiniteact - SCIPintervalGetInf(nlhdlrexprdata->quadactivities[i]);
4125 
4126  SCIPintervalSetRoundingMode(roundmode);
4127  }
4128  else if( SCIPintervalGetInf(nlhdlrexprdata->quadactivities[i]) <= -SCIP_INTERVAL_INFINITY &&
4129  nlhdlrexprdata->nneginfinityquadact == 1 )
4130  rest_i.inf = nlhdlrexprdata->minquadfiniteact;
4131  else
4132  rest_i.inf = -SCIP_INTERVAL_INFINITY;
4133 
4134 #ifdef SCIP_DISABLED_CODE /* I (SV) added the following in cons_quadratic to fix/workaround some bug. Maybe we'll need this here, too? */
4135  /* FIXME in theory, rest_i should not be empty here
4136  * what we tried to do here is to remove the contribution of the i'th bilinear term (=bilinterm) to [minquadactivity,maxquadactivity] from rhs
4137  * however, quadactivity is computed differently (as x*(a1*y1+...+an*yn)) than q_i (a*ak*yk) and since interval arithmetics do overestimation,
4138  * it can happen that q_i is actually slightly larger than quadactivity, which results in rest_i being (slightly) empty
4139  * a proper fix could be to compute the quadactivity also as x*a1*y1+...+x*an*yn if sqrcoef=0, but due to taking
4140  * also infinite bounds into account, this complicates the code even further
4141  * instead, I'll just work around this by turning an empty rest_i into a small non-empty one
4142  */
4144  {
4145  assert(SCIPisSumRelEQ(scip, rest_i.inf, rest_i.sup));
4146  SCIPswapReals(&rest_i.inf, &rest_i.sup);
4147  }
4148 #endif
4149  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, rest_i));
4150 
4151  /* compute rhs_i */
4152  SCIPintervalSub(SCIP_INTERVAL_INFINITY, &rhs_i, rhs, rest_i);
4153 
4155  continue;
4156 
4157  /* try to propagate */
4158  if( !isPropagableTerm(expr, i) )
4159  {
4160  assert(lincoef == 0.0);
4161 
4162  if( sqrcoef != 0.0 )
4163  {
4164  assert(sqrexpr != NULL);
4165  assert(nadjbilin == 0);
4166 
4167  /* solve sqrcoef sqrexpr in rhs_i */
4168  SCIP_CALL( propagateBoundsLinExpr(scip, sqrexpr, sqrcoef, rhs_i, infeasible, nreductions) );
4169  }
4170  else
4171  {
4172  /* qexpr only appears in a term of the form qexpr * other_expr (or other_expr * qexpr); we only care about
4173  * getting bounds for the product, thus we will compute these bounds when qexpr appears as qexpr *
4174  * other_expr; note that if it appears as other_expr * qexpr, then when we process other_expr bounds for the
4175  * product will be computed
4176  * TODO: we can actually avoid computing rhs_i in the case that qexpr is not propagable and it appears as
4177  * other_expr * qexpr
4178  */
4179  SCIP_EXPR* expr1;
4180  SCIP_EXPR* prodexpr;
4181  SCIP_Real prodcoef;
4182 
4183  assert(nadjbilin == 1);
4184  SCIPexprGetQuadraticBilinTerm(expr, adjbilin[0], &expr1, NULL, &prodcoef, NULL, &prodexpr);
4185 
4186  if( expr1 == qexpr )
4187  {
4188  /* solve prodcoef prodexpr in rhs_i */
4189  SCIP_CALL( propagateBoundsLinExpr(scip, prodexpr, prodcoef, rhs_i, infeasible, nreductions) );
4190  }
4191  }
4192  }
4193  else
4194  {
4195  SCIP_INTERVAL b;
4196  SCIP_EXPR* expr1 = NULL;
4197  SCIP_EXPR* expr2 = NULL;
4198  SCIP_Real bilincoef = 0.0;
4199  int nbilin = 0;
4200  int pos2 = 0;
4201  int j;
4202 
4203  /* set b to [c_l] */
4204  SCIPintervalSet(&b, lincoef);
4205 
4206  /* add [\sum_{j \in P_l} b_lj expr_j + c_l] into b */
4207  for( j = 0; j < nadjbilin; ++j )
4208  {
4209  SCIP_INTERVAL bterm;
4210  SCIP_INTERVAL expr2bounds;
4211 
4212  SCIPexprGetQuadraticBilinTerm(expr, adjbilin[j], &expr1, &expr2, &bilincoef, &pos2, NULL);
4213 
4214  if( expr1 != qexpr )
4215  continue;
4216 
4217  expr2bounds = SCIPgetExprBoundsNonlinear(scip, expr2);
4218  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, expr2bounds) )
4219  {
4220  *infeasible = TRUE;
4221  break;
4222  }
4223 
4224  /* b += [b_lj * expr_j] for j \in P_l */
4225  SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &bterm, expr2bounds, bilincoef);
4226  SCIPintervalAdd(SCIP_INTERVAL_INFINITY, &b, b, bterm);
4227 
4228  /* remember b_lj and expr_j to propagate them too */
4229  bilinexprs[nbilin] = expr2;
4230  bilincoefs[nbilin] = bilincoef;
4231  nbilin++;
4232  }
4233 
4234  if( !*infeasible )
4235  {
4236  /* solve a_i expr_i^2 + b expr_i in rhs_i */
4237  SCIP_CALL( propagateBoundsQuadExpr(scip, qexpr, sqrcoef, b, rhs_i, infeasible, nreductions) );
4238  }
4239 
4240  if( nbilin > 0 && !*infeasible )
4241  {
4242  /* if 0 is not in [expr_i], then propagate bilincoefs^T bilinexpr in rhs_i/expr_i - a_i expr_i - c_i */
4243  SCIP_INTERVAL bilinrhs;
4244  SCIP_INTERVAL qexprbounds;
4245 
4246  qexprbounds = SCIPgetExprBoundsNonlinear(scip, qexpr);
4247  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, qexprbounds) )
4248  {
4249  *infeasible = TRUE;
4250  }
4251  else
4252  {
4253  /* compute bilinrhs := [rhs_i/expr_i - a_i expr_i] */
4254  computeRangeForBilinearProp(qexprbounds, sqrcoef, rhs_i, &bilinrhs);
4255 
4257  {
4258  int nreds;
4259 
4260  /* propagate \sum_{j \in P_i} b_ij expr_j + c_i in bilinrhs */
4261  SCIP_CALL( reversePropagateLinearExpr(scip, bilinexprs, nbilin, bilincoefs, lincoef, bilinrhs,
4262  infeasible, &nreds) );
4263 
4264  /* TODO FIXME: we are overestimating the number of reductions: an expr might be tightened many times! */
4265  *nreductions += nreds;
4266  }
4267  }
4268  }
4269  }
4270 
4271  /* stop if we find infeasibility */
4272  if( *infeasible )
4273  break;
4274  }
4275 
4276  SCIPfreeBufferArray(scip, &bilincoefs);
4277  SCIPfreeBufferArray(scip, &bilinexprs);
4278 
4279  return SCIP_OKAY;
4280 }
4281 
4282 /** callback to free data of handler */
4283 static
4284 SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataQuadratic)
4285 { /*lint --e{715}*/
4286  assert(nlhdlrdata != NULL);
4287 
4288  SCIPfreeBlockMemory(scip, nlhdlrdata);
4289 
4290  return SCIP_OKAY;
4291 }
4292 
4293 /** nonlinear handler copy callback */
4294 static
4295 SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrQuadratic)
4296 { /*lint --e{715}*/
4297  assert(targetscip != NULL);
4298  assert(sourcenlhdlr != NULL);
4299  assert(strcmp(SCIPnlhdlrGetName(sourcenlhdlr), NLHDLR_NAME) == 0);
4300 
4301  SCIP_CALL( SCIPincludeNlhdlrQuadratic(targetscip) );
4302 
4303  return SCIP_OKAY;
4304 }
4305 
4306 /** includes quadratic nonlinear handler in nonlinear constraint handler */
4308  SCIP* scip /**< SCIP data structure */
4309  )
4310 {
4311  SCIP_NLHDLRDATA* nlhdlrdata;
4312  SCIP_NLHDLR* nlhdlr;
4313 
4314  assert(scip != NULL);
4315 
4316  /* create nonlinear handler specific data */
4317  SCIP_CALL( SCIPallocBlockMemory(scip, &nlhdlrdata) );
4318  BMSclearMemory(nlhdlrdata);
4319 
4321  NLHDLR_ENFOPRIORITY, nlhdlrDetectQuadratic, nlhdlrEvalauxQuadratic, nlhdlrdata) );
4322 
4323  SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrQuadratic);
4324  SCIPnlhdlrSetFreeHdlrData(nlhdlr, nlhdlrFreehdlrdataQuadratic);
4325  SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrFreeexprdataQuadratic);
4326  SCIPnlhdlrSetSepa(nlhdlr, NULL, nlhdlrEnfoQuadratic, NULL, NULL);
4327  SCIPnlhdlrSetProp(nlhdlr, nlhdlrIntevalQuadratic, nlhdlrReversepropQuadratic);
4328 
4329  /* parameters */
4330  SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/useintersectioncuts",
4331  "whether to use intersection cuts for quadratic constraints to separate",
4332  &nlhdlrdata->useintersectioncuts, FALSE, DEFAULT_USEINTERCUTS, NULL, NULL) );
4333 
4334  SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/usestrengthening",
4335  "whether the strengthening should be used",
4336  &nlhdlrdata->usestrengthening, FALSE, DEFAULT_USESTRENGTH, NULL, NULL) );
4337 
4338  SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/useboundsasrays",
4339  "use bounds of variables in quadratic as rays for intersection cuts",
4340  &nlhdlrdata->useboundsasrays, FALSE, DEFAULT_USEBOUNDS, NULL, NULL) );
4341 
4342  SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/ncutslimit",
4343  "limit for number of cuts generated consecutively",
4344  &nlhdlrdata->ncutslimit, FALSE, DEFAULT_NCUTS, 0, INT_MAX, NULL, NULL) );
4345 
4346  SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/ncutslimitroot",
4347  "limit for number of cuts generated at root node",
4348  &nlhdlrdata->ncutslimitroot, FALSE, DEFAULT_NCUTSROOT, 0, INT_MAX, NULL, NULL) );
4349 
4350  SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/maxrank",
4351  "maximal rank a slackvar can have",
4352  &nlhdlrdata->maxrank, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
4353 
4354  SCIP_CALL( SCIPaddRealParam(scip, "nlhdlr/" NLHDLR_NAME "/mincutviolation",
4355  "minimal cut violation the generated cuts must fulfill to be added to the LP",
4356  &nlhdlrdata->mincutviolation, FALSE, 1e-4, 0.0, SCIPinfinity(scip), NULL, NULL) );
4357 
4358  SCIP_CALL( SCIPaddRealParam(scip, "nlhdlr/" NLHDLR_NAME "/minviolation",
4359  "minimal violation the constraint must fulfill such that a cut is generated",
4360  &nlhdlrdata->mincutviolation, FALSE, INTERCUTS_MINVIOL, 0.0, SCIPinfinity(scip), NULL, NULL) );
4361 
4362  SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/atwhichnodes",
4363  "determines at which nodes cut is used (if it's -1, it's used only at the root node, if it's n >= 0, it's used at every multiple of n",
4364  &nlhdlrdata->atwhichnodes, FALSE, 1, -1, INT_MAX, NULL, NULL) );
4365 
4366  SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/nstrengthlimit",
4367  "limit for number of rays we do the strengthening for",
4368  &nlhdlrdata->nstrengthlimit, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
4369 
4370  SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/ignorebadrayrestriction",
4371  "should cut be generated even with bad numerics when restricting to ray?",
4372  &nlhdlrdata->ignorebadrayrestriction, FALSE, TRUE, NULL, NULL) );
4373 
4374  SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/ignorenhighre",
4375  "should cut be added even when range / efficacy is large?",
4376  &nlhdlrdata->ignorehighre, FALSE, TRUE, NULL, NULL) );
4377 
4378  /* statistic table */
4379  assert(SCIPfindTable(scip, TABLE_NAME_QUADRATIC) == NULL);
4381  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputQuadratic,
4383  return SCIP_OKAY;
4384 }
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
static SCIP_Bool areCoefsNumericsGood(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_Real *coefs1234a, SCIP_Real *coefs4b, SCIP_Bool iscase4)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:101
SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
Definition: scip_lp.c:596
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE insertRayEntry(SCIP *scip, RAYS *rays, SCIP_Real coef, int coefidx, int coefpos)
void SCIPexprGetQuadraticData(SCIP_EXPR *expr, SCIP_Real *constant, int *nlinexprs, SCIP_EXPR ***linexprs, SCIP_Real **lincoefs, int *nquadexprs, int *nbilinexprs, SCIP_Real **eigenvalues, SCIP_Real **eigenvectors)
Definition: expr.c:4057
static SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeexprdataQuadratic)
SCIP_RETCODE SCIPgetLPBInvRow(SCIP *scip, int r, SCIP_Real *coefs, int *inds, int *ninds)
Definition: scip_lp.c:705
SCIP_Real SCIPfeastol(SCIP *scip)
int SCIP_ROUNDMODE
Definition: intervalarith.h:55
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:84
SCIP_RETCODE SCIPincludeTable(SCIP *scip, const char *name, const char *desc, SCIP_Bool active, SCIP_DECL_TABLECOPY((*tablecopy)), SCIP_DECL_TABLEFREE((*tablefree)), SCIP_DECL_TABLEINIT((*tableinit)), SCIP_DECL_TABLEEXIT((*tableexit)), SCIP_DECL_TABLEINITSOL((*tableinitsol)), SCIP_DECL_TABLEEXITSOL((*tableexitsol)), SCIP_DECL_TABLEOUTPUT((*tableoutput)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
Definition: scip_table.c:47
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE generateIntercut(SCIP *scip, SCIP_EXPR *expr, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_ROWPREP *rowprep, SCIP_Bool overestimate, SCIP_Bool *success)
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:82
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:356
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition: scip_expr.c:1476
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPcomputeExprQuadraticCurvature(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPRCURV *curv, SCIP_HASHMAP *assumevarfixed, SCIP_Bool storeeigeninfo)
Definition: scip_expr.c:2549
#define SCIPquadprecSumQD(r, a, b)
Definition: dbldblarith.h:53
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:877
static SCIP_RETCODE insertRayEntries(SCIP *scip, RAYS *rays, SCIP_Real *densetableaucols, int *rayentry2conspos, int raylength, int nray, int conspos, SCIP_Real factor, int *nnonz, SCIP_Bool *success)
static SCIP_RETCODE addRowToCut(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_Real cutcoef, SCIP_ROW *row, SCIP_Bool *success)
#define SCIP_NLHDLR_METHOD_SEPABELOW
Definition: type_nlhdlr.h:42
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3798
static SCIP_DECL_NLHDLRINTEVAL(nlhdlrIntevalQuadratic)
#define SCIP_NLHDLR_METHOD_NONE
Definition: type_nlhdlr.h:41
#define SCIP_MAXSTRLEN
Definition: def.h:293
void SCIPnlhdlrSetFreeExprData(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRFREEEXPRDATA((*freeexprdata)))
Definition: nlhdlr.c:85
SCIP_BASESTAT SCIPcolGetBasisStatus(SCIP_COL *col)
Definition: lp.c:16997
static void combineRays(SCIP_Real *raycoefs1, int *rayidx1, int raynnonz1, SCIP_Real *raycoefs2, int *rayidx2, int raynnonz2, SCIP_Real *newraycoefs, int *newrayidx, int *newraynnonz, SCIP_Real coef1, SCIP_Real coef2)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
static long bound
SCIP_Bool SCIPisSumRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_Real computeMaxBoundaryForBilinearProp(SCIP_Real a, SCIP_Real c, SCIP_Real x1, SCIP_Real x2)
static SCIP_RETCODE rayInRecessionCone(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, RAYS *rays, int j, int i, SCIP_Real sidefactor, SCIP_Bool iscase4, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real wzlp, SCIP_Real kappa, SCIP_Real alpha, SCIP_Bool *inreccone, SCIP_Bool *success)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17966
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
static SCIP_Real computeRoot(SCIP *scip, SCIP_Real *coefs)
SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_TABLE * SCIPfindTable(SCIP *scip, const char *name)
Definition: scip_table.c:85
SCIP_RETCODE SCIPregisterExprUsageNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool useauxvar, SCIP_Bool useactivityforprop, SCIP_Bool useactivityforsepabelow, SCIP_Bool useactivityforsepaabove)
int SCIProwGetNLPNonz(SCIP_ROW *row)
Definition: lp.c:17193
SCIP_RETCODE SCIPcheckExprQuadratic(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool *isquadratic)
Definition: scip_expr.c:2340
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17258
#define FALSE
Definition: def.h:87
void SCIPexprSetCurvature(SCIP_EXPR *expr, SCIP_EXPRCURV curvature)
Definition: expr.c:4006
void SCIPnlhdlrSetFreeHdlrData(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRFREEHDLRDATA((*freehdlrdata)))
Definition: nlhdlr.c:74
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip_copy.c:2591
SCIP_BASESTAT SCIProwGetBasisStatus(SCIP_ROW *row)
Definition: lp.c:17306
static SCIP_Bool raysAreDependent(SCIP *scip, SCIP_Real *raycoefs1, int *rayidx1, int raynnonz1, SCIP_Real *raycoefs2, int *rayidx2, int raynnonz2, SCIP_Real *coef)
static SCIP_Real computeIntersectionPoint(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_Bool iscase4, SCIP_Real *coefs1234a, SCIP_Real *coefs4b, SCIP_Real *coefscondition)
char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:664
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10755
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds)
#define TRUE
Definition: def.h:86
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static SCIP_RETCODE createAndStoreSparseRays(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *auxvar, RAYS **raysptr, SCIP_Bool *success)
SCIP_NLHDLR * SCIPfindNlhdlrNonlinear(SCIP_CONSHDLR *conshdlr, const char *name)
#define DEFAULT_USEINTERCUTS
void SCIPintervalSolveUnivariateQuadExpressionPositiveAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_Real lincoeff, SCIP_Real rhs, SCIP_INTERVAL xbnds)
static SCIP_RETCODE reversePropagateLinearExpr(SCIP *scip, SCIP_EXPR **linexprs, int nlinexprs, SCIP_Real *lincoefs, SCIP_Real constant, SCIP_INTERVAL rhs, SCIP_Bool *infeasible, int *nreductions)
#define DEFAULT_NCUTSROOT
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition: expr.c:3954
static SCIP_DECL_NLHDLRDETECT(nlhdlrDetectQuadratic)
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:10278
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
#define NLHDLR_DESC
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:99
#define QUAD_SCALE(x, a)
Definition: dbldblarith.h:41
static SCIP_RETCODE storeDenseTableauRow(SCIP *scip, SCIP_COL *col, int *basicvarpos2tableaurow, int nbasiccol, int raylength, SCIP_Real *binvrow, SCIP_Real *binvarow, SCIP_Real *tableaurows)
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_Bool isPropagable(SCIP_EXPR *qexpr)
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition: tree.c:7444
static SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxQuadratic)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
#define QUAD_ASSIGN(a, constant)
Definition: dbldblarith.h:42
#define SCIP_NLHDLR_METHOD_ALL
Definition: type_nlhdlr.h:46
SCIP_RETCODE SCIPgetLPColsData(SCIP *scip, SCIP_COL ***cols, int *ncols)
Definition: scip_lp.c:462
variable expression handler
static SCIP_RETCODE computeStrengthenedIntercut(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, RAYS *rays, SCIP_Real sidefactor, SCIP_Bool iscase4, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real wzlp, SCIP_Real kappa, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Bool *success, SCIP_Bool *strengthsuccess)
SCIP_Bool SCIPexprAreQuadraticExprsVariables(SCIP_EXPR *expr)
Definition: expr.c:4185
static SCIP_Real computeWRayLinear(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Real sidefactor, SCIP_Real *raycoefs, int *rayidx, int raynnonz)
#define SCIPdebugMsg
Definition: scip_message.h:69
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:74
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
#define QUAD_TO_DBL(x)
Definition: dbldblarith.h:40
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1907
#define INTERCUTS_MINVIOL
static SCIP_DECL_NLHDLRREVERSEPROP(nlhdlrReversepropQuadratic)
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
static SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrQuadratic)
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7434
static void freeRays(SCIP *scip, RAYS **rays)
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip_lp.c:658
SCIP_Real inf
Definition: intervalarith.h:46
#define TABLE_DESC_QUADRATIC
#define TABLE_EARLIEST_STAGE_QUADRATIC
static void doBinarySearch(SCIP *scip, SCIP_Real a, SCIP_Real b, SCIP_Real c, SCIP_Real d, SCIP_Real e, SCIP_Real *sol)
SCIP_Real SCIPcolGetPrimsol(SCIP_COL *col)
Definition: lp.c:16962
SCIP_Longint SCIPexprGetActivityTag(SCIP_EXPR *expr)
Definition: expr.c:3970
int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:604
SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
Definition: expr.c:3872
static SCIP_RETCODE addColToCut(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real cutcoef, SCIP_COL *col)
SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1889
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:141
#define SCIPallocBuffer(scip, ptr)
Definition: scip_mem.h:113
SCIP_RETCODE SCIPincludeNlhdlrNonlinear(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
SCIP_RETCODE SCIPincludeNlhdlrQuadratic(SCIP *scip)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:128
SCIP_RETCODE SCIPprintTransSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:1848
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
void SCIProwprepSetSidetype(SCIP_ROWPREP *rowprep, SCIP_SIDETYPE sidetype)
Definition: misc_rowprep.c:737
#define QUAD(x)
Definition: dbldblarith.h:38
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17251
void SCIPintervalSquareRoot(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
void SCIPexprGetQuadraticQuadTerm(SCIP_EXPR *quadexpr, int termidx, SCIP_EXPR **expr, SCIP_Real *lincoef, SCIP_Real *sqrcoef, int *nadjbilin, int **adjbilin, SCIP_EXPR **sqrexpr)
Definition: expr.c:4104
#define NULL
Definition: lpi_spx1.cpp:155
SCIP_Real SCIPintervalQuadUpperBound(SCIP_Real infinity, SCIP_Real a, SCIP_INTERVAL b_, SCIP_INTERVAL x)
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
static SCIP_RETCODE computeIntercut(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, RAYS *rays, SCIP_Real sidefactor, SCIP_Bool iscase4, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real wzlp, SCIP_Real kappa, SCIP_ROWPREP *rowprep, SCIP_Real *interpoints, SCIP_SOL *sol, SCIP_Bool *success)
#define INTERLOG(x)
power and signed power expression handlers
#define REALABS(x)
Definition: def.h:201
int SCIPintervalPropagateWeightedSum(SCIP_Real infinity, int noperands, SCIP_INTERVAL *operands, SCIP_Real *weights, SCIP_Real constant, SCIP_INTERVAL rhs, SCIP_INTERVAL *resultants, SCIP_Bool *infeasible)
#define TABLE_NAME_QUADRATIC
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:617
static SCIP_RETCODE constructBasicVars2TableauRowMap(SCIP *scip, int *map)
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1443
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
Definition: misc_rowprep.c:558
#define SCIP_CALL(x)
Definition: def.h:384
void SCIProwprepAddSide(SCIP_ROWPREP *rowprep, SCIP_Real side)
Definition: misc_rowprep.c:714
SCIP_Real sup
Definition: intervalarith.h:47
#define NLHDLR_ENFOPRIORITY
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17268
static SCIP_RETCODE findVertexAndGetRays(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_SOL *sol, SCIP_SOL *vertex, SCIP_VAR *auxvar, RAYS **raysptr, SCIP_Bool *success)
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:241
static SCIP_Bool isPropagableTerm(SCIP_EXPR *qexpr, int idx)
#define SCIPquadprecProdDD(r, a, b)
Definition: dbldblarith.h:49
#define SCIP_INTERVAL_INFINITY
Definition: def.h:199
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17204
static SCIP_RETCODE createRays(SCIP *scip, RAYS **rays)
#define SCIPquadprecSqrtQ(r, a)
Definition: dbldblarith.h:62
SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
void SCIPnlhdlrSetSepa(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINITSEPA((*initsepa)), SCIP_DECL_NLHDLRENFO((*enfo)), SCIP_DECL_NLHDLRESTIMATE((*estimate)), SCIP_DECL_NLHDLREXITSEPA((*exitsepa)))
Definition: nlhdlr.c:123
SCIP_RETCODE SCIPprintExprQuadratic(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:2433
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1212
SCIP_RETCODE SCIPgetLPBInvARow(SCIP *scip, int r, SCIP_Real *binvrow, SCIP_Real *coefs, int *inds, int *ninds)
Definition: scip_lp.c:776
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17214
void SCIPintervalSetRoundingModeDownwards(void)
#define SCIP_Bool
Definition: def.h:84
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:159
void SCIProwprepAddConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
Definition: misc_rowprep.c:728
static SCIP_RETCODE propagateBoundsQuadExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_Real sqrcoef, SCIP_INTERVAL b, SCIP_INTERVAL rhs, SCIP_Bool *infeasible, int *nreductions)
static SCIP_RETCODE findRho(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, RAYS *rays, int idx, SCIP_Real sidefactor, SCIP_Bool iscase4, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real wzlp, SCIP_Real kappa, SCIP_Real *interpoints, SCIP_Real *rho, SCIP_Bool *success)
SCIP_EXPRCURV
Definition: type_expr.h:48
constraint handler for nonlinear constraints specified by algebraic expressions
void SCIPmergeRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2473
#define SCIPquadprecSquareD(r, a)
Definition: dbldblarith.h:50
#define MAX(x, y)
Definition: tclique_def.h:83
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:85
SCIP_Real SCIPnextafter(SCIP_Real from, SCIP_Real to)
Definition: misc.c:9265
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:976
void SCIPnlhdlrSetProp(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINTEVAL((*inteval)), SCIP_DECL_NLHDLRREVERSEPROP((*reverseprop)))
Definition: nlhdlr.c:110
#define DEFAULT_USESTRENGTH
#define SCIPquadprecProdQD(r, a, b)
Definition: dbldblarith.h:54
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:17621
SCIP_RETCODE SCIPgetLPBasisInd(SCIP *scip, int *basisind)
Definition: scip_lp.c:677
SCIP_COL ** SCIPgetLPCols(SCIP *scip)
Definition: scip_lp.c:497
static SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataQuadratic)
static SCIP_RETCODE intercutsComputeCommonQuantities(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *auxvar, SCIP_Real sidefactor, SCIP_SOL *sol, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real *wzlp, SCIP_Real *kappa)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
#define BMSclearMemory(ptr)
Definition: memory.h:122
static void computeRangeForBilinearProp(SCIP_INTERVAL exprdom, SCIP_Real coef, SCIP_INTERVAL rhs, SCIP_INTERVAL *range)
static SCIP_RETCODE setVarToNearestBound(SCIP *scip, SCIP_SOL *sol, SCIP_SOL *vertex, SCIP_VAR *var, SCIP_Real *factor, SCIP_Bool *success)
#define SCIPquadprecSumQQ(r, a, b)
Definition: dbldblarith.h:58
SCIP_RETCODE SCIPtightenExprIntervalNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_INTERVAL newbounds, SCIP_Bool *cutoff, int *ntightenings)
static SCIP_DECL_TABLEOUTPUT(tableOutputQuadratic)
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1991
product expression handler
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition: lp.c:17224
SCIP_VAR ** b
Definition: circlepacking.c:56
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1553
#define SCIPfreeBuffer(scip, ptr)
Definition: scip_mem.h:125
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:17008
SCIP_Real SCIProwprepGetSide(SCIP_ROWPREP *rowprep)
Definition: misc_rowprep.c:634
static SCIP_Bool isQuadConsViolated(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *auxvar, SCIP_SOL *sol, SCIP_Real sidefactor)
SCIP_Longint SCIPgetCurBoundsTagNonlinear(SCIP_CONSHDLR *conshdlr)
#define SCIP_NLHDLR_METHOD_ACTIVITY
Definition: type_nlhdlr.h:45
void SCIPintervalSetRoundingModeUpwards(void)
int * lpposray
SCIP_VAR * a
Definition: circlepacking.c:57
static SCIP_RETCODE storeDenseTableauRowsByColumns(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, int raylength, SCIP_VAR *auxvar, SCIP_Real *tableaurows, int *rayentry2conspos)
void SCIPexprGetQuadraticBilinTerm(SCIP_EXPR *expr, int termidx, SCIP_EXPR **expr1, SCIP_EXPR **expr2, SCIP_Real *coef, int *pos2, SCIP_EXPR **prodexpr)
Definition: expr.c:4147
SCIP_Real * rays
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:17467
#define NLHDLR_NAME
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
#define SCIP_Real
Definition: def.h:177
static SCIP_Real evalPhiAtRay(SCIP_Real t, SCIP_Real a, SCIP_Real b, SCIP_Real c, SCIP_Real d, SCIP_Real e)
static SCIP_Real computeEigenvecDotRay(SCIP_Real *eigenvec, int nquadvars, SCIP_Real *raycoefs, int *rayidx, int raynnonz)
static SCIP_DECL_NLHDLRENFO(nlhdlrEnfoQuadratic)
#define NLHDLR_DETECTPRIORITY
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2197
static SCIP_Real computeMaxForBilinearProp(SCIP_Real a, SCIP_Real c, SCIP_INTERVAL dom)
SCIP_NLHDLRDATA * SCIPnlhdlrGetData(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:191
#define SCIP_Longint
Definition: def.h:162
#define TABLE_POSITION_QUADRATIC
static SCIP_RETCODE computeRestrictionToRay(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Real sidefactor, SCIP_Bool iscase4, SCIP_Real *raycoefs, int *rayidx, int raynnonz, SCIP_Real *vb, SCIP_Real *vzlp, SCIP_Real *wcoefs, SCIP_Real wzlp, SCIP_Real kappa, SCIP_Real *coefs1234a, SCIP_Real *coefs4b, SCIP_Real *coefscondition, SCIP_Bool *success)
struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
Definition: type_nlhdlr.h:404
int * raysidx
SCIP_RETCODE SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
Definition: misc_rowprep.c:538
struct SCIP_NlhdlrData SCIP_NLHDLRDATA
Definition: type_nlhdlr.h:403
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
sum expression handler
int rayssize
int SCIPgetNLPCols(SCIP *scip)
Definition: scip_lp.c:518
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17976
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
Definition: misc_rowprep.c:881
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real minviol, SCIP_Real *viol, SCIP_Bool *success)
SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:123
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:561
static void constructLPPos2ConsPosMap(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *auxvar, int *map)
static SCIP_RETCODE createBoundRays(SCIP *scip, RAYS **rays, int size)
#define BINSEARCH_MAXITERS
#define SCIPallocClearBlockMemory(scip, ptr)
Definition: scip_mem.h:82
SCIPallocBlockMemory(scip, subsol))
static int countBasicVars(SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_VAR *auxvar, SCIP_Bool *nozerostat)
public functions of nonlinear handlers of nonlinear constraints
#define DEFAULT_USEBOUNDS
SCIP_Longint SCIPgetNLPs(SCIP *scip)
SCIP_INTERVAL SCIPgetExprBoundsNonlinear(SCIP *scip, SCIP_EXPR *expr)
int SCIPcolGetLPPos(SCIP_COL *col)
Definition: lp.c:17059
SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
#define SCIP_NLHDLR_METHOD_SEPABOTH
Definition: type_nlhdlr.h:44
nonlinear handler to handle quadratic expressions
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1352
static SCIP_Real isCase4a(SCIP_Real tsol, SCIP_Real *coefs4a, SCIP_Real *coefscondition)
#define SCIP_NLHDLR_METHOD_SEPAABOVE
Definition: type_nlhdlr.h:43
static SCIP_RETCODE propagateBoundsLinExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_Real b, SCIP_INTERVAL rhs, SCIP_Bool *infeasible, int *nreductions)
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:130
preparation of a linear inequality to become a SCIP_ROW
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:48
#define DEFAULT_NCUTS
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2089
int * raysbegin
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:319
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:119
void SCIPnlhdlrSetCopyHdlr(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRCOPYHDLR((*copy)))
Definition: nlhdlr.c:63