SCIP

    Solving Constraint Integer Programs

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