Scippy

    SCIP

    Solving Constraint Integer Programs

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