SCIP

    Solving Constraint Integer Programs

    nlhdlr_bilinear.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file nlhdlr_bilinear.c
    26 * @ingroup DEFPLUGINS_NLHDLR
    27 * @brief bilinear nonlinear handler
    28 * @author Benjamin Mueller
    29 */
    30
    31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    32
    34#include "scip/cons_nonlinear.h"
    35#include "scip/expr_product.h"
    36#include "scip/expr_var.h"
    37
    38/* fundamental nonlinear handler properties */
    39#define NLHDLR_NAME "bilinear"
    40#define NLHDLR_DESC "bilinear handler for expressions"
    41#define NLHDLR_DETECTPRIORITY -10 /**< it is important that the nlhdlr runs after the default nldhlr */
    42#define NLHDLR_ENFOPRIORITY -10
    43
    44#define MIN_INTERIORITY 0.01 /**< minimum interiority for a reference point for applying separation */
    45#define MIN_ABSBOUNDSIZE 0.1 /**< minimum size of variable bounds for applying separation */
    46
    47/* properties of the bilinear nlhdlr statistics table */
    48#define TABLE_NAME_BILINEAR "nlhdlr_bilinear"
    49#define TABLE_DESC_BILINEAR "bilinear nlhdlr statistics table"
    50#define TABLE_POSITION_BILINEAR 14800 /**< the position of the statistics table */
    51#define TABLE_EARLIEST_STAGE_BILINEAR SCIP_STAGE_INITSOLVE /**< output of the statistics table is only printed from this stage onwards */
    52
    53
    54/*
    55 * Data structures
    56 */
    57
    58/** nonlinear handler expression data */
    59struct SCIP_NlhdlrExprData
    60{
    61 SCIP_Real underineqs[6]; /**< inequalities for underestimation */
    62 int nunderineqs; /**< total number of inequalities for underestimation */
    63 SCIP_Real overineqs[6]; /**< inequalities for overestimation */
    64 int noverineqs; /**< total number of inequalities for overestimation */
    65 SCIP_Longint lastnodeid; /**< id of the last node that has been used for separation */
    66 int nseparoundslastnode; /**< number of separation calls of the last node */
    67};
    68
    69/** nonlinear handler data */
    70struct SCIP_NlhdlrData
    71{
    72 SCIP_EXPR** exprs; /**< expressions that have been detected by the nlhdlr */
    73 int nexprs; /**< total number of expression that have been detected */
    74 int exprsize; /**< size of exprs array */
    75 SCIP_HASHMAP* exprmap; /**< hashmap to store the position of each expression in the exprs array */
    76
    77 /* parameter */
    78 SCIP_Bool useinteval; /**< whether to use the interval evaluation callback of the nlhdlr */
    79 SCIP_Bool usereverseprop; /**< whether to use the reverse propagation callback of the nlhdlr */
    80 int maxseparoundsroot; /**< maximum number of separation rounds in the root node */
    81 int maxseparounds; /**< maximum number of separation rounds in a local node */
    82 int maxsepadepth; /**< maximum depth to apply separation */
    83};
    84
    85/*
    86 * Local methods
    87 */
    88
    89/** helper function to compute the violation of an inequality of the form xcoef * x <= ycoef * y + constant for two
    90 * corner points of the domain [lbx,ubx] x [lby,uby]
    91 */
    92static
    94 SCIP_VAR* x, /**< first variable */
    95 SCIP_VAR* y, /**< second variable */
    96 SCIP_Real xcoef, /**< x-coefficient */
    97 SCIP_Real ycoef, /**< y-coefficient */
    98 SCIP_Real constant, /**< constant */
    99 SCIP_Real* viol1, /**< buffer to store the violation of the first corner point */
    100 SCIP_Real* viol2 /**< buffer to store the violation of the second corner point */
    101 )
    102{
    103 SCIP_Real norm;
    104 assert(viol1 != NULL);
    105 assert(viol2 != NULL);
    106
    107 norm = sqrt(SQR(xcoef) + SQR(ycoef));
    108
    109 /* inequality can be used for underestimating xy if and only if xcoef * ycoef > 0 */
    110 if( xcoef * ycoef >= 0 )
    111 {
    112 /* violation for top-left and bottom-right corner */
    113 *viol1 = MAX(0, (xcoef * SCIPvarGetLbLocal(x) - ycoef * SCIPvarGetUbLocal(y) - constant) / norm); /*lint !e666*/ /*lint !e661*/
    114 *viol2 = MAX(0, (xcoef * SCIPvarGetUbLocal(x) - ycoef * SCIPvarGetLbLocal(y) - constant) / norm); /*lint !e666*/ /*lint !e661*/
    115 }
    116 else
    117 {
    118 /* violation for top-right and bottom-left corner */
    119 *viol1 = MAX(0, (xcoef * SCIPvarGetUbLocal(x) - ycoef * SCIPvarGetUbLocal(y) - constant) / norm); /*lint !e666*/ /*lint !e661*/
    120 *viol2 = MAX(0, (xcoef * SCIPvarGetLbLocal(x) - ycoef * SCIPvarGetLbLocal(y) - constant) / norm); /*lint !e666*/ /*lint !e661*/
    121 }
    122}
    123
    124/** auxiliary function to decide whether to use inequalities for a strong relaxation of bilinear terms or not */
    125static
    127 SCIP* scip, /**< SCIP data structure */
    128 SCIP_VAR* x, /**< x variable */
    129 SCIP_VAR* y, /**< y variable */
    130 SCIP_Real refx, /**< reference point for x */
    131 SCIP_Real refy /**< reference point for y */
    132 )
    133{
    134 SCIP_Real lbx;
    135 SCIP_Real ubx;
    136 SCIP_Real lby;
    137 SCIP_Real uby;
    138 SCIP_Real interiorityx;
    139 SCIP_Real interiorityy;
    140 SCIP_Real interiority;
    141
    142 assert(x != NULL);
    143 assert(y != NULL);
    144 assert(x != y);
    145
    146 /* get variable bounds */
    147 lbx = SCIPvarGetLbLocal(x);
    148 ubx = SCIPvarGetUbLocal(x);
    149 lby = SCIPvarGetLbLocal(y);
    150 uby = SCIPvarGetUbLocal(y);
    151
    152 /* compute interiority */
    153 interiorityx = MIN(refx-lbx, ubx-refx) / MAX(ubx-lbx, SCIPepsilon(scip)); /*lint !e666*/
    154 interiorityy = MIN(refy-lby, uby-refy) / MAX(uby-lby, SCIPepsilon(scip)); /*lint !e666*/
    155 interiority = 2.0*MIN(interiorityx, interiorityy);
    156
    157 return ubx - lbx >= MIN_ABSBOUNDSIZE && uby - lby >= MIN_ABSBOUNDSIZE && interiority >= MIN_INTERIORITY;
    158}
    159
    160/** helper function to update the best relaxation for a bilinear term when using valid linear inequalities */
    161static
    163 SCIP* scip, /**< SCIP data structure */
    164 SCIP_VAR* RESTRICT x, /**< first variable */
    165 SCIP_VAR* RESTRICT y, /**< second variable */
    166 SCIP_Real bilincoef, /**< coefficient of the bilinear term */
    167 SCIP_SIDETYPE violside, /**< side of quadratic constraint that is violated */
    168 SCIP_Real refx, /**< reference point for the x variable */
    169 SCIP_Real refy, /**< reference point for the y variable */
    170 SCIP_Real* RESTRICT ineqs, /**< coefficients of each linear inequality; stored as triple (xcoef,ycoef,constant) */
    171 int nineqs, /**< total number of inequalities */
    172 SCIP_Real mccormickval, /**< value of the McCormick relaxation at the reference point */
    173 SCIP_Real* RESTRICT bestcoefx, /**< pointer to update the x coefficient */
    174 SCIP_Real* RESTRICT bestcoefy, /**< pointer to update the y coefficient */
    175 SCIP_Real* RESTRICT bestconst, /**< pointer to update the constant */
    176 SCIP_Real* RESTRICT bestval, /**< value of the best relaxation that have been found so far */
    177 SCIP_Bool* success /**< buffer to store whether we found a better relaxation */
    178 )
    179{
    180 SCIP_Real constshift[2] = {0.0, 0.0};
    181 SCIP_Real constant;
    182 SCIP_Real xcoef;
    183 SCIP_Real ycoef;
    184 SCIP_Real lbx;
    185 SCIP_Real ubx;
    186 SCIP_Real lby;
    187 SCIP_Real uby;
    188 SCIP_Bool update;
    189 SCIP_Bool overestimate;
    190 int i;
    191
    192 assert(x != y);
    193 assert(!SCIPisZero(scip, bilincoef));
    194 assert(nineqs >= 0 && nineqs <= 2);
    195 assert(bestcoefx != NULL);
    196 assert(bestcoefy != NULL);
    197 assert(bestconst != NULL);
    198 assert(bestval != NULL);
    199
    200 /* no inequalities available */
    201 if( nineqs == 0 )
    202 return;
    203 assert(ineqs != NULL);
    204
    205 lbx = SCIPvarGetLbLocal(x);
    206 ubx = SCIPvarGetUbLocal(x);
    207 lby = SCIPvarGetLbLocal(y);
    208 uby = SCIPvarGetUbLocal(y);
    209 overestimate = (violside == SCIP_SIDETYPE_LEFT);
    210
    211 /* check cases for which we can't compute a tighter relaxation */
    212 if( SCIPisFeasLE(scip, refx, lbx) || SCIPisFeasGE(scip, refx, ubx)
    213 || SCIPisFeasLE(scip, refy, lby) || SCIPisFeasGE(scip, refy, uby) )
    214 return;
    215
    216 /* due to the feasibility tolerances of the LP and NLP solver, it might possible that the reference point is
    217 * violating the linear inequalities; to ensure that we compute a valid underestimate, we relax the linear
    218 * inequality by changing its constant part
    219 */
    220 for( i = 0; i < nineqs; ++i )
    221 {
    222 constshift[i] = MAX(0.0, ineqs[3*i] * refx - ineqs[3*i+1] * refy - ineqs[3*i+2]);
    223 SCIPdebugMsg(scip, "constant shift of inequality %d = %.16f\n", i, constshift[i]);
    224 }
    225
    226 /* try to use both inequalities */
    227 if( nineqs == 2 )
    228 {
    229 SCIPcomputeBilinEnvelope2(scip, bilincoef, lbx, ubx, refx, lby, uby, refy, overestimate, ineqs[0], ineqs[1],
    230 ineqs[2] + constshift[0], ineqs[3], ineqs[4], ineqs[5] + constshift[1], &xcoef, &ycoef, &constant, &update);
    231
    232 if( update )
    233 {
    234 SCIP_Real val = xcoef * refx + ycoef * refy + constant;
    235 SCIP_Real relimpr = 1.0 - (REALABS(val - bilincoef * refx * refy) + 1e-4) / (REALABS(*bestval - bilincoef * refx * refy) + 1e-4);
    236 SCIP_Real absimpr = REALABS(val - (*bestval));
    237
    238 /* update relaxation if possible */
    239 if( relimpr > 0.05 && absimpr > 1e-3 && ((overestimate && SCIPisRelLT(scip, val, *bestval))
    240 || (!overestimate && SCIPisRelGT(scip, val, *bestval))) )
    241 {
    242 *bestcoefx = xcoef;
    243 *bestcoefy = ycoef;
    244 *bestconst = constant;
    245 *bestval = val;
    246 *success = TRUE;
    247 }
    248 }
    249 }
    250
    251 /* use inequalities individually */
    252 for( i = 0; i < nineqs; ++i )
    253 {
    254 SCIPcomputeBilinEnvelope1(scip, bilincoef, lbx, ubx, refx, lby, uby, refy, overestimate, ineqs[3*i], ineqs[3*i+1],
    255 ineqs[3*i+2] + constshift[i], &xcoef, &ycoef, &constant, &update);
    256
    257 if( update )
    258 {
    259 SCIP_Real val = xcoef * refx + ycoef * refy + constant;
    260 SCIP_Real relimpr = 1.0 - (REALABS(val - bilincoef * refx * refy) + 1e-4)
    261 / (REALABS(mccormickval - bilincoef * refx * refy) + 1e-4);
    262 SCIP_Real absimpr = REALABS(val - (*bestval));
    263
    264 /* update relaxation if possible */
    265 if( relimpr > 0.05 && absimpr > 1e-3 && ((overestimate && SCIPisRelLT(scip, val, *bestval))
    266 || (!overestimate && SCIPisRelGT(scip, val, *bestval))) )
    267 {
    268 *bestcoefx = xcoef;
    269 *bestcoefy = ycoef;
    270 *bestconst = constant;
    271 *bestval = val;
    272 *success = TRUE;
    273 }
    274 }
    275 }
    276}
    277
    278/** helper function to determine whether a given point satisfy given inequalities */
    279static
    281 SCIP* scip, /**< SCIP data structure */
    282 SCIP_Real x, /**< x-coordinate */
    283 SCIP_Real y, /**< y-coordinate */
    284 SCIP_Real lbx, /**< lower bound of x */
    285 SCIP_Real ubx, /**< upper bound of x */
    286 SCIP_Real lby, /**< lower bound of y */
    287 SCIP_Real uby, /**< upper bound of y */
    288 SCIP_Real* ineqs, /**< inequalities of the form coefx x <= coefy y + constant */
    289 int nineqs /**< total number of inequalities */
    290 )
    291{
    292 int i;
    293
    294 assert(ineqs != NULL);
    295 assert(nineqs > 0);
    296
    297 /* check whether point satisfies the bounds */
    298 if( SCIPisLT(scip, x, lbx) || SCIPisGT(scip, x, ubx)
    299 || SCIPisLT(scip, y, lby) || SCIPisGT(scip, y, uby) )
    300 return FALSE;
    301
    302 /* check whether point satisfy the linear inequalities */
    303 for( i = 0; i < nineqs; ++i )
    304 {
    305 SCIP_Real coefx = ineqs[3*i];
    306 SCIP_Real coefy = ineqs[3*i+1];
    307 SCIP_Real constant = ineqs[3*i+2];
    308
    309 /* TODO check with an absolute comparison? */
    310 if( SCIPisGT(scip, coefx*x - coefy*y - constant, 0.0) )
    311 return FALSE;
    312 }
    313
    314 return TRUE;
    315}
    316
    317/** helper function for computing all vertices of the polytope described by the linear inequalities and the local
    318 * extrema of the bilinear term along each inequality
    319 *
    320 * @note there are at most 22 points where the min/max can be achieved (given that there are at most 4 inequalities)
    321 * - corners of [lbx,ubx]x[lby,uby] (4)
    322 * - two intersection points for each inequality with the box (8)
    323 * - global maximum / minimum on each inequality (4)
    324 * - intersection between two inequalities (6)
    325 */
    326static
    328 SCIP* scip, /**< SCIP data structure */
    329 SCIP_CONSHDLR* conshdlr, /**< constraint handler, if levelset == TRUE, otherwise can be NULL */
    330 SCIP_EXPR* expr, /**< product expression */
    331 SCIP_INTERVAL exprbounds, /**< bounds on product expression, only used if levelset == TRUE */
    332 SCIP_Real* underineqs, /**< inequalities for underestimation */
    333 int nunderineqs, /**< total number of inequalities for underestimation */
    334 SCIP_Real* overineqs, /**< inequalities for overestimation */
    335 int noverineqs, /**< total number of inequalities for overestimation */
    336 SCIP_Bool levelset, /**< should the level set be considered? */
    337 SCIP_Real* xs, /**< array to store x-coordinates of computed points */
    338 SCIP_Real* ys, /**< array to store y-coordinates of computed points */
    339 int* npoints /**< buffer to store the total number of computed points */
    340 )
    341{
    342 SCIP_EXPR* child1;
    343 SCIP_EXPR* child2;
    344 SCIP_Real ineqs[12];
    345 SCIP_INTERVAL boundsx;
    346 SCIP_INTERVAL boundsy;
    347 SCIP_Real lbx;
    348 SCIP_Real ubx;
    349 SCIP_Real lby;
    350 SCIP_Real uby;
    351 int nineqs = 0;
    352 int i;
    353
    354 assert(scip != NULL);
    355 assert(conshdlr != NULL || !levelset);
    356 assert(expr != NULL);
    357 assert(xs != NULL);
    358 assert(ys != NULL);
    359 assert(SCIPexprGetNChildren(expr) == 2);
    360 assert(noverineqs + nunderineqs > 0);
    361 assert(noverineqs + nunderineqs <= 4);
    362
    363 *npoints = 0;
    364
    365 /* collect inequalities */
    366 for( i = 0; i < noverineqs; ++i )
    367 {
    368 SCIPdebugMsg(scip, "over-inequality %d: %g*x <= %g*y + %g\n", i, overineqs[3*i], overineqs[3*i+1], overineqs[3*i+2]);
    369 ineqs[3*nineqs] = overineqs[3*i];
    370 ineqs[3*nineqs+1] = overineqs[3*i+1];
    371 ineqs[3*nineqs+2] = overineqs[3*i+2];
    372 ++nineqs;
    373 }
    374 for( i = 0; i < nunderineqs; ++i )
    375 {
    376 SCIPdebugMsg(scip, "under-inequality %d: %g*x <= %g*y + %g 0\n", i, underineqs[3*i], underineqs[3*i+1], underineqs[3*i+2]);
    377 ineqs[3*nineqs] = underineqs[3*i];
    378 ineqs[3*nineqs+1] = underineqs[3*i+1];
    379 ineqs[3*nineqs+2] = underineqs[3*i+2];
    380 ++nineqs;
    381 }
    382 assert(nineqs == noverineqs + nunderineqs);
    383
    384 /* collect children */
    385 child1 = SCIPexprGetChildren(expr)[0];
    386 child2 = SCIPexprGetChildren(expr)[1];
    387 assert(child1 != NULL && child2 != NULL);
    388 assert(child1 != child2);
    389
    390 /* collect bounds of children */
    391 if( !levelset )
    392 {
    393 /* if called from inteval, then use activity */
    394 boundsx = SCIPexprGetActivity(child1);
    395 boundsy = SCIPexprGetActivity(child2);
    396 }
    397 else
    398 {
    399 /* if called from reverseprop, then use bounds */
    400 boundsx = SCIPgetExprBoundsNonlinear(scip, child1);
    401 boundsy = SCIPgetExprBoundsNonlinear(scip, child2);
    402
    403 /* if children bounds are empty, then returning with *npoints==0 is the way to go */
    406 return;
    407 }
    408 lbx = boundsx.inf;
    409 ubx = boundsx.sup;
    410 lby = boundsy.inf;
    411 uby = boundsy.sup;
    412 SCIPdebugMsg(scip, "x = [%g,%g], y=[%g,%g]\n", lbx, ubx, lby, uby);
    413
    414 /* corner points that satisfy all inequalities */
    415 for( i = 0; i < 4; ++i )
    416 {
    417 SCIP_Real cx = i < 2 ? lbx : ubx;
    418 SCIP_Real cy = (i % 2) == 0 ? lby : uby;
    419
    420 SCIPdebugMsg(scip, "corner point (%g,%g) feasible? %u\n", cx, cy, isPointFeasible(scip, cx, cy, lbx, ubx, lby, uby, ineqs, nineqs));
    421
    422 if( isPointFeasible(scip, cx, cy, lbx, ubx, lby, uby, ineqs, nineqs) )
    423 {
    424 xs[*npoints] = cx;
    425 ys[*npoints] = cy;
    426 ++(*npoints);
    427 }
    428 }
    429
    430 /* intersection point of inequalities with [lbx,ubx] x [lby,uby] and extremum of xy on each inequality */
    431 for( i = 0; i < nineqs; ++i )
    432 {
    433 SCIP_Real coefx = ineqs[3*i];
    434 SCIP_Real coefy = ineqs[3*i+1];
    435 SCIP_Real constant = ineqs[3*i+2];
    436 SCIP_Real px[5] = {lbx, ubx, (coefy*lby + constant)/coefx, (coefy*uby + constant)/coefx, 0.0};
    437 SCIP_Real py[5] = {(coefx*lbx - constant)/coefy, (coefx*ubx - constant)/coefy, lby, uby, 0.0};
    438 int j;
    439
    440 /* the last entry corresponds to the extremum of xy on the line */
    441 py[4] = (-constant) / (2.0 * coefy);
    442 px[4] = constant / (2.0 * coefx);
    443
    444 for( j = 0; j < 5; ++j )
    445 {
    446 SCIPdebugMsg(scip, "intersection point (%g,%g) feasible? %u\n", px[j], py[j], isPointFeasible(scip, px[j], py[j], lbx, ubx, lby, uby, ineqs, nineqs));
    447 if( isPointFeasible(scip, px[j], py[j], lbx, ubx, lby, uby, ineqs, nineqs) )
    448 {
    449 xs[*npoints] = px[j];
    450 ys[*npoints] = py[j];
    451 ++(*npoints);
    452 }
    453 }
    454 }
    455
    456 /* intersection point between two inequalities */
    457 for( i = 0; i < nineqs - 1; ++i )
    458 {
    459 SCIP_Real coefx1 = ineqs[3*i];
    460 SCIP_Real coefy1 = ineqs[3*i+1];
    461 SCIP_Real constant1 = ineqs[3*i+2];
    462 int j;
    463
    464 for( j = i + 1; j < nineqs; ++j )
    465 {
    466 SCIP_Real coefx2 = ineqs[3*j];
    467 SCIP_Real coefy2 = ineqs[3*j+1];
    468 SCIP_Real constant2 = ineqs[3*j+2];
    469 SCIP_Real px;
    470 SCIP_Real py;
    471
    472 /* no intersection point -> skip */
    473 if( SCIPisZero(scip, coefx2*coefy1 - coefx1 * coefy2) )
    474 continue;
    475
    476 py = (constant2 * coefx1 - constant1 * coefx2)/ (coefx2 * coefy1 - coefx1 * coefy2);
    477 px = (coefy1 * py + constant1) / coefx1;
    478 assert(SCIPisRelEQ(scip, px, (coefy2 * py + constant2) / coefx2));
    479
    480 if( isPointFeasible(scip, px, py, lbx, ubx, lby, uby, ineqs, nineqs) )
    481 {
    482 xs[*npoints] = px;
    483 ys[*npoints] = py;
    484 ++(*npoints);
    485 }
    486 }
    487 }
    488
    489 assert(*npoints <= 22);
    490
    491 /* consider the intersection of the level set with
    492 *
    493 * 1. the boundary of the box
    494 * 2. the linear inequalities
    495 *
    496 * this adds at most for 4 (level set curves) * 4 (inequalities) * 2 (intersection points) for all linear
    497 * inequalities and 4 (level set curves) * 2 (intersection points) with the boundary of the box
    498 */
    499 if( !levelset )
    500 return;
    501
    502 /* compute intersection of level sets with the boundary */
    503 for( i = 0; i < 2; ++i )
    504 {
    505 SCIP_Real vals[4] = {lbx, ubx, lby, uby};
    506 SCIP_Real val;
    507 int k;
    508
    509 /* fix auxiliary variable to its lower or upper bound and consider the coefficient of the product */
    510 val = (i == 0) ? exprbounds.inf : exprbounds.sup;
    511 val /= SCIPgetCoefExprProduct(expr);
    512
    513 for( k = 0; k < 4; ++k )
    514 {
    515 if( !SCIPisZero(scip, vals[k]) )
    516 {
    517 SCIP_Real res = val / vals[k];
    518
    519 assert(SCIPisRelGE(scip, SCIPgetCoefExprProduct(expr)*res*vals[k], exprbounds.inf));
    520 assert(SCIPisRelLE(scip, SCIPgetCoefExprProduct(expr)*res*vals[k], exprbounds.sup));
    521
    522 /* fix x to lbx or ubx */
    523 if( k < 2 && isPointFeasible(scip, vals[k], res, lbx, ubx, lby, uby, ineqs, nineqs) )
    524 {
    525 xs[*npoints] = vals[k];
    526 ys[*npoints] = res;
    527 ++(*npoints);
    528 }
    529 /* fix y to lby or uby */
    530 else if( k >= 2 && isPointFeasible(scip, res, vals[k], lbx, ubx, lby, uby, ineqs, nineqs) )
    531 {
    532 xs[*npoints] = res;
    533 ys[*npoints] = vals[k];
    534 ++(*npoints);
    535 }
    536 }
    537 }
    538 }
    539
    540 /* compute intersection points of level sets with the linear inequalities */
    541 for( i = 0; i < nineqs; ++i )
    542 {
    543 SCIP_INTERVAL result;
    544 SCIP_Real coefx = ineqs[3*i];
    545 SCIP_Real coefy = ineqs[3*i+1];
    546 SCIP_Real constant = ineqs[3*i+2];
    547 SCIP_INTERVAL sqrcoef;
    548 SCIP_INTERVAL lincoef;
    549 SCIP_Real px;
    550 SCIP_Real py;
    551 int k;
    552
    553 /* solve system of coefx x = coefy y + constant and X = xy which is the same as computing the solutions of
    554 *
    555 * (coefy / coefx) y^2 + (constant / coefx) y = inf(X) or sup(X)
    556 */
    557 SCIPintervalSet(&sqrcoef, coefy / coefx);
    558 SCIPintervalSet(&lincoef, constant / coefx);
    559
    560 for( k = 0; k < 2; ++k )
    561 {
    562 SCIP_INTERVAL rhs;
    563 SCIP_INTERVAL ybnds;
    564
    565 /* set right-hand side */
    566 if( k == 0 )
    567 SCIPintervalSet(&rhs, exprbounds.inf);
    568 else
    569 SCIPintervalSet(&rhs, exprbounds.sup);
    570
    571 SCIPintervalSetBounds(&ybnds, lby, uby);
    572 SCIPintervalSolveUnivariateQuadExpression(SCIP_INTERVAL_INFINITY, &result, sqrcoef, lincoef, rhs, ybnds);
    573
    574 /* interval is empty -> no solution available */
    576 continue;
    577
    578 /* compute and check point */
    579 py = SCIPintervalGetInf(result);
    580 px = (coefy * py + constant) / coefx;
    581
    582 if( isPointFeasible(scip, px, py, lbx, ubx, lby, uby, ineqs, nineqs) )
    583 {
    584 xs[*npoints] = px;
    585 ys[*npoints] = py;
    586 ++(*npoints);
    587 }
    588
    589 /* check for a second solution */
    590 if( SCIPintervalGetInf(result) != SCIPintervalGetSup(result) ) /*lint !e777*/
    591 {
    592 py = SCIPintervalGetSup(result);
    593 px = (coefy * py + constant) / coefx;
    594
    595 if( isPointFeasible(scip, px, py, lbx, ubx, lby, uby, ineqs, nineqs) )
    596 {
    597 xs[*npoints] = px;
    598 ys[*npoints] = py;
    599 ++(*npoints);
    600 }
    601 }
    602 }
    603 }
    604
    605 assert(*npoints <= 62);
    606}
    607
    608/** computes interval for a bilinear term when using at least one inequality */
    609static
    611 SCIP* scip, /**< SCIP data structure */
    612 SCIP_EXPR* expr, /**< product expression */
    613 SCIP_Real* underineqs, /**< inequalities for underestimation */
    614 int nunderineqs, /**< total number of inequalities for underestimation */
    615 SCIP_Real* overineqs, /**< inequalities for overestimation */
    616 int noverineqs /**< total number of inequalities for overestimation */
    617 )
    618{
    619 SCIP_INTERVAL interval = {0., 0.};
    620 SCIP_Real xs[22];
    621 SCIP_Real ys[22];
    622 SCIP_Real inf;
    623 SCIP_Real sup;
    624 int npoints;
    625 int i;
    626
    627 assert(scip != NULL);
    628 assert(expr != NULL);
    629 assert(SCIPexprGetNChildren(expr) == 2);
    630 assert(noverineqs + nunderineqs <= 4);
    631
    632 /* no inequalities available -> skip computation */
    633 if( noverineqs == 0 && nunderineqs == 0 )
    634 {
    636 return interval;
    637 }
    638
    639 /* x or y has empty interval -> empty */
    642 {
    643 SCIPintervalSetEmpty(&interval);
    644 return interval;
    645 }
    646
    647 /* compute all feasible points (since we use levelset == FALSE, the value of interval doesn't matter) */
    648 getFeasiblePointsBilinear(scip, NULL, expr, interval, underineqs, nunderineqs, overineqs,
    649 noverineqs, FALSE, xs, ys, &npoints);
    650
    651 /* no feasible point left -> return an empty interval */
    652 if( npoints == 0 )
    653 {
    654 SCIPintervalSetEmpty(&interval);
    655 return interval;
    656 }
    657
    658 /* compute the minimum and maximum over all computed points */
    659 inf = xs[0] * ys[0];
    660 sup = inf;
    661 SCIPdebugMsg(scip, "point 0: (%g,%g) -> inf = sup = %g\n", xs[0], ys[0], inf);
    662 for( i = 1; i < npoints; ++i )
    663 {
    664 inf = MIN(inf, xs[i] * ys[i]);
    665 sup = MAX(sup, xs[i] * ys[i]);
    666 SCIPdebugMsg(scip, "point %d: (%g,%g) -> inf = %g, sup = %g\n", i, xs[i], ys[i], inf, sup);
    667 }
    668 assert(inf <= sup);
    669
    670 /* adjust infinite values */
    671 inf = MAX(inf, -SCIP_INTERVAL_INFINITY);
    672 sup = MIN(sup, SCIP_INTERVAL_INFINITY);
    673
    674 /* multiply resulting interval with coefficient of the product expression */
    675 SCIPintervalSetBounds(&interval, inf, sup);
    676 if( SCIPgetCoefExprProduct(expr) != 1.0 )
    678
    679 return interval;
    680}
    681
    682/** uses inequalities for bilinear terms to get stronger bounds during reverse propagation */
    683static
    685 SCIP* scip, /**< SCIP data structure */
    686 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
    687 SCIP_EXPR* expr, /**< product expression */
    688 SCIP_INTERVAL exprbounds, /**< bounds on product expression */
    689 SCIP_Real* underineqs, /**< inequalities for underestimation */
    690 int nunderineqs, /**< total number of inequalities for underestimation */
    691 SCIP_Real* overineqs, /**< inequalities for overestimation */
    692 int noverineqs, /**< total number of inequalities for overestimation */
    693 SCIP_INTERVAL* intervalx, /**< buffer to store the new interval for x */
    694 SCIP_INTERVAL* intervaly /**< buffer to store the new interval for y */
    695 )
    696{
    697 SCIP_Real xs[62];
    698 SCIP_Real ys[62];
    699 SCIP_Real exprinf;
    700 SCIP_Real exprsup;
    701 SCIP_Bool first = TRUE;
    702 int npoints;
    703 int i;
    704
    705 assert(scip != NULL);
    706 assert(conshdlr != NULL);
    707 assert(expr != NULL);
    708 assert(intervalx != NULL);
    709 assert(intervaly != NULL);
    710 assert(SCIPexprGetNChildren(expr) == 2);
    711
    712 assert(noverineqs + nunderineqs > 0);
    713
    714 /* set intervals to be empty */
    715 SCIPintervalSetEmpty(intervalx);
    716 SCIPintervalSetEmpty(intervaly);
    717
    718 /* compute feasible points */
    719 getFeasiblePointsBilinear(scip, conshdlr, expr, exprbounds, underineqs, nunderineqs, overineqs,
    720 noverineqs, TRUE, xs, ys, &npoints);
    721
    722 /* no feasible points left -> problem is infeasible */
    723 if( npoints == 0 )
    724 return;
    725
    726 /* get bounds of the product expression */
    727 exprinf = exprbounds.inf;
    728 exprsup = exprbounds.sup;
    729
    730 /* update intervals with the computed points */
    731 for( i = 0; i < npoints; ++i )
    732 {
    733 SCIP_Real val = SCIPgetCoefExprProduct(expr) * xs[i] * ys[i];
    734
    735#ifndef NDEBUG
    736 {
    741
    742 assert(nunderineqs == 0 || isPointFeasible(scip, xs[i], ys[i], lbx, ubx, lby, uby, underineqs, nunderineqs));
    743 assert(noverineqs == 0 || isPointFeasible(scip, xs[i], ys[i], lbx, ubx, lby, uby, overineqs, noverineqs));
    744 }
    745#endif
    746
    747 /* only accept points for which the value of x*y is in the interval of the product expression
    748 *
    749 * NOTE: in order to consider all relevant points, we are a bit conservative here and relax the interval of
    750 * the expression by SCIPfeastol()
    751 */
    752 if( SCIPisRelGE(scip, val, exprinf - SCIPfeastol(scip)) && SCIPisRelLE(scip, val, exprsup + SCIPfeastol(scip)) )
    753 {
    754 if( first )
    755 {
    756 SCIPintervalSet(intervalx, xs[i]);
    757 SCIPintervalSet(intervaly, ys[i]);
    758 first = FALSE;
    759 }
    760 else
    761 {
    762 (*intervalx).inf = MIN((*intervalx).inf, xs[i]);
    763 (*intervalx).sup = MAX((*intervalx).sup, xs[i]);
    764 (*intervaly).inf = MIN((*intervaly).inf, ys[i]);
    765 (*intervaly).sup = MAX((*intervaly).sup, ys[i]);
    766 }
    767
    768 SCIPdebugMsg(scip, "consider points (%g,%g)=%g for reverse propagation\n", xs[i], ys[i], val);
    769 }
    770 }
    771}
    772
    773/** helper function to compute the convex envelope of a bilinear term when two linear inequalities are given; we
    774 * use the same notation and formulas as in Locatelli 2016
    775 */
    776static
    778 SCIP* scip, /**< SCIP data structure */
    779 SCIP_Real x, /**< reference point for x */
    780 SCIP_Real y, /**< reference point for y */
    781 SCIP_Real mi, /**< coefficient of x in the first linear inequality */
    782 SCIP_Real qi, /**< constant in the first linear inequality */
    783 SCIP_Real mj, /**< coefficient of x in the second linear inequality */
    784 SCIP_Real qj, /**< constant in the second linear inequality */
    785 SCIP_Real* RESTRICT xi, /**< buffer to store x coordinate of the first point */
    786 SCIP_Real* RESTRICT yi, /**< buffer to store y coordinate of the first point */
    787 SCIP_Real* RESTRICT xj, /**< buffer to store x coordinate of the second point */
    788 SCIP_Real* RESTRICT yj, /**< buffer to store y coordinate of the second point */
    789 SCIP_Real* RESTRICT xcoef, /**< buffer to store the x coefficient of the envelope */
    790 SCIP_Real* RESTRICT ycoef, /**< buffer to store the y coefficient of the envelope */
    791 SCIP_Real* RESTRICT constant /**< buffer to store the constant of the envelope */
    792 )
    793{
    794 SCIP_Real QUAD(xiq);
    795 SCIP_Real QUAD(yiq);
    796 SCIP_Real QUAD(xjq);
    797 SCIP_Real QUAD(yjq);
    798 SCIP_Real QUAD(xcoefq);
    799 SCIP_Real QUAD(ycoefq);
    800 SCIP_Real QUAD(constantq);
    801 SCIP_Real QUAD(tmpq);
    802
    803 assert(xi != NULL);
    804 assert(yi != NULL);
    805 assert(xj != NULL);
    806 assert(yj != NULL);
    807 assert(xcoef != NULL);
    808 assert(ycoef != NULL);
    809 assert(constant != NULL);
    810
    811 if( SCIPisEQ(scip, mi, mj) )
    812 {
    813 /* xi = (x + mi * y - qi) / (2.0*mi) */
    814 SCIPquadprecProdDD(xiq, mi, y);
    815 SCIPquadprecSumQD(xiq, xiq, x);
    816 SCIPquadprecSumQD(xiq, xiq, -qi);
    817 SCIPquadprecDivQD(xiq, xiq, 2.0 * mi);
    818 assert(EPSEQ((x + mi * y - qi) / (2.0*mi), QUAD_TO_DBL(xiq), 1e-3));
    819
    820 /* yi = mi*(*xi) + qi */
    821 SCIPquadprecProdQD(yiq, xiq, mi);
    822 SCIPquadprecSumQD(yiq, yiq, qi);
    823 assert(EPSEQ(mi*QUAD_TO_DBL(xiq) + qi, QUAD_TO_DBL(yiq), 1e-3));
    824
    825 /* xj = (*xi) + (qi - qj)/ (2.0*mi) */
    826 SCIPquadprecSumDD(xjq, qi, -qj);
    827 SCIPquadprecDivQD(xjq, xjq, 2.0 * mi);
    828 SCIPquadprecSumQQ(xjq, xjq, xiq);
    829 assert(EPSEQ(QUAD_TO_DBL(xiq) + (qi - qj)/ (2.0*mi), QUAD_TO_DBL(xjq), 1e-3));
    830
    831 /* yj = mj * (*xj) + qj */
    832 SCIPquadprecProdQD(yjq, xjq, mj);
    833 SCIPquadprecSumQD(yjq, yjq, qj);
    834 assert(EPSEQ(mj * QUAD_TO_DBL(xjq) + qj, QUAD_TO_DBL(yjq), 1e-3));
    835
    836 /* ycoef = (*xi) + (qi - qj) / (4.0*mi) note that this is wrong in Locatelli 2016 */
    837 SCIPquadprecSumDD(ycoefq, qi, -qj);
    838 SCIPquadprecDivQD(ycoefq, ycoefq, 4.0 * mi);
    839 SCIPquadprecSumQQ(ycoefq, ycoefq, xiq);
    840 assert(EPSEQ(QUAD_TO_DBL(xiq) + (qi - qj) / (4.0*mi), QUAD_TO_DBL(ycoefq), 1e-3));
    841
    842 /* xcoef = 2.0*mi*(*xi) - mi * (*ycoef) + qi */
    843 SCIPquadprecProdQD(xcoefq, xiq, 2.0 * mi);
    844 SCIPquadprecProdQD(tmpq, ycoefq, -mi);
    845 SCIPquadprecSumQQ(xcoefq, xcoefq, tmpq);
    846 SCIPquadprecSumQD(xcoefq, xcoefq, qi);
    847 assert(EPSEQ(2.0*mi*QUAD_TO_DBL(xiq) - mi * QUAD_TO_DBL(ycoefq) + qi, QUAD_TO_DBL(xcoefq), 1e-3));
    848
    849 /* constant = -mj*SQR(*xj) - (*ycoef) * qj */
    850 SCIPquadprecSquareQ(constantq, xjq);
    851 SCIPquadprecProdQD(constantq, constantq, -mj);
    852 SCIPquadprecProdQD(tmpq, ycoefq, -qj);
    853 SCIPquadprecSumQQ(constantq, constantq, tmpq);
    854 /* assert(EPSEQ(-mj*SQR(QUAD_TO_DBL(xjq)) - QUAD_TO_DBL(ycoefq) * qj, QUAD_TO_DBL(constantq), 1e-3)); */
    855
    856 *xi = QUAD_TO_DBL(xiq);
    857 *yi = QUAD_TO_DBL(yiq);
    858 *xj = QUAD_TO_DBL(xjq);
    859 *yj = QUAD_TO_DBL(yjq);
    860 *ycoef = QUAD_TO_DBL(ycoefq);
    861 *xcoef = QUAD_TO_DBL(xcoefq);
    862 *constant = QUAD_TO_DBL(constantq);
    863 }
    864 else if( mi > 0.0 )
    865 {
    866 assert(mj > 0.0);
    867
    868 /* xi = (y + sqrt(mi*mj)*x - qi) / (REALABS(mi) + sqrt(mi*mj)) */
    869 SCIPquadprecProdDD(xiq, mi, mj);
    870 SCIPquadprecSqrtQ(xiq, xiq);
    871 SCIPquadprecProdQD(xiq, xiq, x);
    872 SCIPquadprecSumQD(xiq, xiq, y);
    873 SCIPquadprecSumQD(xiq, xiq, -qi); /* (y + sqrt(mi*mj)*x - qi) */
    874 SCIPquadprecProdDD(tmpq, mi, mj);
    875 SCIPquadprecSqrtQ(tmpq, tmpq);
    876 SCIPquadprecSumQD(tmpq, tmpq, REALABS(mi)); /* REALABS(mi) + sqrt(mi*mj) */
    877 SCIPquadprecDivQQ(xiq, xiq, tmpq);
    878 assert(EPSEQ((y + sqrt(mi*mj)*x - qi) / (REALABS(mi) + sqrt(mi*mj)), QUAD_TO_DBL(xiq), 1e-3));
    879
    880 /* yi = mi*(*xi) + qi */
    881 SCIPquadprecProdQD(yiq, xiq, mi);
    882 SCIPquadprecSumQD(yiq, yiq, qi);
    883 assert(EPSEQ(mi*(QUAD_TO_DBL(xiq)) + qi, QUAD_TO_DBL(yiq), 1e-3));
    884
    885 /* xj = (y + sqrt(mi*mj)*x - qj) / (REALABS(mj) + sqrt(mi*mj)) */
    886 SCIPquadprecProdDD(xjq, mi, mj);
    887 SCIPquadprecSqrtQ(xjq, xjq);
    888 SCIPquadprecProdQD(xjq, xjq, x);
    889 SCIPquadprecSumQD(xjq, xjq, y);
    890 SCIPquadprecSumQD(xjq, xjq, -qj); /* (y + sqrt(mi*mj)*x - qj) */
    891 SCIPquadprecProdDD(tmpq, mi, mj);
    892 SCIPquadprecSqrtQ(tmpq, tmpq);
    893 SCIPquadprecSumQD(tmpq, tmpq, REALABS(mj)); /* REALABS(mj) + sqrt(mi*mj) */
    894 SCIPquadprecDivQQ(xjq, xjq, tmpq);
    895 assert(EPSEQ((y + sqrt(mi*mj)*x - qj) / (REALABS(mj) + sqrt(mi*mj)), QUAD_TO_DBL(xjq), 1e-3));
    896
    897 /* yj = mj*(*xj) + qj */
    898 SCIPquadprecProdQD(yjq, xjq, mj);
    899 SCIPquadprecSumQD(yjq, yjq, qj);
    900 assert(EPSEQ(mj*QUAD_TO_DBL(xjq) + qj, QUAD_TO_DBL(yjq), 1e-3));
    901
    902 /* ycoef = (2.0*mj*(*xj) + qj - 2.0*mi*(*xi) - qi) / (mj - mi) */
    903 SCIPquadprecProdQD(ycoefq, xjq, 2.0 * mj);
    904 SCIPquadprecSumQD(ycoefq, ycoefq, qj);
    905 SCIPquadprecProdQD(tmpq, xiq, -2.0 * mi);
    906 SCIPquadprecSumQQ(ycoefq, ycoefq, tmpq);
    907 SCIPquadprecSumQD(ycoefq, ycoefq, -qi);
    908 SCIPquadprecSumDD(tmpq, mj, -mi);
    909 SCIPquadprecDivQQ(ycoefq, ycoefq, tmpq);
    910 assert(EPSEQ((2.0*mj*QUAD_TO_DBL(xjq) + qj - 2.0*mi*QUAD_TO_DBL(xiq) - qi) / (mj - mi), QUAD_TO_DBL(ycoefq), 1e-3));
    911
    912 /* xcoef = 2.0*mj*(*xj) + qj - mj*(*ycoef) */
    913 SCIPquadprecProdQD(xcoefq, xjq, 2.0 * mj);
    914 SCIPquadprecSumQD(xcoefq, xcoefq, qj);
    915 SCIPquadprecProdQD(tmpq, ycoefq, -mj);
    916 SCIPquadprecSumQQ(xcoefq, xcoefq, tmpq);
    917 assert(EPSEQ(2.0*mj*QUAD_TO_DBL(xjq) + qj - mj*QUAD_TO_DBL(ycoefq), QUAD_TO_DBL(xcoefq), 1e-3));
    918
    919 /* constant = -mj*SQR(*xj) - (*ycoef) * qj */
    920 SCIPquadprecSquareQ(constantq, xjq);
    921 SCIPquadprecProdQD(constantq, constantq, -mj);
    922 SCIPquadprecProdQD(tmpq, ycoefq, -qj);
    923 SCIPquadprecSumQQ(constantq, constantq, tmpq);
    924 /* assert(EPSEQ(-mj*SQR(QUAD_TO_DBL(xjq)) - QUAD_TO_DBL(ycoefq) * qj, QUAD_TO_DBL(constantq), 1e-3)); */
    925
    926 *xi = QUAD_TO_DBL(xiq);
    927 *yi = QUAD_TO_DBL(yiq);
    928 *xj = QUAD_TO_DBL(xjq);
    929 *yj = QUAD_TO_DBL(yjq);
    930 *ycoef = QUAD_TO_DBL(ycoefq);
    931 *xcoef = QUAD_TO_DBL(xcoefq);
    932 *constant = QUAD_TO_DBL(constantq);
    933 }
    934 else
    935 {
    936 assert(mi < 0.0 && mj < 0.0);
    937
    938 /* apply variable transformation x = -x in case for overestimation */
    939 computeBilinEnvelope2(scip, -x, y, -mi, qi, -mj, qj, xi, yi, xj, yj, xcoef, ycoef, constant);
    940
    941 /* revert transformation; multiply cut by -1 and change -x by x */
    942 *xi = -(*xi);
    943 *xj = -(*xj);
    944 *ycoef = -(*ycoef);
    945 *constant = -(*constant);
    946 }
    947}
    948
    949/** output method of statistics table to output file stream 'file' */
    950static
    951SCIP_DECL_TABLEOUTPUT(tableOutputBilinear)
    952{ /*lint --e{715}*/
    953 SCIP_NLHDLR* nlhdlr;
    954 SCIP_NLHDLRDATA* nlhdlrdata;
    955 SCIP_CONSHDLR* conshdlr;
    956 SCIP_HASHMAP* hashmap;
    957 SCIP_EXPRITER* it;
    958 int resfound = 0;
    959 int restotal = 0;
    960 int c;
    961
    962 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
    963 assert(conshdlr != NULL);
    964 nlhdlr = SCIPfindNlhdlrNonlinear(conshdlr, NLHDLR_NAME);
    965 assert(nlhdlr != NULL);
    966 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    967 assert(nlhdlrdata != NULL);
    968
    969 /* allocate memory */
    970 SCIP_CALL( SCIPhashmapCreate(&hashmap, SCIPblkmem(scip), nlhdlrdata->nexprs) );
    972
    973 for( c = 0; c < nlhdlrdata->nexprs; ++c )
    974 {
    975 assert(!SCIPhashmapExists(hashmap, nlhdlrdata->exprs[c]));
    976 SCIP_CALL( SCIPhashmapInsertInt(hashmap, nlhdlrdata->exprs[c], 0) );
    977 }
    978
    979 /* count in how many constraints each expression is contained */
    980 for( c = 0; c < SCIPconshdlrGetNConss(conshdlr); ++c )
    981 {
    982 SCIP_CONS* cons = SCIPconshdlrGetConss(conshdlr)[c];
    983 SCIP_EXPR* expr;
    984
    986
    987 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) ) /*lint !e441*//*lint !e440*/
    988 {
    989 if( SCIPhashmapExists(hashmap, expr) )
    990 {
    991 int nuses = SCIPhashmapGetImageInt(hashmap, expr);
    992 SCIP_CALL( SCIPhashmapSetImageInt(hashmap, expr, nuses + 1) );
    993 }
    994 }
    995 }
    996
    997 /* compute success ratio */
    998 for( c = 0; c < nlhdlrdata->nexprs; ++c )
    999 {
    1000 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
    1001 int nuses;
    1002
    1003 nuses = SCIPhashmapGetImageInt(hashmap, nlhdlrdata->exprs[c]);
    1004 assert(nuses > 0);
    1005
    1006 nlhdlrexprdata = SCIPgetNlhdlrExprDataNonlinear(nlhdlr, nlhdlrdata->exprs[c]);
    1007 assert(nlhdlrexprdata != NULL);
    1008
    1009 if( nlhdlrexprdata->nunderineqs > 0 || nlhdlrexprdata->noverineqs > 0 )
    1010 resfound += nuses;
    1011 restotal += nuses;
    1012 }
    1013
    1014 /* print statistics */
    1015 SCIPinfoMessage(scip, file, "Bilinear Nlhdlr : %10s %10s\n", "#found", "#total");
    1016 SCIPinfoMessage(scip, file, " %-17s:", "");
    1017 SCIPinfoMessage(scip, file, " %10d", resfound);
    1018 SCIPinfoMessage(scip, file, " %10d", restotal);
    1019 SCIPinfoMessage(scip, file, "\n");
    1020
    1021 /* free memory */
    1022 SCIPfreeExpriter(&it);
    1023 SCIPhashmapFree(&hashmap);
    1024
    1025 return SCIP_OKAY;
    1026}
    1027
    1028/** collects bilinear nonlinear handler statistics into a SCIP_DATATREE object */
    1029static
    1030SCIP_DECL_TABLECOLLECT(tableCollectBilinear)
    1031{
    1032 SCIP_NLHDLR* nlhdlr;
    1033 SCIP_NLHDLRDATA* nlhdlrdata;
    1034 SCIP_CONSHDLR* conshdlr;
    1035 SCIP_HASHMAP* hashmap;
    1036 SCIP_EXPRITER* it;
    1037 int resfound = 0;
    1038 int restotal = 0;
    1039 int c;
    1040
    1041 assert(scip != NULL);
    1042 assert(table != NULL);
    1043 assert(datatree != NULL);
    1044
    1045 /* Find the nonlinear constraint handler */
    1046 conshdlr = SCIPfindConshdlr(scip, "nonlinear");
    1047 assert(conshdlr != NULL);
    1048
    1049 /* Find the bilinear nonlinear handler */
    1050 nlhdlr = SCIPfindNlhdlrNonlinear(conshdlr, NLHDLR_NAME);
    1051 assert(nlhdlr != NULL);
    1052
    1053 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1054 assert(nlhdlrdata != NULL);
    1055
    1056 /* Allocate memory */
    1057 SCIP_CALL( SCIPhashmapCreate(&hashmap, SCIPblkmem(scip), nlhdlrdata->nexprs) );
    1059
    1060 /* Initialize hashmap */
    1061 for( c = 0; c < nlhdlrdata->nexprs; ++c )
    1062 {
    1063 assert(!SCIPhashmapExists(hashmap, nlhdlrdata->exprs[c]));
    1064 SCIP_CALL( SCIPhashmapInsertInt(hashmap, nlhdlrdata->exprs[c], 0) );
    1065 }
    1066
    1067 /* Count occurrences of each expression in constraints */
    1068 for( c = 0; c < SCIPconshdlrGetNConss(conshdlr); ++c )
    1069 {
    1070 SCIP_CONS* cons = SCIPconshdlrGetConss(conshdlr)[c];
    1071 SCIP_EXPR* expr;
    1072
    1074
    1075 for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) ) /*lint !e441*//*lint !e440*/
    1076 {
    1077 if( SCIPhashmapExists(hashmap, expr) )
    1078 {
    1079 int nuses = SCIPhashmapGetImageInt(hashmap, expr);
    1080 SCIP_CALL( SCIPhashmapSetImageInt(hashmap, expr, nuses + 1) );
    1081 }
    1082 }
    1083 }
    1084
    1085 /* Compute success ratio */
    1086 for( c = 0; c < nlhdlrdata->nexprs; ++c )
    1087 {
    1088 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
    1089 int nuses;
    1090
    1091 nuses = SCIPhashmapGetImageInt(hashmap, nlhdlrdata->exprs[c]);
    1092 assert(nuses > 0);
    1093
    1094 nlhdlrexprdata = SCIPgetNlhdlrExprDataNonlinear(nlhdlr, nlhdlrdata->exprs[c]);
    1095 assert(nlhdlrexprdata != NULL);
    1096
    1097 if( nlhdlrexprdata->nunderineqs > 0 || nlhdlrexprdata->noverineqs > 0 )
    1098 resfound += nuses;
    1099 restotal += nuses;
    1100 }
    1101
    1102 /* Insert statistics into the data tree */
    1103 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "expressionsfound", resfound) );
    1104 SCIP_CALL( SCIPinsertDatatreeInt(scip, datatree, "expressionstotal", restotal) );
    1105
    1106 /* Free memory */
    1107 SCIPfreeExpriter(&it);
    1108 SCIPhashmapFree(&hashmap);
    1109
    1110 return SCIP_OKAY;
    1111}
    1112
    1113
    1114/*
    1115 * Callback methods of nonlinear handler
    1116 */
    1117
    1118/** nonlinear handler copy callback */
    1119static
    1120SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrBilinear)
    1121{ /*lint --e{715}*/
    1122 assert(targetscip != NULL);
    1123 assert(sourcenlhdlr != NULL);
    1124
    1126
    1127 SCIP_CALL( SCIPincludeNlhdlrBilinear(targetscip) );
    1128
    1129 return SCIP_OKAY;
    1130}
    1131
    1132/** callback to free data of handler */
    1133static
    1134SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataBilinear)
    1135{ /*lint --e{715}*/
    1136 assert(nlhdlrdata != NULL);
    1137 assert((*nlhdlrdata)->nexprs == 0);
    1138
    1139 if( (*nlhdlrdata)->exprmap != NULL )
    1140 {
    1141 assert(SCIPhashmapGetNElements((*nlhdlrdata)->exprmap) == 0);
    1142 SCIPhashmapFree(&(*nlhdlrdata)->exprmap);
    1143 }
    1144
    1145 SCIPfreeBlockMemoryArrayNull(scip, &(*nlhdlrdata)->exprs, (*nlhdlrdata)->exprsize);
    1146 SCIPfreeBlockMemory(scip, nlhdlrdata);
    1147
    1148 return SCIP_OKAY;
    1149}
    1150
    1151/** callback to free expression specific data */
    1152static
    1153SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataBilinear)
    1154{ /*lint --e{715}*/
    1155 SCIP_NLHDLRDATA* nlhdlrdata;
    1156 int pos;
    1157
    1158 assert(expr != NULL);
    1159
    1160 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1161 assert(nlhdlrdata != NULL);
    1162 assert(nlhdlrdata->nexprs > 0);
    1163 assert(nlhdlrdata->exprs != NULL);
    1164 assert(nlhdlrdata->exprmap != NULL);
    1165 assert(SCIPhashmapExists(nlhdlrdata->exprmap, (void*)expr));
    1166
    1167 pos = SCIPhashmapGetImageInt(nlhdlrdata->exprmap, (void*)expr);
    1168 assert(pos >= 0 && pos < nlhdlrdata->nexprs);
    1169 assert(nlhdlrdata->exprs[pos] == expr);
    1170
    1171 /* move the last expression to the free position */
    1172 if( nlhdlrdata->nexprs > 0 && pos != nlhdlrdata->nexprs - 1 )
    1173 {
    1174 SCIP_EXPR* lastexpr = nlhdlrdata->exprs[nlhdlrdata->nexprs - 1];
    1175 assert(expr != lastexpr);
    1176 assert(SCIPhashmapExists(nlhdlrdata->exprmap, (void*)lastexpr));
    1177
    1178 nlhdlrdata->exprs[pos] = lastexpr;
    1179 nlhdlrdata->exprs[nlhdlrdata->nexprs - 1] = NULL;
    1180 SCIP_CALL( SCIPhashmapSetImageInt(nlhdlrdata->exprmap, (void*)lastexpr, pos) );
    1181 }
    1182
    1183 /* remove expression from the nonlinear handler data */
    1184 SCIP_CALL( SCIPhashmapRemove(nlhdlrdata->exprmap, (void*)expr) );
    1185 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
    1186 --nlhdlrdata->nexprs;
    1187
    1188 /* free nonlinear handler expression data */
    1189 SCIPfreeBlockMemoryNull(scip, nlhdlrexprdata);
    1190
    1191 return SCIP_OKAY;
    1192}
    1193
    1194/** callback to be called in initialization */
    1195#define nlhdlrInitBilinear NULL
    1196
    1197/** callback to be called in deinitialization */
    1198static
    1199SCIP_DECL_NLHDLREXIT(nlhdlrExitBilinear)
    1200{ /*lint --e{715}*/
    1201 assert(SCIPnlhdlrGetData(nlhdlr) != NULL);
    1202 assert(SCIPnlhdlrGetData(nlhdlr)->nexprs == 0);
    1203
    1204 return SCIP_OKAY;
    1205}
    1206
    1207/** callback to detect structure in expression tree */
    1208static
    1209SCIP_DECL_NLHDLRDETECT(nlhdlrDetectBilinear)
    1210{ /*lint --e{715}*/
    1211 SCIP_NLHDLRDATA* nlhdlrdata;
    1212
    1213 assert(expr != NULL);
    1214 assert(participating != NULL);
    1215
    1216 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1217 assert(nlhdlrdata);
    1218
    1219 /* only during solving will we have the extra inequalities that we rely on so much here */
    1221 return SCIP_OKAY;
    1222
    1223 /* check for product expressions with two children */
    1224 if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2
    1225 && (nlhdlrdata->exprmap == NULL || !SCIPhashmapExists(nlhdlrdata->exprmap, (void*)expr)) )
    1226 {
    1227 SCIP_EXPR** children;
    1228 SCIP_Bool valid;
    1229 int c;
    1230
    1231 children = SCIPexprGetChildren(expr);
    1232 assert(children != NULL);
    1233
    1234 /* detection is only successful if both children will have auxiliary variable or are variables
    1235 * that are not binary variables */
    1236 valid = TRUE;
    1237 for( c = 0; c < 2; ++c )
    1238 {
    1239 assert(children[c] != NULL);
    1240 if( SCIPgetExprNAuxvarUsesNonlinear(children[c]) == 0 &&
    1241 (!SCIPisExprVar(scip, children[c]) || SCIPvarIsBinary(SCIPgetVarExprVar(children[c]))) )
    1242 {
    1243 valid = FALSE;
    1244 break;
    1245 }
    1246 }
    1247
    1248 if( valid )
    1249 {
    1250 /* create expression data for the nonlinear handler */
    1251 SCIP_CALL( SCIPallocClearBlockMemory(scip, nlhdlrexprdata) );
    1252 (*nlhdlrexprdata)->lastnodeid = -1;
    1253
    1254 /* ensure that there is enough memory to store the detected expression */
    1255 if( nlhdlrdata->exprsize < nlhdlrdata->nexprs + 1 )
    1256 {
    1257 int newsize = SCIPcalcMemGrowSize(scip, nlhdlrdata->nexprs + 1);
    1258 assert(newsize > nlhdlrdata->exprsize);
    1259
    1260 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &nlhdlrdata->exprs, nlhdlrdata->exprsize, newsize) );
    1261 nlhdlrdata->exprsize = newsize;
    1262 }
    1263
    1264 /* create expression map, if not done so far */
    1265 if( nlhdlrdata->exprmap == NULL )
    1266 {
    1267 SCIP_CALL( SCIPhashmapCreate(&nlhdlrdata->exprmap, SCIPblkmem(scip), SCIPgetNVars(scip)) );
    1268 }
    1269
    1270#ifndef NDEBUG
    1271 {
    1272 int i;
    1273
    1274 for( i = 0; i < nlhdlrdata->nexprs; ++i )
    1275 assert(nlhdlrdata->exprs[i] != expr);
    1276 }
    1277#endif
    1278
    1279 /* add expression to nlhdlrdata and capture it */
    1280 nlhdlrdata->exprs[nlhdlrdata->nexprs] = expr;
    1281 SCIPcaptureExpr(expr);
    1282 SCIP_CALL( SCIPhashmapInsertInt(nlhdlrdata->exprmap, (void*)expr, nlhdlrdata->nexprs) );
    1283 ++nlhdlrdata->nexprs;
    1284
    1285 /* tell children that we will use their auxvar and use its activity for both estimate and domain propagation */
    1286 SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, children[0], TRUE, nlhdlrdata->useinteval
    1287 || nlhdlrdata->usereverseprop, TRUE, TRUE) );
    1288 SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, children[1], TRUE, nlhdlrdata->useinteval
    1289 || nlhdlrdata->usereverseprop, TRUE, TRUE) );
    1290 }
    1291 }
    1292
    1293 if( *nlhdlrexprdata != NULL )
    1294 {
    1295 /* we want to join separation and domain propagation, if not disabled by parameter */
    1296 *participating = SCIP_NLHDLR_METHOD_SEPABOTH;
    1297 if( nlhdlrdata->useinteval || nlhdlrdata->usereverseprop )
    1298 *participating |= SCIP_NLHDLR_METHOD_ACTIVITY;
    1299 }
    1300
    1301#ifdef SCIP_DEBUG
    1302 if( *participating )
    1303 {
    1304 SCIPdebugMsg(scip, "detected expr ");
    1305 SCIPprintExpr(scip, expr, NULL);
    1306 SCIPinfoMessage(scip, NULL, " participating: %d\n", *participating);
    1307 }
    1308#endif
    1309
    1310 return SCIP_OKAY;
    1311}
    1312
    1313/** auxiliary evaluation callback of nonlinear handler */
    1314static
    1315SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxBilinear)
    1316{ /*lint --e{715}*/
    1317 SCIP_VAR* var1;
    1318 SCIP_VAR* var2;
    1319 SCIP_Real coef;
    1320
    1321 assert(SCIPisExprProduct(scip, expr));
    1322 assert(SCIPexprGetNChildren(expr) == 2);
    1323
    1325 assert(var1 != NULL);
    1327 assert(var2 != NULL);
    1328 coef = SCIPgetCoefExprProduct(expr);
    1329
    1330 *auxvalue = coef * SCIPgetSolVal(scip, sol, var1) * SCIPgetSolVal(scip, sol, var2);
    1331
    1332 return SCIP_OKAY;
    1333}
    1334
    1335/** separation initialization method of a nonlinear handler (called during CONSINITLP) */
    1336#define nlhdlrInitSepaBilinear NULL
    1337
    1338/** separation deinitialization method of a nonlinear handler (called during CONSEXITSOL) */
    1339#define nlhdlrExitSepaBilinear NULL
    1340
    1341/** nonlinear handler separation callback */
    1342#define nlhdlrEnfoBilinear NULL
    1343
    1344/** nonlinear handler under/overestimation callback */
    1345static
    1346SCIP_DECL_NLHDLRESTIMATE(nlhdlrEstimateBilinear)
    1347{ /*lint --e{715}*/
    1348 SCIP_NLHDLRDATA* nlhdlrdata;
    1349 SCIP_VAR* x;
    1350 SCIP_VAR* y;
    1351 SCIP_VAR* auxvar;
    1352 SCIP_Real lincoefx = 0.0;
    1353 SCIP_Real lincoefy = 0.0;
    1354 SCIP_Real linconstant = 0.0;
    1355 SCIP_Real refpointx;
    1356 SCIP_Real refpointy;
    1357 SCIP_Real violation;
    1358 SCIP_Longint nodeid;
    1359 SCIP_Bool mccsuccess = TRUE;
    1360 SCIP_ROWPREP* rowprep;
    1361
    1362 assert(rowpreps != NULL);
    1363
    1364 *success = FALSE;
    1365 *addedbranchscores = FALSE;
    1366
    1367 /* check whether an inequality is available */
    1368 if( nlhdlrexprdata->noverineqs == 0 && nlhdlrexprdata->nunderineqs == 0 )
    1369 return SCIP_OKAY;
    1370
    1371 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1372 assert(nlhdlrdata != NULL);
    1373
    1375
    1376 /* update last node */
    1377 if( nlhdlrexprdata->lastnodeid != nodeid )
    1378 {
    1379 nlhdlrexprdata->lastnodeid = nodeid;
    1380 nlhdlrexprdata->nseparoundslastnode = 0;
    1381 }
    1382
    1383 /* update separation round */
    1384 ++nlhdlrexprdata->nseparoundslastnode;
    1385
    1386 /* check working limits */
    1387 if( (SCIPgetDepth(scip) == 0 && nlhdlrexprdata->nseparoundslastnode > nlhdlrdata->maxseparoundsroot)
    1388 || (SCIPgetDepth(scip) > 0 && nlhdlrexprdata->nseparoundslastnode > nlhdlrdata->maxseparounds)
    1389 || SCIPgetDepth(scip) > nlhdlrdata->maxsepadepth )
    1390 return SCIP_OKAY;
    1391
    1392 /* collect variables */
    1394 assert(x != NULL);
    1396 assert(y != NULL);
    1397 auxvar = SCIPgetExprAuxVarNonlinear(expr);
    1398 assert(auxvar != NULL);
    1399
    1400 /* get and adjust the reference points */
    1401 refpointx = MIN(MAX(SCIPgetSolVal(scip, sol, x), SCIPvarGetLbLocal(x)),SCIPvarGetUbLocal(x)); /*lint !e666*/
    1402 refpointy = MIN(MAX(SCIPgetSolVal(scip, sol, y), SCIPvarGetLbLocal(y)),SCIPvarGetUbLocal(y)); /*lint !e666*/
    1403 assert(SCIPisLE(scip, refpointx, SCIPvarGetUbLocal(x)) && SCIPisGE(scip, refpointx, SCIPvarGetLbLocal(x)));
    1404 assert(SCIPisLE(scip, refpointy, SCIPvarGetUbLocal(y)) && SCIPisGE(scip, refpointy, SCIPvarGetLbLocal(y)));
    1405
    1406 /* use McCormick inequalities to decide whether we want to separate or not */
    1408 SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y), refpointy, overestimate, &lincoefx, &lincoefy, &linconstant,
    1409 &mccsuccess);
    1410
    1411 /* too large values in McCormick inequalities -> skip */
    1412 if( !mccsuccess )
    1413 return SCIP_OKAY;
    1414
    1415 /* compute violation for the McCormick relaxation */
    1416 violation = lincoefx * refpointx + lincoefy * refpointy + linconstant - SCIPgetSolVal(scip, sol, auxvar);
    1417 if( overestimate )
    1418 violation = -violation;
    1419
    1420 /* only use a tighter relaxations if McCormick does not separate the reference point */
    1421 if( SCIPisFeasLE(scip, violation, 0.0) && useBilinIneqs(scip, x, y, refpointx, refpointy) )
    1422 {
    1423 SCIP_Bool useoverestineq = SCIPgetCoefExprProduct(expr) > 0.0 ? overestimate : !overestimate;
    1424 SCIP_Real mccormickval = lincoefx * refpointx + lincoefy * refpointy + linconstant;
    1425 SCIP_Real* ineqs;
    1426 SCIP_Real bestval;
    1427 int nineqs;
    1428
    1429 /* McCormick relaxation is too weak */
    1430 bestval = mccormickval;
    1431
    1432 /* get the inequalities that might lead to a tighter relaxation */
    1433 if( useoverestineq )
    1434 {
    1435 ineqs = nlhdlrexprdata->overineqs;
    1436 nineqs = nlhdlrexprdata->noverineqs;
    1437 }
    1438 else
    1439 {
    1440 ineqs = nlhdlrexprdata->underineqs;
    1441 nineqs = nlhdlrexprdata->nunderineqs;
    1442 }
    1443
    1444 /* use linear inequalities to update relaxation */
    1446 overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT,
    1447 refpointx, refpointy, ineqs, nineqs, mccormickval,
    1448 &lincoefx, &lincoefy, &linconstant, &bestval,
    1449 success);
    1450
    1451#ifndef NDEBUG
    1452 /* check whether cut is really valid */
    1453 if( *success )
    1454 {
    1455 assert(!overestimate || SCIPisLE(scip, bestval, mccormickval));
    1456 assert(overestimate || SCIPisGE(scip, bestval, mccormickval));
    1457 }
    1458#endif
    1459 }
    1460
    1461 if( *success )
    1462 {
    1464 SCIProwprepAddConstant(rowprep, linconstant);
    1465 SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, 2) );
    1466 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, x, lincoefx) );
    1467 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, y, lincoefy) );
    1468 SCIP_CALL( SCIPsetPtrarrayVal(scip, rowpreps, 0, rowprep) );
    1469 }
    1470
    1471 return SCIP_OKAY;
    1472}
    1473
    1474/** nonlinear handler interval evaluation callback */
    1475static
    1476SCIP_DECL_NLHDLRINTEVAL(nlhdlrIntevalBilinear)
    1477{ /*lint --e{715}*/
    1478 SCIP_NLHDLRDATA* nlhdlrdata;
    1479 assert(nlhdlrexprdata != NULL);
    1480
    1481 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1482 assert(nlhdlrdata != NULL);
    1483
    1484 if( nlhdlrdata->useinteval && nlhdlrexprdata->nunderineqs + nlhdlrexprdata->noverineqs > 0 )
    1485 {
    1486 SCIP_INTERVAL tmp = intevalBilinear(scip, expr, nlhdlrexprdata->underineqs, nlhdlrexprdata->nunderineqs,
    1487 nlhdlrexprdata->overineqs, nlhdlrexprdata->noverineqs);
    1488
    1489 /* intersect intervals if we have learned a tighter interval */
    1490 if( SCIPisGT(scip, tmp.inf, (*interval).inf) || SCIPisLT(scip, tmp.sup, (*interval).sup) )
    1491 SCIPintervalIntersect(interval, *interval, tmp);
    1492 }
    1493
    1494 return SCIP_OKAY;
    1495}
    1496
    1497/** nonlinear handler callback for reverse propagation */
    1498static
    1499SCIP_DECL_NLHDLRREVERSEPROP(nlhdlrReversepropBilinear)
    1500{ /*lint --e{715}*/
    1501 SCIP_NLHDLRDATA* nlhdlrdata;
    1502
    1503 assert(nlhdlrexprdata != NULL);
    1504
    1505 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1506 assert(nlhdlrdata != NULL);
    1507
    1508 if( nlhdlrdata->usereverseprop && nlhdlrexprdata->nunderineqs + nlhdlrexprdata->noverineqs > 0 )
    1509 {
    1510 SCIP_EXPR* childx;
    1511 SCIP_EXPR* childy;
    1512 SCIP_INTERVAL intervalx;
    1513 SCIP_INTERVAL intervaly;
    1514
    1515 assert(SCIPexprGetNChildren(expr) == 2);
    1516 childx = SCIPexprGetChildren(expr)[0];
    1517 childy = SCIPexprGetChildren(expr)[1];
    1518 assert(childx != NULL && childy != NULL);
    1519
    1522
    1523 /* compute bounds on x and y */
    1524 reversePropBilinear(scip, conshdlr, expr, bounds, nlhdlrexprdata->underineqs, nlhdlrexprdata->nunderineqs,
    1525 nlhdlrexprdata->overineqs, nlhdlrexprdata->noverineqs, &intervalx, &intervaly);
    1526
    1527 /* tighten bounds of x */
    1528 SCIPdebugMsg(scip, "try to tighten bounds of x: [%g,%g] -> [%g,%g]\n",
    1530 intervalx.inf, intervalx.sup);
    1531
    1532 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[0], intervalx, infeasible,
    1533 nreductions) );
    1534
    1535 if( !(*infeasible) )
    1536 {
    1537 /* tighten bounds of y */
    1538 SCIPdebugMsg(scip, "try to tighten bounds of y: [%g,%g] -> [%g,%g]\n",
    1540 intervaly.inf, intervaly.sup);
    1542 infeasible, nreductions) );
    1543 }
    1544 }
    1545
    1546 return SCIP_OKAY;
    1547}
    1548
    1549/*
    1550 * nonlinear handler specific interface methods
    1551 */
    1552
    1553/** includes bilinear nonlinear handler in nonlinear constraint handler */
    1555 SCIP* scip /**< SCIP data structure */
    1556 )
    1557{
    1558 SCIP_NLHDLRDATA* nlhdlrdata;
    1559 SCIP_NLHDLR* nlhdlr;
    1560
    1561 assert(scip != NULL);
    1562
    1563 /**! [SnippetIncludeNlhdlrBilinear] */
    1564 /* create nonlinear handler specific data */
    1565 SCIP_CALL( SCIPallocBlockMemory(scip, &nlhdlrdata) );
    1566 BMSclearMemory(nlhdlrdata);
    1567
    1569 NLHDLR_ENFOPRIORITY, nlhdlrDetectBilinear, nlhdlrEvalauxBilinear, nlhdlrdata) );
    1570 assert(nlhdlr != NULL);
    1571
    1572 SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrBilinear);
    1573 SCIPnlhdlrSetFreeHdlrData(nlhdlr, nlhdlrFreehdlrdataBilinear);
    1574 SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrFreeExprDataBilinear);
    1575 SCIPnlhdlrSetInitExit(nlhdlr, nlhdlrInitBilinear, nlhdlrExitBilinear);
    1577 SCIPnlhdlrSetProp(nlhdlr, nlhdlrIntevalBilinear, nlhdlrReversepropBilinear);
    1578
    1579 /* parameters */
    1580 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/useinteval",
    1581 "whether to use the interval evaluation callback of the nlhdlr",
    1582 &nlhdlrdata->useinteval, FALSE, TRUE, NULL, NULL) );
    1583
    1584 SCIP_CALL( SCIPaddBoolParam(scip, "nlhdlr/" NLHDLR_NAME "/usereverseprop",
    1585 "whether to use the reverse propagation callback of the nlhdlr",
    1586 &nlhdlrdata->usereverseprop, FALSE, TRUE, NULL, NULL) );
    1587
    1588 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/maxseparoundsroot",
    1589 "maximum number of separation rounds in the root node",
    1590 &nlhdlrdata->maxseparoundsroot, FALSE, 10, 0, INT_MAX, NULL, NULL) );
    1591
    1592 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/maxseparounds",
    1593 "maximum number of separation rounds in a local node",
    1594 &nlhdlrdata->maxseparounds, FALSE, 1, 0, INT_MAX, NULL, NULL) );
    1595
    1596 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/maxsepadepth",
    1597 "maximum depth to apply separation",
    1598 &nlhdlrdata->maxsepadepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
    1599
    1600 /* statistic table */
    1603 NULL, NULL, NULL, NULL, NULL, NULL, tableOutputBilinear, tableCollectBilinear,
    1605 /**! [SnippetIncludeNlhdlrBilinear] */
    1606
    1607 return SCIP_OKAY;
    1608}
    1609
    1610/** returns an array of expressions that have been detected by the bilinear nonlinear handler */
    1612 SCIP_NLHDLR* nlhdlr /**< nonlinear handler */
    1613 )
    1614{
    1615 SCIP_NLHDLRDATA* nlhdlrdata;
    1616
    1617 assert(nlhdlr != NULL);
    1618
    1620
    1621 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1622 assert(nlhdlrdata);
    1623
    1624 return nlhdlrdata->exprs;
    1625}
    1626
    1627/** returns the total number of expressions that have been detected by the bilinear nonlinear handler */
    1629 SCIP_NLHDLR* nlhdlr /**< nonlinear handler */
    1630 )
    1631{
    1632 SCIP_NLHDLRDATA* nlhdlrdata;
    1633
    1634 assert(nlhdlr != NULL);
    1635
    1637
    1638 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    1639 assert(nlhdlrdata);
    1640
    1641 return nlhdlrdata->nexprs;
    1642}
    1643
    1644/** adds a globally valid inequality of the form \f$\text{xcoef}\cdot x \leq \text{ycoef} \cdot y + \text{constant}\f$ to a product expression of the form \f$x\cdot y\f$ */
    1646 SCIP* scip, /**< SCIP data structure */
    1647 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
    1648 SCIP_EXPR* expr, /**< product expression */
    1649 SCIP_Real xcoef, /**< x coefficient */
    1650 SCIP_Real ycoef, /**< y coefficient */
    1651 SCIP_Real constant, /**< constant part */
    1652 SCIP_Bool* success /**< buffer to store whether inequality has been accepted */
    1653 )
    1654{
    1655 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
    1656 SCIP_VAR* x;
    1657 SCIP_VAR* y;
    1658 SCIP_Real* ineqs;
    1659 SCIP_Real viol1;
    1660 SCIP_Real viol2;
    1661 SCIP_Bool underestimate;
    1662 int nineqs;
    1663 int i;
    1664
    1665 assert(scip != NULL);
    1666 assert(nlhdlr != NULL);
    1667 assert(expr != NULL);
    1668 assert(SCIPexprGetNChildren(expr) == 2);
    1669 assert(xcoef != SCIP_INVALID); /*lint !e777 */
    1670 assert(ycoef != SCIP_INVALID); /*lint !e777 */
    1671 assert(constant != SCIP_INVALID); /*lint !e777 */
    1672 assert(success != NULL);
    1673
    1675
    1676 *success = FALSE;
    1677
    1678 /* find nonlinear handler expression handler data */
    1679 nlhdlrexprdata = SCIPgetNlhdlrExprDataNonlinear(nlhdlr, expr);
    1680
    1681 if( nlhdlrexprdata == NULL )
    1682 {
    1683 SCIPwarningMessage(scip, "nonlinear expression data has not been found. "
    1684 "Skip SCIPaddConsExprExprProductBilinearIneq()\n");
    1685 return SCIP_OKAY;
    1686 }
    1687
    1688 /* ignore inequalities that only yield to a (possible) bound tightening */
    1689 if( SCIPisFeasZero(scip, xcoef) || SCIPisFeasZero(scip, ycoef) )
    1690 return SCIP_OKAY;
    1691
    1692 /* collect variables */
    1695 assert(x != NULL);
    1696 assert(y != NULL);
    1697 assert(x != y);
    1698
    1699 /* normalize inequality s.t. xcoef in {-1,1} */
    1700 if( !SCIPisEQ(scip, REALABS(xcoef), 1.0) )
    1701 {
    1702 constant /= REALABS(xcoef);
    1703 ycoef /= REALABS(xcoef);
    1704 xcoef /= REALABS(xcoef);
    1705 }
    1706
    1707 /* coefficients of the inequality determine whether the inequality can be used for under- or overestimation */
    1708 underestimate = xcoef * ycoef > 0;
    1709
    1710 SCIPdebugMsg(scip, "add inequality for a bilinear term: %g %s <= %g %s + %g (underestimate=%u)\n", xcoef,
    1711 SCIPvarGetName(x), ycoef, SCIPvarGetName(y), constant, underestimate);
    1712
    1713 /* compute violation of the inequality of the important corner points */
    1714 getIneqViol(x, y, xcoef, ycoef, constant, &viol1, &viol2);
    1715 SCIPdebugMsg(scip, "violations of inequality = (%g,%g)\n", viol1, viol2);
    1716
    1717 /* inequality does not cutoff one of the important corner points -> skip */
    1718 if( SCIPisFeasLE(scip, MAX(viol1, viol2), 0.0) )
    1719 return SCIP_OKAY;
    1720
    1721 if( underestimate )
    1722 {
    1723 ineqs = nlhdlrexprdata->underineqs;
    1724 nineqs = nlhdlrexprdata->nunderineqs;
    1725 }
    1726 else
    1727 {
    1728 ineqs = nlhdlrexprdata->overineqs;
    1729 nineqs = nlhdlrexprdata->noverineqs;
    1730 }
    1731 assert( nineqs >= 0 );
    1732 assert( ineqs != NULL );
    1733 assert( 3 * nineqs <= 6 );
    1734
    1735 /* check for a duplicate */
    1736 for( i = 0; i < nineqs; ++i )
    1737 {
    1738 if( SCIPisFeasEQ(scip, xcoef, ineqs[3*i]) && SCIPisFeasEQ(scip, ycoef, ineqs[3*i+1]) /*lint !e661*/
    1739 && SCIPisFeasEQ(scip, constant, ineqs[3*i+2]) )
    1740 {
    1741 SCIPdebugMsg(scip, "inequality already found -> skip\n");
    1742 return SCIP_OKAY;
    1743 }
    1744 }
    1745
    1746 /* compute violations of existing inequalities */
    1747 for( i = 0; i < nineqs; ++i )
    1748 {
    1749 SCIP_Real ineqviol1;
    1750 SCIP_Real ineqviol2;
    1751
    1752 getIneqViol(x, y, ineqs[3*i], ineqs[3*i+1], ineqs[3*i+2], &ineqviol1, &ineqviol2); /*lint !e661*/
    1753
    1754 /* check whether an existing inequality is dominating the candidate */
    1755 if( SCIPisGE(scip, ineqviol1, viol1) && SCIPisGE(scip, ineqviol2, viol2) )
    1756 {
    1757 SCIPdebugMsg(scip, "inequality is dominated by %d -> skip\n", i);
    1758 return SCIP_OKAY;
    1759 }
    1760
    1761 /* replace inequality if candidate is dominating it */
    1762 if( SCIPisLT(scip, ineqviol1, viol1) && SCIPisLT(scip, ineqviol2, viol2) )
    1763 {
    1764 SCIPdebugMsg(scip, "inequality dominates %d -> replace\n", i);
    1765 ineqs[3*i] = xcoef; /*lint !e661*/
    1766 ineqs[3*i+1] = ycoef; /*lint !e661*/
    1767 ineqs[3*i+2] = constant; /*lint !e661*/
    1768 *success = TRUE;
    1769 }
    1770 }
    1771
    1772 /* inequality is not dominated by other inequalities -> add if we have less than 2 inequalities */
    1773 if( nineqs < 2 )
    1774 {
    1775 ineqs[3*nineqs] = xcoef;
    1776 ineqs[3*nineqs + 1] = ycoef;
    1777 ineqs[3*nineqs + 2] = constant;
    1778 *success = TRUE;
    1779 SCIPdebugMsg(scip, "add inequality\n");
    1780
    1781 /* increase number of inequalities */
    1782 if( underestimate )
    1783 ++(nlhdlrexprdata->nunderineqs);
    1784 else
    1785 ++(nlhdlrexprdata->noverineqs);
    1786 }
    1787
    1788 if( *success )
    1789 {
    1790 /* With the added inequalities, we can potentially compute tighter activities for the expression,
    1791 * so constraints that contain this expression should be propagated again.
    1792 * We don't have a direct expression to constraint mapping, though. This call marks all expr-constraints
    1793 * which include any of the variables that this expression depends on for propagation.
    1794 */
    1796 }
    1797
    1798 return SCIP_OKAY;
    1799}
    1800
    1801/** computes coefficients of linearization of a bilinear term in a reference point */
    1803 SCIP* scip, /**< SCIP data structure */
    1804 SCIP_Real bilincoef, /**< coefficient of bilinear term */
    1805 SCIP_Real refpointx, /**< point where to linearize first variable */
    1806 SCIP_Real refpointy, /**< point where to linearize second variable */
    1807 SCIP_Real* lincoefx, /**< buffer to add coefficient of first variable in linearization */
    1808 SCIP_Real* lincoefy, /**< buffer to add coefficient of second variable in linearization */
    1809 SCIP_Real* linconstant, /**< buffer to add constant of linearization */
    1810 SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
    1811 )
    1812{
    1813 SCIP_Real constant;
    1814
    1815 assert(scip != NULL);
    1816 assert(lincoefx != NULL);
    1817 assert(lincoefy != NULL);
    1818 assert(linconstant != NULL);
    1819 assert(success != NULL);
    1820
    1821 if( bilincoef == 0.0 )
    1822 return;
    1823
    1824 if( SCIPisInfinity(scip, REALABS(refpointx)) || SCIPisInfinity(scip, REALABS(refpointy)) )
    1825 {
    1826 *success = FALSE;
    1827 return;
    1828 }
    1829
    1830 /* bilincoef * x * y -> bilincoef * (refpointx * refpointy + refpointy * (x - refpointx) + refpointx * (y - refpointy))
    1831 * = -bilincoef * refpointx * refpointy + bilincoef * refpointy * x + bilincoef * refpointx * y
    1832 */
    1833
    1834 constant = -bilincoef * refpointx * refpointy;
    1835
    1836 if( SCIPisInfinity(scip, REALABS(bilincoef * refpointx)) || SCIPisInfinity(scip, REALABS(bilincoef * refpointy))
    1837 || SCIPisInfinity(scip, REALABS(constant)) )
    1838 {
    1839 *success = FALSE;
    1840 return;
    1841 }
    1842
    1843 *lincoefx += bilincoef * refpointy;
    1844 *lincoefy += bilincoef * refpointx;
    1845 *linconstant += constant;
    1846}
    1847
    1848/** computes coefficients of McCormick under- or overestimation of a bilinear term */
    1850 SCIP* scip, /**< SCIP data structure */
    1851 SCIP_Real bilincoef, /**< coefficient of bilinear term */
    1852 SCIP_Real lbx, /**< lower bound on first variable */
    1853 SCIP_Real ubx, /**< upper bound on first variable */
    1854 SCIP_Real refpointx, /**< reference point for first variable */
    1855 SCIP_Real lby, /**< lower bound on second variable */
    1856 SCIP_Real uby, /**< upper bound on second variable */
    1857 SCIP_Real refpointy, /**< reference point for second variable */
    1858 SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
    1859 SCIP_Real* lincoefx, /**< buffer to add coefficient of first variable in linearization */
    1860 SCIP_Real* lincoefy, /**< buffer to add coefficient of second variable in linearization */
    1861 SCIP_Real* linconstant, /**< buffer to add constant of linearization */
    1862 SCIP_Bool* success /**< buffer to set to FALSE if linearization has failed due to large numbers */
    1863 )
    1864{
    1865 SCIP_Real constant;
    1866 SCIP_Real coefx;
    1867 SCIP_Real coefy;
    1868
    1869 assert(scip != NULL);
    1870 assert(!SCIPisInfinity(scip, lbx));
    1871 assert(!SCIPisInfinity(scip, -ubx));
    1872 assert(!SCIPisInfinity(scip, lby));
    1873 assert(!SCIPisInfinity(scip, -uby));
    1874 assert(SCIPisInfinity(scip, -lbx) || SCIPisLE(scip, lbx, ubx));
    1875 assert(SCIPisInfinity(scip, -lby) || SCIPisLE(scip, lby, uby));
    1876 assert(SCIPisInfinity(scip, -lbx) || SCIPisLE(scip, lbx, refpointx));
    1877 assert(SCIPisInfinity(scip, -lby) || SCIPisLE(scip, lby, refpointy));
    1878 assert(SCIPisInfinity(scip, ubx) || SCIPisGE(scip, ubx, refpointx));
    1879 assert(SCIPisInfinity(scip, uby) || SCIPisGE(scip, uby, refpointy));
    1880 assert(lincoefx != NULL);
    1881 assert(lincoefy != NULL);
    1882 assert(linconstant != NULL);
    1883 assert(success != NULL);
    1884
    1885 if( bilincoef == 0.0 )
    1886 return;
    1887
    1888 if( overestimate )
    1889 bilincoef = -bilincoef;
    1890
    1891 if( SCIPisRelEQ(scip, lbx, ubx) && SCIPisRelEQ(scip, lby, uby) )
    1892 {
    1893 /* both x and y are mostly fixed */
    1894 SCIP_Real cand1;
    1895 SCIP_Real cand2;
    1896 SCIP_Real cand3;
    1897 SCIP_Real cand4;
    1898
    1899 coefx = 0.0;
    1900 coefy = 0.0;
    1901
    1902 /* estimate x * y by constant */
    1903 cand1 = lbx * lby;
    1904 cand2 = lbx * uby;
    1905 cand3 = ubx * lby;
    1906 cand4 = ubx * uby;
    1907
    1908 /* take most conservative value for underestimator */
    1909 if( bilincoef < 0.0 )
    1910 constant = bilincoef * MAX( MAX(cand1, cand2), MAX(cand3, cand4) );
    1911 else
    1912 constant = bilincoef * MIN( MIN(cand1, cand2), MIN(cand3, cand4) );
    1913 }
    1914 else if( bilincoef > 0.0 )
    1915 {
    1916 /* either x or y is not fixed and coef > 0.0 */
    1917 if( !SCIPisInfinity(scip, -lbx) && !SCIPisInfinity(scip, -lby) &&
    1918 (SCIPisInfinity(scip, ubx) || SCIPisInfinity(scip, uby)
    1919 || (uby - refpointy) * (ubx - refpointx) >= (refpointy - lby) * (refpointx - lbx)) )
    1920 {
    1921 if( SCIPisRelEQ(scip, lbx, ubx) )
    1922 {
    1923 /* x*y = lbx * y + (x-lbx) * y >= lbx * y + (x-lbx) * lby >= lbx * y + min{(ubx-lbx) * lby, 0 * lby} */
    1924 coefx = 0.0;
    1925 coefy = bilincoef * lbx;
    1926 constant = bilincoef * (lby < 0.0 ? (ubx-lbx) * lby : 0.0);
    1927 }
    1928 else if( SCIPisRelEQ(scip, lby, uby) )
    1929 {
    1930 /* x*y = lby * x + (y-lby) * x >= lby * x + (y-lby) * lbx >= lby * x + min{(uby-lby) * lbx, 0 * lbx} */
    1931 coefx = bilincoef * lby;
    1932 coefy = 0.0;
    1933 constant = bilincoef * (lbx < 0.0 ? (uby-lby) * lbx : 0.0);
    1934 }
    1935 else
    1936 {
    1937 coefx = bilincoef * lby;
    1938 coefy = bilincoef * lbx;
    1939 constant = -bilincoef * lbx * lby;
    1940 }
    1941 }
    1942 else if( !SCIPisInfinity(scip, ubx) && !SCIPisInfinity(scip, uby) )
    1943 {
    1944 if( SCIPisRelEQ(scip, lbx, ubx) )
    1945 {
    1946 /* x*y = ubx * y + (x-ubx) * y >= ubx * y + (x-ubx) * uby >= ubx * y + min{(lbx-ubx) * uby, 0 * uby} */
    1947 coefx = 0.0;
    1948 coefy = bilincoef * ubx;
    1949 constant = bilincoef * (uby > 0.0 ? (lbx - ubx) * uby : 0.0);
    1950 }
    1951 else if( SCIPisRelEQ(scip, lby, uby) )
    1952 {
    1953 /* x*y = uby * x + (y-uby) * x >= uby * x + (y-uby) * ubx >= uby * x + min{(lby-uby) * ubx, 0 * ubx} */
    1954 coefx = bilincoef * uby;
    1955 coefy = 0.0;
    1956 constant = bilincoef * (ubx > 0.0 ? (lby - uby) * ubx : 0.0);
    1957 }
    1958 else
    1959 {
    1960 coefx = bilincoef * uby;
    1961 coefy = bilincoef * ubx;
    1962 constant = -bilincoef * ubx * uby;
    1963 }
    1964 }
    1965 else
    1966 {
    1967 *success = FALSE;
    1968 return;
    1969 }
    1970 }
    1971 else
    1972 {
    1973 /* either x or y is not fixed and coef < 0.0 */
    1974 if( !SCIPisInfinity(scip, ubx) && !SCIPisInfinity(scip, -lby) &&
    1975 (SCIPisInfinity(scip, -lbx) || SCIPisInfinity(scip, uby)
    1976 || (ubx - lbx) * (refpointy - lby) <= (uby - lby) * (refpointx - lbx)) )
    1977 {
    1978 if( SCIPisRelEQ(scip, lbx, ubx) )
    1979 {
    1980 /* x*y = ubx * y + (x-ubx) * y <= ubx * y + (x-ubx) * lby <= ubx * y + max{(lbx-ubx) * lby, 0 * lby} */
    1981 coefx = 0.0;
    1982 coefy = bilincoef * ubx;
    1983 constant = bilincoef * (lby < 0.0 ? (lbx - ubx) * lby : 0.0);
    1984 }
    1985 else if( SCIPisRelEQ(scip, lby, uby) )
    1986 {
    1987 /* x*y = lby * x + (y-lby) * x <= lby * x + (y-lby) * ubx <= lby * x + max{(uby-lby) * ubx, 0 * ubx} */
    1988 coefx = bilincoef * lby;
    1989 coefy = 0.0;
    1990 constant = bilincoef * (ubx > 0.0 ? (uby - lby) * ubx : 0.0);
    1991 }
    1992 else
    1993 {
    1994 coefx = bilincoef * lby;
    1995 coefy = bilincoef * ubx;
    1996 constant = -bilincoef * ubx * lby;
    1997 }
    1998 }
    1999 else if( !SCIPisInfinity(scip, -lbx) && !SCIPisInfinity(scip, uby) )
    2000 {
    2001 if( SCIPisRelEQ(scip, lbx, ubx) )
    2002 {
    2003 /* x*y = lbx * y + (x-lbx) * y <= lbx * y + (x-lbx) * uby <= lbx * y + max{(ubx-lbx) * uby, 0 * uby} */
    2004 coefx = 0.0;
    2005 coefy = bilincoef * lbx;
    2006 constant = bilincoef * (uby > 0.0 ? (ubx - lbx) * uby : 0.0);
    2007 }
    2008 else if( SCIPisRelEQ(scip, lby, uby) )
    2009 {
    2010 /* x*y = uby * x + (y-uby) * x <= uby * x + (y-uby) * lbx <= uby * x + max{(lby-uby) * lbx, 0 * lbx} */
    2011 coefx = bilincoef * uby;
    2012 coefy = 0.0;
    2013 constant = bilincoef * (lbx < 0.0 ? (lby - uby) * lbx : 0.0);
    2014 }
    2015 else
    2016 {
    2017 coefx = bilincoef * uby;
    2018 coefy = bilincoef * lbx;
    2019 constant = -bilincoef * lbx * uby;
    2020 }
    2021 }
    2022 else
    2023 {
    2024 *success = FALSE;
    2025 return;
    2026 }
    2027 }
    2028
    2029 if( SCIPisInfinity(scip, REALABS(coefx)) || SCIPisInfinity(scip, REALABS(coefy))
    2030 || SCIPisInfinity(scip, REALABS(constant)) )
    2031 {
    2032 *success = FALSE;
    2033 return;
    2034 }
    2035
    2036 if( overestimate )
    2037 {
    2038 coefx = -coefx;
    2039 coefy = -coefy;
    2040 constant = -constant;
    2041 }
    2042
    2043 SCIPdebugMsg(scip, "%.15g * x[%.15g,%.15g] * y[%.15g,%.15g] %c= %.15g * x %+.15g * y %+.15g\n", bilincoef, lbx, ubx,
    2044 lby, uby, overestimate ? '<' : '>', coefx, coefy, constant);
    2045
    2046 *lincoefx += coefx;
    2047 *lincoefy += coefy;
    2048 *linconstant += constant;
    2049}
    2050
    2051/** computes coefficients of linearization of a bilinear term in a reference point when given a linear inequality
    2052 * involving only the variables of the bilinear term
    2053 *
    2054 * @note the formulas are extracted from "Convex envelopes of bivariate functions through the solution of KKT systems"
    2055 * by Marco Locatelli
    2056 */
    2058 SCIP* scip, /**< SCIP data structure */
    2059 SCIP_Real bilincoef, /**< coefficient of bilinear term */
    2060 SCIP_Real lbx, /**< lower bound on first variable */
    2061 SCIP_Real ubx, /**< upper bound on first variable */
    2062 SCIP_Real refpointx, /**< reference point for first variable */
    2063 SCIP_Real lby, /**< lower bound on second variable */
    2064 SCIP_Real uby, /**< upper bound on second variable */
    2065 SCIP_Real refpointy, /**< reference point for second variable */
    2066 SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
    2067 SCIP_Real xcoef, /**< x coefficient of linear inequality; must be in {-1,0,1} */
    2068 SCIP_Real ycoef, /**< y coefficient of linear inequality */
    2069 SCIP_Real constant, /**< constant of linear inequality */
    2070 SCIP_Real* RESTRICT lincoefx, /**< buffer to store coefficient of first variable in linearization */
    2071 SCIP_Real* RESTRICT lincoefy, /**< buffer to store coefficient of second variable in linearization */
    2072 SCIP_Real* RESTRICT linconstant, /**< buffer to store constant of linearization */
    2073 SCIP_Bool* RESTRICT success /**< buffer to store whether linearization was successful */
    2074 )
    2075{
    2076 SCIP_Real xs[2] = {lbx, ubx};
    2077 SCIP_Real ys[2] = {lby, uby};
    2078 SCIP_Real minx;
    2079 SCIP_Real maxx;
    2080 SCIP_Real miny;
    2081 SCIP_Real maxy;
    2082 SCIP_Real QUAD(lincoefyq);
    2083 SCIP_Real QUAD(lincoefxq);
    2084 SCIP_Real QUAD(linconstantq);
    2085 SCIP_Real QUAD(denomq);
    2086 SCIP_Real QUAD(mjq);
    2087 SCIP_Real QUAD(qjq);
    2088 SCIP_Real QUAD(xjq);
    2089 SCIP_Real QUAD(yjq);
    2090 SCIP_Real QUAD(tmpq);
    2091 SCIP_Real vx;
    2092 SCIP_Real vy;
    2093 int n;
    2094 int i;
    2095
    2096 assert(scip != NULL);
    2097 assert(!SCIPisInfinity(scip, lbx));
    2098 assert(!SCIPisInfinity(scip, -ubx));
    2099 assert(!SCIPisInfinity(scip, lby));
    2100 assert(!SCIPisInfinity(scip, -uby));
    2101 assert(SCIPisLE(scip, lbx, ubx));
    2102 assert(SCIPisLE(scip, lby, uby));
    2103 assert(SCIPisLE(scip, lbx, refpointx));
    2104 assert(SCIPisGE(scip, ubx, refpointx));
    2105 assert(SCIPisLE(scip, lby, refpointy));
    2106 assert(SCIPisGE(scip, uby, refpointy));
    2107 assert(lincoefx != NULL);
    2108 assert(lincoefy != NULL);
    2109 assert(linconstant != NULL);
    2110 assert(success != NULL);
    2111 assert(xcoef == 0.0 || xcoef == -1.0 || xcoef == 1.0); /*lint !e777*/
    2112 assert(ycoef != SCIP_INVALID && ycoef != 0.0); /*lint !e777*/
    2113 assert(constant != SCIP_INVALID); /*lint !e777*/
    2114
    2115 *success = FALSE;
    2116 *lincoefx = SCIP_INVALID;
    2117 *lincoefy = SCIP_INVALID;
    2118 *linconstant = SCIP_INVALID;
    2119
    2120 /* reference point does not satisfy linear inequality */
    2121 if( SCIPisFeasGT(scip, xcoef * refpointx - ycoef * refpointy - constant, 0.0) )
    2122 return;
    2123
    2124 /* compute minimal and maximal bounds on x and y for accepting the reference point */
    2125 minx = lbx + 0.01 * (ubx-lbx);
    2126 maxx = ubx - 0.01 * (ubx-lbx);
    2127 miny = lby + 0.01 * (uby-lby);
    2128 maxy = uby - 0.01 * (uby-lby);
    2129
    2130 /* check whether the reference point is in [minx,maxx]x[miny,maxy] */
    2131 if( SCIPisLE(scip, refpointx, minx) || SCIPisGE(scip, refpointx, maxx)
    2132 || SCIPisLE(scip, refpointy, miny) || SCIPisGE(scip, refpointy, maxy) )
    2133 return;
    2134
    2135 /* always consider xy without the bilinear coefficient */
    2136 if( bilincoef < 0.0 )
    2137 overestimate = !overestimate;
    2138
    2139 /* we use same notation as in "Convex envelopes of bivariate functions through the solution of KKT systems", 2016 */
    2140 /* mj = xcoef / ycoef */
    2141 SCIPquadprecDivDD(mjq, xcoef, ycoef);
    2142
    2143 /* qj = -constant / ycoef */
    2144 SCIPquadprecDivDD(qjq, -constant, ycoef);
    2145
    2146 /* mj > 0 => underestimate; mj < 0 => overestimate */
    2147 if( SCIPisNegative(scip, QUAD_TO_DBL(mjq)) != overestimate )
    2148 return;
    2149
    2150 /* get the corner point that satisfies the linear inequality xcoef*x <= ycoef*y + constant */
    2151 if( !overestimate )
    2152 {
    2153 ys[0] = uby;
    2154 ys[1] = lby;
    2155 }
    2156
    2157 vx = SCIP_INVALID;
    2158 vy = SCIP_INVALID;
    2159 n = 0;
    2160 for( i = 0; i < 2; ++i )
    2161 {
    2162 SCIP_Real activity = xcoef * xs[i] - ycoef * ys[i] - constant;
    2163 if( SCIPisLE(scip, activity, 0.0) )
    2164 {
    2165 /* corner point is satisfies inequality */
    2166 vx = xs[i];
    2167 vy = ys[i];
    2168 }
    2169 else if( SCIPisFeasGT(scip, activity, 0.0) )
    2170 /* corner point is clearly cut off */
    2171 ++n;
    2172 }
    2173
    2174 /* skip if no corner point satisfies the inequality or if no corner point is cut off
    2175 * (that is, all corner points satisfy the inequality almost [1e-9..1e-6]) */
    2176 if( n != 1 || vx == SCIP_INVALID || vy == SCIP_INVALID ) /*lint !e777*/
    2177 return;
    2178
    2179 /* denom = mj*(refpointx - vx) + vy - refpointy */
    2180 SCIPquadprecSumDD(denomq, refpointx, -vx); /* refpoint - vx */
    2181 SCIPquadprecProdQQ(denomq, denomq, mjq); /* mj * (refpoint - vx) */
    2182 SCIPquadprecSumQD(denomq, denomq, vy); /* mj * (refpoint - vx) + vy */
    2183 SCIPquadprecSumQD(denomq, denomq, -refpointy); /* mj * (refpoint - vx) + vy - refpointy */
    2184
    2185 if( SCIPisZero(scip, QUAD_TO_DBL(denomq)) )
    2186 return;
    2187
    2188 /* (xj,yj) is the projection onto the line xcoef*x = ycoef*y + constant */
    2189 /* xj = (refpointx*(vy - qj) - vx*(refpointy - qj)) / denom */
    2190 SCIPquadprecProdQD(xjq, qjq, -1.0); /* - qj */
    2191 SCIPquadprecSumQD(xjq, xjq, vy); /* vy - qj */
    2192 SCIPquadprecProdQD(xjq, xjq, refpointx); /* refpointx * (vy - qj) */
    2193 SCIPquadprecProdQD(tmpq, qjq, -1.0); /* - qj */
    2194 SCIPquadprecSumQD(tmpq, tmpq, refpointy); /* refpointy - qj */
    2195 SCIPquadprecProdQD(tmpq, tmpq, -vx); /* - vx * (refpointy - qj) */
    2196 SCIPquadprecSumQQ(xjq, xjq, tmpq); /* refpointx * (vy - qj) - vx * (refpointy - qj) */
    2197 SCIPquadprecDivQQ(xjq, xjq, denomq); /* (refpointx * (vy - qj) - vx * (refpointy - qj)) / denom */
    2198
    2199 /* yj = mj * xj + qj */
    2200 SCIPquadprecProdQQ(yjq, mjq, xjq);
    2201 SCIPquadprecSumQQ(yjq, yjq, qjq);
    2202
    2203 assert(SCIPisFeasEQ(scip, xcoef*QUAD_TO_DBL(xjq) - ycoef*QUAD_TO_DBL(yjq) - constant, 0.0));
    2204
    2205 /* check whether the projection is in [minx,maxx] x [miny,maxy]; this avoids numerical difficulties when the
    2206 * projection is close to the variable bounds
    2207 */
    2208 if( SCIPisLE(scip, QUAD_TO_DBL(xjq), minx) || SCIPisGE(scip, QUAD_TO_DBL(xjq), maxx)
    2209 || SCIPisLE(scip, QUAD_TO_DBL(yjq), miny) || SCIPisGE(scip, QUAD_TO_DBL(yjq), maxy) )
    2210 return;
    2211
    2212 assert(vy - QUAD_TO_DBL(mjq)*vx - QUAD_TO_DBL(qjq) != 0.0);
    2213
    2214 /* lincoefy = (mj*SQR(xj) - 2.0*mj*vx*xj - qj*vx + vx*vy) / (vy - mj*vx - qj) */
    2215 SCIPquadprecSquareQ(lincoefyq, xjq); /* xj^2 */
    2216 SCIPquadprecProdQQ(lincoefyq, lincoefyq, mjq); /* mj * xj^2 */
    2217 SCIPquadprecProdQQ(tmpq, mjq, xjq); /* mj * xj */
    2218 SCIPquadprecProdQD(tmpq, tmpq, -2.0 * vx); /* -2 * vx * mj * xj */
    2219 SCIPquadprecSumQQ(lincoefyq, lincoefyq, tmpq); /* mj * xj^2 -2 * vx * mj * xj */
    2220 SCIPquadprecProdQD(tmpq, qjq, -vx); /* -qj * vx */
    2221 SCIPquadprecSumQQ(lincoefyq, lincoefyq, tmpq); /* mj * xj^2 -2 * vx * mj * xj -qj * vx */
    2222 SCIPquadprecProdDD(tmpq, vx, vy); /* vx * vy */
    2223 SCIPquadprecSumQQ(lincoefyq, lincoefyq, tmpq); /* mj * xj^2 -2 * vx * mj * xj -qj * vx + vx * vy */
    2224 SCIPquadprecProdQD(tmpq, mjq, vx); /* mj * vx */
    2225 SCIPquadprecSumQD(tmpq, tmpq, -vy); /* -vy + mj * vx */
    2226 SCIPquadprecSumQQ(tmpq, tmpq, qjq); /* -vy + mj * vx + qj */
    2227 QUAD_SCALE(tmpq, -1.0); /* vy - mj * vx - qj */
    2228 SCIPquadprecDivQQ(lincoefyq, lincoefyq, tmpq); /* (mj * xj^2 -2 * vx * mj * xj -qj * vx + vx * vy) / (vy - mj * vx - qj) */
    2229
    2230 /* lincoefx = 2.0*mj*xj + qj - mj*(*lincoefy) */
    2231 SCIPquadprecProdQQ(lincoefxq, mjq, xjq); /* mj * xj */
    2232 QUAD_SCALE(lincoefxq, 2.0); /* 2 * mj * xj */
    2233 SCIPquadprecSumQQ(lincoefxq, lincoefxq, qjq); /* 2 * mj * xj + qj */
    2234 SCIPquadprecProdQQ(tmpq, mjq, lincoefyq); /* mj * lincoefy */
    2235 QUAD_SCALE(tmpq, -1.0); /* - mj * lincoefy */
    2236 SCIPquadprecSumQQ(lincoefxq, lincoefxq, tmpq); /* 2 * mj * xj + qj - mj * lincoefy */
    2237
    2238 /* linconstant = -mj*SQR(xj) - (*lincoefy)*qj */
    2239 SCIPquadprecSquareQ(linconstantq, xjq); /* xj^2 */
    2240 SCIPquadprecProdQQ(linconstantq, linconstantq, mjq); /* mj * xj^2 */
    2241 QUAD_SCALE(linconstantq, -1.0); /* - mj * xj^2 */
    2242 SCIPquadprecProdQQ(tmpq, lincoefyq, qjq); /* lincoefy * qj */
    2243 QUAD_SCALE(tmpq, -1.0); /* - lincoefy * qj */
    2244 SCIPquadprecSumQQ(linconstantq, linconstantq, tmpq); /* - mj * xj^2 - lincoefy * qj */
    2245
    2246 /* consider the bilinear coefficient */
    2247 SCIPquadprecProdQD(lincoefxq, lincoefxq, bilincoef);
    2248 SCIPquadprecProdQD(lincoefyq, lincoefyq, bilincoef);
    2249 SCIPquadprecProdQD(linconstantq, linconstantq, bilincoef);
    2250 *lincoefx = QUAD_TO_DBL(lincoefxq);
    2251 *lincoefy = QUAD_TO_DBL(lincoefyq);
    2252 *linconstant = QUAD_TO_DBL(linconstantq);
    2253
    2254 /* cut needs to be tight at (vx,vy) and (xj,yj); otherwise we consider the cut to be numerically bad */
    2255 *success = SCIPisFeasEQ(scip, (*lincoefx)*vx + (*lincoefy)*vy + (*linconstant), bilincoef*vx*vy)
    2256 && SCIPisFeasEQ(scip, (*lincoefx)*QUAD_TO_DBL(xjq) + (*lincoefy)*QUAD_TO_DBL(yjq) + (*linconstant),
    2257 bilincoef*QUAD_TO_DBL(xjq)*QUAD_TO_DBL(yjq));
    2258
    2259#ifndef NDEBUG
    2260 {
    2261 SCIP_Real activity = (*lincoefx)*refpointx + (*lincoefy)*refpointy + (*linconstant);
    2262
    2263 /* cut needs to under- or overestimate the bilinear term at the reference point */
    2264 if( bilincoef < 0.0 )
    2265 overestimate = !overestimate;
    2266
    2267 if( overestimate )
    2268 assert(SCIPisFeasGE(scip, activity, bilincoef*refpointx*refpointy));
    2269 else
    2270 assert(SCIPisFeasLE(scip, activity, bilincoef*refpointx*refpointy));
    2271 }
    2272#endif
    2273}
    2274
    2275/** computes coefficients of linearization of a bilinear term in a reference point when given two linear inequalities
    2276 * involving only the variables of the bilinear term
    2277 *
    2278 * @note the formulas are extracted from "Convex envelopes of bivariate functions through the solution of KKT systems"
    2279 * by Marco Locatelli
    2280 */
    2282 SCIP* scip, /**< SCIP data structure */
    2283 SCIP_Real bilincoef, /**< coefficient of bilinear term */
    2284 SCIP_Real lbx, /**< lower bound on first variable */
    2285 SCIP_Real ubx, /**< upper bound on first variable */
    2286 SCIP_Real refpointx, /**< reference point for first variable */
    2287 SCIP_Real lby, /**< lower bound on second variable */
    2288 SCIP_Real uby, /**< upper bound on second variable */
    2289 SCIP_Real refpointy, /**< reference point for second variable */
    2290 SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
    2291 SCIP_Real xcoef1, /**< x coefficient of linear inequality; must be in {-1,0,1} */
    2292 SCIP_Real ycoef1, /**< y coefficient of linear inequality */
    2293 SCIP_Real constant1, /**< constant of linear inequality */
    2294 SCIP_Real xcoef2, /**< x coefficient of linear inequality; must be in {-1,0,1} */
    2295 SCIP_Real ycoef2, /**< y coefficient of linear inequality */
    2296 SCIP_Real constant2, /**< constant of linear inequality */
    2297 SCIP_Real* RESTRICT lincoefx, /**< buffer to store coefficient of first variable in linearization */
    2298 SCIP_Real* RESTRICT lincoefy, /**< buffer to store coefficient of second variable in linearization */
    2299 SCIP_Real* RESTRICT linconstant, /**< buffer to store constant of linearization */
    2300 SCIP_Bool* RESTRICT success /**< buffer to store whether linearization was successful */
    2301 )
    2302{
    2303 SCIP_Real mi, mj, qi, qj, xi, xj, yi, yj;
    2304 SCIP_Real xcoef, ycoef, constant;
    2305 SCIP_Real minx, maxx, miny, maxy;
    2306
    2307 assert(scip != NULL);
    2308 assert(!SCIPisInfinity(scip, lbx));
    2309 assert(!SCIPisInfinity(scip, -ubx));
    2310 assert(!SCIPisInfinity(scip, lby));
    2311 assert(!SCIPisInfinity(scip, -uby));
    2312 assert(SCIPisLE(scip, lbx, ubx));
    2313 assert(SCIPisLE(scip, lby, uby));
    2314 assert(SCIPisLE(scip, lbx, refpointx));
    2315 assert(SCIPisGE(scip, ubx, refpointx));
    2316 assert(SCIPisLE(scip, lby, refpointy));
    2317 assert(SCIPisGE(scip, uby, refpointy));
    2318 assert(lincoefx != NULL);
    2319 assert(lincoefy != NULL);
    2320 assert(linconstant != NULL);
    2321 assert(success != NULL);
    2322 assert(xcoef1 != 0.0 && xcoef1 != SCIP_INVALID); /*lint !e777*/
    2323 assert(ycoef1 != SCIP_INVALID && ycoef1 != 0.0); /*lint !e777*/
    2324 assert(constant1 != SCIP_INVALID); /*lint !e777*/
    2325 assert(xcoef2 != 0.0 && xcoef2 != SCIP_INVALID); /*lint !e777*/
    2326 assert(ycoef2 != SCIP_INVALID && ycoef2 != 0.0); /*lint !e777*/
    2327 assert(constant2 != SCIP_INVALID); /*lint !e777*/
    2328
    2329 *success = FALSE;
    2330 *lincoefx = SCIP_INVALID;
    2331 *lincoefy = SCIP_INVALID;
    2332 *linconstant = SCIP_INVALID;
    2333
    2334 /* reference point does not satisfy linear inequalities */
    2335 if( SCIPisFeasGT(scip, xcoef1 * refpointx - ycoef1 * refpointy - constant1, 0.0)
    2336 || SCIPisFeasGT(scip, xcoef2 * refpointx - ycoef2 * refpointy - constant2, 0.0) )
    2337 return;
    2338
    2339 /* compute minimal and maximal bounds on x and y for accepting the reference point */
    2340 minx = lbx + 0.01 * (ubx-lbx);
    2341 maxx = ubx - 0.01 * (ubx-lbx);
    2342 miny = lby + 0.01 * (uby-lby);
    2343 maxy = uby - 0.01 * (uby-lby);
    2344
    2345 /* check the reference point is in the interior of the domain */
    2346 if( SCIPisLE(scip, refpointx, minx) || SCIPisGE(scip, refpointx, maxx)
    2347 || SCIPisLE(scip, refpointy, miny) || SCIPisFeasGE(scip, refpointy, maxy) )
    2348 return;
    2349
    2350 /* the sign of the x-coefficients of the two inequalities must be different; otherwise the convex or concave
    2351 * envelope can be computed via SCIPcomputeBilinEnvelope1 for each inequality separately
    2352 */
    2353 if( (xcoef1 > 0) == (xcoef2 > 0) )
    2354 return;
    2355
    2356 /* always consider xy without the bilinear coefficient */
    2357 if( bilincoef < 0.0 )
    2358 overestimate = !overestimate;
    2359
    2360 /* we use same notation as in "Convex envelopes of bivariate functions through the solution of KKT systems", 2016 */
    2361 mi = xcoef1 / ycoef1;
    2362 qi = -constant1 / ycoef1;
    2363 mj = xcoef2 / ycoef2;
    2364 qj = -constant2 / ycoef2;
    2365
    2366 /* mi, mj > 0 => underestimate; mi, mj < 0 => overestimate */
    2367 if( SCIPisNegative(scip, mi) != overestimate || SCIPisNegative(scip, mj) != overestimate )
    2368 return;
    2369
    2370 /* compute cut according to Locatelli 2016 */
    2371 computeBilinEnvelope2(scip, refpointx, refpointy, mi, qi, mj, qj, &xi, &yi, &xj, &yj, &xcoef, &ycoef, &constant);
    2372 assert(SCIPisRelEQ(scip, mi*xi + qi, yi));
    2373 assert(SCIPisRelEQ(scip, mj*xj + qj, yj));
    2374
    2375 /* it might happen that (xi,yi) = (xj,yj) if the two lines intersect */
    2376 if( SCIPisEQ(scip, xi, xj) && SCIPisEQ(scip, yi, yj) )
    2377 return;
    2378
    2379 /* check whether projected points are in the interior */
    2380 if( SCIPisLE(scip, xi, minx) || SCIPisGE(scip, xi, maxx) || SCIPisLE(scip, yi, miny) || SCIPisGE(scip, yi, maxy) )
    2381 return;
    2382 if( SCIPisLE(scip, xj, minx) || SCIPisGE(scip, xj, maxx) || SCIPisLE(scip, yj, miny) || SCIPisGE(scip, yj, maxy) )
    2383 return;
    2384
    2385 *lincoefx = bilincoef * xcoef;
    2386 *lincoefy = bilincoef * ycoef;
    2387 *linconstant = bilincoef * constant;
    2388
    2389 /* cut needs to be tight at (vx,vy) and (xj,yj) */
    2390 *success = SCIPisFeasEQ(scip, (*lincoefx)*xi + (*lincoefy)*yi + (*linconstant), bilincoef*xi*yi)
    2391 && SCIPisFeasEQ(scip, (*lincoefx)*xj + (*lincoefy)*yj + (*linconstant), bilincoef*xj*yj);
    2392
    2393#ifndef NDEBUG
    2394 {
    2395 SCIP_Real activity = (*lincoefx)*refpointx + (*lincoefy)*refpointy + (*linconstant);
    2396
    2397 /* cut needs to under- or overestimate the bilinear term at the reference point */
    2398 if( bilincoef < 0.0 )
    2399 overestimate = !overestimate;
    2400
    2401 if( overestimate )
    2402 assert(SCIPisFeasGE(scip, activity, bilincoef*refpointx*refpointy));
    2403 else
    2404 assert(SCIPisFeasLE(scip, activity, bilincoef*refpointx*refpointy));
    2405 }
    2406#endif
    2407}
    SCIP_VAR ** y
    Definition: circlepacking.c:64
    SCIP_VAR ** x
    Definition: circlepacking.c:63
    constraint handler for nonlinear constraints specified by algebraic expressions
    #define SCIPquadprecDivQD(r, a, b)
    Definition: dbldblarith.h:65
    #define SCIPquadprecDivQQ(r, a, b)
    Definition: dbldblarith.h:69
    #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 SCIPquadprecProdQQ(r, a, b)
    Definition: dbldblarith.h:66
    #define SCIPquadprecSumQD(r, a, b)
    Definition: dbldblarith.h:62
    #define SCIPquadprecSquareQ(r, a)
    Definition: dbldblarith.h:68
    #define QUAD(x)
    Definition: dbldblarith.h:47
    #define SCIPquadprecSumDD(r, a, b)
    Definition: dbldblarith.h:60
    #define SCIPquadprecSumQQ(r, a, b)
    Definition: dbldblarith.h:67
    #define SCIPquadprecDivDD(r, a, b)
    Definition: dbldblarith.h:61
    #define QUAD_TO_DBL(x)
    Definition: dbldblarith.h:49
    #define NULL
    Definition: def.h:257
    #define SCIP_Longint
    Definition: def.h:150
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_INTERVAL_INFINITY
    Definition: def.h:189
    #define SCIP_Bool
    Definition: def.h:100
    #define MIN(x, y)
    Definition: def.h:233
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define SQR(x)
    Definition: def.h:208
    #define EPSEQ(x, y, eps)
    Definition: def.h:192
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define RESTRICT
    Definition: def.h:269
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    product expression handler
    variable expression handler
    SCIP_RETCODE SCIPmarkExprPropagateNonlinear(SCIP *scip, SCIP_EXPR *expr)
    unsigned int SCIPgetExprNAuxvarUsesNonlinear(SCIP_EXPR *expr)
    SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
    SCIP_EXPR * SCIPgetExprNonlinear(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_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3304
    int SCIPhashmapGetNElements(SCIP_HASHMAP *hashmap)
    Definition: misc.c:3576
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3179
    SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3482
    SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3400
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
    Definition: scip_message.c:120
    int SCIPgetNExprsBilinear(SCIP_NLHDLR *nlhdlr)
    void SCIPcomputeBilinEnvelope2(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real xcoef1, SCIP_Real ycoef1, SCIP_Real constant1, SCIP_Real xcoef2, SCIP_Real ycoef2, SCIP_Real constant2, SCIP_Real *RESTRICT lincoefx, SCIP_Real *RESTRICT lincoefy, SCIP_Real *RESTRICT linconstant, SCIP_Bool *RESTRICT success)
    void SCIPaddBilinMcCormick(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
    void SCIPcomputeBilinEnvelope1(SCIP *scip, SCIP_Real bilincoef, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real refpointx, SCIP_Real lby, SCIP_Real uby, SCIP_Real refpointy, SCIP_Bool overestimate, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Real *RESTRICT lincoefx, SCIP_Real *RESTRICT lincoefy, SCIP_Real *RESTRICT linconstant, SCIP_Bool *RESTRICT success)
    SCIP_RETCODE SCIPaddIneqBilinear(SCIP *scip, SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Bool *success)
    void SCIPaddBilinLinearization(SCIP *scip, SCIP_Real bilincoef, SCIP_Real refpointx, SCIP_Real refpointy, SCIP_Real *lincoefx, SCIP_Real *lincoefy, SCIP_Real *linconstant, SCIP_Bool *success)
    SCIP_EXPR ** SCIPgetExprsBilinear(SCIP_NLHDLR *nlhdlr)
    SCIP_RETCODE SCIPincludeNlhdlrBilinear(SCIP *scip)
    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 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
    int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4782
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4739
    SCIP_RETCODE SCIPinsertDatatreeInt(SCIP *scip, SCIP_DATATREE *datatree, const char *name, int value)
    SCIP_RETCODE SCIPsetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx, void *val)
    int SCIPexprGetNChildren(SCIP_EXPR *expr)
    Definition: expr.c:3872
    SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1490
    SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
    Definition: expriter.c:969
    SCIP_Real SCIPgetCoefExprProduct(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
    Definition: scip_expr.c:1443
    SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
    Definition: expriter.c:683
    SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1457
    SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2362
    SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
    Definition: scip_expr.c:1512
    SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
    Definition: expriter.c:858
    SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
    Definition: expr.c:3882
    SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
    Definition: expr_var.c:423
    SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
    Definition: expr.c:4028
    void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2376
    void SCIPcaptureExpr(SCIP_EXPR *expr)
    Definition: scip_expr.c:1435
    SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
    Definition: expriter.c:501
    SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
    void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
    void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds)
    void SCIPintervalIntersect(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
    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)
    SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
    void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
    #define SCIPallocClearBlockMemory(scip, ptr)
    Definition: scip_mem.h:91
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
    Definition: scip_mem.h:99
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
    Definition: scip_mem.h:111
    #define SCIPfreeBlockMemoryNull(scip, ptr)
    Definition: scip_mem.h:109
    #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
    SCIP_NLHDLREXPRDATA * SCIPgetNlhdlrExprDataNonlinear(SCIP_NLHDLR *nlhdlr, SCIP_EXPR *expr)
    void SCIPnlhdlrSetInitExit(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINIT((*init)), SCIP_DECL_NLHDLREXIT((*exit_)))
    Definition: nlhdlr.c:111
    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:8513
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    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_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisRelLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisRelLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisRelGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisRelGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPepsilon(SCIP *scip)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
    Definition: scip_tree.c:91
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23510
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_RETCODE SCIPensureRowprepSize(SCIP *scip, SCIP_ROWPREP *rowprep, int size)
    Definition: misc_rowprep.c:887
    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 SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
    Definition: misc_rowprep.c:563
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    #define NLHDLR_DETECTPRIORITY
    #define TABLE_DESC_BILINEAR
    #define TABLE_EARLIEST_STAGE_BILINEAR
    static SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataBilinear)
    static SCIP_DECL_TABLEOUTPUT(tableOutputBilinear)
    static void updateBilinearRelaxation(SCIP *scip, SCIP_VAR *RESTRICT x, SCIP_VAR *RESTRICT y, SCIP_Real bilincoef, SCIP_SIDETYPE violside, SCIP_Real refx, SCIP_Real refy, SCIP_Real *RESTRICT ineqs, int nineqs, SCIP_Real mccormickval, SCIP_Real *RESTRICT bestcoefx, SCIP_Real *RESTRICT bestcoefy, SCIP_Real *RESTRICT bestconst, SCIP_Real *RESTRICT bestval, SCIP_Bool *success)
    #define NLHDLR_ENFOPRIORITY
    static SCIP_DECL_NLHDLRINTEVAL(nlhdlrIntevalBilinear)
    static void reversePropBilinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *expr, SCIP_INTERVAL exprbounds, SCIP_Real *underineqs, int nunderineqs, SCIP_Real *overineqs, int noverineqs, SCIP_INTERVAL *intervalx, SCIP_INTERVAL *intervaly)
    #define TABLE_POSITION_BILINEAR
    static SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrdataBilinear)
    static SCIP_DECL_NLHDLREXIT(nlhdlrExitBilinear)
    static void computeBilinEnvelope2(SCIP *scip, SCIP_Real x, SCIP_Real y, SCIP_Real mi, SCIP_Real qi, SCIP_Real mj, SCIP_Real qj, SCIP_Real *RESTRICT xi, SCIP_Real *RESTRICT yi, SCIP_Real *RESTRICT xj, SCIP_Real *RESTRICT yj, SCIP_Real *RESTRICT xcoef, SCIP_Real *RESTRICT ycoef, SCIP_Real *RESTRICT constant)
    static SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrBilinear)
    #define nlhdlrExitSepaBilinear
    static SCIP_DECL_TABLECOLLECT(tableCollectBilinear)
    static SCIP_INTERVAL intevalBilinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real *underineqs, int nunderineqs, SCIP_Real *overineqs, int noverineqs)
    #define NLHDLR_DESC
    static SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxBilinear)
    static SCIP_DECL_NLHDLRDETECT(nlhdlrDetectBilinear)
    #define NLHDLR_NAME
    #define nlhdlrInitBilinear
    static SCIP_DECL_NLHDLRREVERSEPROP(nlhdlrReversepropBilinear)
    #define MIN_INTERIORITY
    #define TABLE_NAME_BILINEAR
    static SCIP_DECL_NLHDLRESTIMATE(nlhdlrEstimateBilinear)
    #define nlhdlrInitSepaBilinear
    #define nlhdlrEnfoBilinear
    static SCIP_Bool isPointFeasible(SCIP *scip, SCIP_Real x, SCIP_Real y, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real lby, SCIP_Real uby, SCIP_Real *ineqs, int nineqs)
    static SCIP_Bool useBilinIneqs(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, SCIP_Real refx, SCIP_Real refy)
    #define MIN_ABSBOUNDSIZE
    static void getFeasiblePointsBilinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_EXPR *expr, SCIP_INTERVAL exprbounds, SCIP_Real *underineqs, int nunderineqs, SCIP_Real *overineqs, int noverineqs, SCIP_Bool levelset, SCIP_Real *xs, SCIP_Real *ys, int *npoints)
    static void getIneqViol(SCIP_VAR *x, SCIP_VAR *y, SCIP_Real xcoef, SCIP_Real ycoef, SCIP_Real constant, SCIP_Real *viol1, SCIP_Real *viol2)
    bilinear nonlinear handler
    SCIP_Real sup
    Definition: intervalarith.h:57
    SCIP_Real inf
    Definition: intervalarith.h:56
    @ SCIP_EXPRITER_DFS
    Definition: type_expr.h:718
    @ SCIP_SIDETYPE_RIGHT
    Definition: type_lp.h:66
    @ SCIP_SIDETYPE_LEFT
    Definition: type_lp.h:65
    enum SCIP_SideType SCIP_SIDETYPE
    Definition: type_lp.h:68
    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
    struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
    Definition: type_nlhdlr.h:453
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_STAGE_INITSOLVE
    Definition: type_set.h:52