SCIP

    Solving Constraint Integer Programs

    nlhdlr_quotient.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_quotient.c
    26 * @ingroup DEFPLUGINS_NLHDLR
    27 * @brief quotient nonlinear handler
    28 * @author Benjamin Mueller
    29 * @author Fabian Wegscheider
    30 *
    31 * @todo implement INITSEPA
    32 * @todo use the convex envelope for x/y described in Tawarmalani and Sahinidis (2002) if y has a finite upper bound
    33 */
    34
    36#include "scip/cons_nonlinear.h"
    38#include "scip/nlhdlr.h"
    40
    41/* fundamental nonlinear handler properties */
    42#define NLHDLR_NAME "quotient"
    43#define NLHDLR_DESC "nonlinear handler for quotient expressions"
    44#define NLHDLR_DETECTPRIORITY 20
    45#define NLHDLR_ENFOPRIORITY 20
    46
    47/** translate from one value of infinity to another
    48 *
    49 * if val is ≥ infty1, then give infty2, else give val
    50 */
    51#define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
    52
    53/*lint -e666*/
    54
    55/*
    56 * Data structures
    57 */
    58
    59/** nonlinear handler expression data */
    60struct SCIP_NlhdlrExprData
    61{
    62 SCIP_EXPR* numexpr; /**< expression of the numerator */
    63 SCIP_Real numcoef; /**< coefficient of the numerator */
    64 SCIP_Real numconst; /**< constant of the numerator */
    65 SCIP_EXPR* denomexpr; /**< expression of the denominator */
    66 SCIP_Real denomcoef; /**< coefficient of the denominator */
    67 SCIP_Real denomconst; /**< constant of the denominator */
    68 SCIP_Real constant; /**< constant */
    69};
    70
    71/*
    72 * Local methods
    73 */
    74
    75/** helper method to create nonlinear handler expression data */
    76static
    78 SCIP* scip, /**< SCIP data structure */
    79 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< nonlinear handler expression data */
    80 SCIP_EXPR* numexpr, /**< expression of the numerator */
    81 SCIP_Real numcoef, /**< coefficient of the numerator */
    82 SCIP_Real numconst, /**< constant of the numerator */
    83 SCIP_EXPR* denomexpr, /**< expression of the denominator */
    84 SCIP_Real denomcoef, /**< coefficient of the denominator */
    85 SCIP_Real denomconst, /**< constant of the denominator */
    86 SCIP_Real constant /**< constant */
    87 )
    88{
    89 assert(nlhdlrexprdata != NULL);
    90 assert(numexpr != NULL);
    91 assert(denomexpr != NULL);
    92 assert(!SCIPisZero(scip, numcoef));
    93 assert(!SCIPisZero(scip, denomcoef));
    94
    95 /* allocate memory */
    96 SCIP_CALL( SCIPallocBlockMemory(scip, nlhdlrexprdata) );
    97
    98 /* store values */
    99 (*nlhdlrexprdata)->numexpr = numexpr;
    100 (*nlhdlrexprdata)->numcoef = numcoef;
    101 (*nlhdlrexprdata)->numconst = numconst;
    102 (*nlhdlrexprdata)->denomexpr = denomexpr;
    103 (*nlhdlrexprdata)->denomcoef = denomcoef;
    104 (*nlhdlrexprdata)->denomconst = denomconst;
    105 (*nlhdlrexprdata)->constant = constant;
    106
    107 /* capture expressions */
    108 SCIPcaptureExpr(numexpr);
    109 SCIPcaptureExpr(denomexpr);
    110
    111 return SCIP_OKAY;
    112}
    113
    114/** helper method to free nonlinear handler expression data */
    115static
    117 SCIP* scip, /**< SCIP data structure */
    118 SCIP_NLHDLREXPRDATA** nlhdlrexprdata /**< nonlinear handler expression data */
    119 )
    120{
    121 assert(nlhdlrexprdata != NULL);
    122 assert(*nlhdlrexprdata != NULL);
    123 assert((*nlhdlrexprdata)->numexpr != NULL);
    124 assert((*nlhdlrexprdata)->denomexpr != NULL);
    125
    126 /* release expressions */
    127 SCIP_CALL( SCIPreleaseExpr(scip, &(*nlhdlrexprdata)->denomexpr) );
    128 SCIP_CALL( SCIPreleaseExpr(scip, &(*nlhdlrexprdata)->numexpr) );
    129
    130 /* free expression data of nonlinear handler */
    131 SCIPfreeBlockMemory(scip, nlhdlrexprdata);
    132
    133 return SCIP_OKAY;
    134}
    135
    136/** helper method to transform an expression g(x) into a*f(x) + b */
    137static
    139 SCIP* scip, /**< SCIP data structure */
    140 SCIP_EXPR* expr, /**< expression */
    141 SCIP_EXPR** target, /**< pointer to store the expression f(x) */
    142 SCIP_Real* coef, /**< pointer to store the coefficient */
    143 SCIP_Real* constant /**< pointer to store the constant */
    144 )
    145{
    146 assert(expr != NULL);
    147 assert(target != NULL);
    148 assert(coef != NULL);
    149 assert(constant != NULL);
    150
    151 /* expression is a sum with one child */
    152 if( SCIPisExprSum(scip, expr) && SCIPexprGetNChildren(expr) == 1 )
    153 {
    154 *target = SCIPexprGetChildren(expr)[0];
    155 *coef = SCIPgetCoefsExprSum(expr)[0];
    156 *constant = SCIPgetConstantExprSum(expr);
    157 }
    158 else /* otherwise return 1 * f(x) + 0 */
    159 {
    160 *target = expr;
    161 *coef = 1.0;
    162 *constant = 0.0;
    163 }
    164}
    165
    166/** helper method to detect an expression of the form (a*x + b) / (c*y + d) + e
    167 *
    168 * Due to the expansion of products, there are two types of expressions that can be detected:
    169 *
    170 * 1. prod(f(x), pow(g(y),-1))
    171 * 2. sum(prod(f(x),pow(g(y),-1)), pow(g(y),-1))
    172 *
    173 * @todo At the moment quotients like xy / z are not detected, because they are turned into a product expression
    174 * with three children, i.e., x * y * (1 / z).
    175 */
    176static
    178 SCIP* scip, /**< SCIP data structure */
    179 SCIP_EXPR* expr, /**< expression */
    180 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< pointer to store nonlinear handler expression data */
    181 SCIP_Bool* success /**< pointer to store whether nonlinear handler should be called for this expression */
    182 )
    183{
    184 SCIP_EXPR** children;
    185 SCIP_EXPR* denomexpr = NULL;
    186 SCIP_EXPR* numexpr = NULL;
    187 SCIP_EXPR* xexpr = NULL;
    188 SCIP_EXPR* yexpr = NULL;
    189 SCIP_Real a, b, c, d, e;
    190 SCIP_Real nomfac = 1.0;
    191 SCIP_Real numconst = 0.0;
    192
    193 assert(scip != NULL);
    194 assert(expr != NULL);
    195
    196 *success = FALSE;
    197 a = 0.0;
    198 b = 0.0;
    199 c = 0.0;
    200 d = 0.0;
    201 e = 0.0;
    202
    203 /* possible structures only have two children */
    204 if( SCIPexprGetNChildren(expr) != 2 )
    205 return SCIP_OKAY;
    206
    207 /* expression must be either a product or a sum */
    208 if( !SCIPisExprProduct(scip, expr) && !SCIPisExprSum(scip, expr) )
    209 return SCIP_OKAY;
    210
    211 children = SCIPexprGetChildren(expr);
    212 assert(children != NULL);
    213
    214 /* case: prod(f(x), pow(g(y),-1)) */
    215 if( SCIPisExprProduct(scip, expr) )
    216 {
    217 if( SCIPisExprPower(scip, children[0]) && SCIPgetExponentExprPow(children[0]) == -1.0 ) /*lint !e777*/
    218 {
    219 denomexpr = SCIPexprGetChildren(children[0])[0];
    220 numexpr = children[1];
    221 }
    222 else if( SCIPisExprPower(scip, children[1]) && SCIPgetExponentExprPow(children[1]) == -1.0 ) /*lint !e777*/
    223 {
    224 denomexpr = SCIPexprGetChildren(children[1])[0];
    225 numexpr = children[0];
    226 }
    227
    228 /* remember to scale the numerator by the coefficient stored in the product expression */
    229 nomfac = SCIPgetCoefExprProduct(expr);
    230 }
    231 /* case: sum(prod(f(x),pow(g(y),-1)), pow(g(y),-1)) */
    232 else
    233 {
    234 SCIP_Real* sumcoefs;
    235
    236 assert(SCIPisExprSum(scip, expr));
    237 sumcoefs = SCIPgetCoefsExprSum(expr);
    238
    239 /* children[0] is 1/g(y) and children[1] is a product of f(x) and 1/g(y) */
    240 if( SCIPisExprPower(scip, children[0]) && SCIPgetExponentExprPow(children[0]) == -1.0
    241 && SCIPisExprProduct(scip, children[1]) && SCIPexprGetNChildren(children[1]) == 2 ) /* lint !e777 */
    242 {
    243 SCIP_Real prodcoef = SCIPgetCoefExprProduct(children[1]);
    244
    245 if( children[0] == SCIPexprGetChildren(children[1])[0] )
    246 {
    247 denomexpr = SCIPexprGetChildren(children[0])[0];
    248 numexpr = SCIPexprGetChildren(children[1])[1];
    249 }
    250 else if( children[0] == SCIPexprGetChildren(children[1])[1] )
    251 {
    252 denomexpr = SCIPexprGetChildren(children[0])[0];
    253 numexpr = SCIPexprGetChildren(children[1])[0];
    254 }
    255
    256 /* remember scalar and constant for numerator */
    257 nomfac = sumcoefs[1] * prodcoef;
    258 numconst = sumcoefs[0];
    259 }
    260 /* children[1] is 1/g(y) and children[0] is a product of f(x) and 1/g(y) */
    261 else if( SCIPisExprPower(scip, children[1]) && SCIPgetExponentExprPow(children[1]) == -1.0
    262 && SCIPisExprProduct(scip, children[0]) && SCIPexprGetNChildren(children[0]) == 2 ) /* lint !e777 */
    263 {
    264 SCIP_Real prodcoef = SCIPgetCoefExprProduct(children[0]);
    265
    266 if( children[1] == SCIPexprGetChildren(children[0])[0] )
    267 {
    268 denomexpr = SCIPexprGetChildren(children[1])[0];
    269 numexpr = SCIPexprGetChildren(children[0])[1];
    270 }
    271 else if( children[1] == SCIPexprGetChildren(children[0])[1] )
    272 {
    273 denomexpr = SCIPexprGetChildren(children[1])[0];
    274 numexpr = SCIPexprGetChildren(children[0])[0];
    275 }
    276
    277 /* remember scalar and constant for numerator */
    278 nomfac = sumcoefs[0] * prodcoef;
    279 numconst = sumcoefs[1];
    280 }
    281
    282 /* remember the constant of the sum expression */
    283 e = SCIPgetConstantExprSum(expr);
    284 }
    285
    286 if( denomexpr != NULL && numexpr != NULL )
    287 {
    288 /* transform numerator and denominator to detect structures like (a * f(x) + b) / (c * f(x) + d) */
    289 transformExpr(scip, numexpr, &xexpr, &a, &b);
    290 transformExpr(scip, denomexpr, &yexpr, &c, &d);
    291
    292 SCIPdebugMsg(scip, "detected numerator (%g * %p + %g) and denominator (%g * %p + %g)\n", a, (void*)xexpr, b,
    293 c, (void*)yexpr, d);
    294
    295 /* detection is only be successful if the expression of the numerator an denominator are the same
    296 * (so boundtightening can be stronger than default) or we are going to provide estimators (there will be an auxvar)
    297 */
    298 *success = (xexpr == yexpr) || (SCIPgetExprNAuxvarUsesNonlinear(expr) > 0);
    299
    300#ifdef SCIP_DEBUG
    301 SCIPinfoMessage(scip, NULL, "Expression for numerator: ");
    302 SCIP_CALL( SCIPprintExpr(scip, xexpr, NULL) );
    303 SCIPinfoMessage(scip, NULL, "\nExpression for denominator: ");
    304 SCIP_CALL( SCIPprintExpr(scip, yexpr, NULL) );
    305 SCIPinfoMessage(scip, NULL, "\n");
    306#endif
    307 }
    308
    309 /* register usage of xexpr and yexpr
    310 * create nonlinear handler expression data
    311 */
    312 if( *success )
    313 {
    314 assert(xexpr != NULL);
    315 assert(xexpr != NULL);
    316 assert(a != 0.0);
    317 assert(c != 0.0);
    318
    319 assert(SCIPgetExprNAuxvarUsesNonlinear(expr) > 0 || xexpr == yexpr);
    320
    321 /* request auxiliary variables for xexpr and yexpr if we will estimate
    322 * mark that the bounds of the expression are important to construct the estimators
    323 * (TODO check the curvature of the univariate quotient, as bounds may actually not be used)
    324 * if univariate, then we also do inteval and reverseprop, so mark that the activities will be used for inteval
    325 */
    328 xexpr == yexpr,
    331
    332 if( xexpr != yexpr && SCIPgetExprNAuxvarUsesNonlinear(expr) > 0 )
    333 {
    335 }
    336
    337 a = nomfac * a;
    338 b = nomfac * b + numconst;
    339
    342 SCIPdebugMsg(scip, "detected quotient expression (%g * %p + %g) / (%g * %p + %g) + %g\n", a, (void*)xexpr,
    343 b, c, (void*)yexpr, d, e);
    344 SCIP_CALL( exprdataCreate(scip, nlhdlrexprdata, xexpr, a, b, yexpr, c, d, e) );
    345 }
    346
    347 return SCIP_OKAY;
    348}
    349
    350/** helper method to compute interval for (a x + b) / (c x + d) + e */
    351static
    353 SCIP* scip, /**< SCIP data structure */
    354 SCIP_INTERVAL bnds, /**< bounds on x */
    355 SCIP_Real a, /**< coefficient in numerator */
    356 SCIP_Real b, /**< constant in numerator */
    357 SCIP_Real c, /**< coefficient in denominator */
    358 SCIP_Real d, /**< constant in denominator */
    359 SCIP_Real e /**< constant */
    360 )
    361{
    362 SCIP_INTERVAL result;
    363 SCIP_INTERVAL denominterval;
    364 SCIP_INTERVAL numinterval;
    365 int i;
    366
    367 assert(scip != NULL);
    368
    369 /* return empty interval if the domain of x is empty */
    371 {
    372 SCIPintervalSetEmpty(&result);
    373 return result;
    374 }
    375
    376 /* compute bounds for denominator */
    377 SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &denominterval, bnds, c);
    378 SCIPintervalAddScalar(SCIP_INTERVAL_INFINITY, &denominterval, denominterval, d);
    379
    380 /* there is no useful interval if 0 is in the interior of the interval of the denominator */
    381 if( SCIPintervalGetInf(denominterval) < 0.0 && SCIPintervalGetSup(denominterval) > 0.0 )
    382 {
    384 return result;
    385 }
    386
    387 /* a d = b c implies that f(x) = b / d + e, i.e., f is constant */
    388 if( a*d - b*c == 0.0 )
    389 {
    390 SCIPintervalSet(&result, b / d + e);
    391 return result;
    392 }
    393
    394 /*
    395 * evaluate for [x.inf,x.inf] and [x.sup,x.sup] independently
    396 */
    397 SCIPintervalSetEmpty(&result);
    398
    399 for( i = 0; i < 2; ++i )
    400 {
    401 SCIP_INTERVAL quotinterval;
    402 SCIP_Real val = (i == 0) ? bnds.inf : bnds.sup;
    403
    404 /* set the resulting interval to a / c if the bounds is infinite */
    405 if( SCIPisInfinity(scip, REALABS(val)) )
    406 {
    407 SCIPintervalSet(&quotinterval, a);
    408 SCIPintervalDivScalar(SCIP_INTERVAL_INFINITY, &quotinterval, quotinterval, c);
    409 }
    410 else
    411 {
    412 /* a x' + b */
    413 SCIPintervalSet(&numinterval, val);
    414 SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &numinterval, numinterval, a);
    415 SCIPintervalAddScalar(SCIP_INTERVAL_INFINITY, &numinterval, numinterval, b);
    416
    417 /* c x' + d */
    418 SCIPintervalSet(&denominterval, val);
    419 SCIPintervalMulScalar(SCIP_INTERVAL_INFINITY, &denominterval, denominterval, c);
    420 SCIPintervalAddScalar(SCIP_INTERVAL_INFINITY, &denominterval, denominterval, d);
    421
    422 /* (a x' + b) / (c x' + d) + e */
    423 SCIPintervalDiv(SCIP_INTERVAL_INFINITY, &quotinterval, numinterval, denominterval);
    424 SCIPintervalAddScalar(SCIP_INTERVAL_INFINITY, &quotinterval, quotinterval, e);
    425 }
    426
    427 /* unify with the resulting interval */
    428 SCIPintervalUnify(&result, result, quotinterval);
    429 }
    430
    431 return result;
    432}
    433
    434/** helper method to compute reverse propagation for (a x + b) / (c x + d) + e */
    435static
    437 SCIP_INTERVAL bnds, /**< bounds on (a x + b) / (c x + d) + e */
    438 SCIP_Real a, /**< coefficient in numerator */
    439 SCIP_Real b, /**< constant in numerator */
    440 SCIP_Real c, /**< coefficient in denominator */
    441 SCIP_Real d, /**< constant in denominator */
    442 SCIP_Real e /**< constant */
    443 )
    444{
    445 SCIP_INTERVAL result;
    446 int i;
    447
    448 SCIPintervalSetEmpty(&result);
    449
    450 /* return empty interval if the domain of the expression is empty */
    452 return result;
    453
    454 /* substract constant from bounds of the expression */
    456
    457 /* if the expression is constant or the limit lies inside the domain, nothing can be propagated */
    458 if( a*d - b*c == 0.0 || (bnds.inf < a / c && bnds.sup > a / c) )
    459 {
    461 return result;
    462 }
    463
    464 /* compute bounds for [x.inf,x.inf] and [x.sup,x.sup] independently */
    465 for( i = 0; i < 2; ++i )
    466 {
    469 SCIP_INTERVAL quotient;
    470 SCIP_Real val = (i == 0) ? bnds.inf : bnds.sup;
    471
    472 /* (d * x' - b) */
    476
    477 /* (a - c * x') */
    481
    482 /* (d * x' - b) / (a - c * x') */
    484
    485 /* unify with the resulting interval */
    486 SCIPintervalUnify(&result, result, quotient);
    487 }
    488
    489 return result;
    490}
    491
    492/** adds data to given rowprep; the generated estimator is always locally valid
    493 *
    494 * @note the constant is moved to the left- or right-hand side
    495 * @note other than the name of this function may indicate, it does not create a rowprep
    496 */
    497static
    499 SCIP* scip, /**< SCIP data structure */
    500 SCIP_ROWPREP* rowprep, /**< a rowprep where to store the estimator */
    501 SCIP_VAR** vars, /**< variables */
    502 SCIP_Real* coefs, /**< coefficients */
    503 SCIP_Real constant, /**< constant */
    504 int nlinvars /**< total number of variables */
    505 )
    506{
    507 assert(scip != NULL);
    508 assert(rowprep != NULL);
    509 assert(coefs != NULL);
    510 assert(vars != NULL);
    511
    512 /* create rowprep */
    513 SCIProwprepAddSide(rowprep, -constant);
    514 SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nlinvars + 1) );
    515
    516 /* add coefficients */
    517 SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, nlinvars, vars, coefs) );
    518
    519 return SCIP_OKAY;
    520}
    521
    522/** computes an estimator at a given point for the univariate case (ax + b) / (cx + d) + e
    523 *
    524 * Depending on the reference point, the estimator is a tangent or a secant on the graph.
    525 * It depends on whether we are under- or overestimating, whether we are on the left or
    526 * on the right side of the singularity at -d/c, and whether it is the monotone increasing
    527 * (ad - bc > 0) or decreasing part (ad - bc < 0). Together, there are 8 cases:
    528 *
    529 * - mon. incr. + overestimate + left hand side --> secant
    530 * - mon. incr. + overestimate + right hand side --> tangent
    531 * - mon. incr. + understimate + left hand side --> tangent
    532 * - mon. incr. + understimate + right hand side --> secant
    533 * - mon. decr. + overestimate + left hand side --> tangent
    534 * - mon. decr. + overestimate + right hand side --> secant
    535 * - mon. decr. + understimate + left hand side --> secant
    536 * - mon. decr. + understimate + right hand side --> tangent
    537 */
    538static
    540 SCIP* scip, /**< SCIP data structure */
    541 SCIP_Real lbx, /**< local lower bound of x */
    542 SCIP_Real ubx, /**< local upper bound of x */
    543 SCIP_Real gllbx, /**< global lower bound of x */
    544 SCIP_Real glubx, /**< global upper bound of x */
    545 SCIP_Real solx, /**< solution value of x */
    546 SCIP_Real a, /**< coefficient in numerator */
    547 SCIP_Real b, /**< constant in numerator */
    548 SCIP_Real c, /**< coefficient in denominator */
    549 SCIP_Real d, /**< constant in denominator */
    550 SCIP_Real e, /**< constant */
    551 SCIP_Real* coef, /**< pointer to store the coefficient */
    552 SCIP_Real* constant, /**< pointer to store the constant */
    553 SCIP_Bool overestimate, /**< whether the expression should be overestimated */
    554 SCIP_Bool* local, /**< pointer to store whether the estimate is locally valid */
    555 SCIP_Bool* branchinguseful, /**< pointer to store whether branching on the expression would improve the estimator */
    556 SCIP_Bool* success /**< buffer to store whether separation was successful */
    557 )
    558{
    559 SCIP_Real singularity;
    560 SCIP_Bool isinleftpart;
    561 SCIP_Bool monincreasing;
    562
    563 assert(lbx <= solx && solx <= ubx);
    564 assert(coef != NULL);
    565 assert(constant != NULL);
    566 assert(local != NULL);
    567 assert(branchinguseful != NULL);
    568 assert(success != NULL);
    569
    570 *branchinguseful = TRUE;
    571 *success = FALSE;
    572 *coef = 0.0;
    573 *constant = 0.0;
    574 singularity = -d / c;
    575
    576 /* estimate is globally valid if local and global bounds are equal */
    577 *local = gllbx != lbx || glubx != ubx; /*lint !e777*/
    578
    579 /* if 0 is in the denom interval, estimation is not possible */
    580 if( SCIPisLE(scip, lbx, singularity) && SCIPisGE(scip, ubx, singularity) )
    581 return SCIP_OKAY;
    582
    583 isinleftpart = (ubx < singularity);
    584 monincreasing = (a * d - b * c > 0.0);
    585
    586 /* this encodes the 8 cases explained above */
    587 if( monincreasing == (overestimate == isinleftpart) )
    588 {
    589 SCIP_Real lbeval;
    590 SCIP_Real ubeval;
    591
    592 /* if one of the bounds is infinite, secant cannot be computed */
    593 if( SCIPisInfinity(scip, -lbx) || SCIPisInfinity(scip, ubx) )
    594 return SCIP_OKAY;
    595
    596 lbeval = (a * lbx + b) / (c * lbx + d) + e;
    597 ubeval = (a * ubx + b) / (c * ubx + d) + e;
    598
    599 /* compute coefficient and constant of linear estimator */
    600 *coef = (ubeval - lbeval) / (ubx - lbx);
    601 *constant = ubeval - (*coef) * ubx;
    602 }
    603 else
    604 {
    605 SCIP_Real soleval;
    606
    607 soleval = (a * solx + b) / (c * solx + d) + e;
    608
    609 /* compute coefficient and constant of linear estimator */
    610 *coef = (a * d - b * c) / SQR(d + c * solx);
    611 *constant = soleval - (*coef) * solx;
    612
    613 /* gradient cuts are globally valid if the singularity is not in [gllbx,glubx] */
    614 *local = SCIPisLE(scip, gllbx, singularity) && SCIPisGE(scip, glubx, singularity);
    615
    616 /* branching will not improve the convexification via tangent cuts */
    617 *branchinguseful = FALSE;
    618 }
    619
    620 /* avoid huge values in the cut */
    621 if( SCIPisHugeValue(scip, REALABS(*coef)) || SCIPisHugeValue(scip, REALABS(*constant)) )
    622 return SCIP_OKAY;
    623
    624 *success = TRUE;
    625
    626 return SCIP_OKAY;
    627}
    628
    629/** helper method to compute estimator for the univariate case; the estimator is stored in a given rowprep */
    630static
    632 SCIP* scip, /**< SCIP data structure */
    633 SCIP_SOL* sol, /**< solution point (or NULL for the LP solution) */
    634 SCIP_EXPR* xexpr, /**< argument expression */
    635 SCIP_Real a, /**< coefficient in numerator */
    636 SCIP_Real b, /**< constant in numerator */
    637 SCIP_Real c, /**< coefficient in denominator */
    638 SCIP_Real d, /**< constant in denominator */
    639 SCIP_Real e, /**< constant */
    640 SCIP_Bool overestimate, /**< whether the expression should be overestimated */
    641 SCIP_ROWPREP* rowprep, /**< a rowprep where to store the estimator */
    642 SCIP_Bool* branchinguseful, /**< pointer to store whether branching on the expression would improve the estimator */
    643 SCIP_Bool* success /**< buffer to store whether separation was successful */
    644 )
    645{
    646 SCIP_VAR* x;
    647 SCIP_Real constant;
    648 SCIP_Real coef;
    649 SCIP_Real gllbx;
    650 SCIP_Real glubx;
    651 SCIP_Real lbx;
    652 SCIP_Real ubx;
    653 SCIP_Real solx;
    654 SCIP_Bool local;
    655 SCIP_INTERVAL bnd;
    656
    657 assert(rowprep != NULL);
    658 assert(branchinguseful != NULL);
    659 assert(success != NULL);
    660
    662
    663 /* get local bounds on xexpr */
    669 lbx = bnd.inf;
    670 ubx = bnd.sup;
    671
    672 /* check whether variable has been fixed or has empty interval */
    673 if( SCIPisEQ(scip, lbx, ubx) || ubx < lbx )
    674 {
    675 *success = FALSE;
    676 return SCIP_OKAY;
    677 }
    678
    679 /* get global variable bounds */
    680 gllbx = SCIPvarGetLbGlobal(x);
    681 glubx = SCIPvarGetUbGlobal(x);
    682
    683 /* get and adjust solution value */
    684 solx = SCIPgetSolVal(scip, sol, x);
    685 solx = MIN(MAX(solx, lbx), ubx);
    686
    687 /* compute an estimator */
    688 SCIP_CALL( estimateUnivariate(scip, lbx, ubx, gllbx, glubx, solx, a, b, c, d, e, &coef, &constant, overestimate, &local, branchinguseful, success) );
    689
    690 /* add estimator to rowprep, if successful */
    691 if( *success )
    692 {
    693 (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "quot_%s_%lld", SCIPvarGetName(x), SCIPgetNLPs(scip));
    694 SCIP_CALL( createRowprep(scip, rowprep, &x, &coef, constant, 1) );
    695 SCIProwprepSetLocal(rowprep, local);
    696 }
    697
    698 return SCIP_OKAY;
    699}
    700
    701/** helper method to compute a gradient cut for
    702 * \f[
    703 * h^c(x,y) := \frac{1}{y} \left(\frac{x + \sqrt{\text{lbx}\cdot\text{ubx}}}{\sqrt{\text{lbx}} + \sqrt{\text{ubx}}}\right)^2
    704 * \f]
    705 * at a given reference point
    706 *
    707 * See Zamora and Grossmann (1988) for more details.
    708 */
    709static
    711 SCIP_Real lbx, /**< lower bound of x */
    712 SCIP_Real ubx, /**< upper bound of x */
    713 SCIP_Real solx, /**< solution value of x */
    714 SCIP_Real soly, /**< solution value of y */
    715 SCIP_Real* coefx, /**< pointer to store the coefficient of x */
    716 SCIP_Real* coefy, /**< pointer to store the coefficient of y */
    717 SCIP_Real* constant /**< pointer to store the constant */
    718 )
    719{
    720 SCIP_Real tmp1;
    721 SCIP_Real tmp2;
    722
    723 assert(lbx >= 0.0);
    724 assert(lbx <= ubx);
    725 assert(soly > 0.0);
    726 assert(coefx != NULL);
    727 assert(coefy != NULL);
    728 assert(constant != NULL);
    729
    730 tmp1 = sqrt(lbx * ubx) + solx;
    731 tmp2 = SQR(sqrt(lbx) + sqrt(ubx)) * soly; /*lint !e666*/
    732 assert(tmp2 > 0.0);
    733
    734 *coefx = 2.0 * tmp1 / tmp2;
    735 *coefy = -SQR(tmp1) / (tmp2 * soly);
    736 *constant = 2.0 * sqrt(lbx * ubx) * tmp1 / tmp2;
    737}
    738
    739/** computes an over- or underestimator at a given point for the bivariate case x/y &le;/&ge; z
    740 *
    741 * There are the following cases for y > 0:
    742 *
    743 * 1. lbx < 0 < ubx:
    744 * Rewrite x / y = z as x = y * z and use McCormick to compute a valid inequality of the form
    745 * x = y * z &le; a * y + b * z + c. Note that b > 0 because of y > 0. The inequality is then transformed
    746 * to x / b - a/b * y - c/b &le; z, which results in a valid underestimator for x / y over the set
    747 * {(x,y) | lbz &le; x / y &le; ubz}. Note that overestimating/underestimating the bilinear term with McCormick
    748 * results in an underestimator/overestimator for x / y.
    749 *
    750 * 2. lbx &ge; 0 or ubx &le; 0:
    751 * - overestimation: use \f$z \leq \frac{1}{\text{lby}\cdot\text{uby}} \min(\text{uby}\cdot x - \text{lbx}\cdot y + \text{lbx}\cdot\text{lby}, \text{lby}\cdot x - \text{ubx}\cdot y + \text{ubx}\cdot\text{uby})\f$
    752 * - underestimation: use \f$z \geq x/y \geq \frac{1}{y} \frac{x + \sqrt{\text{lbx}\cdot\text{ubx}}}{\sqrt{\text{lbx} + \sqrt{\text{ubx}}}}\f$ and build gradient cut
    753 *
    754 * If y < 0, swap and negate its bounds and compute the respective opposite estimator (and negate it).
    755 *
    756 * If 0 is in the interval of y, nothing is possible.
    757 */
    758static
    760 SCIP* scip, /**< SCIP data structure */
    761 SCIP_Real lbx, /**< lower bound of x */
    762 SCIP_Real ubx, /**< upper bound of x */
    763 SCIP_Real lby, /**< lower bound of y */
    764 SCIP_Real uby, /**< upper bound of y */
    765 SCIP_Real lbz, /**< lower bound of z */
    766 SCIP_Real ubz, /**< lower bound of z */
    767 SCIP_Real solx, /**< reference point for x */
    768 SCIP_Real soly, /**< reference point for y */
    769 SCIP_Real solz, /**< reference point for z */
    770 SCIP_Bool overestimate, /**< whether the expression should be overestimated */
    771 SCIP_Real* coefx, /**< pointer to store the x coefficient */
    772 SCIP_Real* coefy, /**< pointer to store the y coefficient */
    773 SCIP_Real* constant, /**< pointer to store the constant */
    774 SCIP_Bool* branchingusefulx, /**< pointer to store whether branching on x would improve the estimator */
    775 SCIP_Bool* branchingusefuly, /**< pointer to store whether branching on y would improve the estimator */
    776 SCIP_Bool* success /**< buffer to store whether computing the estimator was successful */
    777 )
    778{
    779 SCIP_Bool negatedx = FALSE;
    780 SCIP_Bool negatedy = FALSE;
    781
    782 assert(lbx <= solx && solx <= ubx);
    783 assert(lby <= soly && soly <= uby);
    784 assert(lbz <= solz && solz <= ubz);
    785 assert(coefx != NULL);
    786 assert(coefy != NULL);
    787 assert(constant != NULL);
    788 assert(branchingusefulx != NULL);
    789 assert(branchingusefuly != NULL);
    790 assert(success != NULL);
    791
    792 *branchingusefulx = TRUE;
    793 *branchingusefuly = TRUE;
    794 *success = TRUE;
    795 *coefx = 0.0;
    796 *coefy = 0.0;
    797 *constant = 0.0;
    798
    799 /* if 0 is in [lby,uby], then it is not possible to compute an estimator */
    800 if( SCIPisLE(scip, lby, 0.0) && SCIPisGE(scip, uby, 0.0) )
    801 {
    802 *success = FALSE;
    803 return SCIP_OKAY;
    804 }
    805
    806 /* negate bounds of y if it is not positive */
    807 if( uby < 0.0 )
    808 {
    809 SCIP_Real tmp = uby;
    810
    811 uby = -lby;
    812 lby = -tmp;
    813 soly = -soly;
    814 negatedy = TRUE;
    815 overestimate = !overestimate;
    816 }
    817
    818 /* case 1: 0 is in the interior of [lbx,ubx] */
    819 if( lbx < 0.0 && 0.0 < ubx )
    820 {
    821 SCIP_Real mccoefy = 0.0;
    822 SCIP_Real mccoefaux = 0.0;
    823 SCIP_Real mcconst = 0.0;
    824
    825 /* as explained in the description of this method, overestimating/underestimating the bilinear term results in an
    826 * underestimator/overestimator for x / y
    827 */
    828 SCIPaddBilinMcCormick(scip, 1.0, lbz, ubz, solz, lby, uby, soly, !overestimate, &mccoefaux, &mccoefy, &mcconst,
    829 success);
    830 assert(mccoefaux >= 0.0);
    831
    832 if( !(*success) )
    833 return SCIP_OKAY;
    834
    835 /* resulting estimator is x/b - a/b * y - c/b, where a*y + b*z + c is the estimator for y*z */
    836 *coefx = 1.0 / mccoefaux;
    837 *coefy = -mccoefy / mccoefaux;
    838 *constant = -mcconst / mccoefaux;
    839 }
    840 /* case 2: 0 is not in the interior of [lbx,ubx] */
    841 else
    842 {
    843 /* negate bounds of x if it is negative */
    844 if( ubx <= 0.0 )
    845 {
    846 SCIP_Real tmp = ubx;
    847
    848 ubx = -lbx;
    849 lbx = -tmp;
    850 solx = -solx;
    851 negatedx = TRUE;
    852 overestimate = !overestimate;
    853 }
    854
    855 /* case 2a */
    856 if( overestimate )
    857 {
    858 /* check where the minimum is attained */
    859 if( uby * solx - lbx * soly + lbx * lby <= lby * solx - ubx * soly + ubx * uby )
    860 {
    861 *coefx = 1.0 / lby;
    862 *coefy = -lbx / (lby * uby);
    863 *constant = lbx / uby;
    864 }
    865 else
    866 {
    867 *coefx = 1.0 / uby;
    868 *coefy = -ubx / (lby * uby);
    869 *constant = ubx / lby;
    870 }
    871 }
    872 /* case 2b */
    873 else
    874 {
    875 /* compute gradient cut for h^c(x,y) at (solx,soly) */
    876 hcGradCut(lbx, ubx, solx, soly, coefx, coefy, constant);
    877
    878 /* estimator is independent of the bounds of y */
    879 *branchingusefuly = FALSE;
    880 }
    881 }
    882
    883 /* reverse negations of x and y in the resulting estimator */
    884 if( negatedx )
    885 *coefx = -(*coefx);
    886 if( negatedy )
    887 *coefy = -(*coefy);
    888
    889 /* if exactly one variable has been negated, then we have computed an underestimate/overestimate for the negated
    890 * expression, which results in an overestimate/underestimate for the original expression
    891 */
    892 if( negatedx != negatedy )
    893 {
    894 *coefx = -(*coefx);
    895 *coefy = -(*coefy);
    896 *constant = -(*constant);
    897 }
    898
    899 /* avoid huge values in the estimator */
    900 if( SCIPisHugeValue(scip, REALABS(*coefx)) || SCIPisHugeValue(scip, REALABS(*coefy))
    901 || SCIPisHugeValue(scip, REALABS(*constant)) )
    902 {
    903 *success = FALSE;
    904 return SCIP_OKAY;
    905 }
    906
    907 return SCIP_OKAY;
    908}
    909
    910/** construct an estimator for a quotient expression of the form (ax + b) / (cy + d) + e
    911 *
    912 * The resulting estimator is stored in a rowprep.
    913 *
    914 * The method first computes an estimator for x' / y' with x := ax + b and y := cy + d
    915 * and then transforms this estimator to one for the quotient (ax + b) / (cy + d) + e.
    916 */
    917static
    919 SCIP* scip, /**< SCIP data structure */
    920 SCIP_EXPR* xexpr, /**< numerator expression */
    921 SCIP_EXPR* yexpr, /**< denominator expression */
    922 SCIP_VAR* auxvar, /**< auxiliary variable */
    923 SCIP_SOL* sol, /**< solution point (or NULL for the LP solution) */
    924 SCIP_Real a, /**< coefficient of numerator */
    925 SCIP_Real b, /**< constant of numerator */
    926 SCIP_Real c, /**< coefficient of denominator */
    927 SCIP_Real d, /**< constant of denominator */
    928 SCIP_Real e, /**< constant term */
    929 SCIP_Bool overestimate, /**< whether the expression should be overestimated */
    930 SCIP_ROWPREP* rowprep, /**< a rowprep where to store the estimator */
    931 SCIP_Bool* branchingusefulx, /**< pointer to store whether branching on x would improve the estimator */
    932 SCIP_Bool* branchingusefuly, /**< pointer to store whether branching on y would improve the estimator */
    933 SCIP_Bool* success /**< buffer to store whether separation was successful */
    934 )
    935{
    936 SCIP_VAR* vars[2];
    937 SCIP_Real coefs[2] = {0.0, 0.0};
    938 SCIP_Real constant = 0.0;
    939 SCIP_Real solx;
    940 SCIP_Real soly;
    941 SCIP_Real solz;
    942 SCIP_Real lbx;
    943 SCIP_Real ubx;
    944 SCIP_Real lby;
    945 SCIP_Real uby;
    946 SCIP_Real lbz;
    947 SCIP_Real ubz;
    948 SCIP_INTERVAL bnd;
    949
    950 assert(xexpr != NULL);
    951 assert(yexpr != NULL);
    952 assert(xexpr != yexpr);
    953 assert(auxvar != NULL);
    954 assert(rowprep != NULL);
    955 assert(branchingusefulx != NULL);
    956 assert(branchingusefuly != NULL);
    957 assert(success != NULL);
    958
    959 vars[0] = SCIPgetExprAuxVarNonlinear(xexpr);
    960 vars[1] = SCIPgetExprAuxVarNonlinear(yexpr);
    961
    962 /* get bounds for x, y, and z */
    968 lbx = bnd.inf;
    969 ubx = bnd.sup;
    970
    976 lby = bnd.inf;
    977 uby = bnd.sup;
    978
    979 lbz = SCIPvarGetLbLocal(auxvar);
    980 ubz = SCIPvarGetUbLocal(auxvar);
    981
    982 /* check whether one of the variables has been fixed or has empty domain */
    983 if( SCIPisEQ(scip, lbx, ubx) || SCIPisEQ(scip, lby, uby) || ubx < lbx || uby < lby )
    984 {
    985 *success = FALSE;
    986 return SCIP_OKAY;
    987 }
    988
    989 /* get and adjust solution values */
    990 solx = SCIPgetSolVal(scip, sol, vars[0]);
    991 soly = SCIPgetSolVal(scip, sol, vars[1]);
    992 solz = SCIPgetSolVal(scip, sol, auxvar);
    993 solx = MIN(MAX(solx, lbx), ubx);
    994 soly = MIN(MAX(soly, lby), uby);
    995 solz = MIN(MAX(solz, lbz), ubz);
    996
    997 /* compute an estimator */
    999 MIN(a * lbx, a * ubx) + b, MAX(a * lbx, a * ubx) + b, /* bounds of x' */
    1000 MIN(c * lby, c * uby) + d, MAX(c * lby, c * uby) + d, /* bounds of y' */
    1001 lbz, ubz, a * solx + b, c * soly + d, solz, overestimate, &coefs[0], &coefs[1], &constant,
    1002 branchingusefulx, branchingusefuly, success) );
    1003
    1004 /* add estimator to rowprep, if successful */
    1005 if( *success )
    1006 {
    1007 /* transform estimator Ax' + By'+ C = A(ax + b) + B (cy + d) + C = (Aa) x + (Bc) y + (C + Ab + Bd);
    1008 * add the constant e separately
    1009 */
    1010 constant += coefs[0] * b + coefs[1] * d + e;
    1011 coefs[0] *= a;
    1012 coefs[1] *= c;
    1013
    1014 /* prepare rowprep */
    1015 (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "quot_%s_%s_%lld", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]),
    1016 SCIPgetNLPs(scip));
    1017 SCIP_CALL( createRowprep(scip, rowprep, vars, coefs, constant, 2) );
    1018 }
    1019
    1020 return SCIP_OKAY;
    1021}
    1022
    1023/*
    1024 * Callback methods of nonlinear handler
    1025 */
    1026
    1027/** nonlinear handler copy callback */
    1028static
    1029SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrQuotient)
    1030{ /*lint --e{715}*/
    1031 assert(targetscip != NULL);
    1032 assert(sourcenlhdlr != NULL);
    1033
    1035
    1036 SCIP_CALL( SCIPincludeNlhdlrQuotient(targetscip) );
    1037
    1038 return SCIP_OKAY;
    1039}
    1040
    1041
    1042/** callback to free expression specific data */
    1043static
    1044SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataQuotient)
    1045{ /*lint --e{715}*/
    1046 assert(nlhdlrexprdata != NULL);
    1047 assert(*nlhdlrexprdata != NULL);
    1048
    1049 /* free expression data of nonlinear handler */
    1050 SCIP_CALL( exprdataFree(scip, nlhdlrexprdata) );
    1051
    1052 return SCIP_OKAY;
    1053}
    1054
    1055
    1056/** callback to detect structure in expression tree */
    1057static
    1058SCIP_DECL_NLHDLRDETECT(nlhdlrDetectQuotient)
    1059{ /*lint --e{715}*/
    1060 SCIP_Bool success;
    1061
    1062 assert(nlhdlrexprdata != NULL);
    1063
    1064 /* call detection routine */
    1065 SCIP_CALL( detectExpr(scip, expr, nlhdlrexprdata, &success) );
    1066
    1067 if( success )
    1068 {
    1069 if( SCIPgetExprNAuxvarUsesNonlinear(expr) > 0 )
    1070 *participating = SCIP_NLHDLR_METHOD_SEPABOTH;
    1071
    1072 if( (*nlhdlrexprdata)->numexpr == (*nlhdlrexprdata)->denomexpr )
    1073 {
    1074 /* if univariate, then we also do inteval and reverseprop */
    1075 *participating |= SCIP_NLHDLR_METHOD_ACTIVITY;
    1076
    1077 /* if univariate, then all our methods are enforcing */
    1078 *enforcing |= *participating;
    1079 }
    1080 }
    1081
    1082 return SCIP_OKAY;
    1083}
    1084
    1085
    1086/** auxiliary evaluation callback of nonlinear handler */
    1087static
    1088SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxQuotient)
    1089{ /*lint --e{715}*/
    1090 SCIP_VAR* auxvarx;
    1091 SCIP_VAR* auxvary;
    1092 SCIP_Real solvalx;
    1093 SCIP_Real solvaly;
    1094 SCIP_Real nomval;
    1095 SCIP_Real denomval;
    1096
    1097 assert(expr != NULL);
    1098 assert(auxvalue != NULL);
    1099
    1100 /**! [SnippetNlhdlrEvalauxQuotient] */
    1101 /* get auxiliary variables */
    1102 auxvarx = SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->numexpr);
    1103 auxvary = SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->denomexpr);
    1104 assert(auxvarx != NULL);
    1105 assert(auxvary != NULL);
    1106
    1107 /* get solution values of the auxiliary variables */
    1108 solvalx = SCIPgetSolVal(scip, sol, auxvarx);
    1109 solvaly = SCIPgetSolVal(scip, sol, auxvary);
    1110
    1111 /* evaluate expression w.r.t. the values of the auxiliary variables */
    1112 nomval = nlhdlrexprdata->numcoef * solvalx + nlhdlrexprdata->numconst;
    1113 denomval = nlhdlrexprdata->denomcoef * solvaly + nlhdlrexprdata->denomconst;
    1114
    1115 /* return SCIP_INVALID if the denominator evaluates to zero */
    1116 *auxvalue = (denomval != 0.0) ? nlhdlrexprdata->constant + nomval / denomval : SCIP_INVALID;
    1117 /**! [SnippetNlhdlrEvalauxQuotient] */
    1118
    1119 return SCIP_OKAY;
    1120}
    1121
    1122
    1123/** nonlinear handler under/overestimation callback
    1124 *
    1125 * @todo which of the paramters did I not use, but have to be taken into consideration?
    1126*/
    1127static
    1128SCIP_DECL_NLHDLRESTIMATE(nlhdlrEstimateQuotient)
    1129{ /*lint --e{715}*/
    1130 SCIP_Bool branchingusefulx = FALSE;
    1131 SCIP_Bool branchingusefuly = FALSE;
    1132 SCIP_ROWPREP* rowprep;
    1133
    1134 assert(nlhdlr != NULL);
    1135 assert(expr != NULL);
    1136 assert(nlhdlrexprdata != NULL);
    1137 assert(rowpreps != NULL);
    1138
    1139 /** ![SnippetNlhdlrEstimateQuotient] */
    1140 *addedbranchscores = FALSE;
    1141 *success = FALSE;
    1142
    1144
    1145 if( nlhdlrexprdata->numexpr == nlhdlrexprdata->denomexpr )
    1146 {
    1147 /* univariate case */
    1148 SCIP_CALL( estimateUnivariateQuotient(scip, sol, nlhdlrexprdata->numexpr, nlhdlrexprdata->numcoef, nlhdlrexprdata->numconst,
    1149 nlhdlrexprdata->denomcoef, nlhdlrexprdata->denomconst, nlhdlrexprdata->constant, overestimate, rowprep,
    1150 &branchingusefulx, success) );
    1151 }
    1152 else
    1153 {
    1154 /* bivariate case */
    1155 SCIP_CALL( estimateBivariateQuotient(scip, nlhdlrexprdata->numexpr, nlhdlrexprdata->denomexpr, SCIPgetExprAuxVarNonlinear(expr), sol,
    1156 nlhdlrexprdata->numcoef, nlhdlrexprdata->numconst, nlhdlrexprdata->denomcoef, nlhdlrexprdata->denomconst,
    1157 nlhdlrexprdata->constant, overestimate, rowprep,
    1158 &branchingusefulx, &branchingusefuly, success) );
    1159 }
    1160
    1161 if( *success )
    1162 {
    1163 SCIP_CALL( SCIPsetPtrarrayVal(scip, rowpreps, 0, rowprep) );
    1164 }
    1165 else
    1166 {
    1167 SCIPfreeRowprep(scip, &rowprep);
    1168 }
    1169
    1170 /* add branching scores if requested */
    1171 if( addbranchscores )
    1172 {
    1173 SCIP_EXPR* exprs[2];
    1174 SCIP_Real violation;
    1175 int nexprs = 0;
    1176
    1177 if( branchingusefulx )
    1178 exprs[nexprs++] = nlhdlrexprdata->numexpr;
    1179 if( branchingusefuly )
    1180 exprs[nexprs++] = nlhdlrexprdata->denomexpr;
    1181
    1182 /* compute violation w.r.t. the auxiliary variable(s) */
    1183#ifndef BRSCORE_ABSVIOL
    1184 SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violation, NULL, NULL) );
    1185#else
    1186 SCIP_CALL( SCIPgetExprAbsAuxViolationNonlinear(scip, expr, auxvalue, sol, &violation, NULL, NULL) );
    1187#endif
    1188 assert(violation > 0.0); /* there should be a violation if we were called to enforce */
    1189
    1190 SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violation, sol, addedbranchscores) );
    1191 }
    1192 /** ![SnippetNlhdlrEstimateQuotient] */
    1193
    1194 return SCIP_OKAY;
    1195}
    1196
    1197/** nonlinear handler solution linearization callback */
    1198static
    1199SCIP_DECL_NLHDLRSOLLINEARIZE(nlhdlrSollinearizeQuotient)
    1200{ /*lint --e{715}*/
    1201 SCIP_VAR* x;
    1202 SCIP_Real lbx;
    1203 SCIP_Real ubx;
    1204 SCIP_Real solx;
    1205 int c;
    1206
    1207 assert(nlhdlr != NULL);
    1208 assert(expr != NULL);
    1209 assert(nlhdlrexprdata != NULL);
    1210
    1211 /* in the bivariate case, we do not get globally valid estimators */
    1212 if( nlhdlrexprdata->numexpr != nlhdlrexprdata->denomexpr )
    1213 return SCIP_OKAY;
    1214
    1215 x = SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->numexpr);
    1216 lbx = SCIPvarGetLbGlobal(x);
    1217 ubx = SCIPvarGetUbGlobal(x);
    1218 solx = SCIPgetSolVal(scip, sol, x);
    1219 solx = MAX(MIN(solx, ubx), lbx);
    1220
    1221 for( c = (overestimate ? 0 : 1); c < (underestimate ? 2 : 1); ++c ) /* c == 0: overestimate, c == 1: underestimate */
    1222 {
    1223 SCIP_ROWPREP* rowprep;
    1224 SCIP_Bool success = FALSE;
    1225 SCIP_Bool local = TRUE;
    1226 SCIP_Bool branchinguseful;
    1227 SCIP_Real coef;
    1228 SCIP_Real constant;
    1229
    1230 /* compute estimator, will be secant or gradient */
    1231 SCIP_CALL( estimateUnivariate(scip, lbx, ubx, lbx, ubx, solx,
    1232 nlhdlrexprdata->numcoef, nlhdlrexprdata->numconst, nlhdlrexprdata->denomcoef, nlhdlrexprdata->denomconst, nlhdlrexprdata->constant,
    1233 &coef, &constant, c == 0, &local, &branchinguseful, &success) );
    1234
    1235 /* skip if not successful, only locally valid, or just a secant (branchinguseful is TRUE) */
    1236 if( !success || local || branchinguseful )
    1237 continue;
    1238
    1240 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, x, coef) );
    1242 SCIProwprepAddConstant(rowprep, constant);
    1243 (void) SCIPsnprintf(SCIProwprepGetName(rowprep), SCIP_MAXSTRLEN, "quot_%s_sol%d", SCIPvarGetName(x), SCIPsolGetIndex(sol));
    1244
    1245 SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, SCIPgetHugeValue(scip), &success) );
    1246
    1247 /* if cleanup succeeded and rowprep is still global, add to cutpool */
    1248 if( success && !SCIProwprepIsLocal(rowprep) )
    1249 {
    1250 SCIP_ROW* row;
    1251
    1252 SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
    1253 SCIP_CALL( SCIPaddPoolCut(scip, row) );
    1254 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    1255 }
    1256
    1257 SCIPfreeRowprep(scip, &rowprep);
    1258 }
    1259
    1260 return SCIP_OKAY;
    1261}
    1262
    1263/** nonlinear handler interval evaluation callback */
    1264static
    1265SCIP_DECL_NLHDLRINTEVAL(nlhdlrIntevalQuotient)
    1266{ /*lint --e{715}*/
    1267 SCIP_INTERVAL bnds;
    1268
    1269 assert(nlhdlrexprdata != NULL);
    1270 assert(nlhdlrexprdata->numexpr != NULL);
    1271 assert(nlhdlrexprdata->denomexpr != NULL);
    1272
    1273 /* it is not possible to compute tighter intervals if both expressions are different
    1274 * we should not be called in this case, as we haven't said we would participate in this activity in detect
    1275 */
    1276 assert(nlhdlrexprdata->numexpr == nlhdlrexprdata->denomexpr);
    1277
    1278 /**! [SnippetNlhdlrIntevalQuotient] */
    1279 /* get activity of the numerator (= denominator) expression */
    1280 bnds = SCIPexprGetActivity(nlhdlrexprdata->numexpr);
    1281
    1282 /* call interval evaluation for the univariate quotient expression */
    1283 *interval = intEvalQuotient(scip, bnds, nlhdlrexprdata->numcoef, nlhdlrexprdata->numconst,
    1284 nlhdlrexprdata->denomcoef, nlhdlrexprdata->denomconst, nlhdlrexprdata->constant);
    1285 /**! [SnippetNlhdlrIntevalQuotient] */
    1286
    1287 return SCIP_OKAY;
    1288}
    1289
    1290
    1291/** nonlinear handler callback for reverse propagation */
    1292static
    1293SCIP_DECL_NLHDLRREVERSEPROP(nlhdlrReversepropQuotient)
    1294{ /*lint --e{715}*/
    1295 SCIP_INTERVAL result;
    1296
    1297 assert(nlhdlrexprdata != NULL);
    1298 assert(nlhdlrexprdata->numexpr != NULL);
    1299 assert(nlhdlrexprdata->denomexpr != NULL);
    1300
    1301 /* it is not possible to compute tighter intervals if both expressions are different
    1302 * we should not be called in this case, as we haven't said we would participate in this activity in detect
    1303 */
    1304 assert(nlhdlrexprdata->numexpr == nlhdlrexprdata->denomexpr);
    1305
    1306 SCIPdebugMsg(scip, "call reverse propagation for expression (%g %p + %g) / (%g %p + %g) + %g bounds [%g,%g]\n",
    1307 nlhdlrexprdata->numcoef, (void*)nlhdlrexprdata->numexpr, nlhdlrexprdata->numconst,
    1308 nlhdlrexprdata->denomcoef, (void*)nlhdlrexprdata->denomexpr, nlhdlrexprdata->denomconst,
    1309 nlhdlrexprdata->constant, bounds.inf, bounds.sup);
    1310
    1311 /* call reverse propagation */
    1312 /**! [SnippetNlhdlrReversepropQuotient] */
    1313 result = reversepropQuotient(bounds, nlhdlrexprdata->numcoef, nlhdlrexprdata->numconst,
    1314 nlhdlrexprdata->denomcoef, nlhdlrexprdata->denomconst, nlhdlrexprdata->constant);
    1315
    1316 SCIPdebugMsg(scip, "try to tighten bounds of %p: [%g,%g] -> [%g,%g]\n",
    1317 (void*)nlhdlrexprdata->numexpr, SCIPgetExprBoundsNonlinear(scip, nlhdlrexprdata->numexpr).inf,
    1318 SCIPgetExprBoundsNonlinear(scip, nlhdlrexprdata->numexpr).sup, result.inf, result.sup);
    1319
    1320 /* tighten bounds of the expression */
    1321 SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, nlhdlrexprdata->numexpr, result, infeasible, nreductions) );
    1322 /**! [SnippetNlhdlrReversepropQuotient] */
    1323
    1324 return SCIP_OKAY;
    1325}
    1326
    1327
    1328/*
    1329 * nonlinear handler specific interface methods
    1330 */
    1331
    1332/** includes quotient nonlinear handler in nonlinear constraint handler */
    1334 SCIP* scip /**< SCIP data structure */
    1335 )
    1336{
    1337 SCIP_NLHDLRDATA* nlhdlrdata;
    1338 SCIP_NLHDLR* nlhdlr;
    1339
    1340 assert(scip != NULL);
    1341
    1342 /* create nonlinear handler data */
    1343 nlhdlrdata = NULL;
    1344
    1346 NLHDLR_ENFOPRIORITY, nlhdlrDetectQuotient, nlhdlrEvalauxQuotient, nlhdlrdata) );
    1347 assert(nlhdlr != NULL);
    1348
    1349 SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrQuotient);
    1350 SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrFreeExprDataQuotient);
    1351 SCIPnlhdlrSetSepa(nlhdlr, NULL, NULL, nlhdlrEstimateQuotient, NULL);
    1352 SCIPnlhdlrSetSollinearize(nlhdlr, nlhdlrSollinearizeQuotient);
    1353 SCIPnlhdlrSetProp(nlhdlr, nlhdlrIntevalQuotient, nlhdlrReversepropQuotient);
    1354
    1355 return SCIP_OKAY;
    1356}
    SCIP_VAR * a
    Definition: circlepacking.c:66
    SCIP_VAR ** b
    Definition: circlepacking.c:65
    SCIP_VAR ** x
    Definition: circlepacking.c:63
    constraint handler for nonlinear constraints specified by algebraic expressions
    #define NULL
    Definition: def.h:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #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 TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    unsigned int SCIPgetExprNAuxvarUsesNonlinear(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPgetExprRelAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
    SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPtightenExprIntervalNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_INTERVAL newbounds, SCIP_Bool *cutoff, int *ntightenings)
    SCIP_RETCODE SCIPaddExprsViolScoreNonlinear(SCIP *scip, SCIP_EXPR **exprs, int nexprs, SCIP_Real violscore, SCIP_SOL *sol, SCIP_Bool *success)
    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_RETCODE SCIPgetExprAbsAuxViolationNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Real auxvalue, SCIP_SOL *sol, SCIP_Real *viol, SCIP_Bool *violunder, SCIP_Bool *violover)
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    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)
    SCIP_RETCODE SCIPincludeNlhdlrQuotient(SCIP *scip)
    SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
    Definition: scip_cut.c:336
    SCIP_RETCODE SCIPsetPtrarrayVal(SCIP *scip, SCIP_PTRARRAY *ptrarray, int idx, void *val)
    int SCIPexprGetNChildren(SCIP_EXPR *expr)
    Definition: expr.c:3872
    SCIP_Real SCIPgetExponentExprPow(SCIP_EXPR *expr)
    Definition: expr_pow.c:3449
    SCIP_Bool SCIPisExprProduct(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1490
    SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1479
    SCIP_Real * SCIPgetCoefsExprSum(SCIP_EXPR *expr)
    Definition: expr_sum.c:1554
    SCIP_Real SCIPgetCoefExprProduct(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
    Definition: scip_expr.c:1443
    SCIP_RETCODE SCIPprintExpr(SCIP *scip, SCIP_EXPR *expr, FILE *file)
    Definition: scip_expr.c:1512
    SCIP_Bool SCIPisExprPower(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1501
    SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
    Definition: expr.c:3882
    SCIP_Real SCIPgetConstantExprSum(SCIP_EXPR *expr)
    Definition: expr_sum.c:1569
    SCIP_INTERVAL SCIPexprGetActivity(SCIP_EXPR *expr)
    Definition: expr.c:4028
    void SCIPcaptureExpr(SCIP_EXPR *expr)
    Definition: scip_expr.c:1435
    SCIP_RETCODE SCIPevalExprActivity(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1742
    void SCIPintervalIntersectEps(SCIP_INTERVAL *resultant, SCIP_Real eps, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
    SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
    void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
    void SCIPintervalUnify(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
    void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real 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)
    void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
    void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
    void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
    SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
    void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #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
    void SCIPnlhdlrSetSollinearize(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRSOLLINEARIZE((*sollinearize)))
    Definition: nlhdlr.c:155
    void SCIPnlhdlrSetSepa(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINITSEPA((*initsepa)), SCIP_DECL_NLHDLRENFO((*enfo)), SCIP_DECL_NLHDLRESTIMATE((*estimate)), SCIP_DECL_NLHDLREXITSEPA((*exitsepa)))
    Definition: nlhdlr.c:137
    const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:167
    SCIP_RETCODE SCIPincludeNlhdlrNonlinear(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
    SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    int SCIPsolGetIndex(SCIP_SOL *sol)
    Definition: sol.c:4305
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_Longint SCIPgetNLPs(SCIP *scip)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPgetHugeValue(SCIP *scip)
    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_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
    Definition: var.c:24174
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23299
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
    Definition: var.c:24152
    SCIP_RETCODE SCIPcleanupRowprep2(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefbound, SCIP_Bool *success)
    SCIP_RETCODE SCIPensureRowprepSize(SCIP *scip, SCIP_ROWPREP *rowprep, int size)
    Definition: misc_rowprep.c:887
    char * SCIProwprepGetName(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:689
    SCIP_Bool SCIProwprepIsLocal(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:679
    void SCIProwprepAddConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
    Definition: misc_rowprep.c:760
    SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
    Definition: misc_rowprep.c:913
    SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONS *cons)
    SCIP_RETCODE SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
    Definition: misc_rowprep.c:563
    SCIP_RETCODE SCIPaddRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep, int nvars, SCIP_VAR **vars, SCIP_Real *coefs)
    Definition: misc_rowprep.c:938
    void SCIProwprepSetLocal(SCIP_ROWPREP *rowprep, SCIP_Bool islocal)
    Definition: misc_rowprep.c:780
    void SCIProwprepAddSide(SCIP_ROWPREP *rowprep, SCIP_Real side)
    Definition: misc_rowprep.c:746
    void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
    Definition: misc_rowprep.c:583
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    INLINE SCIP_Longint numerator(Rational &r)
    INLINE SCIP_Longint denominator(Rational &r)
    private functions of nonlinear handlers of nonlinear constraints
    bilinear nonlinear handler
    static void hcGradCut(SCIP_Real lbx, SCIP_Real ubx, SCIP_Real solx, SCIP_Real soly, SCIP_Real *coefx, SCIP_Real *coefy, SCIP_Real *constant)
    #define NLHDLR_DETECTPRIORITY
    static void transformExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR **target, SCIP_Real *coef, SCIP_Real *constant)
    static SCIP_RETCODE exprdataCreate(SCIP *scip, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_EXPR *numexpr, SCIP_Real numcoef, SCIP_Real numconst, SCIP_EXPR *denomexpr, SCIP_Real denomcoef, SCIP_Real denomconst, SCIP_Real constant)
    #define NLHDLR_ENFOPRIORITY
    static SCIP_RETCODE exprdataFree(SCIP *scip, SCIP_NLHDLREXPRDATA **nlhdlrexprdata)
    static SCIP_DECL_NLHDLRREVERSEPROP(nlhdlrReversepropQuotient)
    static SCIP_RETCODE estimateUnivariate(SCIP *scip, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real gllbx, SCIP_Real glubx, SCIP_Real solx, SCIP_Real a, SCIP_Real b, SCIP_Real c, SCIP_Real d, SCIP_Real e, SCIP_Real *coef, SCIP_Real *constant, SCIP_Bool overestimate, SCIP_Bool *local, SCIP_Bool *branchinguseful, SCIP_Bool *success)
    static SCIP_INTERVAL reversepropQuotient(SCIP_INTERVAL bnds, SCIP_Real a, SCIP_Real b, SCIP_Real c, SCIP_Real d, SCIP_Real e)
    static SCIP_RETCODE estimateBivariateQuotient(SCIP *scip, SCIP_EXPR *xexpr, SCIP_EXPR *yexpr, SCIP_VAR *auxvar, SCIP_SOL *sol, SCIP_Real a, SCIP_Real b, SCIP_Real c, SCIP_Real d, SCIP_Real e, SCIP_Bool overestimate, SCIP_ROWPREP *rowprep, SCIP_Bool *branchingusefulx, SCIP_Bool *branchingusefuly, SCIP_Bool *success)
    static SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataQuotient)
    static SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrQuotient)
    static SCIP_DECL_NLHDLRSOLLINEARIZE(nlhdlrSollinearizeQuotient)
    static SCIP_INTERVAL intEvalQuotient(SCIP *scip, SCIP_INTERVAL bnds, SCIP_Real a, SCIP_Real b, SCIP_Real c, SCIP_Real d, SCIP_Real e)
    #define infty2infty(infty1, infty2, val)
    #define NLHDLR_DESC
    #define NLHDLR_NAME
    static SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxQuotient)
    static SCIP_DECL_NLHDLRINTEVAL(nlhdlrIntevalQuotient)
    static SCIP_RETCODE estimateBivariate(SCIP *scip, SCIP_Real lbx, SCIP_Real ubx, SCIP_Real lby, SCIP_Real uby, SCIP_Real lbz, SCIP_Real ubz, SCIP_Real solx, SCIP_Real soly, SCIP_Real solz, SCIP_Bool overestimate, SCIP_Real *coefx, SCIP_Real *coefy, SCIP_Real *constant, SCIP_Bool *branchingusefulx, SCIP_Bool *branchingusefuly, SCIP_Bool *success)
    static SCIP_RETCODE createRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR **vars, SCIP_Real *coefs, SCIP_Real constant, int nlinvars)
    static SCIP_RETCODE estimateUnivariateQuotient(SCIP *scip, SCIP_SOL *sol, SCIP_EXPR *xexpr, SCIP_Real a, SCIP_Real b, SCIP_Real c, SCIP_Real d, SCIP_Real e, SCIP_Bool overestimate, SCIP_ROWPREP *rowprep, SCIP_Bool *branchinguseful, SCIP_Bool *success)
    static SCIP_RETCODE detectExpr(SCIP *scip, SCIP_EXPR *expr, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_Bool *success)
    static SCIP_DECL_NLHDLRESTIMATE(nlhdlrEstimateQuotient)
    static SCIP_DECL_NLHDLRDETECT(nlhdlrDetectQuotient)
    quotient nonlinear handler
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    preparation of a linear inequality to become a SCIP_ROW
    SCIP_Real sup
    Definition: intervalarith.h:57
    SCIP_Real inf
    Definition: intervalarith.h:56
    @ SCIP_SIDETYPE_RIGHT
    Definition: type_lp.h:66
    @ SCIP_SIDETYPE_LEFT
    Definition: type_lp.h:65
    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