Scippy

    SCIP

    Solving Constraint Integer Programs

    nlhdlr_signomial.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file nlhdlr_signomial.c
    26 * @ingroup DEFPLUGINS_NLHDLR
    27 * @brief signomial nonlinear handler
    28 * @author Liding Xu
    29 */
    30
    31#ifdef SCIP_SIGCUT_DEBUG
    32#ifndef SCIP_SIG_DEBUG
    33#define SCIP_SIG_DEBUG
    34#endif
    35#endif
    36
    37#ifdef SCIP_SIG_DEBUG
    38#define SCIP_DEBUG
    39#endif
    40
    42#include "scip/cons_nonlinear.h"
    44#include "scip/pub_nlhdlr.h"
    45#include "scip/scip_expr.h"
    46#include "scip/expr_var.h"
    47#include "scip/expr_pow.h"
    48
    49/* fundamental nonlinear handler properties */
    50#define NLHDLR_NAME "signomial"
    51#define NLHDLR_DESC "handler for signomial expressions"
    52#define NLHDLR_DETECTPRIORITY 30
    53#define NLHDLR_ENFOPRIORITY 30
    54
    55/* handler specific parameters */
    56#define NLHDLR_MAXNUNDERVARS 14 /**< maximum number of variables when underestimating a concave power function (maximum: 14) */
    57#define NLHDLR_MINCUTSCALE 1e-5 /**< minimum scale factor when scaling a cut (minimum: 1e-6) */
    58
    59
    60/** nonlinear handler expression data
    61 *
    62 * A signomial expression admits the form \f$ cx^a = y \f$, where \f$ y \f$ is an auxiliary variable representing this
    63 * expression and all \f$ x \f$ are positive.
    64 *
    65 * The natural formulation of the expression is defined as \f$ x^a = t = y/c \f$, where \f$ t \f$ is a
    66 * non-existant slack variable denoting \f$ y/c \f$. The variables in \f$x\f$ with positive exponents form positive
    67 * variables \f$ u \f$, and the associated exponents form positive exponents \f$ f \f$. The variables in \f$ x \f$ with
    68 * negative exponents and \f$ t \f$ form negative variables \f$ v \f$, and the associated exponents form negative
    69 * exponents \f$ g \f$. Let \f$ s = \max(|f|,|g|) \f$ be a normalization constant, where \f$ |\cdot| \f$ denotes the L1 norm. Apply a scaling step:
    70 * Dividing the entries of \f$ f \f$ by \f$ s \f$, and dividing the entries of \f$ g \f$ by \f$ s \f$ as well. Then \f$ x^a = t \f$ has
    71 * a reformulation \f$ u^f = v^g \f$, where \f$ u^f, v^g \f$ are two concave power functions.
    72 */
    73struct SCIP_NlhdlrExprData
    74{
    75 SCIP_Real coef; /**< coefficient \f$c\f$ */
    76 SCIP_EXPR** factors; /**< expression factors representing \f$x\f$ */
    77 int nfactors; /**< number of factors */
    78 int nvars; /**< number of variables \f$(x,y)\f$ */
    79 SCIP_Real* exponents; /**< exponents \f$e\f$ */
    80 int nposvars; /**< number of positive variables \f$u\f$ */
    81 int nnegvars; /**< number of negative variables \f$v\f$ */
    82 SCIP_Bool* signs; /**< indicators for sign of variables after reformulation, TRUE for positive, FALSE for negative */
    83 SCIP_Real* refexponents; /**< exponents of \f$(x,t)\f$ after reformulation (always positive) */
    84 SCIP_Bool isstorecapture; /**< are all variables already got? */
    85
    86 /* working parameters will be modified after getting all variables */
    87 SCIP_VAR** vars; /**< variables \f$(x,y)\f$ */
    88 SCIP_INTERVAL* intervals; /**< intervals storing lower and upper bounds of variables \f$(x,y)\f$ */
    89 SCIP_Real* box; /**< the upper/lower bounds of variables, used in SCIPcomputeFacetVertexPolyhedralNonlinear() */
    90 SCIP_Real* xstar; /**< the values of variables, used in SCIPcomputeFacetVertexPolyhedralNonlinear() */
    91 SCIP_Real* facetcoefs; /**< the coefficients of variables, returned by SCIPcomputeFacetVertexPolyhedralNonlinear() */
    92};
    93
    94/** nonlinear handler data */
    95struct SCIP_NlhdlrData
    96{
    97 /* parameters */
    98 int maxnundervars; /**< maximum number of variables in underestimating a concave power function */
    99 SCIP_Real mincutscale; /**< minimum scale factor when scaling a cut */
    100};
    101
    102/** data struct to be passed on to vertexpoly-evalfunction (see SCIPcomputeFacetVertexPolyhedralNonlinear) */
    103typedef struct
    104{
    105 SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< expression data */
    106 SCIP_Bool sign; /**< the sign of variables in the reformulated constraint for vertexpoly-evalfunction */
    107 int nsignvars; /**< the number of variables in the reformulated constraint for vertexpoly-evalfunction */
    108 SCIP* scip; /**< SCIP data structure */
    110
    111
    112/*
    113 * Local methods
    114 */
    115
    116#ifdef SCIP_SIGCUT_DEBUG
    117
    118/** print the information on a signomial term */
    119static
    121 SCIP* scip, /**< SCIP data structure */
    122 SCIP_EXPR* expr, /**< expression */
    123 SCIP_NLHDLREXPRDATA* nlhdlrexprdata /**< expression data */
    124 )
    125{
    126 assert(expr != NULL);
    127
    128 /* print overall statistics and the expression */
    129 SCIPdebugMsg(scip, " #all variables: %d, #positive exponent variables: %d, #negative exponent variables: %d, auxvar: %s \n expr: ",
    130 nlhdlrexprdata->nvars, nlhdlrexprdata->nposvars, nlhdlrexprdata->nnegvars, SCIPvarGetName(SCIPgetExprAuxVarNonlinear(expr)) );
    131 SCIPprintExpr(scip, expr, NULL);
    132
    133 /* if variables are detected, we can print more information */
    134 if( !nlhdlrexprdata->isstorecapture )
    135 {
    136 SCIPinfoMessage(scip, NULL, "\n");
    137 return SCIP_OKAY;
    138 }
    139
    140 /* print the natural formulation of the expression */
    141 SCIPinfoMessage(scip, NULL, ". natural formulation c x^a = y: %.2f", nlhdlrexprdata->coef);
    142 for( int i = 0; i < nlhdlrexprdata->nvars - 1; i++ )
    143 {
    144 SCIPinfoMessage(scip, NULL, "%s^%.2f", SCIPvarGetName(nlhdlrexprdata->vars[i]), nlhdlrexprdata->exponents[i]);
    145 }
    146 SCIPinfoMessage(scip, NULL, " = %s", SCIPvarGetName(nlhdlrexprdata->vars[nlhdlrexprdata->nvars - 1]));
    147
    148 /* print the reformulation of the expression */
    149 SCIPinfoMessage(scip, NULL, ". Reformulation u^f = v^g: ");
    150 if( nlhdlrexprdata->nposvars == 0 )
    151 {
    153 }
    154 else
    155 {
    156 for( int i = 0; i < nlhdlrexprdata->nvars; i++ )
    157 if( nlhdlrexprdata->signs[i] )
    158 {
    159 SCIPinfoMessage(scip, NULL, "%s^%.2f", SCIPvarGetName(nlhdlrexprdata->vars[i]), nlhdlrexprdata->refexponents[i]);
    160 }
    161 }
    162 SCIPinfoMessage(scip, NULL, " = ");
    163 if( nlhdlrexprdata->nnegvars == 0 )
    164 {
    166 }
    167 else
    168 {
    169 for( int i = 0; i < nlhdlrexprdata->nvars; i++ )
    170 {
    171 if( !nlhdlrexprdata->signs[i] )
    172 {
    173 if( i == nlhdlrexprdata->nvars - 1 )
    174 {
    175 SCIPinfoMessage(scip, NULL, "(%s/%.2f)^%.2f", SCIPvarGetName(nlhdlrexprdata->vars[i]), nlhdlrexprdata->coef, nlhdlrexprdata->refexponents[i]);
    176 }
    177 else
    178 {
    179 SCIPinfoMessage(scip, NULL, "%s^%.2f", SCIPvarGetName(nlhdlrexprdata->vars[i]), nlhdlrexprdata->refexponents[i]);
    180 }
    181 }
    182 }
    183 }
    184 SCIPinfoMessage(scip, NULL, "\n");
    185
    186 return SCIP_OKAY;
    187}
    188
    189#endif
    190
    191/** free the memory of expression data */
    192static
    194 SCIP* scip, /**< SCIP data structure */
    195 SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< expression data */
    196 SCIP_Bool ispartial /**< free the partially allocated memory or the fully allocated memory? */
    197 )
    198{
    199 SCIPfreeBlockMemoryArrayNull(scip, &(*nlhdlrexprdata)->factors, (*nlhdlrexprdata)->nfactors);
    200 SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->exponents, (*nlhdlrexprdata)->nfactors);
    201 if( !ispartial )
    202 {
    203 int nvars = (*nlhdlrexprdata)->nvars;
    204 SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->signs, nvars);
    205 SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->refexponents, nvars);
    206 SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->vars, nvars);
    207 SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->intervals, nvars);
    208 SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->box, 2*nvars); /*lint !e647*/
    209 SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->xstar, nvars);
    210 SCIPfreeBlockMemoryArray(scip, &(*nlhdlrexprdata)->facetcoefs, nvars);
    211 }
    212 SCIPfreeBlockMemory(scip, nlhdlrexprdata);
    213 *nlhdlrexprdata = NULL;
    214}
    215
    216/** reforms a rowprep to a standard form for nonlinear handlers
    217 *
    218 * The input rowprep is of the form \f$ a_u u + a_v v + b \f$.
    219 * If in the overestimate mode, then we relax \f$ t \le x^a \f$, i.e., \f$ 0 \le u^f - v^g \f$. This implies that \f$ t \f$ is in \f$ v = (v',t) \f$.
    220 * Therefore, the valid inequality is \f$ 0 \le a_u u + a_v v + b \f$. As overestimate mode requires that \f$ t \f$ is in the left hand side,
    221 * the coefficients of \f$ t \f$ must be made negative while keeping the sign of the inequality, we can show that \f$ a_t \le 0 \f$, so it suffices
    222 * to divide the both sides by \f$ -a_t \ge 0\f$, which yields \f$ t \le (a_u u + a_v' v' + b) / -a_t \f$.
    223 * A rowprep in standard form only contains an estimator of the expression and no auxvar.
    224 * If in the underestimate mode, then we relax \f$ x^a \le t \f$, i.e., \f$ u^f - v^g \le 0 \f$. This implies that \f$ t \f$ is in \f$ v = (v',t) \f$.
    225 * Therefore, the valid inequality is \f$ a_u u + a_v v + b \le 0 \f$. As overestimate mode requires that \f$ t \f$ is in the left hand side,
    226 * the coefficients of \f$ t \f$ must be made negative while keeping the sign of the inequality, we can show that \f$ a_t \le 0 \f$, so it suffices
    227 * to divide the both sides by \f$ -a_t \ge 0 \f$, which yields \f$ (a_u u + a_v' v' + b) / -a_t \le t \f$.
    228 * A rowprep in standard form only contains an estimator of the expression and no auxvar.
    229 */
    230static
    232 SCIP* scip, /**< SCIP data structure */
    233 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< expression data */
    234 SCIP_ROWPREP* rowprep, /**< cut to be reformulated */
    235 SCIP_Real mincutscale, /**< min scaling factor for the cut in rowprep */
    236 SCIP_Bool* success /**< pointer to store whether the reformulating was successful */
    237 )
    238{
    239 int i;
    240 int nvars;
    241 SCIP_Real coefauxvar;
    242 SCIP_Real scale;
    243 SCIP_Real* coefs;
    244 SCIP_VAR* auxvar;
    245 SCIP_VAR** vars;
    246
    247 assert(rowprep != NULL);
    248 assert(nlhdlrexprdata != NULL);
    249
    250 coefs = SCIProwprepGetCoefs(rowprep);
    251 vars = SCIProwprepGetVars(rowprep);
    252 nvars = SCIProwprepGetNVars(rowprep);
    253
    254 /* find auxvar's cut coefficient and set it to zero */
    255 auxvar = nlhdlrexprdata->vars[nlhdlrexprdata->nfactors];
    256 coefauxvar = 1.0;
    257 for( i = 0; i < nvars; i++ )
    258 {
    259 if( vars[i] == auxvar )
    260 {
    261 coefauxvar = coefs[i];
    262 coefs[i] = 0.0;
    263 break;
    264 }
    265 }
    266
    267 if( SCIPisZero(scip, coefauxvar) || coefauxvar >= 0.0 )
    268 {
    269 *success = FALSE;
    270 }
    271 else
    272 {
    273 /* the reformation scales the cut so that coefficients and constant are divided by the absolute value of coefauxvar */
    274 assert(coefauxvar < 0.0);
    275 scale = -1.0 / coefauxvar;
    276 for( i = 0; i < nvars; i++ )
    277 {
    278 if( vars[i] == auxvar )
    279 continue;
    280 coefs[i] *= scale;
    281 }
    282 /* set the side to scale*side by adding -side and adding scale*side */
    283 SCIProwprepAddSide(rowprep, SCIProwprepGetSide(rowprep) * (-1.0 + scale));
    284
    285 *success = SCIPisGT(scip, scale, mincutscale);
    286 }
    287}
    288
    289/** store and capture variables associated with the expression and its subexpressions */
    290static
    292 SCIP* scip, /**< SCIP data structure */
    293 SCIP_EXPR* expr, /**< expression */
    294 SCIP_NLHDLREXPRDATA* nlhdlrexprdata /**< expression data */
    295 )
    296{
    297 int c;
    298
    299 assert(!nlhdlrexprdata->isstorecapture);
    300
    301 /* get and capture variables \f$x\f$ */
    302 for( c = 0; c < nlhdlrexprdata->nfactors; ++c )
    303 {
    304 nlhdlrexprdata->vars[c] = SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->factors[c]);
    305 assert(nlhdlrexprdata->vars[c] != NULL);
    306
    307 SCIP_CALL( SCIPcaptureVar(scip, nlhdlrexprdata->vars[c]) );
    308 }
    309
    310 /* get and capture variable \f$y\f$ */
    311 nlhdlrexprdata->vars[c] = SCIPgetExprAuxVarNonlinear(expr);
    312 assert(nlhdlrexprdata->vars[c] != NULL);
    313 SCIP_CALL( SCIPcaptureVar(scip, nlhdlrexprdata->vars[c]) );
    314
    315 nlhdlrexprdata->isstorecapture = TRUE;
    316
    317 return SCIP_OKAY;
    318}
    319
    320/** get bounds of variables x,t and check whether they are box constrained signomial variables */
    321static
    323 SCIP* scip, /**< SCIP data structure */
    324 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< expression data */
    325 SCIP_Bool* isboxsignomial /**< buffer to store whether variables are box constrained signomial variables */
    326 )
    327{
    328 int c;
    329 SCIP_Real powinf;
    330 SCIP_Real powsup;
    331 SCIP_Real productinf = 1;
    332 SCIP_Real productsup = 1;
    333
    334 assert(nlhdlrexprdata->isstorecapture);
    335
    336 *isboxsignomial = FALSE;
    337
    338 /* get bounds of x */
    339 for( c = 0; c < nlhdlrexprdata->nfactors; c++ )
    340 {
    341 SCIP_Real inf = SCIPvarGetLbLocal(nlhdlrexprdata->vars[c]);
    342 SCIP_Real sup = SCIPvarGetUbLocal(nlhdlrexprdata->vars[c]);
    343
    344 /* if the bounds of the variable are not positive and finite, or (bounds equal) then the expression is not a signomial */
    345 if( !SCIPisPositive(scip, inf) || !SCIPisPositive(scip, sup) || SCIPisInfinity(scip, sup) || SCIPisEQ(scip, inf, sup) )
    346 return;
    347
    348 nlhdlrexprdata->intervals[c].inf = inf;
    349 nlhdlrexprdata->intervals[c].sup = MAX(sup, inf + 0.1);
    350 powinf = pow(inf, nlhdlrexprdata->exponents[c]);
    351 powsup = pow(sup, nlhdlrexprdata->exponents[c]);
    352 productinf *= MIN(powinf, powsup);
    353 productsup *= MAX(powinf, powsup);
    354 }
    355
    356 /* compute bounds of t by bounds of x */
    357 nlhdlrexprdata->intervals[c].inf = productinf;
    358 nlhdlrexprdata->intervals[c].sup = productsup;
    359
    360 *isboxsignomial = TRUE;
    361}
    362
    363/** evaluate expression at solution w.r.t. auxiliary variables */
    364static
    365SCIP_DECL_VERTEXPOLYFUN(nlhdlrExprEvalPower)
    366{
    367 int i;
    368 int j;
    369 SCIP_Real val;
    370 VERTEXPOLYFUN_EVALDATA* evaldata;
    371 SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
    372
    373 assert(args != NULL);
    374
    375 evaldata = (VERTEXPOLYFUN_EVALDATA *)funcdata;
    376
    377 assert(evaldata != NULL);
    378 assert(nargs == evaldata->nsignvars);
    379
    380 nlhdlrexprdata = evaldata->nlhdlrexprdata;
    381
    382#ifdef SCIP_MORE_DEBUG
    383 SCIPdebugMsg(evaldata->scip, "eval vertexpolyfun\n");
    384#endif
    385 val = 1.0;
    386 for( i = 0, j = 0; i < nlhdlrexprdata->nvars; ++i )
    387 {
    388 if( nlhdlrexprdata->signs[i] != evaldata->sign )
    389 continue;
    390 /* the reformulated exponent of args[j] is found */
    391 val *= pow(args[j], nlhdlrexprdata->refexponents[i]);
    392 j++;
    393 }
    394
    395 return val;
    396}
    397
    398/** determine whether a power function \f$ w^h \f$ is special and add an overunderestimator or underestimator to a given rowprep
    399 *
    400 * \f$ w^h \f$ is special, if all variables are fixed, or it is a constant to estimate, a univariate power to estimate,
    401 * or a bivariate power to underestimate. The estimator is multiplied by the multiplier and stored in the rowprep.
    402 */
    403static
    405 SCIP* scip, /**< SCIP data structure */
    406 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler expression data */
    407 SCIP_Bool sign, /**< the sign of variables of the power function */
    408 SCIP_Real multiplier, /**< the multiplier of the estimator */
    409 SCIP_Bool overestimate, /**< whether overestimate or underestimator the power function */
    410 SCIP_SOL* sol, /**< solution \f$ w' \f$ to use in estimation */
    411 SCIP_ROWPREP* rowprep, /**< rowprep where to store estimator */
    412 SCIP_Bool* isspecial, /**< buffer to store whether this function is a special case */
    413 SCIP_Bool* success /**< buffer to store whether successful */
    414 )
    415{
    416 int i;
    417 SCIP_Bool allfixed = TRUE;
    418 int nsignvars;
    419
    420 assert(scip != NULL);
    421 assert(nlhdlrexprdata != NULL);
    422 assert(rowprep != NULL);
    423 assert(isspecial != NULL);
    424 assert(success != NULL);
    425
    426 *success = FALSE;
    427 /* check whether all variables are fixed */
    428 for( i = 0; i < nlhdlrexprdata->nvars; ++i )
    429 {
    430 if( nlhdlrexprdata->signs[i] != sign )
    431 continue;
    432
    433 if( !SCIPisRelEQ(scip, nlhdlrexprdata->intervals[i].inf, nlhdlrexprdata->intervals[i].sup) )
    434 {
    435 allfixed = FALSE;
    436 break;
    437 }
    438 }
    439
    440 /* allfixed is a special case */
    441 if( allfixed )
    442 {
    443 /* return a constant */
    444 SCIP_Real funcval = 1.0;
    445 SCIP_Real scale;
    446 SCIP_Real val;
    447
    448 for( i = 0; i < nlhdlrexprdata->nvars; ++i )
    449 {
    450 if( nlhdlrexprdata->signs[i] != sign )
    451 continue;
    452
    453 scale = i == (nlhdlrexprdata->nvars - 1) ? nlhdlrexprdata->coef : 1.0;
    454 val = SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[i]) / scale;
    455 funcval *= pow(val, nlhdlrexprdata->refexponents[i]);
    456 }
    457 SCIProwprepAddConstant(rowprep, multiplier * funcval);
    458 *isspecial = TRUE;
    459
    460 return SCIP_OKAY;
    461 }
    462
    463 /* number of variables in the power function */
    464 nsignvars = sign ? nlhdlrexprdata->nposvars : nlhdlrexprdata->nnegvars;
    465
    466 /* if the power function has no more than 2 variables, this a special case */
    467 *isspecial = ( nsignvars <= 1 ) || ( nsignvars == 2 && !overestimate );
    468 if( !*isspecial )
    469 return SCIP_OKAY;
    470
    471 if( nsignvars == 0 )
    472 {
    473 /* constant case */
    474 SCIProwprepAddConstant(rowprep, multiplier);
    475 *success = TRUE;
    476 }
    477 else if( nsignvars == 1 )
    478 {
    479 /* univariate case, w^h */
    480 for( i = 0; i < nlhdlrexprdata->nvars; ++i )
    481 {
    482 if( nlhdlrexprdata->signs[i] == sign )
    483 {
    484 /* the variable w is found */
    485 SCIP_Real scale = i == (nlhdlrexprdata->nvars - 1) ? nlhdlrexprdata->coef : 1;
    486 SCIP_VAR* var = nlhdlrexprdata->vars[i];
    487 SCIP_Real refexponent = nlhdlrexprdata->refexponents[i];
    488 if( refexponent == 1.0 )
    489 {
    490 /* h = 1, a univariate linear function. Only rescale, no need for linearization */
    491 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, multiplier / scale) );
    492 }
    493 else
    494 {
    495 /* a univariate power function */
    496 SCIP_Real facetconstant;
    497 SCIP_Real facetcoef;
    498 SCIP_Real val = SCIPgetSolVal(scip, sol, var) / scale;
    499 /* local (using bounds) depends on whether we under- or overestimate */
    500 SCIP_Bool islocal = !overestimate;
    501 SCIPestimateRoot(scip, refexponent, overestimate, nlhdlrexprdata->intervals[i].inf, nlhdlrexprdata->intervals[i].sup,
    502 val, &facetconstant, &facetcoef, &islocal, success);
    503 SCIProwprepAddConstant(rowprep, multiplier * facetconstant);
    504 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, multiplier * facetcoef / scale) );
    505 }
    506 }
    507 }
    508 *success = TRUE;
    509 }
    510 else if( nsignvars == 2 && !overestimate )
    511 {
    512 /* bivariate case, f(w) = w^h = f_0(w_0) f_1(w_1). The convex under envelope is the maxmimum of
    513 * two affine functions, each of which is determined by three extreme points the box bound.
    514 * One affine function is supported by three lower left points; the other affine function is
    515 * supported by three upper right points. For a point xstar in the box, its corresponding affine function can be determined by
    516 * which region (upper right or lower left half space) the point is in. Thus, we can determine the region, and use the
    517 * associated three extreme point to interpolate the affine function.
    518 */
    519 SCIP_Bool isupperright;
    520 SCIP_Real dw0, dw1;
    521 SCIP_Real f0w0l, f0w0u, f1w1l, f1w1u;
    522 SCIP_Real fw0lw1u, fw0uw1l;
    523 SCIP_Real facetconstant;
    524 SCIP_Real facetcoefs[2] = {0.0, 0.0};
    525 SCIP_VAR* vars[2] = {NULL, NULL};
    526 SCIP_Real refexponents[2] = {0.0, 0.0};
    527 SCIP_Real xstar[2] = {0.0, 0.0};;
    528 SCIP_Real scale[2] = {0.0, 0.0};;
    529 SCIP_Real box[4] = {0.0, 0.0, 0.0, 0.0};
    530 int j = 0;
    531
    532 /* get refexponents, xstar, scale, and box */
    533 for( i = 0; i < nlhdlrexprdata->nvars; ++i )
    534 {
    535 if( nlhdlrexprdata->signs[i] != sign )
    536 continue;
    537 box[2 * j] = nlhdlrexprdata->intervals[i].inf;
    538 box[2 * j + 1] = nlhdlrexprdata->intervals[i].sup;
    539 refexponents[j] = nlhdlrexprdata->refexponents[i];
    540 scale[j] = i == (nlhdlrexprdata->nvars - 1) ? nlhdlrexprdata->coef : 1;
    541 vars[j] = nlhdlrexprdata->vars[i];
    542 xstar[j] = SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[j]) / scale[j];
    543 j++;
    544 }
    545
    546 /* compute the box length*/
    547 dw0 = box[1] - box[0];
    548 dw1 = box[3] - box[2];
    549
    550 /* determine the location (upper right or lower left half sapce) of the xstar.
    551 * (dw1, dw0) is the direction vector to the upper right half space.
    552 */
    553 isupperright = ( (xstar[0] - box[0]) * dw1 + (xstar[1] - box[3]) * dw0 ) > 0.0;
    554
    555 /* compute function values of f_0, f_1 at vertices */
    556 f0w0l = pow(box[0], refexponents[0]);
    557 f0w0u = pow(box[1], refexponents[0]);
    558 f1w1l = pow(box[2], refexponents[1]);
    559 f1w1u = pow(box[3], refexponents[1]);
    560 fw0lw1u = f0w0l * f1w1u;
    561 fw0uw1l = f0w0u * f1w1l;
    562 if( isupperright )
    563 {
    564 /* underestimator: fw0uw1u + (fw0uw1u - fw0lw1u) / (dw0) * (x0 - w0u) + (fw0uw1u - fw0uw1l) / (dw1) * (x1 - w1u) */
    565 SCIP_Real fw0uw1u = f0w0u * f1w1u;
    566 facetcoefs[0] = (fw0uw1u - fw0lw1u) / dw0;
    567 facetcoefs[1] = (fw0uw1u - fw0uw1l) / dw1;
    568 facetconstant = fw0uw1u - facetcoefs[0] * box[1] - facetcoefs[1] * box[3];
    569 }
    570 else
    571 {
    572 /* underestimator: fw0lw1l + (fw0uw1l - fw0lw1l) / (dw0) * (x0 - w0l) + (fw0lw1u- fw0lw1l) / (dw1) * (x1 - w1l) */
    573 SCIP_Real fw0lw1l = f0w0l * f1w1l;
    574 facetcoefs[0] = (fw0uw1l - fw0lw1l) / dw0;
    575 facetcoefs[1] = (fw0lw1u - fw0lw1l) / dw1;
    576 facetconstant = fw0lw1l - facetcoefs[0] * box[0] - facetcoefs[1] * box[2];
    577 }
    578 SCIProwprepAddConstant(rowprep, multiplier * facetconstant);
    579 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, vars[0], multiplier * facetcoefs[0] / scale[0]) );
    580 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, vars[1], multiplier * facetcoefs[1] / scale[1]) );
    581 *success = TRUE;
    582 }
    583
    584 return SCIP_OKAY;
    585}
    586
    587/** adds an underestimator for a multivariate concave power function \f$ w^h \f$ to a given rowprep
    588 *
    589 * Calls \ref SCIPcomputeFacetVertexPolyhedralNonlinear() for \f$ w^h \f$ and
    590 * box set to local bounds of auxiliary variables. The estimator is multiplied
    591 * by the multiplier and stored in the rowprep.
    592 */
    593static
    595 SCIP* scip, /**< SCIP data structure */
    596 SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
    597 SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
    598 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler expression data */
    599 SCIP_Bool sign, /**< the sign of variables of the power function */
    600 SCIP_Real multiplier, /**< the multiplier of the estimator */
    601 SCIP_SOL* sol, /**< solution \f$ w' \f$ to use*/
    602 SCIP_Real targetvalue, /**< a target value to achieve; if not reachable, then can give up early */
    603 SCIP_ROWPREP* rowprep, /**< rowprep where to store estimator */
    604 SCIP_Bool* success /**< buffer to store whether successful */
    605 )
    606{
    607 int i;
    608 int j;
    609 int nsignvars;
    610 SCIP_Real facetconstant;
    611 SCIP_Real scale;
    612 SCIP_Real* box;
    613 SCIP_Real* facetcoefs;
    614 SCIP_Real* xstar;
    615 VERTEXPOLYFUN_EVALDATA evaldata;
    616
    617 assert(scip != NULL);
    618 assert(nlhdlr != NULL);
    619 assert(nlhdlrexprdata != NULL);
    620 assert(rowprep != NULL);
    621 assert(success != NULL);
    622
    623 *success = FALSE;
    624
    625 /* number of variables of sign */
    626 nsignvars = sign ? nlhdlrexprdata->nposvars : nlhdlrexprdata->nnegvars;
    627
    628 /* data structure to evaluate the power function */
    629 evaldata.nlhdlrexprdata = nlhdlrexprdata;
    630 evaldata.sign = sign;
    631 evaldata.nsignvars = nsignvars;
    632 evaldata.scip = scip;
    633
    634 /* compute box constraints and reference value of variables*/
    635 xstar = nlhdlrexprdata->xstar;
    636 box = nlhdlrexprdata->box;
    637 j = 0;
    638 for( i = 0; i < nlhdlrexprdata->nvars; ++i )
    639 {
    640 if( nlhdlrexprdata->signs[i] != sign )
    641 continue;
    642
    643 box[2 * j] = nlhdlrexprdata->intervals[i].inf;
    644 box[2 * j + 1] = nlhdlrexprdata->intervals[i].sup;
    645 scale = i == (nlhdlrexprdata->nvars - 1) ? nlhdlrexprdata->coef : 1.0;
    646 xstar[j] = SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[i]) / scale;
    647 j++;
    648 }
    649
    650 /* find a facet of the underestimator */
    651 facetcoefs = nlhdlrexprdata->facetcoefs;
    652 SCIP_CALL( SCIPcomputeFacetVertexPolyhedralNonlinear(scip, conshdlr, FALSE, nlhdlrExprEvalPower, (void*)&evaldata, xstar, box,
    653 nsignvars, targetvalue, success, facetcoefs, &facetconstant) );
    654
    655 if( !*success )
    656 {
    657 SCIPdebugMsg(scip, "failed to compute facet of convex hull\n");
    658 return SCIP_OKAY;
    659 }
    660
    661 /* set coefficients in the rowprep */
    662 SCIProwprepAddConstant(rowprep, multiplier * facetconstant);
    663 j = 0;
    664 for( i = 0; i < nlhdlrexprdata->nvars; ++i )
    665 {
    666 if( nlhdlrexprdata->signs[i] != sign )
    667 continue;
    668 scale = i == (nlhdlrexprdata->nvars - 1) ? nlhdlrexprdata->coef : 1.0;
    669 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, nlhdlrexprdata->vars[i], multiplier * facetcoefs[j] / scale) );
    670 j++;
    671 }
    672
    673 return SCIP_OKAY;
    674}
    675
    676/** adds an overestimator for a concave power function \f$ w^h \f$ to a given rowprep
    677 *
    678 * The estimator is multiplied by the multiplier and stored in the rowprep.
    679 */
    680static
    682 SCIP* scip, /**< SCIP data structure */
    683 SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler expression data */
    684 SCIP_Bool sign, /**< the sign of variables of the power function */
    685 SCIP_Real multiplier, /**< the multiplier of the estimator */
    686 SCIP_SOL* sol, /**< solution to use */
    687 SCIP_ROWPREP* rowprep, /**< rowprep where to store estimator */
    688 SCIP_Bool* success /**< buffer to store whether successful */
    689 )
    690{
    691 int i;
    692 SCIP_Real facetcoef;
    693 SCIP_Real facetconstant;
    694 SCIP_Real funcval;
    695 SCIP_Real refexponent;
    696 SCIP_Real sumrefexponents;
    697 SCIP_Real scale;
    698 SCIP_Real val;
    699 SCIP_VAR* var;
    700 assert(scip != NULL);
    701 assert(nlhdlrexprdata != NULL);
    702 assert(rowprep != NULL);
    703 assert(success != NULL);
    704
    705 *success = FALSE;
    706
    707 /* compute the value and the sum of reformulated exponents of the power function */
    708 sumrefexponents = 0;
    709 funcval = 1;
    710 for( i = 0; i < nlhdlrexprdata->nvars; ++i )
    711 {
    712 if( nlhdlrexprdata->signs[i] != sign )
    713 continue;
    714 scale = i == (nlhdlrexprdata->nvars - 1) ? nlhdlrexprdata->coef : 1.0;
    715 val = SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[i]) / scale;
    716 val = MAX(val, 0.1);
    717 refexponent = nlhdlrexprdata->refexponents[i];
    718 sumrefexponents += refexponent;
    719 funcval *= pow(val, refexponent);
    720 }
    721
    722 /* overestimate by gradient cut: w'^h + h w'^(h - 1)(w - w') */
    723 facetconstant = (1 - sumrefexponents) * funcval;
    724 SCIProwprepAddConstant(rowprep, multiplier * facetconstant);
    725 for( i = 0; i < nlhdlrexprdata->nvars; ++i )
    726 {
    727 if( nlhdlrexprdata->signs[i] != sign )
    728 continue;
    729 scale = i == (nlhdlrexprdata->nvars - 1) ? nlhdlrexprdata->coef : 1.0;
    730 var = nlhdlrexprdata->vars[i];
    731 val = SCIPgetSolVal(scip, sol, var) / scale;
    732 val = MAX(val, 0.1);
    733 facetcoef = nlhdlrexprdata->refexponents[i] * funcval / val;
    734 SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, multiplier * facetcoef / scale) );
    735 }
    736
    737 *success = TRUE;
    738
    739 return SCIP_OKAY;
    740}
    741
    742/*
    743 * Callback methods of nonlinear handler
    744 */
    745
    746/** nonlinear handler estimation callback */
    747static
    748SCIP_DECL_NLHDLRESTIMATE(nlhdlrEstimateSignomial)
    749{ /*lint --e{715}*/
    750 SCIP_Bool isboxsignomial;
    751 SCIP_Bool isspecial;
    752 SCIP_Bool undersign;
    753 SCIP_Bool oversign;
    754 int i;
    755 int nundervars;
    756 SCIP_Real undermultiplier;
    757 SCIP_Real overmultiplier;
    758 SCIP_NLHDLRDATA* nlhdlrdata;
    759 SCIP_ROWPREP* rowprep;
    760 SCIP_Real targetunder;
    761 SCIP_Real scale;
    762
    763 assert(conshdlr != NULL);
    764 assert(nlhdlr != NULL);
    765 assert(expr != NULL);
    766 assert(nlhdlrexprdata != NULL);
    767 assert(rowpreps != NULL);
    768 *success = FALSE;
    769 *addedbranchscores = FALSE;
    770
    771 /* store and capture the vars of an expression, if the vars are not stored and captured yet */
    772 if( !nlhdlrexprdata->isstorecapture )
    773 {
    774 SCIP_CALL( storeCaptureVars(scip, expr, nlhdlrexprdata) );
    775 }
    776
    777 /* check whether all variables have finite positive bounds, which is necessary for the expression to be a signomial term */
    778 /* TODO consider allowing 0.0 lower bounds for u variables (and handle gradients at 0.0) */
    779 isboxsignomial = FALSE;
    780 checkSignomialBounds(scip, nlhdlrexprdata, &isboxsignomial);
    781
    782 if( !isboxsignomial )
    783 return SCIP_OKAY;
    784
    785 nlhdlrdata = SCIPnlhdlrGetData(nlhdlr);
    786
    787 /* determine the sign of variables for over- and underestimators, and the multiplier for estimators in the rowprep */
    788 if( overestimate )
    789 {
    790 /* relax t <= x^a, i.e., 0 <= u^f - v^g, overestimate u^f, underestimate v^g */
    791 oversign = TRUE;
    792 undersign = FALSE;
    793 overmultiplier = 1.0;
    794 undermultiplier = -1.0;
    795 nundervars = nlhdlrexprdata->nnegvars;
    796 }
    797 else
    798 {
    799 /* relax x^a <= t, i.e., u^f - v^g <= 0, underestimate u^f, overestimate v^g */
    800 oversign = FALSE;
    801 undersign = TRUE;
    802 overmultiplier = -1.0;
    803 undermultiplier = 1.0;
    804 nundervars = nlhdlrexprdata->nposvars;
    805 }
    806
    807 /* compute the value of the overestimator, which is a target value for computing the underestimator efficiently */
    808 targetunder = 1.0;
    809 for( i = 0; i < nlhdlrexprdata->nvars; i++ )
    810 {
    811 if( nlhdlrexprdata->signs[i] == oversign )
    812 {
    813 scale = i == (nlhdlrexprdata->nvars - 1) ? nlhdlrexprdata->coef : 1.0;
    814 targetunder *= pow(SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[i]) / scale, nlhdlrexprdata->refexponents[i]);
    815 }
    816 }
    817
    818#ifdef SCIP_SIGCUT_DEBUG
    819 SCIP_Real targetover = 1.0;
    820
    821 /* print information on estimators */
    822 SCIP_CALL( printSignomial(scip, expr, nlhdlrexprdata) );
    823 SCIPinfoMessage(scip, NULL, " Auxvalue: %f, targetvalue: %f, %sestimate.", auxvalue, targetvalue, overestimate ? "over" : "under");
    824
    825 targetunder = 1.0;
    826 for( i = 0; i < nlhdlrexprdata->nvars; i++ )
    827 {
    828 if( nlhdlrexprdata->signs[i] == undersign )
    829 {
    830 scale = i == (nlhdlrexprdata->nvars - 1) ? nlhdlrexprdata->coef : 1.0;
    831 targetover *= pow(SCIPgetSolVal(scip, sol, nlhdlrexprdata->vars[i]) / scale, nlhdlrexprdata->refexponents[i]);
    832 }
    833 }
    834 SCIPinfoMessage(scip, NULL, " Underestimate: %s, overestimate: %s.",
    835 undersign ? "positive" : "negative", oversign ? "positive" : "negative");
    836 SCIPinfoMessage(scip, NULL, " Undervalue (targetover): %f, overvalue (targetunder): %f.", targetover, targetunder);
    837#endif
    838
    839 /* create a rowprep and allocate memory for it */
    841 SCIP_CALL( SCIPensureRowprepSize(scip, rowprep, nlhdlrexprdata->nvars + 1) );
    842
    843 /* only underestimate a concave function, if the number of variables is below a given threshold */
    844 if( nundervars <= nlhdlrdata->maxnundervars )
    845 {
    846 /* compute underestimator */
    847 isspecial = FALSE;
    848 /* check and compute the special case */
    849 SCIP_CALL( estimateSpecialPower(scip, nlhdlrexprdata, undersign, undermultiplier, FALSE, sol, rowprep, &isspecial, success) );
    850 if( !isspecial )
    851 {
    852 SCIP_CALL( underEstimatePower(scip, conshdlr, nlhdlr, nlhdlrexprdata, undersign, undermultiplier, sol, targetunder, rowprep, success) );
    853 }
    854 }
    855
    856 if( *success )
    857 {
    858 /* compute overestimator */
    859 isspecial = FALSE;
    860 /* check and compute the special case */
    861 SCIP_CALL( estimateSpecialPower(scip, nlhdlrexprdata, oversign, overmultiplier, TRUE, sol, rowprep, &isspecial, success) );
    862 if( !isspecial )
    863 {
    864 SCIP_CALL( overEstimatePower(scip, nlhdlrexprdata, oversign, overmultiplier, sol, rowprep, success) );
    865 }
    866 }
    867
    868 if( *success )
    869 {
    870 reformRowprep(scip, nlhdlrexprdata, rowprep, nlhdlrdata->mincutscale, success);
    871 if( *success )
    872 {
    873 SCIP_CALL( SCIPsetPtrarrayVal(scip, rowpreps, 0, rowprep) );
    874 }
    875 }
    876
    877 if( !*success )
    878 SCIPfreeRowprep(scip, &rowprep);
    879
    880 return SCIP_OKAY;
    881}
    882
    883/** callback to detect structure in expression tree */
    884static
    885SCIP_DECL_NLHDLRDETECT(nlhdlrDetectSignomial)
    886{ /*lint --e{715}*/
    887 assert(expr != NULL);
    888 assert(enforcing != NULL);
    889 assert(participating != NULL);
    890
    891 /* for now, we do not get active if separation is already (or does not need to be) provided */
    893 {
    894 return SCIP_OKAY;
    895 }
    896
    897 /* check for product expressions with more than one child */
    898 if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) >= 2 )
    899 {
    900 int c;
    901 int nf = SCIPexprGetNChildren(expr);
    902 int nvars = nf + 1;
    903 SCIP_Bool ismultilinear = TRUE;
    904
    905 /* create expression data for the nonlinear handler */
    906 SCIP_CALL( SCIPallocClearBlockMemory(scip, nlhdlrexprdata) );
    907 (*nlhdlrexprdata)->nfactors = nf;
    908 (*nlhdlrexprdata)->nvars = nvars;
    909
    910 /* allocate memory for expression data */
    911 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlhdlrexprdata)->factors, nf) );
    912 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlhdlrexprdata)->exponents, nf) );
    913
    914 /* get monomial information */
    915 SCIP_CALL( SCIPgetExprMonomialData(scip, expr, &((*nlhdlrexprdata)->coef), (*nlhdlrexprdata)->exponents, (*nlhdlrexprdata)->factors) );
    916
    917 /* skip multilinear terms, since we wouldn't do better than expr_product */
    918 for( c = 0; c < nf; c++ )
    919 {
    920 if( !SCIPisEQ(scip, (*nlhdlrexprdata)->exponents[c], 1.0) )
    921 {
    922 ismultilinear = FALSE;
    923 break;
    924 }
    925 }
    926
    927 if( ismultilinear )
    928 {
    929 /* if multilinear, we free memory of the expression data and do nothing */
    930 freeExprDataMem(scip, nlhdlrexprdata, TRUE);
    931 return SCIP_OKAY;
    932 }
    933 else
    934 {
    935 SCIP_Real normalize;
    936 SCIP_Real sumlexponents = 0;
    937 SCIP_Real sumrexponents = 1;
    938 int nposvars = 0;
    939
    940 /* allocate more memory for expression data */
    941 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlhdlrexprdata)->signs, nvars) );
    942 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlhdlrexprdata)->refexponents, nvars) );
    943 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(*nlhdlrexprdata)->vars, nvars) );
    944 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlhdlrexprdata)->intervals, nvars) );
    945 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlhdlrexprdata)->xstar, nvars) );
    946 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlhdlrexprdata)->facetcoefs, nvars) );
    947 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*nlhdlrexprdata)->box, 2 * nvars) );
    948
    949 (*nlhdlrexprdata)->isstorecapture = FALSE;
    950
    951 /* detect more information for the reformulation: we first compute the sum
    952 * of positive and negative exponents and determine the sign indicators
    953 */
    954 for( c = 0; c < nf; c++ )
    955 {
    956 /* capture sub expressions */
    957 SCIPcaptureExpr((*nlhdlrexprdata)->factors[c]);
    958 if( (*nlhdlrexprdata)->exponents[c] > 0.0 )
    959 {
    960 /* add a positive exponent */
    961 sumlexponents += (*nlhdlrexprdata)->exponents[c];
    962 (*nlhdlrexprdata)->signs[c] = TRUE;
    963 nposvars++;
    964 }
    965 else
    966 {
    967 /* subtract a negative exponent */
    968 sumrexponents -= (*nlhdlrexprdata)->exponents[c];
    969 (*nlhdlrexprdata)->signs[c] = FALSE;
    970 }
    971 /* set null to working variables, meaning that they are not stored yet */
    972 }
    973 (*nlhdlrexprdata)->signs[nf] = FALSE;
    974 (*nlhdlrexprdata)->nposvars = nposvars;
    975 (*nlhdlrexprdata)->nnegvars = nf - nposvars + 1;
    976
    977 /* compute the normalization constant */
    978 normalize = MAX(sumlexponents, sumrexponents);
    979 /* normalize positive and negative exponents */
    980 for( c = 0; c < nf; c++ )
    981 {
    982 if( (*nlhdlrexprdata)->signs[c] )
    983 (*nlhdlrexprdata)->refexponents[c] = (*nlhdlrexprdata)->exponents[c] / normalize;
    984 else
    985 (*nlhdlrexprdata)->refexponents[c] = -(*nlhdlrexprdata)->exponents[c] / normalize;
    986 }
    987 (*nlhdlrexprdata)->refexponents[nf] = 1.0 / normalize;
    988
    989 /* tell children that we will use their auxvar and use its activity for estimation */
    990 for( c = 0; c < nf; c++ )
    991 {
    992 SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, (*nlhdlrexprdata)->factors[c], TRUE, FALSE, TRUE, TRUE) );
    993 }
    994 }
    995 }
    996
    997 if( *nlhdlrexprdata != NULL )
    998 {
    999 *participating = SCIP_NLHDLR_METHOD_SEPABOTH;
    1000 }
    1001
    1002#ifdef SCIP_SIGCUT_DEBUG
    1003 if( *participating )
    1004 {
    1005 SCIPdebugMsg(scip, "scip depth: %d, step: %d, expr pointer: %p, expr data pointer: %p, detected expr: total vars (exps) %d ",
    1006 SCIPgetSubscipDepth(scip), SCIPgetStage(scip), (void *)expr, (void *)nlhdlrexprdata, (*nlhdlrexprdata)->nfactors);
    1007 SCIPprintExpr(scip, expr, NULL);
    1008 SCIPinfoMessage(scip, NULL, " participating: %d\n", *participating);
    1009 }
    1010#endif
    1011
    1012 return SCIP_OKAY;
    1013}
    1014
    1015/** auxiliary evaluation callback of nonlinear handler */
    1016static SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxSignomial)
    1017{ /*lint --e{715}*/
    1018 int c;
    1019 SCIP_Real val;
    1020 SCIP_VAR* var;
    1021
    1022 *auxvalue = nlhdlrexprdata->coef;
    1023 for( c = 0; c < nlhdlrexprdata->nfactors; ++c )
    1024 {
    1025 assert(nlhdlrexprdata->factors[c] != NULL);
    1026
    1027 var = SCIPgetExprAuxVarNonlinear(nlhdlrexprdata->factors[c]);
    1028 assert(var != NULL);
    1029
    1030 val = SCIPgetSolVal(scip, sol, var);
    1031 if( SCIPisPositive(scip, val) )
    1032 {
    1033 *auxvalue *= pow(val, nlhdlrexprdata->exponents[c]);
    1034 }
    1035 else
    1036 {
    1037 *auxvalue = SCIP_INVALID;
    1038 break;
    1039 }
    1040 }
    1041
    1042 return SCIP_OKAY;
    1043}
    1044
    1045/** nonlinear handler copy callback */
    1046static
    1047SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrSignomial)
    1048{ /*lint --e{715}*/
    1049 assert(targetscip != NULL);
    1050 assert(sourcenlhdlr != NULL);
    1051 assert(strcmp(SCIPnlhdlrGetName(sourcenlhdlr), NLHDLR_NAME) == 0);
    1052
    1054
    1055 return SCIP_OKAY;
    1056}
    1057
    1058/** callback to free data of handler */
    1059static
    1060SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrDataSignomial)
    1061{ /*lint --e{715}*/
    1062 assert(nlhdlrdata != NULL);
    1063
    1064 SCIPfreeBlockMemory(scip, nlhdlrdata);
    1065
    1066 return SCIP_OKAY;
    1067}
    1068
    1069/** callback to free expression specific data */
    1070static
    1071SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataSignomial)
    1072{ /*lint --e{715}*/
    1073 int c;
    1074
    1075 /* release expressions */
    1076 for( c = 0; c < (*nlhdlrexprdata)->nfactors; c++ )
    1077 {
    1078 SCIP_CALL( SCIPreleaseExpr(scip, &(*nlhdlrexprdata)->factors[c]) );
    1079 }
    1080
    1081 /* release variables */
    1082 if( (*nlhdlrexprdata)->isstorecapture )
    1083 {
    1084 for( c = 0; c < (*nlhdlrexprdata)->nvars; c++ )
    1085 {
    1086 if( (*nlhdlrexprdata)->vars[c] != NULL )
    1087 {
    1088 SCIP_CALL( SCIPreleaseVar(scip, &(*nlhdlrexprdata)->vars[c]) );
    1089 }
    1090 }
    1091 }
    1092
    1093 /* free memory */
    1094 freeExprDataMem(scip, nlhdlrexprdata, FALSE);
    1095
    1096 return SCIP_OKAY;
    1097}
    1098
    1099
    1100/*
    1101 * nonlinear handler specific interface methods
    1102 */
    1103
    1104/** includes signomial nonlinear handler in nonlinear constraint handler */
    1107 SCIP* scip /**< SCIP data structure */
    1108 )
    1109{
    1110 SCIP_NLHDLRDATA* nlhdlrdata;
    1111 SCIP_NLHDLR* nlhdlr;
    1112
    1113 assert(scip != NULL);
    1114
    1115 /* create nonlinear handler specific data */
    1116 SCIP_CALL( SCIPallocBlockMemory(scip, &nlhdlrdata) );
    1117 BMSclearMemory(nlhdlrdata);
    1118
    1120 NLHDLR_ENFOPRIORITY, nlhdlrDetectSignomial, nlhdlrEvalauxSignomial, nlhdlrdata) );
    1121 assert(nlhdlr != NULL);
    1122
    1123 SCIPnlhdlrSetCopyHdlr(nlhdlr, nlhdlrCopyhdlrSignomial);
    1124 SCIPnlhdlrSetFreeHdlrData(nlhdlr, nlhdlrFreehdlrDataSignomial);
    1125 SCIPnlhdlrSetFreeExprData(nlhdlr, nlhdlrFreeExprDataSignomial);
    1126 SCIPnlhdlrSetSepa(nlhdlr, NULL, NULL, nlhdlrEstimateSignomial, NULL);
    1127
    1128 /* parameters */
    1129 SCIP_CALL( SCIPaddIntParam(scip, "nlhdlr/" NLHDLR_NAME "/maxnundervars",
    1130 "maximum number of variables when underestimating a concave power function",
    1131 &nlhdlrdata->maxnundervars, TRUE, NLHDLR_MAXNUNDERVARS, 2, 14, NULL, NULL) );
    1132 SCIP_CALL( SCIPaddRealParam(scip, "nlhdlr/" NLHDLR_NAME "/mincutscale",
    1133 "minimum scale factor when scaling a cut",
    1134 &nlhdlrdata->mincutscale, TRUE, NLHDLR_MINCUTSCALE, 1e-6, 1e6, NULL, NULL) );
    1135
    1136 return SCIP_OKAY;
    1137}
    constraint handler for nonlinear constraints specified by algebraic expressions
    #define NULL
    Definition: def.h:248
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_CALL(x)
    Definition: def.h:355
    void SCIPestimateRoot(SCIP *scip, SCIP_Real exponent, SCIP_Bool overestimate, SCIP_Real xlb, SCIP_Real xub, SCIP_Real xref, SCIP_Real *constant, SCIP_Real *slope, SCIP_Bool *islocal, SCIP_Bool *success)
    Definition: expr_pow.c:3387
    power and signed power expression handlers
    variable expression handler
    SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
    SCIP_RETCODE SCIPregisterExprUsageNonlinear(SCIP *scip, SCIP_EXPR *expr, SCIP_Bool useauxvar, SCIP_Bool useactivityforprop, SCIP_Bool useactivityforsepabelow, SCIP_Bool useactivityforsepaabove)
    SCIP_RETCODE SCIPcomputeFacetVertexPolyhedralNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_Bool overestimate, SCIP_DECL_VERTEXPOLYFUN((*function)), void *fundata, SCIP_Real *xstar, SCIP_Real *box, int nallvars, SCIP_Real targetvalue, SCIP_Bool *success, SCIP_Real *facetcoefs, SCIP_Real *facetconstant)
    int SCIPgetSubscipDepth(SCIP *scip)
    Definition: scip_copy.c:2588
    SCIP_STAGE SCIPgetStage(SCIP *scip)
    Definition: scip_general.c:444
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_RETCODE SCIPincludeNlhdlrSignomial(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 SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
    Definition: scip_param.c:139
    SCIP_RETCODE 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_RETCODE SCIPgetExprMonomialData(SCIP *scip, SCIP_EXPR *expr, SCIP_Real *coef, SCIP_Real *exponents, SCIP_EXPR **factors)
    Definition: scip_expr.c:2648
    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
    void SCIPcaptureExpr(SCIP_EXPR *expr)
    Definition: scip_expr.c:1435
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    #define SCIPallocClearBlockMemory(scip, ptr)
    Definition: scip_mem.h:91
    #define SCIPallocClearBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:97
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
    Definition: scip_mem.h:111
    #define 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
    SCIP_NLHDLRDATA * SCIPnlhdlrGetData(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:217
    void SCIPnlhdlrSetFreeHdlrData(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRFREEHDLRDATA((*freehdlrdata)))
    Definition: nlhdlr.c:88
    void SCIPnlhdlrSetSepa(SCIP_NLHDLR *nlhdlr, SCIP_DECL_NLHDLRINITSEPA((*initsepa)), SCIP_DECL_NLHDLRENFO((*enfo)), SCIP_DECL_NLHDLRESTIMATE((*estimate)), SCIP_DECL_NLHDLREXITSEPA((*exitsepa)))
    Definition: nlhdlr.c:137
    const char * SCIPnlhdlrGetName(SCIP_NLHDLR *nlhdlr)
    Definition: nlhdlr.c:167
    SCIP_RETCODE SCIPincludeNlhdlrNonlinear(SCIP *scip, SCIP_NLHDLR **nlhdlr, const char *name, const char *desc, int detectpriority, int enfopriority, SCIP_DECL_NLHDLRDETECT((*detect)), SCIP_DECL_NLHDLREVALAUX((*evalaux)), SCIP_NLHDLRDATA *nlhdlrdata)
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(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 SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24234
    SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:1853
    SCIP_VAR ** SCIProwprepGetVars(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:639
    SCIP_Real SCIProwprepGetSide(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:659
    SCIP_RETCODE SCIPensureRowprepSize(SCIP *scip, SCIP_ROWPREP *rowprep, int size)
    Definition: misc_rowprep.c:887
    SCIP_Real * SCIProwprepGetCoefs(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:649
    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
    int SCIProwprepGetNVars(SCIP_ROWPREP *rowprep)
    Definition: misc_rowprep.c:629
    void SCIProwprepAddSide(SCIP_ROWPREP *rowprep, SCIP_Real side)
    Definition: misc_rowprep.c:746
    void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
    Definition: misc_rowprep.c:583
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    #define NLHDLR_DETECTPRIORITY
    #define NLHDLR_MAXNUNDERVARS
    static SCIP_DECL_NLHDLRESTIMATE(nlhdlrEstimateSignomial)
    static void reformRowprep(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_ROWPREP *rowprep, SCIP_Real mincutscale, SCIP_Bool *success)
    static SCIP_RETCODE estimateSpecialPower(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Bool sign, SCIP_Real multiplier, SCIP_Bool overestimate, SCIP_SOL *sol, SCIP_ROWPREP *rowprep, SCIP_Bool *isspecial, SCIP_Bool *success)
    static SCIP_DECL_NLHDLREVALAUX(nlhdlrEvalauxSignomial)
    #define NLHDLR_ENFOPRIORITY
    static void checkSignomialBounds(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Bool *isboxsignomial)
    static SCIP_DECL_NLHDLRCOPYHDLR(nlhdlrCopyhdlrSignomial)
    static SCIP_DECL_NLHDLRDETECT(nlhdlrDetectSignomial)
    static SCIP_RETCODE overEstimatePower(SCIP *scip, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Bool sign, SCIP_Real multiplier, SCIP_SOL *sol, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
    #define NLHDLR_DESC
    static SCIP_RETCODE underEstimatePower(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_NLHDLR *nlhdlr, SCIP_NLHDLREXPRDATA *nlhdlrexprdata, SCIP_Bool sign, SCIP_Real multiplier, SCIP_SOL *sol, SCIP_Real targetvalue, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
    static SCIP_RETCODE storeCaptureVars(SCIP *scip, SCIP_EXPR *expr, SCIP_NLHDLREXPRDATA *nlhdlrexprdata)
    static void freeExprDataMem(SCIP *scip, SCIP_NLHDLREXPRDATA **nlhdlrexprdata, SCIP_Bool ispartial)
    #define NLHDLR_NAME
    #define NLHDLR_MINCUTSCALE
    static SCIP_DECL_VERTEXPOLYFUN(nlhdlrExprEvalPower)
    static SCIP_DECL_NLHDLRFREEHDLRDATA(nlhdlrFreehdlrDataSignomial)
    static SCIP_DECL_NLHDLRFREEEXPRDATA(nlhdlrFreeExprDataSignomial)
    signomial nonlinear handler
    preparation of a linear inequality to become a SCIP_ROW
    public functions of nonlinear handlers of nonlinear constraints
    static void printSignomial(SCIP *scip, FILE *file, char *linebuffer, int *linecnt, SCIP_EXPR *expr, SCIP_Real coef, SCIP_Bool needsign)
    Definition: reader_pip.c:2173
    public functions to work with algebraic expressions
    SCIP_VAR ** vars
    Definition: struct_misc.h:289
    SCIP_NLHDLREXPRDATA * nlhdlrexprdata
    @ 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
    struct SCIP_NlhdlrExprData SCIP_NLHDLREXPRDATA
    Definition: type_nlhdlr.h:453
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63