Scippy

SCIP

Solving Constraint Integer Programs

nlhdlr_soc.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 email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file nlhdlr_soc.c
17  * @ingroup DEFPLUGINS_NLHDLR
18  * @brief nonlinear handler for second order cone constraints
19 
20  * @author Benjamin Mueller
21  * @author Felipe Serrano
22  * @author Fabian Wegscheider
23  *
24  * This is a nonlinear handler for second order cone constraints of the form
25  *
26  * \f[\sqrt{\sum_{i=1}^{n} (v_i^T x + \beta_i)^2} \leq v_{n+1}^T x + \beta_{n+1}.\f]
27  *
28  * Note that \f$v_i\f$, for \f$i \leq n\f$, could be 0, thus allowing a positive constant term inside the root.
29  *
30  * @todo test if it makes sense to only disaggregate when nterms > some parameter
31  *
32  */
33 
34 #include <string.h>
35 
36 #include "scip/nlhdlr_soc.h"
37 #include "scip/cons_nonlinear.h"
38 #include "scip/expr_pow.h"
39 #include "scip/expr_sum.h"
40 #include "scip/expr_var.h"
41 #include "scip/debug.h"
42 #include "scip/pub_nlhdlr.h"
43 #include "scip/nlpi_ipopt.h"
44 
45 
46 /* fundamental nonlinear handler properties */
47 #define NLHDLR_NAME "soc"
48 #define NLHDLR_DESC "nonlinear handler for second-order cone structures"
49 #define NLHDLR_DETECTPRIORITY 100 /**< priority of the nonlinear handler for detection */
50 #define NLHDLR_ENFOPRIORITY 100 /**< priority of the nonlinear handler for enforcement */
51 #define DEFAULT_MINCUTEFFICACY 1e-5 /**< default value for parameter mincutefficacy */
52 #define DEFAULT_COMPEIGENVALUES TRUE /**< default value for parameter compeigenvalues */
53 
54 /*
55  * Data structures
56  */
57 
58 /** nonlinear handler expression data. The data is structured in the following way:
59  *
60  * A 'term' is one of the arguments of the quadratic terms, i.e. \f$v_i^T x + beta_i\f$.
61  * The last term is always the one on the right-hand side. This means that nterms is
62  * equal to n+1 in the above description.
63  *
64  * - vars contains a list of all expressions which are treated as variables (no duplicates)
65  * - offsets contains the constants beta_i of each term
66  * - transcoefs contains the non-zero values of the transformation vectors v_i of each term
67  * - transcoefsidx contains for each entry of transcoefs the position of the respective variable in vars
68  * - termbegins contains the index at which the transcoefs of each term start, with a sentinel value
69  * - nterms is the total number of terms appearing on both sides
70  * - nvars is the total number of unique variables appearing (length of vars)
71  *
72  * Note that the numbers of nonzeroes in v_i is termbegins[i+1] - termbegins[i] and that
73  * the total number of entries in transcoefs and transcoefsidx is termbegins[nterms]
74  *
75  * The disaggregation is implicitly stored in the variables disvars and disrow. An SOC as
76  * described above is replaced by n smaller SOCs
77  *
78  * (v_i^T x + beta_i)^2 <= disvar_i * (v_{n+1}^T x + beta_{n+1})
79  *
80  * and the row sum_i disvar_i <= v_{n+1}^T x + beta_{n+1}.
81  *
82  * The disaggregation only happens if we have more than 3 terms.
83  *
84  * Example: The constraint SQRT(5 + (3x - 4y + 2)^2 + y^2 + 7z^2) <= 5x - y - 1
85  * results in the following nlhdlrexprdata:
86  *
87  * vars = {x, y, z}
88  * offsets = {2, 0, 0, SQRT(5), -1}
89  * transcoefs = {3, -4, 1, SQRT(7), 5, -1}
90  * transcoefsidx = {0, 1, 1, 2, 0, 1}
91  * termbegins = {0, 2, 3, 4, 4, 6}
92  * nvars = 3
93  * nterms = 5
94  *
95  * @note: due to the current implementation, the constant term is the second to last term, except when the SOC was a rotated
96  * SOC, e.g., 1 + x^2 - y*z, i.e., when detected by detectSocQuadraticSimple. In that case, the constant is third to
97  * last term.
98  */
99 struct SCIP_NlhdlrExprData
100 {
101  SCIP_EXPR** vars; /**< expressions which (aux)variables appear on both sides (x) */
102  SCIP_Real* offsets; /**< offsets of both sides (beta_i) */
103  SCIP_Real* transcoefs; /**< non-zeros of linear transformation vectors (v_i) */
104  int* transcoefsidx; /**< mapping of transformation coefficients to variable indices in vars */
105  int* termbegins; /**< starting indices of transcoefs for each term */
106  int nvars; /**< total number of variables appearing */
107  int nterms; /**< number of summands in the SQRT +1 for RHS (n+1) */
108 
109  /* variables for cone disaggregation */
110  SCIP_VAR** disvars; /**< disaggregation variables for each term in lhs */
111  SCIP_ROW* disrow; /**< disaggregation row */
112 };
113 
114 struct SCIP_NlhdlrData
115 {
116  SCIP_Real mincutefficacy; /**< minimum efficacy a cut need to be added */
117  SCIP_Bool compeigenvalues; /**< whether Eigenvalue computations should be done to detect complex cases */
118 };
119 
120 /*
121  * Local methods
122  */
123 
124 #ifdef SCIP_DEBUG
125 /** prints the nlhdlr expression data */
126 static
127 void printNlhdlrExprData(
128  SCIP* scip, /**< SCIP data structure */
129  SCIP_NLHDLREXPRDATA* nlhdlrexprdata /**< pointer to store nonlinear handler expression data */
130  )
131 {
132  int nterms;
133  int i;
134  int j;
135 
136  nterms = nlhdlrexprdata->nterms;
137 
138  SCIPinfoMessage(scip, NULL, "SQRT( ");
139 
140  for( i = 0; i < nterms - 1; ++i )
141  {
142  int startidx;
143 
144  startidx = nlhdlrexprdata->termbegins[i];
145 
146  /* v_i is 0 */
147  if( startidx == nlhdlrexprdata->termbegins[i + 1] )
148  {
149  assert(nlhdlrexprdata->offsets[i] != 0.0);
150 
151  SCIPinfoMessage(scip, NULL, "%f", SQR(nlhdlrexprdata->offsets[i]));
152  continue;
153  }
154 
155  /* v_i is not 0 */
156  SCIPinfoMessage(scip, NULL, "(");
157 
158  for( j = startidx; j < nlhdlrexprdata->termbegins[i + 1]; ++j )
159  {
160  if( nlhdlrexprdata->transcoefs[j] != 1.0 )
161  SCIPinfoMessage(scip, NULL, "%f*", nlhdlrexprdata->transcoefs[j]);
162  if( SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[j]]) != NULL )
163  {
164  SCIPinfoMessage(scip, NULL, "%s", SCIPvarGetName(SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[j]])));
165  SCIPinfoMessage(scip, NULL, "(%p)", (void*)nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[j]]);
166  }
167  else
168  SCIPinfoMessage(scip, NULL, "%p", (void*)nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[j]]);
169 
170  if( j < nlhdlrexprdata->termbegins[i + 1] - 1 )
171  SCIPinfoMessage(scip, NULL, " + ");
172  else if( nlhdlrexprdata->offsets[i] != 0.0 )
173  SCIPinfoMessage(scip, NULL, " + %f", nlhdlrexprdata->offsets[i]);
174  }
175 
176  SCIPinfoMessage(scip, NULL, ")^2");
177 
178  if( i < nterms - 2 )
179  SCIPinfoMessage(scip, NULL, " + ");
180  }
181 
182  SCIPinfoMessage(scip, NULL, " ) <= ");
183 
184  for( j = nlhdlrexprdata->termbegins[nterms-1]; j < nlhdlrexprdata->termbegins[nterms]; ++j )
185  {
186  if( nlhdlrexprdata->transcoefs[j] != 1.0 )
187  SCIPinfoMessage(scip, NULL, "%f*", nlhdlrexprdata->transcoefs[j]);
188  if( SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[j]]) != NULL )
189  SCIPinfoMessage(scip, NULL, "%s", SCIPvarGetName(SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[j]])));
190  else
191  SCIPinfoMessage(scip, NULL, "%p", (void*)nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[j]]);
192 
193  if( j < nlhdlrexprdata->termbegins[nterms] - 1 )
194  SCIPinfoMessage(scip, NULL, " + ");
195  else if( nlhdlrexprdata->offsets[nterms-1] != 0.0 )
196  SCIPinfoMessage(scip, NULL, " + %f", nlhdlrexprdata->offsets[nterms-1]);
197  }
198 
199  SCIPinfoMessage(scip, NULL, "\n");
200 }
201 #endif
202 
203 /** helper method to create variables for the cone disaggregation */
204 static
206  SCIP* scip, /**< SCIP data structure */
207  SCIP_EXPR* expr, /**< expression */
208  SCIP_NLHDLREXPRDATA* nlhdlrexprdata /**< nonlinear handler expression data */
209  )
210 {
211  char name[SCIP_MAXSTRLEN];
212  int ndisvars;
213  int i;
214 
215  assert(nlhdlrexprdata != NULL);
216 
217  ndisvars = nlhdlrexprdata->nterms - 1;
218 
219  /* allocate memory */
220  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &nlhdlrexprdata->disvars, ndisvars) );
221 
222  /* create disaggregation variables representing the epigraph of (v_i^T x + beta_i)^2 / (v_{n+1}^T x + beta_{n+1}) */
223  for( i = 0; i < ndisvars; ++i )
224  {
225  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "conedis_%p_%d", (void*) expr, i);
226  SCIP_CALL( SCIPcreateVarBasic(scip, &nlhdlrexprdata->disvars[i], name, 0.0, SCIPinfinity(scip), 0.0,
228  SCIPvarMarkRelaxationOnly(nlhdlrexprdata->disvars[i]);
229 
230  SCIP_CALL( SCIPaddVar(scip, nlhdlrexprdata->disvars[i]) );
231  SCIP_CALL( SCIPaddVarLocksType(scip, nlhdlrexprdata->disvars[i], SCIP_LOCKTYPE_MODEL, 1, 1) );
232  }
233 
234  return SCIP_OKAY;
235 }
236 
237 /** helper method to free variables for the cone disaggregation */
238 static
240  SCIP* scip, /**< SCIP data structure */
241  SCIP_NLHDLREXPRDATA* nlhdlrexprdata /**< nonlinear handler expression data */
242  )
243 {
244  int ndisvars;
245  int i;
246 
247  assert(nlhdlrexprdata != NULL);
248 
249  if( nlhdlrexprdata->disvars == NULL )
250  return SCIP_OKAY;
251 
252  ndisvars = nlhdlrexprdata->nterms - 1;
253 
254  /* release variables */
255  for( i = 0; i < ndisvars; ++i )
256  {
257  SCIP_CALL( SCIPaddVarLocksType(scip, nlhdlrexprdata->disvars[i], SCIP_LOCKTYPE_MODEL, -1, -1) );
258  SCIP_CALL( SCIPreleaseVar(scip, &nlhdlrexprdata->disvars[i]) );
259  }
260 
261  /* free memory */
262  SCIPfreeBlockMemoryArrayNull(scip, &nlhdlrexprdata->disvars, ndisvars);
263 
264  return SCIP_OKAY;
265 }
266 
267 /** helper method to create the disaggregation row \f$\text{disvars}_i \leq v_{n+1}^T x + \beta_{n+1}\f$ */
268 static
270  SCIP* scip, /**< SCIP data structure */
271  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
272  SCIP_EXPR* expr, /**< expression */
273  SCIP_NLHDLREXPRDATA* nlhdlrexprdata /**< nonlinear handler expression data */
274  )
275 {
276  SCIP_Real beta;
277  char name[SCIP_MAXSTRLEN];
278  int ndisvars;
279  int nterms;
280  int i;
281 
282  assert(scip != NULL);
283  assert(expr != NULL);
284  assert(nlhdlrexprdata != NULL);
285  assert(nlhdlrexprdata->disrow == NULL);
286 
287  nterms = nlhdlrexprdata->nterms;
288  beta = nlhdlrexprdata->offsets[nterms - 1];
289 
290  ndisvars = nterms - 1;
291 
292  /* create row 0 <= beta_{n+1} */
293  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "conedis_%p_row", (void*) expr);
294  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &nlhdlrexprdata->disrow, conshdlr, name,
295  -SCIPinfinity(scip), beta, FALSE, FALSE, TRUE) );
296 
297  /* add disvars to row */
298  for( i = 0; i < ndisvars; ++i )
299  {
300  SCIP_CALL( SCIPaddVarToRow(scip, nlhdlrexprdata->disrow, nlhdlrexprdata->disvars[i], 1.0) );
301  }
302 
303  /* add rhs vars to row */
304  for( i = nlhdlrexprdata->termbegins[nterms - 1]; i < nlhdlrexprdata->termbegins[nterms]; ++i )
305  {
306  SCIP_VAR* var;
307  SCIP_Real coef;
308 
309  var = SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[i]]);
310  assert(var != NULL);
311 
312  coef = -nlhdlrexprdata->transcoefs[i];
313 
314  SCIP_CALL( SCIPaddVarToRow(scip, nlhdlrexprdata->disrow, var, coef) );
315  }
316 
317  return SCIP_OKAY;
318 }
319 
320 /** helper method to create nonlinear handler expression data */
321 static
323  SCIP* scip, /**< SCIP data structure */
324  SCIP_EXPR** vars, /**< expressions which variables appear on both sides (\f$x\f$) */
325  SCIP_Real* offsets, /**< offsets of bot sides (\f$beta_i\f$) */
326  SCIP_Real* transcoefs, /**< non-zeroes of linear transformation vectors (\f$v_i\f$) */
327  int* transcoefsidx, /**< mapping of transformation coefficients to variable indices in vars */
328  int* termbegins, /**< starting indices of transcoefs for each term */
329  int nvars, /**< total number of variables appearing */
330  int nterms, /**< number of summands in the SQRT, +1 for RHS */
331  SCIP_NLHDLREXPRDATA** nlhdlrexprdata /**< pointer to store nonlinear handler expression data */
332  )
333 {
334  int ntranscoefs;
335 
336  assert(vars != NULL);
337  assert(offsets != NULL);
338  assert(transcoefs != NULL);
339  assert(transcoefsidx != NULL);
340  assert(termbegins != NULL);
341  assert(nlhdlrexprdata != NULL);
342 
343  ntranscoefs = termbegins[nterms];
344 
345  SCIP_CALL( SCIPallocBlockMemory(scip, nlhdlrexprdata) );
346  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*nlhdlrexprdata)->vars, vars, nvars) );
347  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*nlhdlrexprdata)->offsets, offsets, nterms) );
348  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*nlhdlrexprdata)->transcoefs, transcoefs, ntranscoefs) );
349  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*nlhdlrexprdata)->transcoefsidx, transcoefsidx, ntranscoefs) );
350  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*nlhdlrexprdata)->termbegins, termbegins, nterms + 1) );
351  (*nlhdlrexprdata)->nvars = nvars;
352  (*nlhdlrexprdata)->nterms = nterms;
353 
354  (*nlhdlrexprdata)->disrow = NULL;
355  (*nlhdlrexprdata)->disvars = NULL;
356 
357 #ifdef SCIP_DEBUG
358  SCIPdebugMsg(scip, "created nlhdlr data for the following soc expression:\n");
359  printNlhdlrExprData(scip, *nlhdlrexprdata);
360  printf("x is %p\n", (void *)vars[0]);
361 #endif
362 
363  return SCIP_OKAY;
364 }
365 
366 /** helper method to free nonlinear handler expression data */
367 static
369  SCIP* scip, /**< SCIP data structure */
370  SCIP_NLHDLREXPRDATA** nlhdlrexprdata /**< pointer to free nonlinear handler expression data */
371  )
372 {
373  int ntranscoefs;
374 
375  assert(nlhdlrexprdata != NULL);
376  assert(*nlhdlrexprdata != NULL);
377 
378  /* free variables and row for cone disaggregation */
379  SCIP_CALL( freeDisaggrVars(scip, *nlhdlrexprdata) );
380 
381  ntranscoefs = (*nlhdlrexprdata)->termbegins[(*nlhdlrexprdata)->nterms];
382 
383  SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->termbegins, (*nlhdlrexprdata)->nterms + 1);
384  SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->transcoefsidx, ntranscoefs);
385  SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->transcoefs, ntranscoefs);
386  SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->offsets, (*nlhdlrexprdata)->nterms);
387  SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->vars, (*nlhdlrexprdata)->nvars);
388  SCIPfreeBlockMemory(scip, nlhdlrexprdata);
389 
390  return SCIP_OKAY;
391 }
392 
393 /** evaluate a single term of the form \f$v_i^T x + \beta_i\f$ */
394 static
396  SCIP* scip, /**< SCIP data structure */
397  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler expression data */
398  SCIP_SOL* sol, /**< solution */
399  int k /**< term to be evaluated */
400  )
401 {
402  SCIP_Real result;
403  int i;
404 
405  assert(scip != NULL);
406  assert(nlhdlrexprdata != NULL);
407  assert(0 <= k && k < nlhdlrexprdata->nterms);
408 
409  result = nlhdlrexprdata->offsets[k];
410 
411  for( i = nlhdlrexprdata->termbegins[k]; i < nlhdlrexprdata->termbegins[k + 1]; ++i )
412  {
413  SCIP_Real varval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[i]]));
414  result += nlhdlrexprdata->transcoefs[i] * varval;
415  }
416 
417  return result;
418 }
419 
420 /** computes gradient cut for a 2D or 3D SOC
421  *
422  * A 3D SOC looks like
423  * \f[
424  * \sqrt{ (v_1^T x + \beta_1)^2 + (v_2^T x + \beta_2)^2 } \leq v_3^T x + \beta_3
425  * \f]
426  *
427  * Let \f$f(x)\f$ be the left-hand-side. The partial derivatives of \f$f\f$ are given by
428  * \f[
429  * \frac{\delta f}{\delta x_j} = \frac{(v_1)_j(v_1^T x + \beta_1) + (v_2)_j (v_2^T x + \beta_2)}{f(x)}
430  * \f]
431  *
432  * and the gradient cut is then \f$f(x^*) + \nabla f(x^*)(x - x^*) \leq v_3^T x + \beta_3\f$.
433  *
434  * A 2D SOC is
435  * \f[
436  * |v_1^T x + \beta_1| \leq v_2^T x + \beta_2
437  * \f]
438  * but we build the cut using the same procedure as for 3D.
439  */
440 static
442  SCIP* scip, /**< SCIP data structure */
443  SCIP_EXPR* expr, /**< expression */
444  SCIP_CONS* cons, /**< the constraint that expr is part of */
445  SCIP_SOL* sol, /**< solution to separate or NULL for the LP solution */
446  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler expression data */
447  SCIP_Real mincutviolation, /**< minimal required cut violation */
448  SCIP_Real rhsval, /**< value of last term at sol */
449  SCIP_ROW** cut /**< pointer to store a cut */
450  )
451 {
452  SCIP_ROWPREP* rowprep;
453  SCIP_Real* transcoefs;
454  SCIP_Real cutcoef;
455  SCIP_Real fvalue;
456  SCIP_Real valterms[2] = {0.0, 0.0}; /* for lint */
457  SCIP_Real cutrhs;
458  SCIP_EXPR** vars;
459  SCIP_VAR* cutvar;
460  int* transcoefsidx;
461  int* termbegins;
462  int nterms;
463  int i;
464  int j;
465 
466  assert(expr != NULL);
467  assert(cons != NULL);
468  assert(nlhdlrexprdata != NULL);
469  assert(mincutviolation >= 0.0);
470  assert(cut != NULL);
471 
472  vars = nlhdlrexprdata->vars;
473  transcoefs = nlhdlrexprdata->transcoefs;
474  transcoefsidx = nlhdlrexprdata->transcoefsidx;
475  termbegins = nlhdlrexprdata->termbegins;
476  nterms = nlhdlrexprdata->nterms;
477 
478  *cut = NULL;
479 
480  /* evaluate lhs terms and compute f(x*) */
481  fvalue = 0.0;
482  for( i = 0; i < nterms - 1; ++i )
483  {
484  valterms[i] = evalSingleTerm(scip, nlhdlrexprdata, sol, i);
485  fvalue += SQR( valterms[i] );
486  }
487  fvalue = SQRT( fvalue );
488 
489  /* don't generate cut if we are not violated @todo: remove this once core detects better when a nlhdlr's cons is
490  * violated
491  */
492  if( fvalue - rhsval <= mincutviolation )
493  {
494  SCIPdebugMsg(scip, "do not generate cut: rhsval %g, fvalue %g violation is %g\n", rhsval, fvalue, fvalue - rhsval);
495  return SCIP_OKAY;
496  }
497 
498  /* if f(x*) = 0 then SOC can't be violated and we shouldn't be here */
499  assert(fvalue > 0.0);
500 
501  /* create cut */
503  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, termbegins[nterms]) );
504 
505  /* cut is f(x*) + \nabla f(x*)^T (x - x*) \leq v_n^T x + \beta_n, i.e.,
506  * \nabla f(x*)^T x - v_n^T x \leq \beta_n + \nabla f(x*)^T x* - f(x*)
507  * thus cutrhs is \beta_n - f(x*) + \nabla f(x*)^T x*
508  */
509  cutrhs = nlhdlrexprdata->offsets[nterms - 1] - fvalue;
510 
511  /* add cut coefficients from lhs terms and compute cut's rhs */
512  for( j = 0; j < nterms - 1; ++j )
513  {
514  for( i = termbegins[j]; i < termbegins[j + 1]; ++i )
515  {
516  cutvar = SCIPgetExprAuxVarNonlinear(vars[transcoefsidx[i]]);
517 
518  /* cutcoef is (the first part of) the partial derivative w.r.t cutvar */
519  cutcoef = transcoefs[i] * valterms[j] / fvalue;
520 
521  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, cutvar, cutcoef) );
522 
523  cutrhs += cutcoef * SCIPgetSolVal(scip, sol, cutvar);
524  }
525  }
526 
527  /* add terms for v_n */
528  for( i = termbegins[nterms - 1]; i < termbegins[nterms]; ++i )
529  {
530  cutvar = SCIPgetExprAuxVarNonlinear(vars[transcoefsidx[i]]);
531  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, cutvar, -transcoefs[i]) );
532  }
533 
534  /* add side */
535  SCIProwprepAddSide(rowprep, cutrhs);
536 
537  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, SCIPinfinity(scip), NULL) );
538 
539  if( SCIPgetRowprepViolation(scip, rowprep, sol, NULL) >= mincutviolation )
540  {
541  (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "soc%d_%p_%d", nterms, (void*) expr, SCIPgetNLPs(scip));
542  SCIP_CALL( SCIPgetRowprepRowCons(scip, cut, rowprep, cons) );
543  }
544  else
545  {
546  SCIPdebugMsg(scip, "%d-SOC rowprep violation %g below mincutviolation %g\n", nterms, SCIPgetRowprepViolation(scip,
547  rowprep, sol, NULL), mincutviolation);
548  /* SCIPprintRowprep(scip, rowprep, NULL); */
549  }
550 
551  /* free memory */
552  SCIPfreeRowprep(scip, &rowprep);
553 
554  return SCIP_OKAY;
555 }
556 
557 /** helper method to compute and add a gradient cut for the k-th cone disaggregation
558  *
559  * After the SOC constraint \f$\sqrt{\sum_{i = 0}^{n-1} (v_i^T x + \beta_i)^2} \leq v_n^T x + \beta_n\f$
560  * has been disaggregated into the row \f$\sum_{i = 0}^{n-1} y_i \leq v_n^T x + \beta_n\f$ and the smaller SOC constraints
561  * \f[
562  * (v_i^T x + \beta_i)^2 \leq (v_n^T x + \beta_n) y_i \text{ for } i \in \{0, \ldots, n -1\},
563  * \f]
564  * we want to separate one of the small rotated cones.
565  * We first transform it into standard form:
566  * \f[
567  * \sqrt{4(v_i^T x + \beta_i)^2 + (v_n^T x + \beta_n - y_i)^2} - v_n^T x - \beta_n - y_i \leq 0.
568  * \f]
569  * Let \f$f(x,y)\f$ be the left-hand-side. We now compute the gradient by
570  * \f{align*}{
571  * \frac{\delta f}{\delta x_j} &= \frac{(v_i)_j(4v_i^T x + 4\beta_i) + (v_n)_j(v_n^T x + \beta_n - y_i)}{\sqrt{4(v_i^T x + \beta_i)^2 + (v_n^T x + \beta_n - y_i)^2}} - (v_n)_j \\
572  * \frac{\delta f}{\delta y_i} &= \frac{y_i - v_n^T x -\beta_n}{\sqrt{4(v_i^T x + \beta_i)^2 + (v_n^T x + \beta_n - y_i)^2}} - 1
573  * \f}
574  * and the gradient cut is then \f$f(x^*, y^*) + \nabla f(x^*,y^*)((x,y) - (x^*, y^*)) \leq 0\f$.
575  */
576 static
578  SCIP* scip, /**< SCIP data structure */
579  SCIP_EXPR* expr, /**< expression */
580  SCIP_CONS* cons, /**< the constraint that expr is part of */
581  SCIP_SOL* sol, /**< solution to separate or NULL for the LP solution */
582  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler expression data */
583  int disaggidx, /**< index of disaggregation to separate */
584  SCIP_Real mincutviolation, /**< minimal required cut violation */
585  SCIP_Real rhsval, /**< value of the rhs term */
586  SCIP_ROW** cut /**< pointer to store a cut */
587  )
588 {
589  SCIP_EXPR** vars;
590  SCIP_VAR** disvars;
591  SCIP_Real* transcoefs;
592  int* transcoefsidx;
593  int* termbegins;
594  SCIP_ROWPREP* rowprep;
595  SCIP_VAR* cutvar;
596  SCIP_Real cutcoef;
597  SCIP_Real fvalue;
598  SCIP_Real disvarval;
599  SCIP_Real lhsval;
600  SCIP_Real constant;
601  SCIP_Real denominator;
602  int ncutvars;
603  int nterms;
604  int i;
605 
606  assert(expr != NULL);
607  assert(cons != NULL);
608  assert(nlhdlrexprdata != NULL);
609  assert(disaggidx < nlhdlrexprdata->nterms);
610  assert(mincutviolation >= 0.0);
611  assert(cut != NULL);
612 
613  vars = nlhdlrexprdata->vars;
614  disvars = nlhdlrexprdata->disvars;
615  transcoefs = nlhdlrexprdata->transcoefs;
616  transcoefsidx = nlhdlrexprdata->transcoefsidx;
617  termbegins = nlhdlrexprdata->termbegins;
618  nterms = nlhdlrexprdata->nterms;
619 
620  /* nterms is equal to n in the description and disaggidx is in {0, ..., n - 1} */
621 
622  *cut = NULL;
623 
624  disvarval = SCIPgetSolVal(scip, sol, disvars[disaggidx]);
625 
626  lhsval = evalSingleTerm(scip, nlhdlrexprdata, sol, disaggidx);
627 
628  denominator = SQRT(4.0 * SQR(lhsval) + SQR(rhsval - disvarval));
629 
630  /* compute value of function to be separated (f(x*,y*)) */
631  fvalue = denominator - rhsval - disvarval;
632 
633  /* if the disagg soc is not violated don't compute cut */
634  if( fvalue <= mincutviolation )
635  {
636  SCIPdebugMsg(scip, "skip cut on disaggregation index %d as violation=%g below minviolation %g\n", disaggidx,
637  fvalue, mincutviolation);
638  return SCIP_OKAY;
639  }
640 
641  /* if the denominator is 0 -> the constraint can't be violated */
642  assert(!SCIPisZero(scip, denominator));
643  /* if v_disaggidx^T x + beta_disaggidx is 0 -> the constraint can't be violated */
644  assert(!SCIPisZero(scip, lhsval));
645 
646  /* compute upper bound on the number of variables in cut: vars in rhs + vars in term + disagg var */
647  ncutvars = (termbegins[nterms] - termbegins[nterms-1]) + (termbegins[disaggidx + 1] - termbegins[disaggidx]) + 1;
648 
649  /* create cut */
651  SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, ncutvars) );
652 
653  /* constant will be grad_f(x*,y*)^T (x*, y*) */
654  constant = 0.0;
655 
656  /* a variable could appear on the lhs and rhs, but we add the coefficients separately */
657 
658  /* add terms for v_disaggidx */
659  for( i = termbegins[disaggidx]; i < termbegins[disaggidx + 1]; ++i )
660  {
661  cutvar = SCIPgetExprAuxVarNonlinear(vars[transcoefsidx[i]]);
662  assert(cutvar != NULL);
663 
664  /* cutcoef is (the first part of) the partial derivative w.r.t cutvar */
665  cutcoef = 4.0 * lhsval * transcoefs[i] / denominator;
666 
667  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, cutvar, cutcoef) );
668 
669  constant += cutcoef * SCIPgetSolVal(scip, sol, cutvar);
670  }
671 
672  /* add terms for v_n */
673  for( i = termbegins[nterms - 1]; i < termbegins[nterms]; ++i )
674  {
675  cutvar = SCIPgetExprAuxVarNonlinear(vars[transcoefsidx[i]]);
676  assert(cutvar != NULL);
677 
678  /* cutcoef is the (second part of) the partial derivative w.r.t cutvar */
679  cutcoef = (rhsval - disvarval) * transcoefs[i] / denominator - transcoefs[i];
680 
681  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, cutvar, cutcoef) );
682 
683  constant += cutcoef * SCIPgetSolVal(scip, sol, cutvar);
684  }
685 
686  /* add term for disvar: cutcoef is the the partial derivative w.r.t. the disaggregation variable */
687  cutcoef = (disvarval - rhsval) / denominator - 1.0;
688  cutvar = disvars[disaggidx];
689 
690  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, cutvar, cutcoef) );
691 
692  constant += cutcoef * SCIPgetSolVal(scip, sol, cutvar);
693 
694  /* add side */
695  SCIProwprepAddSide(rowprep, constant - fvalue);
696 
697  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, SCIPinfinity(scip), NULL) );
698 
699  if( SCIPgetRowprepViolation(scip, rowprep, sol, NULL) >= mincutviolation )
700  {
701  (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "soc_%p_%d_%d", (void*) expr, disaggidx, SCIPgetNLPs(scip));
702  SCIP_CALL( SCIPgetRowprepRowCons(scip, cut, rowprep, cons) );
703  }
704  else
705  {
706  SCIPdebugMsg(scip, "rowprep violation %g below mincutviolation %g\n", SCIPgetRowprepViolation(scip, rowprep, sol,
707  NULL), mincutviolation);
708  /* SCIPprintRowprep(scip, rowprep, NULL); */
709  }
710 
711  /* free memory */
712  SCIPfreeRowprep(scip, &rowprep);
713 
714  return SCIP_OKAY;
715 }
716 
717 /** checks if an expression is quadratic and collects all occurring expressions
718  *
719  * @pre `expr2idx` and `occurringexprs` need to be initialized with capacity 2 * nchildren
720  *
721  * @note We assume that a linear term always appears before its corresponding
722  * quadratic term in quadexpr; this should be ensured by canonicalize
723  */
724 static
726  SCIP* scip, /**< SCIP data structure */
727  SCIP_EXPR* quadexpr, /**< candidate for a quadratic expression */
728  SCIP_HASHMAP* expr2idx, /**< hashmap to store expressions */
729  SCIP_EXPR** occurringexprs, /**< array to store expressions */
730  int* nexprs, /**< buffer to store number of expressions */
731  SCIP_Bool* success /**< buffer to store whether the check was successful */
732  )
733 {
734  SCIP_EXPR** children;
735  int nchildren;
736  int i;
737 
738  assert(scip != NULL);
739  assert(quadexpr != NULL);
740  assert(expr2idx != NULL);
741  assert(occurringexprs != NULL);
742  assert(nexprs != NULL);
743  assert(success != NULL);
744 
745  *nexprs = 0;
746  *success = FALSE;
747  children = SCIPexprGetChildren(quadexpr);
748  nchildren = SCIPexprGetNChildren(quadexpr);
749 
750  /* iterate in reverse order to ensure that quadratic terms are found before linear terms */
751  for( i = nchildren - 1; i >= 0; --i )
752  {
753  SCIP_EXPR* child;
754 
755  child = children[i];
756  if( SCIPisExprPower(scip, child) )
757  {
758  SCIP_EXPR* childarg;
759 
760  if( SCIPgetExponentExprPow(child) != 2.0 )
761  return SCIP_OKAY;
762 
763  childarg = SCIPexprGetChildren(child)[0];
764 
765  if( !SCIPhashmapExists(expr2idx, (void*) childarg) )
766  {
767  SCIP_CALL( SCIPhashmapInsertInt(expr2idx, (void*) childarg, *nexprs) );
768 
769  /* store the expression so we know it later */
770  assert(*nexprs < 2 * nchildren);
771  occurringexprs[*nexprs] = childarg;
772 
773  ++(*nexprs);
774  }
775  }
776  else if( SCIPisExprVar(scip, child) && SCIPvarIsBinary(SCIPgetVarExprVar(child)) )
777  {
778  if( !SCIPhashmapExists(expr2idx, (void*) child) )
779  {
780  SCIP_CALL( SCIPhashmapInsertInt(expr2idx, (void*) child, *nexprs) );
781 
782  /* store the expression so we know it later */
783  assert(*nexprs < 2 * nchildren);
784  occurringexprs[*nexprs] = child;
785 
786  ++(*nexprs);
787  }
788  }
789  else if( SCIPisExprProduct(scip, child) )
790  {
791  SCIP_EXPR* childarg1;
792  SCIP_EXPR* childarg2;
793 
794  if( SCIPexprGetNChildren(child) != 2 )
795  return SCIP_OKAY;
796 
797  childarg1 = SCIPexprGetChildren(child)[0];
798  childarg2 = SCIPexprGetChildren(child)[1];
799 
800  if( !SCIPhashmapExists(expr2idx, (void*) childarg1) )
801  {
802  SCIP_CALL( SCIPhashmapInsertInt(expr2idx, (void*) childarg1, *nexprs) );
803 
804  /* store the expression so we know it later */
805  assert(*nexprs < 2 * nchildren);
806  occurringexprs[*nexprs] = childarg1;
807 
808  ++(*nexprs);
809  }
810 
811  if( !SCIPhashmapExists(expr2idx, (void*) childarg2) )
812  {
813  SCIP_CALL( SCIPhashmapInsertInt(expr2idx, (void*) childarg2, *nexprs) );
814 
815  /* store the expression so we know it later */
816  assert(*nexprs < 2 * nchildren);
817  occurringexprs[*nexprs] = childarg2;
818 
819  ++(*nexprs);
820  }
821  }
822  else
823  {
824  /* if there is a linear term without corresponding quadratic term, it is not a SOC */
825  if( !SCIPhashmapExists(expr2idx, (void*) child) )
826  return SCIP_OKAY;
827  }
828  }
829 
830  *success = TRUE;
831 
832  return SCIP_OKAY;
833 }
834 
835 /* builds the constraint defining matrix and vector of a quadratic expression
836  *
837  * @pre `quadmatrix` and `linvector` need to be initialized with size `nexprs`^2 and `nexprs`, resp.
838  */
839 static
841  SCIP* scip, /**< SCIP data structure */
842  SCIP_EXPR* quadexpr, /**< the quadratic expression */
843  SCIP_HASHMAP* expr2idx, /**< hashmap mapping the occurring expressions to their index */
844  int nexprs, /**< number of occurring expressions */
845  SCIP_Real* quadmatrix, /**< pointer to store (the lower-left triangle of) the quadratic matrix */
846  SCIP_Real* linvector /**< pointer to store the linear vector */
847  )
848 {
849  SCIP_EXPR** children;
850  SCIP_Real* childcoefs;
851  int nchildren;
852  int i;
853 
854  assert(scip != NULL);
855  assert(quadexpr != NULL);
856  assert(expr2idx != NULL);
857  assert(quadmatrix != NULL);
858  assert(linvector != NULL);
859 
860  children = SCIPexprGetChildren(quadexpr);
861  nchildren = SCIPexprGetNChildren(quadexpr);
862  childcoefs = SCIPgetCoefsExprSum(quadexpr);
863 
864  /* iterate over children to build the constraint defining matrix and vector */
865  for( i = 0; i < nchildren; ++i )
866  {
867  int varpos;
868 
869  if( SCIPisExprPower(scip, children[i]) )
870  {
871  assert(SCIPgetExponentExprPow(children[i]) == 2.0);
872  assert(SCIPhashmapExists(expr2idx, (void*) SCIPexprGetChildren(children[i])[0]));
873 
874  varpos = SCIPhashmapGetImageInt(expr2idx, (void*) SCIPexprGetChildren(children[i])[0]);
875  assert(0 <= varpos && varpos < nexprs);
876 
877  quadmatrix[varpos * nexprs + varpos] = childcoefs[i];
878  }
879  else if( SCIPisExprVar(scip, children[i]) && SCIPvarIsBinary(SCIPgetVarExprVar(children[i])) )
880  {
881  assert(SCIPhashmapExists(expr2idx, (void*) children[i]));
882 
883  varpos = SCIPhashmapGetImageInt(expr2idx, (void*) children[i]);
884  assert(0 <= varpos && varpos < nexprs);
885 
886  quadmatrix[varpos * nexprs + varpos] = childcoefs[i];
887  }
888  else if( SCIPisExprProduct(scip, children[i]) )
889  {
890  int varpos2;
891 
892  assert(SCIPexprGetNChildren(children[i]) == 2);
893  assert(SCIPhashmapExists(expr2idx, (void*) SCIPexprGetChildren(children[i])[0]));
894  assert(SCIPhashmapExists(expr2idx, (void*) SCIPexprGetChildren(children[i])[1]));
895 
896  varpos = SCIPhashmapGetImageInt(expr2idx, (void*) SCIPexprGetChildren(children[i])[0]);
897  assert(0 <= varpos && varpos < nexprs);
898 
899  varpos2 = SCIPhashmapGetImageInt(expr2idx, (void*) SCIPexprGetChildren(children[i])[1]);
900  assert(0 <= varpos2 && varpos2 < nexprs);
901  assert(varpos != varpos2);
902 
903  /* Lapack uses only the lower left triangle of the symmetric matrix */
904  quadmatrix[MIN(varpos, varpos2) * nexprs + MAX(varpos, varpos2)] = childcoefs[i] / 2.0;
905  }
906  else
907  {
908  varpos = SCIPhashmapGetImageInt(expr2idx, (void*) children[i]);
909  assert(0 <= varpos && varpos < nexprs);
910 
911  linvector[varpos] = childcoefs[i];
912  }
913  }
914 }
915 
916 /** tries to fill the nlhdlrexprdata for a potential quadratic SOC expression
917  *
918  * We say "try" because the expression might still turn out not to be a SOC at this point.
919  */
920 static
922  SCIP* scip, /**< SCIP data structure */
923  SCIP_EXPR** occurringexprs, /**< array of all occurring expressions (nvars many) */
924  SCIP_Real* eigvecmatrix, /**< array containing the Eigenvectors */
925  SCIP_Real* eigvals, /**< array containing the Eigenvalues */
926  SCIP_Real* bp, /**< product of linear vector b * P (eigvecmatrix^t) */
927  int nvars, /**< number of variables */
928  int* termbegins, /**< pointer to store the termbegins */
929  SCIP_Real* transcoefs, /**< pointer to store the transcoefs */
930  int* transcoefsidx, /**< pointer to store the transcoefsidx */
931  SCIP_Real* offsets, /**< pointer to store the offsets */
932  SCIP_Real* lhsconstant, /**< pointer to store the lhsconstant */
933  int* nterms, /**< pointer to store the total number of terms */
934  SCIP_Bool* success /**< whether the expression is indeed a SOC */
935  )
936 {
937  SCIP_Real sqrteigval;
938  int nextterm = 0;
939  int nexttranscoef = 0;
940  int specialtermidx;
941  int i;
942  int j;
943 
944  assert(scip != NULL);
945  assert(occurringexprs != NULL);
946  assert(eigvecmatrix != NULL);
947  assert(eigvals != NULL);
948  assert(bp != NULL);
949  assert(termbegins != NULL);
950  assert(transcoefs != NULL);
951  assert(transcoefsidx != NULL);
952  assert(offsets != NULL);
953  assert(lhsconstant != NULL);
954  assert(success != NULL);
955 
956  *success = FALSE;
957  *nterms = 0;
958 
959  /* we have lhsconstant + x^t A x + b x <= 0 and A has a single negative eigenvalue; try to build soc;
960  * we now store all the v_i^T x + beta_i on the lhs, and compute the constant
961  */
962  specialtermidx = -1;
963  for( i = 0; i < nvars; ++i )
964  {
965  if( SCIPisZero(scip, eigvals[i]) )
966  continue;
967 
968  if( eigvals[i] < 0.0 )
969  {
970  assert(specialtermidx == -1); /* there should only be one negative eigenvalue */
971 
972  specialtermidx = i;
973 
974  *lhsconstant -= bp[i] * bp[i] / (4.0 * eigvals[i]);
975 
976  continue;
977  }
978 
979  assert(eigvals[i] > 0.0);
980  sqrteigval = SQRT(eigvals[i]);
981 
982  termbegins[nextterm] = nexttranscoef;
983  offsets[nextterm] = bp[i] / (2.0 * sqrteigval);
984  *lhsconstant -= bp[i] * bp[i] / (4.0 * eigvals[i]);
985 
986  /* set transcoefs */
987  for( j = 0; j < nvars; ++j )
988  {
989  if( !SCIPisZero(scip, eigvecmatrix[i * nvars + j]) )
990  {
991  transcoefs[nexttranscoef] = sqrteigval * eigvecmatrix[i * nvars + j];
992  transcoefsidx[nexttranscoef] = j;
993 
994  ++nexttranscoef;
995  }
996  }
997  ++nextterm;
998  }
999  assert(specialtermidx > -1);
1000 
1001  /* process constant; if constant is negative -> no soc */
1002  if( SCIPisNegative(scip, *lhsconstant) )
1003  return SCIP_OKAY;
1004 
1005  /* we need lhsconstant to be >= 0 */
1006  if( *lhsconstant < 0.0 )
1007  *lhsconstant = 0.0;
1008 
1009  /* store constant term */
1010  if( *lhsconstant > 0.0 )
1011  {
1012  termbegins[nextterm] = nexttranscoef;
1013  offsets[nextterm] = SQRT( *lhsconstant );
1014  ++nextterm;
1015  }
1016 
1017  /* now process rhs */
1018  {
1019  SCIP_Real rhstermlb;
1020  SCIP_Real rhstermub;
1021  SCIP_Real signfactor;
1022 
1023  assert(-eigvals[specialtermidx] > 0.0);
1024  sqrteigval = SQRT(-eigvals[specialtermidx]);
1025 
1026  termbegins[nextterm] = nexttranscoef;
1027  offsets[nextterm] = -bp[specialtermidx] / (2.0 * sqrteigval);
1028 
1029  /* the expression can only be an soc if the resulting rhs term does not change sign;
1030  * the rhs term is a linear combination of variables, so estimate its bounds
1031  */
1032  rhstermlb = offsets[nextterm];
1033  for( j = 0; j < nvars; ++j )
1034  {
1035  SCIP_INTERVAL activity;
1036  SCIP_Real aux;
1037 
1038  if( SCIPisZero(scip, eigvecmatrix[specialtermidx * nvars + j]) )
1039  continue;
1040 
1041  SCIP_CALL( SCIPevalExprActivity(scip, occurringexprs[j]) );
1042  activity = SCIPexprGetActivity(occurringexprs[j]);
1043 
1044  if( eigvecmatrix[specialtermidx * nvars + j] > 0.0 )
1045  {
1046  aux = activity.inf;
1047  assert(!SCIPisInfinity(scip, aux));
1048  }
1049  else
1050  {
1051  aux = activity.sup;
1052  assert(!SCIPisInfinity(scip, -aux));
1053  }
1054 
1055  if( SCIPisInfinity(scip, aux) || SCIPisInfinity(scip, -aux) )
1056  {
1057  rhstermlb = -SCIPinfinity(scip);
1058  break;
1059  }
1060  else
1061  rhstermlb += sqrteigval * eigvecmatrix[specialtermidx * nvars + j] * aux;
1062  }
1063 
1064  rhstermub = offsets[nextterm];
1065  for( j = 0; j < nvars; ++j )
1066  {
1067  SCIP_INTERVAL activity;
1068  SCIP_Real aux;
1069 
1070  if( SCIPisZero(scip, eigvecmatrix[specialtermidx * nvars + j]) )
1071  continue;
1072 
1073  SCIP_CALL( SCIPevalExprActivity(scip, occurringexprs[j]) );
1074  activity = SCIPexprGetActivity(occurringexprs[j]);
1075 
1076  if( eigvecmatrix[specialtermidx * nvars + j] > 0.0 )
1077  {
1078  aux = activity.sup;
1079  assert(!SCIPisInfinity(scip, -aux));
1080  }
1081  else
1082  {
1083  aux = activity.inf;
1084  assert(!SCIPisInfinity(scip, aux));
1085  }
1086 
1087  if( SCIPisInfinity(scip, aux) || SCIPisInfinity(scip, -aux) )
1088  {
1089  rhstermub = SCIPinfinity(scip);
1090  break;
1091  }
1092  else
1093  rhstermub += sqrteigval * eigvecmatrix[specialtermidx * nvars + j] * aux;
1094  }
1095 
1096  /* since we are just interested in obtaining an interval that contains the real bounds
1097  * and is tight enough so that we can identify that the rhsvar does not change sign,
1098  * we swap the bounds in case of numerical troubles
1099  */
1100  if( rhstermub < rhstermlb )
1101  {
1102  assert(SCIPisEQ(scip, rhstermub, rhstermlb));
1103  SCIPswapReals(&rhstermub, &rhstermlb);
1104  }
1105 
1106  /* if rhs changes sign -> not a SOC */
1107  if( SCIPisLT(scip, rhstermlb, 0.0) && SCIPisGT(scip, rhstermub, 0.0) )
1108  return SCIP_OKAY;
1109 
1110  signfactor = SCIPisLE(scip, rhstermub, 0.0) ? -1.0 : 1.0;
1111 
1112  offsets[nextterm] *= signfactor;
1113 
1114  /* set transcoefs for rhs term */
1115  for( j = 0; j < nvars; ++j )
1116  {
1117  if( SCIPisZero(scip, eigvecmatrix[specialtermidx * nvars + j]) )
1118  continue;
1119 
1120  transcoefs[nexttranscoef] = signfactor * sqrteigval * eigvecmatrix[specialtermidx * nvars + j];
1121  transcoefsidx[nexttranscoef] = j;
1122 
1123  ++nexttranscoef;
1124  }
1125 
1126  /* if rhs is a constant this method shouldn't have been called */
1127  assert(nexttranscoef > termbegins[nextterm]);
1128 
1129  /* finish processing term */
1130  ++nextterm;
1131  }
1132 
1133  *nterms = nextterm;
1134 
1135  /* sentinel value */
1136  termbegins[nextterm] = nexttranscoef;
1137 
1138  *success = TRUE;
1139 
1140  return SCIP_OKAY;
1141 }
1142 
1143 /** detects if expr &le; auxvar is of the form SQRT(sum_i coef_i (expr_i + shift_i)^2 + const) &le; auxvar
1144  *
1145  * @note if a user inputs the above expression with `const` = -epsilon, then `const` is going to be set to 0.
1146  */
1147 static
1149  SCIP* scip, /**< SCIP data structure */
1150  SCIP_EXPR* expr, /**< expression */
1151  SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< pointer to store nonlinear handler expression data */
1152  SCIP_Bool* success /**< pointer to store whether SOC structure has been detected */
1153  )
1154 {
1155  SCIP_EXPR** children;
1156  SCIP_EXPR* child;
1157  SCIP_EXPR** vars;
1158  SCIP_HASHMAP* expr2idx;
1159  SCIP_HASHSET* linexprs;
1160  SCIP_Real* childcoefs;
1161  SCIP_Real* offsets;
1162  SCIP_Real* transcoefs;
1163  SCIP_Real constant;
1164  SCIP_Bool issoc;
1165  int* transcoefsidx;
1166  int* termbegins;
1167  int nchildren;
1168  int nterms;
1169  int nvars;
1170  int nextentry;
1171  int i;
1172 
1173  assert(expr != NULL);
1174  assert(success != NULL);
1175 
1176  *success = FALSE;
1177  issoc = TRUE;
1178 
1179  /* relation is not "<=" -> skip */
1180  if( SCIPgetExprNLocksPosNonlinear(expr) == 0 )
1181  return SCIP_OKAY;
1182 
1183  assert(SCIPexprGetNChildren(expr) > 0);
1184 
1185  child = SCIPexprGetChildren(expr)[0];
1186  assert(child != NULL);
1187 
1188  /* check whether expression is a SQRT and has a sum as child with at least 2 children and a non-negative constant */
1189  if( ! SCIPisExprPower(scip, expr)
1190  || SCIPgetExponentExprPow(expr) != 0.5
1191  || !SCIPisExprSum(scip, child)
1192  || SCIPexprGetNChildren(child) < 2
1193  || SCIPgetConstantExprSum(child) < 0.0)
1194  {
1195  return SCIP_OKAY;
1196  }
1197 
1198  /* assert(SCIPvarGetLbLocal(auxvar) >= 0.0); */
1199 
1200  /* get children of the sum */
1201  children = SCIPexprGetChildren(child);
1202  nchildren = SCIPexprGetNChildren(child);
1203  childcoefs = SCIPgetCoefsExprSum(child);
1204 
1205  /* TODO: should we initialize the hashmap with size SCIPgetNVars() so that it never has to be resized? */
1206  SCIP_CALL( SCIPhashmapCreate(&expr2idx, SCIPblkmem(scip), nchildren) );
1207  SCIP_CALL( SCIPhashsetCreate(&linexprs, SCIPblkmem(scip), nchildren) );
1208 
1209  /* we create coefs array here already, since we have to fill it in first loop in case of success
1210  * +1 for auxvar
1211  */
1212  SCIP_CALL( SCIPallocBufferArray(scip, &transcoefs, nchildren+1) );
1213 
1214  nterms = 0;
1215 
1216  /* check if all children are squares or linear terms with matching square term:
1217  * if the i-th child is (pow, expr, 2) we store the association <|expr -> i|> in expr2idx and if expr was in
1218  * linexprs, we remove it from there.
1219  * if the i-th child is expr' (different from (pow, expr, 2)) and expr' is not a key of expr2idx, we add it
1220  * to linexprs.
1221  * if at the end there is any expr in linexpr -> we do not have a separable quadratic function.
1222  */
1223  for( i = 0; i < nchildren; ++i )
1224  {
1225  /* handle quadratic expressions children */
1226  if( SCIPisExprPower(scip, children[i]) && SCIPgetExponentExprPow(children[i]) == 2.0 )
1227  {
1228  SCIP_EXPR* squarearg = SCIPexprGetChildren(children[i])[0];
1229 
1230  if( !SCIPhashmapExists(expr2idx, (void*) squarearg) )
1231  {
1232  SCIP_CALL( SCIPhashmapInsertInt(expr2idx, (void *) squarearg, nterms) );
1233  }
1234 
1235  if( childcoefs[i] < 0.0 )
1236  {
1237  issoc = FALSE;
1238  break;
1239  }
1240  transcoefs[nterms] = SQRT(childcoefs[i]);
1241 
1242  SCIP_CALL( SCIPhashsetRemove(linexprs, (void*) squarearg) );
1243  ++nterms;
1244  }
1245  /* handle binary variable children */
1246  else if( SCIPisExprVar(scip, children[i]) && SCIPvarIsBinary(SCIPgetVarExprVar(children[i])) )
1247  {
1248  assert(!SCIPhashmapExists(expr2idx, (void*) children[i]));
1249  assert(!SCIPhashsetExists(linexprs, (void*) children[i]));
1250 
1251  SCIP_CALL( SCIPhashmapInsertInt(expr2idx, (void *) children[i], nterms) );
1252 
1253  if( childcoefs[i] < 0.0 )
1254  {
1255  issoc = FALSE;
1256  break;
1257  }
1258  transcoefs[nterms] = SQRT(childcoefs[i]);
1259 
1260  ++nterms;
1261  }
1262  else
1263  {
1264  if( !SCIPhashmapExists(expr2idx, (void*) children[i]) )
1265  {
1266  SCIP_CALL( SCIPhashsetInsert(linexprs, SCIPblkmem(scip), (void*) children[i]) );
1267  }
1268  }
1269  }
1270 
1271  /* there are linear terms without corresponding quadratic terms or it was detected not to be soc */
1272  if( SCIPhashsetGetNElements(linexprs) > 0 || ! issoc )
1273  {
1274  SCIPfreeBufferArray(scip, &transcoefs);
1275  SCIPhashsetFree(&linexprs, SCIPblkmem(scip) );
1276  SCIPhashmapFree(&expr2idx);
1277  return SCIP_OKAY;
1278  }
1279 
1280  /* add one to terms counter for auxvar */
1281  ++nterms;
1282 
1283  constant = SCIPgetConstantExprSum(child);
1284 
1285  /* compute constant of possible soc expression to check its sign */
1286  for( i = 0; i < nchildren; ++i )
1287  {
1288  if( ! SCIPisExprPower(scip, children[i]) || SCIPgetExponentExprPow(children[i]) != 2.0 )
1289  {
1290  int auxvarpos;
1291 
1292  assert(SCIPhashmapExists(expr2idx, (void*) children[i]) );
1293  auxvarpos = SCIPhashmapGetImageInt(expr2idx, (void*) children[i]);
1294 
1295  constant -= SQR(0.5 * childcoefs[i] / transcoefs[auxvarpos]);
1296  }
1297  }
1298 
1299  /* if the constant is negative -> no SOC */
1300  if( SCIPisNegative(scip, constant) )
1301  {
1302  SCIPfreeBufferArray(scip, &transcoefs);
1303  SCIPhashsetFree(&linexprs, SCIPblkmem(scip) );
1304  SCIPhashmapFree(&expr2idx);
1305  return SCIP_OKAY;
1306  }
1307  else if( SCIPisZero(scip, constant) )
1308  constant = 0.0;
1309  assert(constant >= 0.0);
1310 
1311  /* at this point, we have found an SOC structure */
1312  *success = TRUE;
1313 
1314  nvars = nterms;
1315 
1316  /* add one to terms counter for constant term */
1317  if( constant > 0.0 )
1318  ++nterms;
1319 
1320  /* allocate temporary memory to collect data */
1321  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
1322  SCIP_CALL( SCIPallocBufferArray(scip, &offsets, nterms) );
1323  SCIP_CALL( SCIPallocBufferArray(scip, &transcoefsidx, nvars) );
1324  SCIP_CALL( SCIPallocBufferArray(scip, &termbegins, nterms + 1) );
1325 
1326  /* fill in data for non constant terms of lhs; initialize their offsets */
1327  for( i = 0; i < nvars - 1; ++i )
1328  {
1329  transcoefsidx[i] = i;
1330  termbegins[i] = i;
1331  offsets[i] = 0.0;
1332  }
1333 
1334  /* add constant term and rhs */
1335  vars[nvars - 1] = expr;
1336  if( constant > 0.0 )
1337  {
1338  /* constant term */
1339  termbegins[nterms - 2] = nterms - 2;
1340  offsets[nterms - 2] = SQRT(constant);
1341 
1342  /* rhs */
1343  termbegins[nterms - 1] = nterms - 2;
1344  offsets[nterms - 1] = 0.0;
1345  transcoefsidx[nterms - 2] = nvars - 1;
1346  transcoefs[nterms - 2] = 1.0;
1347 
1348  /* sentinel value */
1349  termbegins[nterms] = nterms - 1;
1350  }
1351  else
1352  {
1353  /* rhs */
1354  termbegins[nterms - 1] = nterms - 1;
1355  offsets[nterms - 1] = 0.0;
1356  transcoefsidx[nterms - 1] = nvars - 1;
1357  transcoefs[nterms - 1] = 1.0;
1358 
1359  /* sentinel value */
1360  termbegins[nterms] = nterms;
1361  }
1362 
1363  /* request required auxiliary variables and fill vars and offsets array */
1364  nextentry = 0;
1365  for( i = 0; i < nchildren; ++i )
1366  {
1367  if( SCIPisExprPower(scip, children[i]) && SCIPgetExponentExprPow(children[i]) == 2.0 )
1368  {
1369  SCIP_EXPR* squarearg;
1370 
1371  squarearg = SCIPexprGetChildren(children[i])[0];
1372  assert(SCIPhashmapGetImageInt(expr2idx, (void*) squarearg) == nextentry);
1373 
1375 
1376  vars[nextentry] = squarearg;
1377  ++nextentry;
1378  }
1379  else if( SCIPisExprVar(scip, children[i]) && SCIPvarIsBinary(SCIPgetVarExprVar(children[i])) )
1380  {
1381  /* handle binary variable children: no need to request auxvar */
1382  assert(SCIPhashmapGetImageInt(expr2idx, (void*) children[i]) == nextentry);
1383  vars[nextentry] = children[i];
1384  ++nextentry;
1385  }
1386  else
1387  {
1388  int auxvarpos;
1389 
1390  assert(SCIPhashmapExists(expr2idx, (void*) children[i]));
1391  auxvarpos = SCIPhashmapGetImageInt(expr2idx, (void*) children[i]);
1392 
1393  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, children[i], TRUE, FALSE, FALSE, FALSE) );
1394 
1395  offsets[auxvarpos] = 0.5 * childcoefs[i] / transcoefs[auxvarpos];
1396  }
1397  }
1398  assert(nextentry == nvars - 1);
1399 
1400 #ifdef SCIP_DEBUG
1401  SCIPdebugMsg(scip, "found SOC structure for expression %p\n", (void*)expr);
1402  SCIPprintExpr(scip, expr, NULL);
1403  SCIPinfoMessage(scip, NULL, " <= auxvar\n");
1404 #endif
1405 
1406  /* create and store nonlinear handler expression data */
1407  SCIP_CALL( createNlhdlrExprData(scip, vars, offsets, transcoefs, transcoefsidx, termbegins,
1408  nvars, nterms, nlhdlrexprdata) );
1409  assert(*nlhdlrexprdata != NULL);
1410 
1411  /* free memory */
1412  SCIPhashsetFree(&linexprs, SCIPblkmem(scip) );
1413  SCIPhashmapFree(&expr2idx);
1414  SCIPfreeBufferArray(scip, &termbegins);
1415  SCIPfreeBufferArray(scip, &transcoefsidx);
1416  SCIPfreeBufferArray(scip, &offsets);
1417  SCIPfreeBufferArray(scip, &vars);
1418  SCIPfreeBufferArray(scip, &transcoefs);
1419 
1420  return SCIP_OKAY;
1421 }
1422 
1423 /** helper method to detect c + sum_i coef_i expr_i^2 - coef_k expr_k^2 &le; 0
1424  * and c + sum_i coef_i expr_i^2 - coef_k expr_k expr_l &le; 0
1425  *
1426  * binary linear variables are interpreted as quadratic terms
1427  *
1428  * @todo: extend this function to detect c + sum_i coef_i (expr_i + const_i)^2 - ...
1429  * this would probably share a lot of code with detectSocNorm
1430  */
1431 static
1433  SCIP* scip, /**< SCIP data structure */
1434  SCIP_EXPR* expr, /**< expression */
1435  SCIP_Real conslhs, /**< lhs of the constraint that the expression defines (or SCIP_INVALID) */
1436  SCIP_Real consrhs, /**< rhs of the constraint that the expression defines (or SCIP_INVALID) */
1437  SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< pointer to store nonlinear handler expression data */
1438  SCIP_Bool* enforcebelow, /**< pointer to store whether we enforce <= (TRUE) or >= (FALSE); only valid when success is TRUE */
1439  SCIP_Bool* success /**< pointer to store whether SOC structure has been detected */
1440  )
1441 {
1442  SCIP_EXPR** children;
1443  SCIP_EXPR** vars = NULL;
1444  SCIP_Real* childcoefs;
1445  SCIP_Real* offsets = NULL;
1446  SCIP_Real* transcoefs = NULL;
1447  int* transcoefsidx = NULL;
1448  int* termbegins = NULL;
1449  SCIP_Real constant;
1450  SCIP_Real lhsconstant;
1451  SCIP_Real lhs;
1452  SCIP_Real rhs;
1453  SCIP_Real rhssign;
1454  SCIP_INTERVAL expractivity;
1455  int ntranscoefs;
1456  int nposquadterms;
1457  int nnegquadterms;
1458  int nposbilinterms;
1459  int nnegbilinterms;
1460  int rhsidx;
1461  int lhsidx;
1462  int specialtermidx;
1463  int nchildren;
1464  int nnzinterms;
1465  int nterms;
1466  int nvars;
1467  int nextentry;
1468  int i;
1469  SCIP_Bool ishyperbolic;
1470 
1471  assert(expr != NULL);
1472  assert(success != NULL);
1473 
1474  *success = FALSE;
1475 
1476  /* check whether expression is a sum with at least 2 children */
1477  if( ! SCIPisExprSum(scip, expr) || SCIPexprGetNChildren(expr) < 2 )
1478  return SCIP_OKAY;
1479 
1480  /* get children of the sum */
1481  children = SCIPexprGetChildren(expr);
1482  nchildren = SCIPexprGetNChildren(expr);
1483  constant = SCIPgetConstantExprSum(expr);
1484 
1485  /* we duplicate the child coefficients since we have to manipulate them */
1486  SCIP_CALL( SCIPduplicateBufferArray(scip, &childcoefs, SCIPgetCoefsExprSum(expr), nchildren) ); /*lint !e666*/
1487 
1488  /* initialize data */
1489  lhsidx = -1;
1490  rhsidx = -1;
1491  nposquadterms = 0;
1492  nnegquadterms = 0;
1493  nposbilinterms = 0;
1494  nnegbilinterms = 0;
1495 
1496  /* check if all children are quadratic or binary linear and count number of positive and negative terms */
1497  for( i = 0; i < nchildren; ++i )
1498  {
1499  if( SCIPisExprPower(scip, children[i]) && SCIPgetExponentExprPow(children[i]) == 2.0 )
1500  {
1501  if( childcoefs[i] > 0.0 )
1502  {
1503  ++nposquadterms;
1504  lhsidx = i;
1505  }
1506  else
1507  {
1508  ++nnegquadterms;
1509  rhsidx = i;
1510  }
1511  }
1512  else if( SCIPisExprVar(scip, children[i]) && SCIPvarIsBinary(SCIPgetVarExprVar(children[i])) )
1513  {
1514  if( childcoefs[i] > 0.0 )
1515  {
1516  ++nposquadterms;
1517  lhsidx = i;
1518  }
1519  else
1520  {
1521  ++nnegquadterms;
1522  rhsidx = i;
1523  }
1524  }
1525  else if( SCIPisExprProduct(scip, children[i]) && SCIPexprGetNChildren(children[i]) == 2 )
1526  {
1527  if( childcoefs[i] > 0.0 )
1528  {
1529  ++nposbilinterms;
1530  lhsidx = i;
1531  }
1532  else
1533  {
1534  ++nnegbilinterms;
1535  rhsidx = i;
1536  }
1537  }
1538  else
1539  {
1540  goto CLEANUP;
1541  }
1542 
1543  /* more than one positive eigenvalue and more than one negative eigenvalue -> can't be convex */
1544  if( nposquadterms > 1 && nnegquadterms > 1 )
1545  goto CLEANUP;
1546 
1547  /* more than one bilinear term -> can't be handled by this method */
1548  if( nposbilinterms + nnegbilinterms > 1 )
1549  goto CLEANUP;
1550 
1551  /* one positive bilinear term and also at least one positive quadratic term -> not a simple SOC */
1552  if( nposbilinterms > 0 && nposquadterms > 0 )
1553  goto CLEANUP;
1554 
1555  /* one negative bilinear term and also at least one negative quadratic term -> not a simple SOC */
1556  if( nnegbilinterms > 0 && nnegquadterms > 0 )
1557  goto CLEANUP;
1558  }
1559 
1560  if( nposquadterms == nchildren || nnegquadterms == nchildren )
1561  goto CLEANUP;
1562 
1563  assert(nposquadterms <= 1 || nnegquadterms <= 1);
1564  assert(nposbilinterms + nnegbilinterms <= 1);
1565  assert(nposbilinterms == 0 || nposquadterms == 0);
1566  assert(nnegbilinterms == 0 || nnegquadterms == 0);
1567 
1568  /* if a bilinear term is involved, it is a hyperbolic expression */
1569  ishyperbolic = (nposbilinterms + nnegbilinterms > 0);
1570 
1571  if( conslhs == SCIP_INVALID || consrhs == SCIP_INVALID ) /*lint !e777*/
1572  {
1573  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
1574  expractivity = SCIPexprGetActivity(expr);
1575 
1576  lhs = (conslhs == SCIP_INVALID ? expractivity.inf : conslhs); /*lint !e777*/
1577  rhs = (consrhs == SCIP_INVALID ? expractivity.sup : consrhs); /*lint !e777*/
1578  }
1579  else
1580  {
1581  lhs = conslhs;
1582  rhs = consrhs;
1583  }
1584 
1585  /* detect case and store lhs/rhs information */
1586  if( (ishyperbolic && nnegbilinterms > 0) || (!ishyperbolic && nnegquadterms < 2) )
1587  {
1588  /* we have -x*y + z^2 ... -> we want to write z^2 ... <= x*y;
1589  * or we have -x^2 + y^2 ... -> we want to write y^2 ... <= x^2;
1590  * in any case, we need a finite rhs
1591  */
1592  assert(nnegbilinterms == 1 || nnegquadterms == 1);
1593  assert(rhsidx != -1);
1594 
1595  /* if rhs is infinity, it can't be soc
1596  * TODO: if it can't be soc, then we should enforce the caller so that we do not try the more complex quadratic
1597  * method
1598  */
1599  if( SCIPisInfinity(scip, rhs) )
1600  goto CLEANUP;
1601 
1602  specialtermidx = rhsidx;
1603  lhsconstant = constant - rhs;
1604  *enforcebelow = TRUE; /* enforce expr <= rhs */
1605  }
1606  else
1607  {
1608  assert(lhsidx != -1);
1609 
1610  /* if lhs is infinity, it can't be soc */
1611  if( SCIPisInfinity(scip, -lhs) )
1612  goto CLEANUP;
1613 
1614  specialtermidx = lhsidx;
1615  lhsconstant = lhs - constant;
1616 
1617  /* negate all coefficients */
1618  for( i = 0; i < nchildren; ++i )
1619  childcoefs[i] = -childcoefs[i];
1620  *enforcebelow = FALSE; /* enforce lhs <= expr */
1621  }
1622  assert(childcoefs[specialtermidx] != 0.0);
1623 
1624  if( ishyperbolic )
1625  {
1626  SCIP_INTERVAL yactivity;
1627  SCIP_INTERVAL zactivity;
1628 
1629  assert(SCIPexprGetNChildren(children[specialtermidx]) == 2);
1630 
1631  SCIP_CALL( SCIPevalExprActivity(scip, SCIPexprGetChildren(children[specialtermidx])[0]) );
1632  yactivity = SCIPexprGetActivity(SCIPexprGetChildren(children[specialtermidx])[0]);
1633 
1634  SCIP_CALL( SCIPevalExprActivity(scip, SCIPexprGetChildren(children[specialtermidx])[1]) );
1635  zactivity = SCIPexprGetActivity(SCIPexprGetChildren(children[specialtermidx])[1]);
1636 
1637  if( SCIPisNegative(scip, yactivity.inf + zactivity.inf) )
1638  {
1639  /* the sum of the expressions in the bilinear term changes sign -> no SOC */
1640  if( SCIPisPositive(scip, yactivity.sup + zactivity.sup) )
1641  goto CLEANUP;
1642 
1643  rhssign = -1.0;
1644  }
1645  else
1646  rhssign = 1.0;
1647 
1648  lhsconstant *= 4.0 / -childcoefs[specialtermidx];
1649  }
1650  else if( SCIPisExprVar(scip, children[specialtermidx]) )
1651  {
1652  /* children[specialtermidx] can be a variable, in which case we treat it as if it is squared */
1653  rhssign = 1.0;
1654  }
1655  else
1656  {
1657  SCIP_INTERVAL rhsactivity;
1658 
1659  assert(SCIPexprGetNChildren(children[specialtermidx]) == 1);
1660  SCIP_CALL( SCIPevalExprActivity(scip, SCIPexprGetChildren(children[specialtermidx])[0]) );
1661  rhsactivity = SCIPexprGetActivity(SCIPexprGetChildren(children[specialtermidx])[0]);
1662 
1663  if( rhsactivity.inf < 0.0 )
1664  {
1665  /* rhs variable changes sign -> no SOC */
1666  if( rhsactivity.sup > 0.0 )
1667  goto CLEANUP;
1668 
1669  rhssign = -1.0;
1670  }
1671  else
1672  rhssign = 1.0;
1673  }
1674 
1675  if( SCIPisNegative(scip, lhsconstant) )
1676  goto CLEANUP;
1677 
1678  if( SCIPisZero(scip, lhsconstant) )
1679  lhsconstant = 0.0;
1680 
1681  /*
1682  * we have found an SOC-representable expression. Now build the nlhdlrexprdata
1683  *
1684  * in the non-hyperbolic case, c + sum_i coef_i expr_i^2 - coef_k expr_k^2 <= 0 is transformed to
1685  * SQRT( c + sum_i coef_i expr_i^2 ) <= coef_k expr_k
1686  * so there are nchildren many vars, nchildren (+ 1 if c != 0) many terms, nchildren many coefficients in the vs
1687  * in SOC representation
1688  *
1689  * in the hyperbolic case, c + sum_i coef_i expr_i^2 - coef_k expr_k expr_l <= 0 is transformed to
1690  * SQRT( 4(c + sum_i coef_i expr_i^2) + (expr_k - expr_l)^2 ) <= expr_k + expr_l
1691  * so there are nchildren + 1many vars, nchildren + 1(+ 1 if c != 0) many terms, nchildren + 3 many coefficients in
1692  * the vs in SOC representation
1693  */
1694 
1695  ntranscoefs = ishyperbolic ? nchildren + 3 : nchildren;
1696  nvars = ishyperbolic ? nchildren + 1 : nchildren;
1697  nterms = nvars;
1698 
1699  /* constant term */
1700  if( lhsconstant > 0.0 )
1701  nterms++;
1702 
1703  /* SOC was detected, allocate temporary memory for data to collect */
1704  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
1705  SCIP_CALL( SCIPallocBufferArray(scip, &offsets, nterms) );
1706  SCIP_CALL( SCIPallocBufferArray(scip, &transcoefs, ntranscoefs) );
1707  SCIP_CALL( SCIPallocBufferArray(scip, &transcoefsidx, ntranscoefs) );
1708  SCIP_CALL( SCIPallocBufferArray(scip, &termbegins, nterms + 1) );
1709 
1710  *success = TRUE;
1711  nextentry = 0;
1712 
1713  /* collect all the v_i and beta_i */
1714  nnzinterms = 0;
1715  for( i = 0; i < nchildren; ++i )
1716  {
1717  /* variable and coef for rhs have to be set to the last entry */
1718  if( i == specialtermidx )
1719  continue;
1720 
1721  /* extract (unique) variable appearing in term */
1722  if( SCIPisExprVar(scip, children[i]) )
1723  {
1724  vars[nextentry] = children[i];
1725 
1726  assert(SCIPvarIsBinary(SCIPgetVarExprVar(vars[nextentry])));
1727  }
1728  else
1729  {
1730  assert(SCIPisExprPower(scip, children[i]));
1731 
1732  /* notify that we will require auxiliary variable */
1734  vars[nextentry] = SCIPexprGetChildren(children[i])[0];
1735  }
1736  assert(vars[nextentry] != NULL);
1737 
1738  /* store v_i and beta_i */
1739  termbegins[nextentry] = nnzinterms;
1740  offsets[nextentry] = 0.0;
1741 
1742  transcoefsidx[nnzinterms] = nextentry;
1743  if( ishyperbolic )
1744  {
1745  /* we eliminate the coefficient of the bilinear term to arrive at standard form */
1746  assert(4.0 * childcoefs[i] / -childcoefs[specialtermidx] > 0.0);
1747  transcoefs[nnzinterms] = SQRT(4.0 * childcoefs[i] / -childcoefs[specialtermidx]);
1748  }
1749  else
1750  {
1751  assert(childcoefs[i] > 0.0);
1752  transcoefs[nnzinterms] = SQRT(childcoefs[i]);
1753  }
1754 
1755  /* finish adding nonzeros */
1756  ++nnzinterms;
1757 
1758  /* finish processing term */
1759  ++nextentry;
1760  }
1761  assert(nextentry == nchildren - 1);
1762 
1763  /* store term for constant (v_i = 0) */
1764  if( lhsconstant > 0.0 )
1765  {
1766  termbegins[nextentry] = nnzinterms;
1767  offsets[nextentry] = SQRT(lhsconstant);
1768 
1769  /* finish processing term; this term has 0 nonzero thus we do not increase nnzinterms */
1770  ++nextentry;
1771  }
1772 
1773  if( !ishyperbolic )
1774  {
1775  /* store rhs term */
1776  if( SCIPisExprVar(scip, children[specialtermidx]) )
1777  {
1778  /* this should be the "children[specialtermidx] can be a variable, in which case we treat it as if it is squared" case */
1779  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, children[specialtermidx], TRUE, FALSE, FALSE, FALSE) );
1780  vars[nvars - 1] = children[specialtermidx];
1781  }
1782  else
1783  {
1784  assert(SCIPisExprPower(scip, children[specialtermidx]));
1785  assert(SCIPexprGetChildren(children[specialtermidx]) != NULL);
1786  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, SCIPexprGetChildren(children[specialtermidx])[0], TRUE, FALSE, FALSE, FALSE) );
1787  vars[nvars - 1] = SCIPexprGetChildren(children[specialtermidx])[0];
1788  }
1789 
1790  assert(childcoefs[specialtermidx] < 0.0);
1791 
1792  termbegins[nextentry] = nnzinterms;
1793  offsets[nextentry] = 0.0;
1794  transcoefs[nnzinterms] = rhssign * SQRT(-childcoefs[specialtermidx]);
1795  transcoefsidx[nnzinterms] = nvars - 1;
1796 
1797  /* finish adding nonzeros */
1798  ++nnzinterms;
1799 
1800  /* finish processing term */
1801  ++nextentry;
1802  }
1803  else
1804  {
1805  /* store last lhs term and rhs term coming from the bilinear term */
1806  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, SCIPexprGetChildren(children[specialtermidx])[0], TRUE, FALSE, FALSE, FALSE) );
1807  vars[nvars - 2] = SCIPexprGetChildren(children[specialtermidx])[0];
1808 
1809  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, SCIPexprGetChildren(children[specialtermidx])[1], TRUE, FALSE, FALSE, FALSE) );
1810  vars[nvars - 1] = SCIPexprGetChildren(children[specialtermidx])[1];
1811 
1812  /* at this point, vars[nvars - 2] = expr_k and vars[nvars - 1] = expr_l;
1813  * on the lhs we have the term (expr_k - expr_l)^2
1814  */
1815  termbegins[nextentry] = nnzinterms;
1816  offsets[nextentry] = 0.0;
1817 
1818  /* expr_k */
1819  transcoefsidx[nnzinterms] = nvars - 2;
1820  transcoefs[nnzinterms] = 1.0;
1821  ++nnzinterms;
1822 
1823  /* - expr_l */
1824  transcoefsidx[nnzinterms] = nvars - 1;
1825  transcoefs[nnzinterms] = -1.0;
1826  ++nnzinterms;
1827 
1828  /* finish processing term */
1829  ++nextentry;
1830 
1831  /* on rhs we have +/-(expr_k + expr_l) */
1832  termbegins[nextentry] = nnzinterms;
1833  offsets[nextentry] = 0.0;
1834 
1835  /* rhssing * expr_k */
1836  transcoefsidx[nnzinterms] = nvars - 2;
1837  transcoefs[nnzinterms] = rhssign;
1838  ++nnzinterms;
1839 
1840  /* rhssing * expr_l */
1841  transcoefsidx[nnzinterms] = nvars - 1;
1842  transcoefs[nnzinterms] = rhssign;
1843  ++nnzinterms;
1844 
1845  /* finish processing term */
1846  ++nextentry;
1847  }
1848  assert(nextentry == nterms);
1849  assert(nnzinterms == ntranscoefs);
1850 
1851  /* sentinel value */
1852  termbegins[nextentry] = nnzinterms;
1853 
1854 #ifdef SCIP_DEBUG
1855  SCIPdebugMsg(scip, "found SOC structure for expression %p\n%f <= ", (void*)expr, lhs);
1856  SCIPprintExpr(scip, expr, NULL);
1857  SCIPinfoMessage(scip, NULL, "<= %f\n", rhs);
1858 #endif
1859 
1860  /* create and store nonlinear handler expression data */
1861  SCIP_CALL( createNlhdlrExprData(scip, vars, offsets, transcoefs, transcoefsidx, termbegins, nvars, nterms,
1862  nlhdlrexprdata) );
1863  assert(*nlhdlrexprdata != NULL);
1864 
1865 CLEANUP:
1866  SCIPfreeBufferArrayNull(scip, &termbegins);
1867  SCIPfreeBufferArrayNull(scip, &transcoefsidx);
1868  SCIPfreeBufferArrayNull(scip, &transcoefs);
1869  SCIPfreeBufferArrayNull(scip, &offsets);
1870  SCIPfreeBufferArrayNull(scip, &vars);
1871  SCIPfreeBufferArrayNull(scip, &childcoefs);
1872 
1873  return SCIP_OKAY;
1874 }
1875 
1876 /** detects complex quadratic expressions that can be represented as SOC constraints
1877  *
1878  * These are quadratic expressions with either exactly one positive or exactly one negative eigenvalue,
1879  * in addition to some extra conditions. One needs to write the quadratic as
1880  * sum eigval_i (eigvec_i . x)^2 + c &le; -eigval_k (eigvec_k . x)^2, where eigval_k is the negative eigenvalue,
1881  * and c must be positive and (eigvec_k . x) must not change sign.
1882  * This is described in more details in
1883  * Mahajan, Ashutosh & Munson, Todd, Exploiting Second-Order Cone Structure for Global Optimization, 2010.
1884  *
1885  * The eigen-decomposition is computed using Lapack.
1886  * Binary linear variables are interpreted as quadratic terms.
1887  *
1888  * @todo: In the case -b <= a + x^2 - y^2 <= b, it is possible to represent both sides by SOC. Currently, the
1889  * datastructure can only handle one SOC. If this should appear more often, it could be worth to extend it,
1890  * such that both sides can be handled (see e.g. instance chp_partload).
1891  * FS: this shouldn't be possible. For a <= b + x^2 - y^2 <= c to be SOC representable on both sides, we would need
1892  * that a - b >= 0 and b -c >= 0, but this implies that a >= c and assuming the constraint is not trivially infeasible,
1893  * a <= b. Thus, a = b = c and the constraint is x^2 == y^2.
1894  *
1895  * @todo: Since cons_nonlinear multiplies as many terms out as possible during presolving, some SOC-representable
1896  * structures cannot be detected, (see e.g. instances bearing or wager). There is currently no obvious way
1897  * to handle this.
1898  */
1899 static
1901  SCIP* scip, /**< SCIP data structure */
1902  SCIP_EXPR* expr, /**< expression */
1903  SCIP_Real conslhs, /**< lhs of the constraint that the expression defines (or SCIP_INVALID) */
1904  SCIP_Real consrhs, /**< rhs of the constraint that the expression defines (or SCIP_INVALID) */
1905  SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< pointer to store nonlinear handler expression data */
1906  SCIP_Bool* enforcebelow, /**< pointer to store whether we enforce <= (TRUE) or >= (FALSE); only
1907  * valid when success is TRUE */
1908  SCIP_Bool* success /**< pointer to store whether SOC structure has been detected */
1909  )
1910 {
1911  SCIP_EXPR** occurringexprs;
1912  SCIP_HASHMAP* expr2idx;
1913  SCIP_Real* offsets;
1914  SCIP_Real* transcoefs;
1915  SCIP_Real* eigvecmatrix;
1916  SCIP_Real* eigvals;
1917  SCIP_Real* lincoefs;
1918  SCIP_Real* bp;
1919  int* transcoefsidx;
1920  int* termbegins;
1921  SCIP_Real constant;
1922  SCIP_Real lhsconstant;
1923  SCIP_Real lhs;
1924  SCIP_Real rhs;
1925  SCIP_INTERVAL expractivity;
1926  int nvars;
1927  int nterms;
1928  int nchildren;
1929  int npos;
1930  int nneg;
1931  int ntranscoefs;
1932  int i;
1933  int j;
1934  SCIP_Bool rhsissoc;
1935  SCIP_Bool lhsissoc;
1936  SCIP_Bool isquadratic;
1937 
1938  assert(expr != NULL);
1939  assert(success != NULL);
1940 
1941  *success = FALSE;
1942 
1943  /* check whether expression is a sum with at least 2 children */
1944  if( ! SCIPisExprSum(scip, expr) || SCIPexprGetNChildren(expr) < 2 )
1945  {
1946  return SCIP_OKAY;
1947  }
1948 
1949  /* we need Lapack to compute eigenvalues/vectors below */
1950  if( !SCIPisIpoptAvailableIpopt() )
1951  return SCIP_OKAY;
1952 
1953  /* get children of the sum */
1954  nchildren = SCIPexprGetNChildren(expr);
1955  constant = SCIPgetConstantExprSum(expr);
1956 
1957  /* initialize data */
1958  offsets = NULL;
1959  transcoefs = NULL;
1960  transcoefsidx = NULL;
1961  termbegins = NULL;
1962  bp = NULL;
1963 
1964  SCIP_CALL( SCIPhashmapCreate(&expr2idx, SCIPblkmem(scip), 2 * nchildren) );
1965  SCIP_CALL( SCIPallocBufferArray(scip, &occurringexprs, 2 * nchildren) );
1966 
1967  /* check if the expression is quadratic and collect all occurring expressions */
1968  SCIP_CALL( checkAndCollectQuadratic(scip, expr, expr2idx, occurringexprs, &nvars, &isquadratic) );
1969 
1970  if( !isquadratic )
1971  {
1972  SCIPfreeBufferArray(scip, &occurringexprs);
1973  SCIPhashmapFree(&expr2idx);
1974  return SCIP_OKAY;
1975  }
1976 
1977  /* check that nvars*nvars doesn't get too large, see also SCIPcomputeExprQuadraticCurvature() */
1978  if( nvars > 7000 )
1979  {
1980  SCIPverbMessage(scip, SCIP_VERBLEVEL_FULL, NULL, "nlhdlr_soc - number of quadratic variables is too large (%d) to check the curvature\n", nvars);
1981  SCIPfreeBufferArray(scip, &occurringexprs);
1982  SCIPhashmapFree(&expr2idx);
1983  return SCIP_OKAY;
1984  }
1985 
1986  assert(SCIPhashmapGetNElements(expr2idx) == nvars);
1987 
1988  /* create datastructures for constaint defining matrix and vector */
1989  SCIP_CALL( SCIPallocClearBufferArray(scip, &eigvecmatrix, nvars * nvars) ); /*lint !e647*/
1990  SCIP_CALL( SCIPallocClearBufferArray(scip, &lincoefs, nvars) );
1991 
1992  /* build constraint defining matrix (stored in eigvecmatrix) and vector (stored in lincoefs) */
1993  buildQuadExprMatrix(scip, expr, expr2idx, nvars, eigvecmatrix, lincoefs);
1994 
1995  SCIP_CALL( SCIPallocBufferArray(scip, &eigvals, nvars) );
1996 
1997  /* compute eigenvalues and vectors, A = PDP^t
1998  * note: eigvecmatrix stores P^t, i.e., P^t_{i,j} = eigvecmatrix[i*nvars+j]
1999  */
2000  if( SCIPcallLapackDsyevIpopt(TRUE, nvars, eigvecmatrix, eigvals) != SCIP_OKAY )
2001  {
2002  SCIPdebugMsg(scip, "Failed to compute eigenvalues and eigenvectors for expression:\n");
2003 
2004 #ifdef SCIP_DEBUG
2005  SCIPdismantleExpr(scip, NULL, expr);
2006 #endif
2007 
2008  goto CLEANUP;
2009  }
2010 
2011  SCIP_CALL( SCIPallocClearBufferArray(scip, &bp, nvars) );
2012 
2013  nneg = 0;
2014  npos = 0;
2015  ntranscoefs = 0;
2016 
2017  /* set small eigenvalues to 0 and compute b*P */
2018  for( i = 0; i < nvars; ++i )
2019  {
2020  for( j = 0; j < nvars; ++j )
2021  {
2022  bp[i] += lincoefs[j] * eigvecmatrix[i * nvars + j];
2023 
2024  /* count the number of transcoefs to be used later */
2025  if( !SCIPisZero(scip, eigvals[i]) && !SCIPisZero(scip, eigvecmatrix[i * nvars + j]) )
2026  ++ntranscoefs;
2027  }
2028 
2029  if( SCIPisZero(scip, eigvals[i]) )
2030  {
2031  /* if there is a purely linear variable, the constraint can't be written as a SOC */
2032  if( !SCIPisZero(scip, bp[i]) )
2033  goto CLEANUP;
2034 
2035  bp[i] = 0.0;
2036  eigvals[i] = 0.0;
2037  }
2038  else if( eigvals[i] > 0.0 )
2039  npos++;
2040  else
2041  nneg++;
2042  }
2043 
2044  /* a proper SOC constraint needs at least 2 variables */
2045  if( npos + nneg < 2 )
2046  goto CLEANUP;
2047 
2048  /* determine whether rhs or lhs of cons is potentially SOC, if any */
2049  rhsissoc = (nneg == 1 && SCIPgetExprNLocksPosNonlinear(expr) > 0);
2050  lhsissoc = (npos == 1 && SCIPgetExprNLocksNegNonlinear(expr) > 0);
2051 
2052  if( rhsissoc || lhsissoc )
2053  {
2054  if( conslhs == SCIP_INVALID || consrhs == SCIP_INVALID ) /*lint !e777*/
2055  {
2056  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
2057  expractivity = SCIPexprGetActivity(expr);
2058  lhs = (conslhs == SCIP_INVALID ? expractivity.inf : conslhs); /*lint !e777*/
2059  rhs = (consrhs == SCIP_INVALID ? expractivity.sup : consrhs); /*lint !e777*/
2060  }
2061  else
2062  {
2063  lhs = conslhs;
2064  rhs = consrhs;
2065  }
2066  }
2067  else
2068  {
2069  /* if none of the sides is potentially SOC, stop */
2070  goto CLEANUP;
2071  }
2072 
2073  /* @TODO: what do we do if both sides are possible? */
2074  if( !rhsissoc )
2075  {
2076  assert(lhsissoc);
2077 
2078  /* lhs is potentially SOC, change signs */
2079  lhsconstant = lhs - constant; /*lint !e644*/
2080 
2081  for( i = 0; i < nvars; ++i )
2082  {
2083  eigvals[i] = -eigvals[i];
2084  bp[i] = -bp[i];
2085  }
2086  *enforcebelow = FALSE; /* enforce lhs <= expr */
2087  }
2088  else
2089  {
2090  lhsconstant = constant - rhs; /*lint !e644*/
2091  *enforcebelow = TRUE; /* enforce expr <= rhs */
2092  }
2093 
2094  /* initialize remaining datastructures for nonlinear handler */
2095  SCIP_CALL( SCIPallocBufferArray(scip, &offsets, npos + nneg + 1) );
2096  SCIP_CALL( SCIPallocBufferArray(scip, &transcoefs, ntranscoefs) );
2097  SCIP_CALL( SCIPallocBufferArray(scip, &transcoefsidx, ntranscoefs) );
2098  SCIP_CALL( SCIPallocBufferArray(scip, &termbegins, npos + nneg + 2) );
2099 
2100  /* try to fill the nlhdlrexprdata (at this point, it can still fail) */
2101  SCIP_CALL( tryFillNlhdlrExprDataQuad(scip, occurringexprs, eigvecmatrix, eigvals, bp, nvars, termbegins, transcoefs,
2102  transcoefsidx, offsets, &lhsconstant, &nterms, success) );
2103 
2104  if( !(*success) )
2105  goto CLEANUP;
2106 
2107  assert(0 < nterms && nterms <= npos + nneg + 1);
2108  assert(ntranscoefs == termbegins[nterms]);
2109 
2110  /*
2111  * at this point, the expression passed all checks and is SOC-representable
2112  */
2113 
2114  /* register all requests for auxiliary variables */
2115  for( i = 0; i < nvars; ++i )
2116  {
2117  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, occurringexprs[i], TRUE, FALSE, FALSE, FALSE) );
2118  }
2119 
2120 #ifdef SCIP_DEBUG
2121  SCIPdebugMsg(scip, "found SOC structure for expression %p\n%f <= ", (void*)expr, lhs);
2122  SCIPprintExpr(scip, expr, NULL);
2123  SCIPinfoMessage(scip, NULL, "<= %f\n", rhs);
2124 #endif
2125 
2126  /* finally, create and store nonlinear handler expression data */
2127  SCIP_CALL( createNlhdlrExprData(scip, occurringexprs, offsets, transcoefs, transcoefsidx, termbegins, nvars, nterms,
2128  nlhdlrexprdata) );
2129  assert(*nlhdlrexprdata != NULL);
2130 
2131 CLEANUP:
2132  SCIPfreeBufferArrayNull(scip, &termbegins);
2133  SCIPfreeBufferArrayNull(scip, &transcoefsidx);
2134  SCIPfreeBufferArrayNull(scip, &transcoefs);
2135  SCIPfreeBufferArrayNull(scip, &offsets);
2136  SCIPfreeBufferArrayNull(scip, &bp);
2137  SCIPfreeBufferArray(scip, &eigvals);
2138  SCIPfreeBufferArray(scip, &lincoefs);
2139  SCIPfreeBufferArray(scip, &eigvecmatrix);
2140  SCIPfreeBufferArray(scip, &occurringexprs);
2141  SCIPhashmapFree(&expr2idx);
2142 
2143  return SCIP_OKAY;
2144 }
2145 
2146 /** helper method to detect SOC structures
2147  *
2148  * The detection runs in 3 steps:
2149  * 1. check if expression is a norm of the form \f$\sqrt{\sum_i (\text{sqrcoef}_i\, \text{expr}_i^2 + \text{lincoef}_i\, \text{expr}_i) + c}\f$
2150  * which can be transformed to the form \f$\sqrt{\sum_i (\text{coef}_i \text{expr}_i + \text{const}_i)^2 + c^*}\f$ with \f$c^* \geq 0\f$.\n
2151  * -> this results in the SOC expr &le; auxvar(expr)
2152  *
2153  * TODO we should generalize and check for sqrt(positive-semidefinite-quadratic)
2154  *
2155  * 2. check if expression represents a quadratic function of one of the following forms (all coefs > 0)
2156  * 1. \f$(\sum_i \text{coef}_i \text{expr}_i^2) - \text{coef}_k \text{expr}_k^2 \leq \text{RHS}\f$ or
2157  * 2. \f$(\sum_i - \text{coef}_i \text{expr}_i^2) + \text{coef}_k \text{expr}_k^2 \geq \text{LHS}\f$ or
2158  * 3. \f$(\sum_i \text{coef}_i \text{expr}_i^2) - \text{coef}_k \text{expr}_k \text{expr}_l \leq \text{RHS}\f$ or
2159  * 4. \f$(\sum_i - \text{coef}_i \text{expr}_i^2) + \text{coef}_k \text{expr}_k \text{expr}_l \geq \text{LHS}\f$,
2160  *
2161  * where RHS &ge; 0 or LHS &le; 0, respectively. For LHS and RHS we use the constraint sides if it is a root expr
2162  * and the bounds of the auxiliary variable otherwise.
2163  * The last two cases are called hyperbolic or rotated second order cone.\n
2164  * -> this results in the SOC \f$\sqrt{(\sum_i \text{coef}_i \text{expr}_i^2) - \text{RHS}} \leq \sqrt{\text{coef}_k} \text{expr}_k\f$
2165  * or \f$\sqrt{4(\sum_i \text{coef}_i \text{expr}_i^2) - 4\text{RHS} + (\text{expr}_k - \text{expr}_l)^2)} \leq \text{expr}_k + \text{expr}_l\f$.
2166  * (analogously for the LHS cases)
2167  *
2168  * 3. check if expression represents a quadratic inequality of the form \f$f(x) = x^TAx + b^Tx + c \leq 0\f$ such that \f$f(x)\f$
2169  * has exactly one negative eigenvalue plus some extra conditions, see detectSocQuadraticComplex().
2170  *
2171  * Note that step 3 is only performed if parameter `compeigenvalues` is set to TRUE.
2172  */
2173 static
2175  SCIP* scip, /**< SCIP data structure */
2176  SCIP_NLHDLRDATA* nlhdlrdata, /**< nonlinear handler data */
2177  SCIP_EXPR* expr, /**< expression */
2178  SCIP_Real conslhs, /**< lhs of the constraint that the expression defines (or SCIP_INVALID) */
2179  SCIP_Real consrhs, /**< rhs of the constraint that the expression defines (or SCIP_INVALID) */
2180  SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< pointer to store nonlinear handler expression data */
2181  SCIP_Bool* enforcebelow, /**< pointer to store whether we enforce <= (TRUE) or >= (FALSE); only
2182  * valid when success is TRUE */
2183  SCIP_Bool* success /**< pointer to store whether SOC structure has been detected */
2184  )
2185 {
2186  assert(expr != NULL);
2187  assert(nlhdlrdata != NULL);
2188  assert(nlhdlrexprdata != NULL);
2189  assert(success != NULL);
2190 
2191  *success = FALSE;
2192 
2193  /* check whether expression is given as norm as described in case 1 above: if we have a constraint
2194  * sqrt(sum x_i^2) <= constant, then it might be better not to handle this here; thus, we only call detectSocNorm
2195  * when the expr is _not_ the root of a constraint
2196  */
2197  if( conslhs == SCIP_INVALID && consrhs == SCIP_INVALID ) /*lint !e777*/
2198  {
2199  SCIP_CALL( detectSocNorm(scip, expr, nlhdlrexprdata, success) );
2200  *enforcebelow = *success;
2201  }
2202 
2203  if( !(*success) )
2204  {
2205  /* check whether expression is a simple soc-respresentable quadratic expression as described in case 2 above */
2206  SCIP_CALL( detectSocQuadraticSimple(scip, expr, conslhs, consrhs, nlhdlrexprdata, enforcebelow, success) );
2207  }
2208 
2209  if( !(*success) && nlhdlrdata->compeigenvalues )
2210  {
2211  /* check whether expression is a more complex soc-respresentable quadratic expression as described in case 3 */
2212  SCIP_CALL( detectSocQuadraticComplex(scip, expr, conslhs, consrhs, nlhdlrexprdata, enforcebelow, success) );
2213  }
2214 
2215  return SCIP_OKAY;
2216 }
2217 
2218 /*
2219  * Callback methods of nonlinear handler
2220  */
2221 
2222 /** nonlinear handler copy callback */
2223 static
2224 SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrSoc)
2225 { /*lint --e{715}*/
2226  assert(targetscip != NULL);
2227  assert(sourcenlhdlr != NULL);
2228  assert(strcmp(SCIPnlhdlrGetName(sourcenlhdlr), NLHDLR_NAME) == 0);
2229 
2230  SCIP_CALL( SCIPincludeNlhdlrSoc(targetscip) );
2231 
2232  return SCIP_OKAY;
2233 }
2234 
2235 /** callback to free data of handler */
2236 static
2237 SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataSoc)
2238 { /*lint --e{715}*/
2239  assert(nlhdlrdata != NULL);
2240 
2241  SCIPfreeBlockMemory(scip, nlhdlrdata);
2242 
2243  return SCIP_OKAY;
2244 }
2245 
2246 /** callback to free expression specific data */
2247 static
2248 SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataSoc)
2249 { /*lint --e{715}*/
2250  assert(*nlhdlrexprdata != NULL);
2251 
2252  SCIP_CALL( freeNlhdlrExprData(scip, nlhdlrexprdata) );
2253 
2254  return SCIP_OKAY;
2255 }
2256 
2257 
2258 /** callback to be called in initialization */
2259 #if 0
2260 static
2262 { /*lint --e{715}*/
2263  SCIPerrorMessage("method of soc nonlinear handler not implemented yet\n");
2264  SCIPABORT(); /*lint --e{527}*/
2265 
2266  return SCIP_OKAY;
2267 }
2268 #else
2269 #define nlhdlrInitSoc NULL
2270 #endif
2271 
2272 
2273 /** callback to be called in deinitialization */
2274 #if 0
2275 static
2277 { /*lint --e{715}*/
2278  SCIPerrorMessage("method of soc nonlinear handler not implemented yet\n");
2279  SCIPABORT(); /*lint --e{527}*/
2280 
2281  return SCIP_OKAY;
2282 }
2283 #else
2284 #define nlhdlrExitSoc NULL
2285 #endif
2286 
2287 
2288 /** callback to detect structure in expression tree */
2289 static
2290 SCIP_DECL_NLHDLRDETECT(nlhdlrDetectSoc)
2291 { /*lint --e{715}*/
2292  SCIP_Real conslhs;
2293  SCIP_Real consrhs;
2294  SCIP_Bool enforcebelow;
2295  SCIP_Bool success;
2296  SCIP_NLHDLRDATA* nlhdlrdata;
2297 
2298  assert(expr != NULL);
2299 
2300  /* don't try if no sepa is required
2301  * TODO implement some bound strengthening
2302  */
2303  if( (*enforcing & SCIP_NLHDLR_METHOD_SEPABOTH) == SCIP_NLHDLR_METHOD_SEPABOTH )
2304  return SCIP_OKAY;
2305 
2306  assert(SCIPgetExprNAuxvarUsesNonlinear(expr) > 0); /* since some sepa is required, there should have been demand for it */
2307 
2308  nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
2309  assert(nlhdlrdata != NULL);
2310 
2311  conslhs = (cons == NULL ? SCIP_INVALID : SCIPgetLhsNonlinear(cons));
2312  consrhs = (cons == NULL ? SCIP_INVALID : SCIPgetRhsNonlinear(cons));
2313 
2314  SCIP_CALL( detectSOC(scip, nlhdlrdata, expr, conslhs, consrhs, nlhdlrexprdata, &enforcebelow, &success) );
2315 
2316  if( !success )
2317  return SCIP_OKAY;
2318 
2319  /* inform what we can do */
2320  *participating = enforcebelow ? SCIP_NLHDLR_METHOD_SEPABELOW : SCIP_NLHDLR_METHOD_SEPAABOVE;
2321 
2322  /* if we have been successful on sqrt(...) <= auxvar, then we enforce
2323  * otherwise, expr is quadratic and we separate for expr <= ub(auxvar) only
2324  * in that case, we enforce only if expr is the root of a constraint, since then replacing auxvar by up(auxvar) does not relax anything (auxvar <= ub(auxvar) is the only constraint on auxvar)
2325  */
2326  if( (SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 0.5) || (cons != NULL) )
2327  *enforcing |= *participating;
2328 
2329  return SCIP_OKAY;
2330 }
2331 
2332 
2333 /** auxiliary evaluation callback of nonlinear handler
2334  * @todo: remember if we are in the original variables and avoid reevaluating
2335  */
2336 static
2337 SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxSoc)
2338 { /*lint --e{715}*/
2339  int i;
2340 
2341  assert(nlhdlrexprdata != NULL);
2342  assert(nlhdlrexprdata->vars != NULL);
2343  assert(nlhdlrexprdata->transcoefs != NULL);
2344  assert(nlhdlrexprdata->transcoefsidx != NULL);
2345  assert(nlhdlrexprdata->nterms > 1);
2346 
2347  /* if the original expression is a norm, evaluate w.r.t. the auxiliary variables */
2348  if( SCIPisExprPower(scip, expr) )
2349  {
2350  assert(SCIPgetExponentExprPow(expr) == 0.5);
2351 
2352  /* compute sum_i coef_i expr_i^2 */
2353  *auxvalue = 0.0;
2354  for( i = 0; i < nlhdlrexprdata->nterms - 1; ++i )
2355  {
2356  SCIP_Real termval;
2357 
2358  termval = evalSingleTerm(scip, nlhdlrexprdata, sol, i);
2359  *auxvalue += SQR(termval);
2360  }
2361 
2362  assert(*auxvalue >= 0.0);
2363 
2364  /* compute SQRT(sum_i coef_i expr_i^2) */
2365  *auxvalue = SQRT(*auxvalue);
2366  }
2367  /* otherwise, evaluate the original quadratic expression w.r.t. the created auxvars of the children */
2368  else
2369  {
2370  SCIP_EXPR** children;
2371  SCIP_Real* childcoefs;
2372  int nchildren;
2373 
2374  assert(SCIPisExprSum(scip, expr));
2375 
2376  children = SCIPexprGetChildren(expr);
2377  childcoefs = SCIPgetCoefsExprSum(expr);
2378  nchildren = SCIPexprGetNChildren(expr);
2379 
2380  *auxvalue = SCIPgetConstantExprSum(expr);
2381 
2382  for( i = 0; i < nchildren; ++i )
2383  {
2384  if( SCIPisExprPower(scip, children[i]) )
2385  {
2386  SCIP_VAR* argauxvar;
2387  SCIP_Real solval;
2388 
2389  assert(SCIPgetExponentExprPow(children[i]) == 2.0);
2390 
2391  argauxvar = SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(children[i])[0]);
2392  assert(argauxvar != NULL);
2393 
2394  solval = SCIPgetSolVal(scip, sol, argauxvar);
2395  *auxvalue += childcoefs[i] * SQR( solval );
2396  }
2397  else if( SCIPisExprProduct(scip, children[i]) )
2398  {
2399  SCIP_VAR* argauxvar1;
2400  SCIP_VAR* argauxvar2;
2401 
2402  assert(SCIPexprGetNChildren(children[i]) == 2);
2403 
2404  argauxvar1 = SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(children[i])[0]);
2405  argauxvar2 = SCIPgetExprAuxVarNonlinear(SCIPexprGetChildren(children[i])[1]);
2406  assert(argauxvar1 != NULL);
2407  assert(argauxvar2 != NULL);
2408 
2409  *auxvalue += childcoefs[i] * SCIPgetSolVal(scip, sol, argauxvar1) * SCIPgetSolVal(scip, sol, argauxvar2);
2410  }
2411  else
2412  {
2413  SCIP_VAR* argauxvar;
2414 
2415  argauxvar = SCIPgetExprAuxVarNonlinear(children[i]);
2416  assert(argauxvar != NULL);
2417 
2418  *auxvalue += childcoefs[i] * SCIPgetSolVal(scip, sol, argauxvar);
2419  }
2420  }
2421  }
2422 
2423  return SCIP_OKAY;
2424 }
2425 
2426 
2427 /** separation deinitialization method of a nonlinear handler (called during CONSINITLP) */
2428 static
2429 SCIP_DECL_NLHDLRINITSEPA(nlhdlrInitSepaSoc)
2430 { /*lint --e{715}*/
2431  assert(conshdlr != NULL);
2432  assert(expr != NULL);
2433  assert(nlhdlrexprdata != NULL);
2434 
2435  /* if we have 3 or more terms in lhs create variable and row for disaggregation */
2436  if( nlhdlrexprdata->nterms > 3 )
2437  {
2438  /* create variables for cone disaggregation */
2439  SCIP_CALL( createDisaggrVars(scip, expr, nlhdlrexprdata) );
2440 
2441 #ifdef WITH_DEBUG_SOLUTION
2442  if( SCIPdebugIsMainscip(scip) )
2443  {
2444  SCIP_Real lhsval;
2445  SCIP_Real rhsval;
2446  SCIP_Real disvarval;
2447  int ndisvars;
2448  int nterms;
2449  int i;
2450  int k;
2451 
2452  /* the debug solution value of the disaggregation variables is set to
2453  * (v_i^T x + beta_i)^2 / (v_{n+1}^T x + beta_{n+1})
2454  * if (v_{n+1}^T x + beta_{n+1}) is different from 0.
2455  * Otherwise, the debug solution value is set to 0.
2456  */
2457 
2458  nterms = nlhdlrexprdata->nterms;
2459 
2460  /* find value of rhs */
2461  rhsval = nlhdlrexprdata->offsets[nterms - 1];
2462  for( i = nlhdlrexprdata->termbegins[nterms - 1]; i < nlhdlrexprdata->termbegins[nterms]; ++i )
2463  {
2464  SCIP_VAR* var;
2465  SCIP_Real varval;
2466 
2467  var = SCIPgetVarExprVar(nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[i]]);
2468 
2469  SCIP_CALL( SCIPdebugGetSolVal(scip, var, &varval) );
2470  rhsval += nlhdlrexprdata->transcoefs[i] * varval;
2471  }
2472 
2473  /* set value of disaggregation vars */
2474  ndisvars = nlhdlrexprdata->nterms - 1;
2475 
2476  if( SCIPisZero(scip, rhsval) )
2477  {
2478  for( i = 0; i < ndisvars; ++i )
2479  {
2480  SCIP_CALL( SCIPdebugAddSolVal(scip, nlhdlrexprdata->disvars[i], 0.0) );
2481  }
2482  }
2483  else
2484  {
2485  /* set value for each disaggregation variable corresponding to quadratic term */
2486  for( k = 0; k < ndisvars; ++k )
2487  {
2488  lhsval = nlhdlrexprdata->offsets[k];
2489 
2490  for( i = nlhdlrexprdata->termbegins[k]; i < nlhdlrexprdata->termbegins[k + 1]; ++i )
2491  {
2492  SCIP_VAR* var;
2493  SCIP_Real varval;
2494 
2495  var = SCIPgetVarExprVar(nlhdlrexprdata->vars[nlhdlrexprdata->transcoefsidx[i]]);
2496 
2497  SCIP_CALL( SCIPdebugGetSolVal(scip, var, &varval) );
2498  lhsval += nlhdlrexprdata->transcoefs[i] * varval;
2499  }
2500 
2501  disvarval = SQR(lhsval) / rhsval;
2502 
2503  SCIP_CALL( SCIPdebugAddSolVal(scip, nlhdlrexprdata->disvars[k], disvarval) );
2504  }
2505  }
2506  }
2507 #endif
2508 
2509  /* create the disaggregation row and store it in nlhdlrexprdata */
2510  SCIP_CALL( createDisaggrRow(scip, conshdlr, expr, nlhdlrexprdata) );
2511  }
2512 
2513  /* TODO add something to the LP as well, at least the disaggregation row */
2514 
2515  return SCIP_OKAY;
2516 }
2517 
2518 
2519 /** separation deinitialization method of a nonlinear handler (called during CONSEXITSOL) */
2520 static
2521 SCIP_DECL_NLHDLREXITSEPA(nlhdlrExitSepaSoc)
2522 { /*lint --e{715}*/
2523  assert(nlhdlrexprdata != NULL);
2524 
2525  /* free disaggreagation row */
2526  if( nlhdlrexprdata->disrow != NULL )
2527  {
2528  SCIP_CALL( SCIPreleaseRow(scip, &nlhdlrexprdata->disrow) );
2529  }
2530 
2531  return SCIP_OKAY;
2532 }
2533 
2534 
2535 /** nonlinear handler separation callback */
2536 static
2537 SCIP_DECL_NLHDLRENFO(nlhdlrEnfoSoc)
2538 { /*lint --e{715}*/
2539  SCIP_NLHDLRDATA* nlhdlrdata;
2540  SCIP_Real rhsval;
2541  int ndisaggrs;
2542  int k;
2543  SCIP_Bool infeasible;
2544 
2545  assert(nlhdlrexprdata != NULL);
2546  assert(nlhdlrexprdata->nterms < 4 || nlhdlrexprdata->disrow != NULL);
2547  assert(nlhdlrexprdata->nterms > 1);
2548 
2549  *result = SCIP_DIDNOTFIND;
2550 
2551  nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
2552  assert(nlhdlrdata != NULL);
2553 
2554  rhsval = evalSingleTerm(scip, nlhdlrexprdata, sol, nlhdlrexprdata->nterms - 1);
2555 
2556  /* if there are three or two terms just compute gradient cut */
2557  if( nlhdlrexprdata->nterms < 4 )
2558  {
2559  SCIP_ROW* row;
2560 
2561  /* compute gradient cut */
2562  SCIP_CALL( generateCutSolSOC(scip, expr, cons, sol, nlhdlrexprdata, SCIPgetLPFeastol(scip), rhsval, &row) );
2563 
2564  /* TODO this code repeats below, factorize out */
2565  if( row != NULL )
2566  {
2567  SCIP_Real cutefficacy;
2568 
2569  cutefficacy = SCIPgetCutEfficacy(scip, sol, row);
2570 
2571  SCIPdebugMsg(scip, "generated row for %d-SOC, efficacy=%g, minefficacy=%g, allowweakcuts=%u\n",
2572  nlhdlrexprdata->nterms, cutefficacy, nlhdlrdata->mincutefficacy, allowweakcuts);
2573 
2574  /* check whether cut is applicable */
2575  if( SCIPisCutApplicable(scip, row) && (allowweakcuts || cutefficacy >= nlhdlrdata->mincutefficacy) )
2576  {
2577  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
2578 
2579 #ifdef SCIP_CONSNONLINEAR_ROWNOTREMOVABLE
2580  /* mark row as not removable from LP for current node, if in enforcement (==addbranchscores) (this can prevent some cycling) */
2581  if( addbranchscores )
2582  SCIPmarkRowNotRemovableLocal(scip, row);
2583 #endif
2584 
2585  if( infeasible )
2586  *result = SCIP_CUTOFF;
2587  else
2588  *result = SCIP_SEPARATED;
2589  }
2590 
2591  /* release row */
2592  SCIP_CALL( SCIPreleaseRow(scip, &row) );
2593  }
2594 #ifdef SCIP_DEBUG
2595  else
2596  {
2597  SCIPdebugMsg(scip, "failed to generate SOC\n");
2598  }
2599 #endif
2600 
2601  return SCIP_OKAY;
2602  }
2603 
2604  ndisaggrs = nlhdlrexprdata->nterms - 1;
2605 
2606  /* check whether the aggregation row is in the LP */
2607  if( !SCIProwIsInLP(nlhdlrexprdata->disrow) && -SCIPgetRowSolFeasibility(scip, nlhdlrexprdata->disrow, sol) > SCIPgetLPFeastol(scip) )
2608  {
2609  SCIP_CALL( SCIPaddRow(scip, nlhdlrexprdata->disrow, TRUE, &infeasible) );
2610  SCIPdebugMsg(scip, "added disaggregation row to LP, cutoff=%u\n", infeasible);
2611 
2612  if( infeasible )
2613  {
2614  *result = SCIP_CUTOFF;
2615  return SCIP_OKAY;
2616  }
2617 
2618  *result = SCIP_SEPARATED;
2619  }
2620 
2621  for( k = 0; k < ndisaggrs && *result != SCIP_CUTOFF; ++k )
2622  {
2623  SCIP_ROW* row;
2624 
2625  /* compute gradient cut */
2626  SCIP_CALL( generateCutSolDisagg(scip, expr, cons, sol, nlhdlrexprdata, k, SCIPgetLPFeastol(scip), rhsval, &row) );
2627 
2628  if( row != NULL )
2629  {
2630  SCIP_Real cutefficacy;
2631 
2632  cutefficacy = SCIPgetCutEfficacy(scip, sol, row);
2633 
2634  SCIPdebugMsg(scip, "generated row for disaggregation %d, efficacy=%g, minefficacy=%g, allowweakcuts=%u\n",
2635  k, cutefficacy, nlhdlrdata->mincutefficacy, allowweakcuts);
2636 
2637  /* check whether cut is applicable */
2638  if( SCIPisCutApplicable(scip, row) && (allowweakcuts || cutefficacy >= nlhdlrdata->mincutefficacy) )
2639  {
2640  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
2641 
2642 #ifdef SCIP_CONSNONLINEAR_ROWNOTREMOVABLE
2643  /* mark row as not removable from LP for current node, if in enforcement (==addbranchscores) (this can prevent some cycling) */
2644  if( addbranchscores )
2645  SCIPmarkRowNotRemovableLocal(scip, row);
2646 #endif
2647 
2648  if( infeasible )
2649  *result = SCIP_CUTOFF;
2650  else
2651  *result = SCIP_SEPARATED;
2652  }
2653 
2654  /* release row */
2655  SCIP_CALL( SCIPreleaseRow(scip, &row) );
2656  }
2657  }
2658 
2659  return SCIP_OKAY;
2660 }
2661 
2662 /*
2663  * nonlinear handler specific interface methods
2664  */
2665 
2666 /** includes SOC nonlinear handler in nonlinear constraint handler */
2668  SCIP* scip /**< SCIP data structure */
2669  )
2670 {
2671  SCIP_NLHDLRDATA* nlhdlrdata;
2672  SCIP_NLHDLR* nlhdlr;
2673 
2674  assert(scip != NULL);
2675 
2676  /* create nonlinear handler data */
2677  SCIP_CALL( SCIPallocClearBlockMemory(scip, &nlhdlrdata) );
2678 
2679  SCIP_CALL( SCIPincludeNlhdlrNonlinear(scip, &nlhdlr, NLHDLR_NAME, NLHDLR_DESC, NLHDLR_DETECTPRIORITY, NLHDLR_ENFOPRIORITY, nlhdlrDetectSoc, nlhdlrEvalauxSoc, nlhdlrdata) );
2680  assert(nlhdlr != NULL);
2681 
2682  SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrSoc);
2683  SCIPnlhdlrSetFreeHdlrData(nlhdlr, nlhdlrFreehdlrdataSoc);
2684  SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrFreeExprDataSoc);
2686  SCIPnlhdlrSetSepa(nlhdlr, nlhdlrInitSepaSoc, nlhdlrEnfoSoc, NULL, nlhdlrExitSepaSoc);
2687 
2688  /* add soc nlhdlr parameters */
2689  /* TODO should we get rid of this and use separating/mineffiacy(root) instead, which is 1e-4? */
2690  SCIP_CALL( SCIPaddRealParam(scip, "nlhdlr/" NLHDLR_NAME "/mincutefficacy",
2691  "Minimum efficacy which a cut needs in order to be added.",
2692  &nlhdlrdata->mincutefficacy, FALSE, DEFAULT_MINCUTEFFICACY, 0.0, SCIPinfinity(scip), NULL, NULL) );
2693 
2694  SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/compeigenvalues",
2695  "Should Eigenvalue computations be done to detect complex cases in quadratic constraints?",
2696  &nlhdlrdata->compeigenvalues, FALSE, DEFAULT_COMPEIGENVALUES, NULL, NULL) );
2697 
2698  return SCIP_OKAY;
2699 }
2700 
2701 /** checks whether constraint is SOC representable in original variables and returns the SOC representation
2702  *
2703  * The SOC representation has the form:
2704  * \f$\sqrt{\sum_{i=1}^{n} (v_i^T x + \beta_i)^2} - v_{n+1}^T x - \beta_{n+1} \lessgtr 0\f$,
2705  * where \f$n+1 = \text{nterms}\f$ and the inequality type is given by sidetype (`SCIP_SIDETYPE_RIGHT` if inequality
2706  * is \f$\leq\f$, `SCIP_SIDETYPE_LEFT` if \f$\geq\f$).
2707  *
2708  * For each term (i.e. for each \f$i\f$ in the above notation as well as \f$n+1\f$), the constant \f$\beta_i\f$ is given by the
2709  * corresponding element `offsets[i-1]` and `termbegins[i-1]` is the starting position of the term in arrays
2710  * `transcoefs` and `transcoefsidx`. The overall number of nonzeros is `termbegins[nterms]`.
2711  *
2712  * Arrays `transcoefs` and `transcoefsidx` have size `termbegins[nterms]` and define the linear expressions \f$v_i^T x\f$
2713  * for each term. For a term \f$i\f$ in the above notation, the nonzeroes are given by elements
2714  * `termbegins[i-1]...termbegins[i]` of `transcoefs` and `transcoefsidx`. There may be no nonzeroes for some term (i.e.,
2715  * constant terms are possible). `transcoefs` contains the coefficients \f$v_i\f$ and `transcoefsidx` contains positions of
2716  * variables in the `vars` array.
2717  *
2718  * The `vars` array has size `nvars` and contains \f$x\f$ variables; each variable is included at most once.
2719  *
2720  * The arrays should be freed by calling SCIPfreeSOCArraysNonlinear().
2721  *
2722  * This function uses the methods that are used in the detection algorithm of the SOC nonlinear handler.
2723  */
2725  SCIP* scip, /**< SCIP data structure */
2726  SCIP_CONS* cons, /**< nonlinear constraint */
2727  SCIP_Bool compeigenvalues, /**< whether eigenvalues should be computed to detect complex cases */
2728  SCIP_Bool* success, /**< pointer to store whether SOC structure has been detected */
2729  SCIP_SIDETYPE* sidetype, /**< pointer to store which side of cons is SOC representable; only
2730  * valid when success is TRUE */
2731  SCIP_VAR*** vars, /**< variables (x) that appear on both sides; no duplicates are allowed */
2732  SCIP_Real** offsets, /**< offsets of both sides (beta_i) */
2733  SCIP_Real** transcoefs, /**< non-zeros of linear transformation vectors (v_i) */
2734  int** transcoefsidx, /**< mapping of transformation coefficients to variable indices in vars */
2735  int** termbegins, /**< starting indices of transcoefs for each term */
2736  int* nvars, /**< total number of variables appearing (i.e. size of vars) */
2737  int* nterms /**< number of summands in the SQRT +1 for RHS (n+1) */
2738  )
2739 {
2740  SCIP_NLHDLRDATA nlhdlrdata;
2741  SCIP_NLHDLREXPRDATA *nlhdlrexprdata;
2742  SCIP_Real conslhs;
2743  SCIP_Real consrhs;
2744  SCIP_EXPR* expr;
2745  SCIP_Bool enforcebelow;
2746  int i;
2747 
2748  assert(cons != NULL);
2749 
2750  expr = SCIPgetExprNonlinear(cons);
2751  assert(expr != NULL);
2752 
2753  nlhdlrdata.mincutefficacy = 0.0;
2754  nlhdlrdata.compeigenvalues = compeigenvalues;
2755 
2756  conslhs = SCIPgetLhsNonlinear(cons);
2757  consrhs = SCIPgetRhsNonlinear(cons);
2758 
2759  SCIP_CALL( detectSOC(scip, &nlhdlrdata, expr, conslhs, consrhs, &nlhdlrexprdata, &enforcebelow, success) );
2760 
2761  /* the constraint must be SOC representable in original variables */
2762  if( *success )
2763  {
2764  assert(nlhdlrexprdata != NULL);
2765 
2766  for( i = 0; i < nlhdlrexprdata->nvars; ++i )
2767  {
2768  if( !SCIPisExprVar(scip, nlhdlrexprdata->vars[i]) )
2769  {
2770  *success = FALSE;
2771  break;
2772  }
2773  }
2774  }
2775 
2776  if( *success )
2777  {
2778  *sidetype = enforcebelow ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT;
2779  SCIP_CALL( SCIPallocBlockMemoryArray(scip, vars, nlhdlrexprdata->nvars) );
2780 
2781  for( i = 0; i < nlhdlrexprdata->nvars; ++i )
2782  {
2783  (*vars)[i] = SCIPgetVarExprVar(nlhdlrexprdata->vars[i]);
2784  assert((*vars)[i] != NULL);
2785  }
2786  SCIPfreeBlockMemoryArray(scip, &nlhdlrexprdata->vars, nlhdlrexprdata->nvars);
2787  *offsets = nlhdlrexprdata->offsets;
2788  *transcoefs = nlhdlrexprdata->transcoefs;
2789  *transcoefsidx = nlhdlrexprdata->transcoefsidx;
2790  *termbegins = nlhdlrexprdata->termbegins;
2791  *nvars = nlhdlrexprdata->nvars;
2792  *nterms = nlhdlrexprdata->nterms;
2793  SCIPfreeBlockMemory(scip, &nlhdlrexprdata);
2794  }
2795  else
2796  {
2797  if( nlhdlrexprdata != NULL )
2798  {
2799  SCIP_CALL( freeNlhdlrExprData(scip, &nlhdlrexprdata) );
2800  }
2801  *vars = NULL;
2802  *offsets = NULL;
2803  *transcoefs = NULL;
2804  *transcoefsidx = NULL;
2805  *termbegins = NULL;
2806  *nvars = 0;
2807  *nterms = 0;
2808  }
2809 
2810  return SCIP_OKAY;
2811 }
2812 
2813 /** frees arrays created by SCIPisSOCNonlinear() */
2815  SCIP* scip, /**< SCIP data structure */
2816  SCIP_VAR*** vars, /**< variables that appear on both sides (x) */
2817  SCIP_Real** offsets, /**< offsets of both sides (beta_i) */
2818  SCIP_Real** transcoefs, /**< non-zeros of linear transformation vectors (v_i) */
2819  int** transcoefsidx, /**< mapping of transformation coefficients to variable indices in vars */
2820  int** termbegins, /**< starting indices of transcoefs for each term */
2821  int nvars, /**< total number of variables appearing */
2822  int nterms /**< number of summands in the SQRT +1 for RHS (n+1) */
2823  )
2824 {
2825  int ntranscoefs;
2826 
2827  if( nvars == 0 )
2828  return;
2829 
2830  assert(vars != NULL);
2831  assert(offsets != NULL);
2832  assert(transcoefs != NULL);
2833  assert(transcoefsidx != NULL);
2834  assert(termbegins != NULL);
2835 
2836  ntranscoefs = (*termbegins)[nterms];
2837 
2838  SCIPfreeBlockMemoryArray(scip, termbegins, nterms + 1);
2839  SCIPfreeBlockMemoryArray(scip, transcoefsidx, ntranscoefs);
2840  SCIPfreeBlockMemoryArray(scip, transcoefs, ntranscoefs);
2841  SCIPfreeBlockMemoryArray(scip, offsets, nterms);
2842  SCIPfreeBlockMemoryArray(scip, vars, nvars);
2843 }
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:101
SCIP_Bool SCIPisIpoptAvailableIpopt(void)
#define nlhdlrInitSoc
Definition: nlhdlr_soc.c:2269
static SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataSoc)
Definition: nlhdlr_soc.c:2237
static volatile int nterms
Definition: interrupt.c:38
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:84
static SCIP_RETCODE createDisaggrVars(SCIP *scip, SCIP_EXPR *expr, SCIP_NLHDLREXPRDATA *nlhdlrexprdata)
Definition: nlhdlr_soc.c:205
SCIP_RETCODE SCIPhashsetRemove(SCIP_HASHSET *hashset, void *element)
Definition: misc.c:3798
SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
Definition: scip_expr.c:1476
unsigned int SCIPgetExprNAuxvarUsesNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1706
#define SCIP_NLHDLR_METHOD_SEPABELOW
Definition: type_nlhdlr.h:42
int SCIPhashsetGetNElements(SCIP_HASHSET *hashset)
Definition: misc.c:3932
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3798
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:117
static SCIP_RETCODE tryFillNlhdlrExprDataQuad(SCIP *scip, SCIP_EXPR **occurringexprs, SCIP_Real *eigvecmatrix, SCIP_Real *eigvals, SCIP_Real *bp, int nvars, int *termbegins, SCIP_Real *transcoefs, int *transcoefsidx, SCIP_Real *offsets, SCIP_Real *lhsconstant, int *nterms, SCIP_Bool *success)
Definition: nlhdlr_soc.c:921
#define SCIP_MAXSTRLEN
Definition: def.h:293
void SCIPnlhdlrSetFreeExprData(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRFREEEXPRDATA((*freeexprdata)))
Definition: nlhdlr.c:85
SCIP_RETCODE SCIPcleanupRowprep2(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefbound, SCIP_Bool *success)
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1686
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
Definition: expr_sum.c:1172
#define NLHDLR_DETECTPRIORITY
Definition: nlhdlr_soc.c:49
SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1245
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17431
SCIP_RETCODE SCIPregisterExprUsageNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool useauxvar, SCIP_Bool useactivityforprop, SCIP_Bool useactivityforsepabelow, SCIP_Bool useactivityforsepaabove)
SCIP_RETCODE SCIPcallLapackDsyevIpopt(SCIP_Bool computeeigenvectors, int N, SCIP_Real *a, SCIP_Real *w)
#define FALSE
Definition: def.h:87
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3014
void SCIPnlhdlrSetFreeHdlrData(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRFREEHDLRDATA((*freehdlrdata)))
Definition: nlhdlr.c:74
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
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
Definition: expr_pow.c:3343
#define TRUE
Definition: def.h:86
SCIP_RETCODE SCIPhashsetCreate(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem, int size)
Definition: misc.c:3699
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
#define DEFAULT_COMPEIGENVALUES
Definition: nlhdlr_soc.c:52
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3132
SCIP_Real SCIPgetLPFeastol(SCIP *scip)
Definition: scip_lp.c:419
SCIP_Bool SCIPhashsetExists(SCIP_HASHSET *hashset, void *element)
Definition: misc.c:3757
SCIP_RETCODE SCIPcreateVarBasic(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype)
Definition: scip_var.c:185
SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
Definition: expr.c:3954
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:10278
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:99
void SCIPfreeSOCArraysNonlinear(SCIP *scip, SCIP_VAR ***vars, SCIP_Real **offsets, SCIP_Real **transcoefs, int **transcoefsidx, int **termbegins, int nvars, int nterms)
Definition: nlhdlr_soc.c:2814
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:123
static SCIP_RETCODE createNlhdlrExprData(SCIP *scip, SCIP_EXPR **vars, SCIP_Real *offsets, SCIP_Real *transcoefs, int *transcoefsidx, int *termbegins, int nvars, int nterms, SCIP_NLHDLREXPRDATA **nlhdlrexprdata)
Definition: nlhdlr_soc.c:322
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE detectSocQuadraticComplex(SCIP *scip, SCIP_EXPR *expr, SCIP_Real conslhs, SCIP_Real consrhs, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_Bool *enforcebelow, SCIP_Bool *success)
Definition: nlhdlr_soc.c:1900
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
variable expression handler
SCIP_RETCODE SCIPensureRowprepSize(SCIP *scip, SCIP_ROWPREP *rowprep, int size)
Definition: misc_rowprep.c:855
#define SCIPdebugMsg
Definition: scip_message.h:69
static SCIP_RETCODE detectSocQuadraticSimple(SCIP *scip, SCIP_EXPR *expr, SCIP_Real conslhs, SCIP_Real consrhs, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_Bool *enforcebelow, SCIP_Bool *success)
Definition: nlhdlr_soc.c:1432
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1454
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17456
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3363
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4256
static SCIP_RETCODE detectSocNorm(SCIP *scip, SCIP_EXPR *expr, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_Bool *success)
Definition: nlhdlr_soc.c:1148
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:3808
#define DEFAULT_MINCUTEFFICACY
Definition: nlhdlr_soc.c:51
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:96
SCIP_Real inf
Definition: intervalarith.h:46
#define NLHDLR_ENFOPRIORITY
Definition: nlhdlr_soc.c:50
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1853
SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
Definition: expr_sum.c:1157
static SCIP_DECL_NLHDLRINITSEPA(nlhdlrInitSepaSoc)
Definition: nlhdlr_soc.c:2429
#define SCIPerrorMessage
Definition: pub_message.h:55
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static void buildQuadExprMatrix(SCIP *scip, SCIP_EXPR *quadexpr, SCIP_HASHMAP *expr2idx, int nexprs, SCIP_Real *quadmatrix, SCIP_Real *linvector)
Definition: nlhdlr_soc.c:840
const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:141
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition: expr_var.c:407
void SCIPhashsetFree(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem)
Definition: misc.c:3730
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)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:128
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:48
static SCIP_RETCODE createDisaggrRow(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *expr, SCIP_NLHDLREXPRDATA *nlhdlrexprdata)
Definition: nlhdlr_soc.c:269
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17251
soc nonlinear handler
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3048
SCIP_EXPR * SCIPgetExprNonlinear(SCIP_CONS *cons)
#define NULL
Definition: lpi_spx1.cpp:155
power and signed power expression handlers
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
static SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxSoc)
Definition: nlhdlr_soc.c:2337
SCIP_Real sup
Definition: intervalarith.h:47
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:216
SCIP_Real SCIPgetRowprepViolation(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Bool *reliable)
Definition: misc_rowprep.c:940
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:241
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:281
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
int SCIPgetExprNLocksNegNonlinear(SCIP_EXPR *expr)
Ipopt NLP interface.
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
#define SCIP_Bool
Definition: def.h:84
static SCIP_DECL_NLHDLRDETECT(nlhdlrDetectSoc)
Definition: nlhdlr_soc.c:2290
void SCIPvarMarkRelaxationOnly(SCIP_VAR *var)
Definition: var.c:17556
constraint handler for nonlinear constraints specified by algebraic expressions
static SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrSoc)
Definition: nlhdlr_soc.c:2224
#define SCIP_DECL_NLHDLRINIT(x)
Definition: type_nlhdlr.h:96
#define MAX(x, y)
Definition: tclique_def.h:83
methods for debugging
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:85
#define nlhdlrExitSoc
Definition: nlhdlr_soc.c:2284
static SCIP_RETCODE generateCutSolDisagg(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, int disaggidx, SCIP_Real mincutviolation, SCIP_Real rhsval, SCIP_ROW **cut)
Definition: nlhdlr_soc.c:577
static SCIP_Real evalSingleTerm(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_SOL *sol, int k)
Definition: nlhdlr_soc.c:395
SCIP_Bool SCIPisExprPower(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1465
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip_cut.c:198
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
int SCIPgetExprNLocksPosNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1553
int SCIPhashmapGetNElements(SCIP_HASHMAP *hashmap)
Definition: misc.c:3473
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1667
#define NLHDLR_DESC
Definition: nlhdlr_soc.c:48
#define NLHDLR_NAME
Definition: nlhdlr_soc.c:47
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1421
SCIP_RETCODE SCIPhashsetInsert(SCIP_HASHSET *hashset, BMS_BLKMEM *blkmem, void *element)
Definition: misc.c:3740
SCIP_RETCODE SCIPincludeNlhdlrSoc(SCIP *scip)
Definition: nlhdlr_soc.c:2667
void SCIPnlhdlrSetInitExit(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINIT((*init)), SCIP_DECL_NLHDLREXIT((*exit_)))
Definition: nlhdlr.c:97
#define SCIP_Real
Definition: def.h:177
static SCIP_DECL_NLHDLRENFO(nlhdlrEnfoSoc)
Definition: nlhdlr_soc.c:2537
static SCIP_RETCODE detectSOC(SCIP *scip, SCIP_NLHDLRDATA *nlhdlrdata, SCIP_EXPR *expr, SCIP_Real conslhs, SCIP_Real consrhs, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_Bool *enforcebelow, SCIP_Bool *success)
Definition: nlhdlr_soc.c:2174
#define SCIP_INVALID
Definition: def.h:197
SCIP_NLHDLRDATA * SCIPnlhdlrGetData(SCIP_NLHDLR *nlhdlr)
Definition: nlhdlr.c:191
#define SCIP_DECL_NLHDLREXIT(x)
Definition: type_nlhdlr.h:105
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2152
struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
Definition: type_nlhdlr.h:404
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:280
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)
static SCIP_RETCODE checkAndCollectQuadratic(SCIP *scip, SCIP_EXPR *quadexpr, SCIP_HASHMAP *expr2idx, SCIP_EXPR **occurringexprs, int *nexprs, SCIP_Bool *success)
Definition: nlhdlr_soc.c:725
sum expression handler
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
Definition: misc_rowprep.c:881
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:102
SCIP_RETCODE SCIPisSOCNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Bool compeigenvalues, SCIP_Bool *success, SCIP_SIDETYPE *sidetype, SCIP_VAR ***vars, SCIP_Real **offsets, SCIP_Real **transcoefs, int **transcoefsidx, int **termbegins, int *nvars, int *nterms)
Definition: nlhdlr_soc.c:2724
SCIP_RETCODE SCIPdismantleExpr(SCIP *scip, FILE *file, SCIP_EXPR *expr)
Definition: scip_expr.c:1596
SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
#define SCIPallocClearBlockMemory(scip, ptr)
Definition: scip_mem.h:82
SCIPallocBlockMemory(scip, subsol))
static SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataSoc)
Definition: nlhdlr_soc.c:2248
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3221
public functions of nonlinear handlers of nonlinear constraints
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1382
static SCIP_DECL_NLHDLREXITSEPA(nlhdlrExitSepaSoc)
Definition: nlhdlr_soc.c:2521
SCIP_Longint SCIPgetNLPs(SCIP *scip)
#define SCIPABORT()
Definition: def.h:356
static SCIP_RETCODE freeNlhdlrExprData(SCIP *scip, SCIP_NLHDLREXPRDATA **nlhdlrexprdata)
Definition: nlhdlr_soc.c:368
SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
#define SCIP_NLHDLR_METHOD_SEPABOTH
Definition: type_nlhdlr.h:44
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1352
#define SCIP_NLHDLR_METHOD_SEPAABOVE
Definition: type_nlhdlr.h:43
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
static SCIP_RETCODE freeDisaggrVars(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata)
Definition: nlhdlr_soc.c:239
static SCIP_RETCODE generateCutSolSOC(SCIP *scip, SCIP_EXPR *expr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Real mincutviolation, SCIP_Real rhsval, SCIP_ROW **cut)
Definition: nlhdlr_soc.c:441
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
void SCIPnlhdlrSetCopyHdlr(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRCOPYHDLR((*copy)))
Definition: nlhdlr.c:63
enum SCIP_SideType SCIP_SIDETYPE
Definition: type_lp.h:58