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
205  	SCIP_RETCODE createDisaggrVars(
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,
227  	               SCIP_VARTYPE_CONTINUOUS) );
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
239  	SCIP_RETCODE freeDisaggrVars(
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
269  	SCIP_RETCODE createDisaggrRow(
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
322  	SCIP_RETCODE createNlhdlrExprData(
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
368  	SCIP_RETCODE freeNlhdlrExprData(
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
395  	SCIP_Real evalSingleTerm(
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
441  	SCIP_RETCODE generateCutSolSOC(
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 */
502  	   SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, SCIP_SIDETYPE_RIGHT, FALSE) );
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
577  	SCIP_RETCODE generateCutSolDisagg(
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 */
650  	   SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, SCIP_SIDETYPE_RIGHT, FALSE) );
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  	   {
(1) Event invalid_type: Argument "SCIPgetNLPs(scip)" to format specifier "%d" was expected to have type "int" but has type "long long". [details]
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
725  	SCIP_RETCODE checkAndCollectQuadratic(
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
840  	void buildQuadExprMatrix(
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
921  	SCIP_RETCODE tryFillNlhdlrExprDataQuad(
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
1148 	SCIP_RETCODE detectSocNorm(
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 	
1374 	         SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, squarearg, TRUE, FALSE, FALSE, FALSE) );
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
1432 	SCIP_RETCODE detectSocQuadraticSimple(
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 */
1733 	         SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, SCIPexprGetChildren(children[i])[0], TRUE, FALSE, FALSE, FALSE) );
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
1900 	SCIP_RETCODE detectSocQuadraticComplex(
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
2174 	SCIP_RETCODE detectSOC(
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
2261 	SCIP_DECL_NLHDLRINIT(nlhdlrInitSoc)
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
2276 	SCIP_DECL_NLHDLREXIT(nlhdlrExitSoc)
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 */
2667 	SCIP_RETCODE SCIPincludeNlhdlrSoc(
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);
2685 	   SCIPnlhdlrSetInitExit(nlhdlr, nlhdlrInitSoc, nlhdlrExitSoc);
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 	 */
2724 	SCIP_RETCODE SCIPisSOCNonlinear(
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() */
2814 	void SCIPfreeSOCArraysNonlinear(
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 	}
2844