Scippy

    SCIP

    Solving Constraint Integer Programs

    sepa_gauge.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 sepa_gauge.c
    26 * @ingroup DEFPLUGINS_SEPA
    27 * @brief gauge separator
    28 * @author Felipe Serrano
    29 *
    30 * @todo should separator only be run when SCIPallColsInLP is true?
    31 * @todo add SCIPisStopped(scip) to the condition of time consuming loops
    32 * @todo check if it makes sense to implement the copy callback
    33 */
    34
    35/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    36
    37#include <assert.h>
    38#include <string.h>
    39
    41#include "scip/scip_nlpi.h"
    42#include "scip/nlpi_ipopt.h"
    43#include "scip/nlpioracle.h"
    44#include "scip/scip_expr.h"
    45#include "scip/pub_expr.h"
    46#include "scip/pub_lp.h"
    47#include "scip/pub_message.h"
    48#include "scip/pub_misc.h"
    49#include "scip/pub_nlp.h"
    50#include "scip/pub_sepa.h"
    51#include "scip/pub_var.h"
    52#include "scip/scip_cut.h"
    53#include "scip/scip_lp.h"
    54#include "scip/scip_mem.h"
    55#include "scip/scip_message.h"
    56#include "scip/scip_nlp.h"
    57#include "scip/scip_numerics.h"
    58#include "scip/scip_param.h"
    59#include "scip/scip_prob.h"
    60#include "scip/scip_sepa.h"
    61#include "scip/scip_sol.h"
    63#include "scip/scip_timing.h"
    64#include "scip/sepa_gauge.h"
    65#include <string.h>
    66
    67
    68#define SEPA_NAME "gauge"
    69#define SEPA_DESC "gauge separator"
    70#define SEPA_PRIORITY 0
    71#define SEPA_FREQ -1
    72#define SEPA_MAXBOUNDDIST 1.0
    73#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
    74#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
    75
    76#define VIOLATIONFAC 100 /**< constraints regarded as violated when violation > VIOLATIONFAC*SCIPfeastol */
    77#define MAX_ITER 75 /**< maximum number of iterations for the line search */
    78
    79#define DEFAULT_NLPITERLIM 1000 /**< default NLP iteration limit */
    80
    81#define NLPFEASFAC 1e-1/**< NLP feasibility tolerance = NLPFEASFAC * SCIP's feasibility tolerance */
    82
    83#define INTERIOROBJVARLB -100 /**< lower bound of the objective variable when computing interior point */
    84
    85/*
    86 * Data structures
    87 */
    88
    89/** side that makes a nlrow convex */
    91{
    92 LHS = 0, /**< left hand side */
    93 RHS = 1 /**< right hand side */
    94};
    96
    97/** position of a point */
    99{
    100 INTERIOR = 0, /**< point is in the interior of the region */
    101 BOUNDARY = 1, /**< point is in the boundary of the region */
    102 EXTERIOR = 2 /**< point is in the exterior of the region */
    104typedef enum Position POSITION;
    105
    106/** separator data */
    107struct SCIP_SepaData
    108{
    109 SCIP_NLROW** nlrows; /**< stores convex nlrows */
    110 CONVEXSIDE* convexsides; /**< which sides make the nlrows convex */
    111 int* nlrowsidx; /**< indices of nlrows that violate the current lp solution */
    112 int nnlrowsidx; /**< total number of convex nonlinear nlrows that violate the current lp solution */
    113 int nnlrows; /**< total number of convex nonlinear nlrows */
    114 int nlrowssize; /**< memory allocated for nlrows, convexsides and nlrowsidx */
    115
    116 SCIP_Bool isintsolavailable; /**< do we have an interior point available? */
    117 SCIP_Bool skipsepa; /**< whether separator should be skipped */
    118 SCIP_SOL* intsol; /**< stores interior point */
    119
    120 int ncuts; /**< number of cuts generated */
    121
    122 /* parameters */
    123 int nlpiterlimit; /**< iteration limit of NLP solver; 0 for no limit */
    124};
    125
    126/*
    127 * Local methods
    128 */
    129
    130/** stores, from the constraints represented by nlrows, the nonlinear convex ones in sepadata */
    131static
    133 SCIP* scip, /**< SCIP data structure */
    134 SCIP_SEPADATA* sepadata, /**< separator data */
    135 SCIP_NLROW** nlrows, /**< nlrows from which to store convex ones */
    136 int nnlrows /**< number of nlrows */
    137 )
    138{
    139 int i;
    140
    141 assert(scip != NULL);
    142 assert(sepadata != NULL);
    143 assert(nlrows != NULL);
    144 assert(nnlrows > 0);
    145
    146 SCIPdebugMsg(scip, "storing convex nlrows\n");
    147
    148 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(sepadata->nlrows), nnlrows) );
    149 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(sepadata->convexsides), nnlrows) );
    150 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(sepadata->nlrowsidx), nnlrows) );
    151 sepadata->nlrowssize = nnlrows;
    152
    153 sepadata->nnlrows = 0;
    154 for( i = 0; i < nnlrows; ++i )
    155 {
    156 SCIP_NLROW* nlrow;
    157
    158 nlrow = nlrows[i];
    159 assert(nlrow != NULL);
    160
    161 /* linear case */
    163 continue;
    164
    165 /* nonlinear case */
    167 {
    168 sepadata->convexsides[sepadata->nnlrows] = RHS;
    169 sepadata->nlrows[sepadata->nnlrows] = nlrow;
    170 ++(sepadata->nnlrows);
    171 }
    173 {
    174 sepadata->convexsides[sepadata->nnlrows] = LHS;
    175 sepadata->nlrows[sepadata->nnlrows] = nlrow;
    176 ++(sepadata->nnlrows);
    177 }
    178 }
    179
    180 return SCIP_OKAY;
    181}
    182
    183/** computes an interior point of a convex NLP relaxation
    184 *
    185 * builds the convex relaxation, modifies it to find an interior
    186 * point, solves it and frees it; more details in @ref sepa_gauge.h
    187 *
    188 * @note the method also counts the number of nonlinear convex constraints and if there are < 2, then the convex
    189 * relaxation is not interesting and the separator will not run again
    190 */
    191static
    193 SCIP* scip, /**< SCIP data structure */
    194 SCIP_SEPADATA* sepadata /**< separator data */
    195 )
    196{
    197 SCIP_NLPIORACLE* nlpioracle;
    198 SCIP_NLPIPROBLEM* nlpiprob;
    199 SCIP_NLPI* nlpi;
    200 SCIP_HASHMAP* var2nlpiidx;
    201 SCIP_Real objvarlb;
    202 SCIP_Real minusone;
    203 SCIP_Real one;
    204 int nconvexnlrows;
    205 int objvaridx;
    206 int nconss;
    207 int nvars;
    208 int i;
    209
    210 assert(scip != NULL);
    211 assert(sepadata != NULL);
    212 assert(!sepadata->skipsepa);
    213
    214 SCIPdebugMsg(scip, "Computing interior point\n");
    215
    216 /* create convex relaxation NLP */
    217 assert(SCIPgetNNlpis(scip) > 0);
    218
    219 nlpi = SCIPgetNlpis(scip)[0];
    220 assert(nlpi != NULL);
    221
    222 nvars = SCIPgetNVars(scip);
    223 SCIP_CALL( SCIPhashmapCreate(&var2nlpiidx, SCIPblkmem(scip), nvars) );
    224 SCIP_CALL( SCIPcreateNlpiProblemFromNlRows(scip, nlpi, &nlpiprob, "gauge-interiorpoint-nlp", SCIPgetNLPNlRows(scip), SCIPgetNNLPNlRows(scip), var2nlpiidx,
    226
    227 /* add objective variable; the problem is \min t, s.t. g(x) <= t, l(x) <= 0, where g are nonlinear and l linear */
    228 objvaridx = nvars;
    229 objvarlb = INTERIOROBJVARLB;
    230 one = 1.0;
    231 SCIP_CALL( SCIPaddNlpiVars(scip, nlpi, nlpiprob, 1, &objvarlb, NULL, NULL) );
    232 SCIP_CALL( SCIPsetNlpiObjective(scip, nlpi, nlpiprob, 1, &objvaridx, &one, NULL, 0.0) );
    233
    234 /* add objective variables to constraints; for this we need to get nlpi oracle to have access to number of
    235 * constraints and which constraints are nonlinear
    236 */
    237 /* @todo: this code is only valid when using IPOPT and needs to be changed when new NLP solvers get interfaced */
    238 assert(strcmp(SCIPnlpiGetName(nlpi), "ipopt") == 0);
    239 nlpioracle = (SCIP_NLPIORACLE *)SCIPgetNlpiOracleIpopt(nlpiprob);
    240 assert(nlpioracle != NULL);
    241 assert(SCIPnlpiOracleGetNVars(nlpioracle) == objvaridx + 1);
    242
    243 minusone = -1.0;
    244 nconvexnlrows = 0;
    245 nconss = SCIPnlpiOracleGetNConstraints(nlpioracle);
    246 for( i = 0; i < nconss; i++ )
    247 {
    248 if( SCIPnlpiOracleIsConstraintNonlinear(nlpioracle, i) )
    249 {
    250 SCIP_CALL( SCIPchgNlpiLinearCoefs(scip, nlpi, nlpiprob, i, 1, &objvaridx, &minusone) );
    251 ++nconvexnlrows;
    252 }
    253 }
    255
    256 /* check if convex relaxation is interesting */
    257 if( nconvexnlrows < 2 )
    258 {
    259 SCIPdebugMsg(scip, "convex relaxation is not interesting, only %d nonlinear convex rows; abort\n", nconvexnlrows);
    260 sepadata->skipsepa = TRUE;
    261 goto CLEANUP;
    262 }
    263
    264 /* add linear rows */
    265 SCIP_CALL( SCIPaddNlpiProblemRows(scip, nlpi, nlpiprob, var2nlpiidx, SCIPgetLPRows(scip), SCIPgetNLPRows(scip)) );
    266
    267 /* compute interior point */
    268 SCIPdebugMsg(scip, "starting interior point computation\n");
    269 SCIP_CALL( SCIPsolveNlpi(scip, nlpi, nlpiprob,
    270 .iterlimit = sepadata->nlpiterlimit > 0 ? sepadata->nlpiterlimit : INT_MAX,
    271 .feastol = NLPFEASFAC * SCIPfeastol(scip),
    272 .opttol = MAX(SCIPfeastol(scip), SCIPdualfeastol(scip))) ); /*lint !e666*/
    273 SCIPdebugMsg(scip, "finish interior point computation\n");
    274
    275#ifdef SCIP_DEBUG
    276 {
    277 SCIP_NLPSTATISTICS nlpstatistics;
    278
    279 /* get statistics */
    280 SCIP_CALL( SCIPgetNlpiStatistics(scip, nlpi, nlpiprob, &nlpstatistics) );
    281
    282 SCIPdebugMsg(scip, "nlpi took iters %d, time %g searching for an find interior point: solstat %d\n",
    283 nlpstatistics.niterations, nlpstatistics.totaltime,
    284 SCIPgetNlpiSolstat(scip, nlpi, nlpiprob));
    285 }
    286#endif
    287
    288 if( SCIPgetNlpiSolstat(scip, nlpi, nlpiprob) <= SCIP_NLPSOLSTAT_FEASIBLE )
    289 {
    290 SCIP_Real* nlpisol;
    291
    292 SCIP_CALL( SCIPgetNlpiSolution(scip, nlpi, nlpiprob, &nlpisol, NULL, NULL, NULL, NULL) );
    293
    294 assert(nlpisol != NULL);
    295 SCIPdebugMsg(scip, "NLP solved: sol found has objvalue = %g\n", nlpisol[objvaridx]);
    296
    297 /* if we found an interior point store it */
    298 if( SCIPisFeasNegative(scip, nlpisol[objvaridx]) )
    299 {
    300 SCIPdebugMsg(scip, "Interior point found!, storing it\n");
    301 SCIP_CALL( SCIPcreateSol(scip, &sepadata->intsol, NULL) );
    302 for( i = 0; i < nvars; i ++ )
    303 {
    304 SCIP_VAR* var;
    305
    306 var = SCIPgetVars(scip)[i];
    307 assert(SCIPhashmapExists(var2nlpiidx, (void*)var) );
    308
    309 /* @todo: filter zero? */
    310 SCIP_CALL( SCIPsetSolVal(scip, sepadata->intsol, var,
    311 nlpisol[SCIPhashmapGetImageInt(var2nlpiidx, (void *)var)]) );
    312 }
    313
    314 sepadata->isintsolavailable = TRUE;
    315 }
    316 else
    317 {
    318 SCIPdebugMsg(scip, "We got a feasible point but not interior (objval: %g)\n", nlpisol[objvaridx]);
    319 sepadata->skipsepa = TRUE;
    320 }
    321 }
    322 else
    323 {
    324 SCIPdebugMsg(scip, "We couldn't get an interior point (stat: %d)\n", SCIPgetNlpiSolstat(scip, nlpi, nlpiprob));
    325 sepadata->skipsepa = TRUE;
    326 }
    327
    328CLEANUP:
    329 /* free memory */
    330 SCIPhashmapFree(&var2nlpiidx);
    331 SCIP_CALL( SCIPfreeNlpiProblem(scip, nlpi, &nlpiprob) );
    332
    333 return SCIP_OKAY;
    334}
    335
    336
    337/** find whether point is in the interior, at the boundary, or in the exterior of the region described by the
    338 * intersection of `nlrows[i]` &le; rhs if `convexsides[i]` = RHS or lhs &le; `nlrows[i]` if `convexsides[i]` = LHS
    339 *
    340 * @note point corresponds to a convex combination between the LP solution and the interior point
    341 */
    342static
    344 SCIP* scip, /**< SCIP data structure */
    345 SCIP_NLROW** nlrows, /**< nlrows defining the region */
    346 int* nlrowsidx, /**< indices of nlrows defining the region */
    347 int nnlrowsidx, /**< number of nlrows indices */
    348 CONVEXSIDE* convexsides, /**< sides of the nlrows involved in the region */
    349 SCIP_SOL* point, /**< point for which we want to know its position */
    350 POSITION* position /**< buffer to store position of sol */
    351 )
    352{
    353 int i;
    354
    355 assert(scip != NULL);
    356 assert(nlrows != NULL);
    357 assert(convexsides != NULL);
    358 assert(nnlrowsidx > 0);
    359 assert(point != NULL);
    360 assert(position != NULL);
    361
    362 *position = INTERIOR;
    363 for( i = 0; i < nnlrowsidx; i++ )
    364 {
    365 SCIP_NLROW* nlrow;
    366 SCIP_Real activity;
    367 CONVEXSIDE convexside;
    368
    369 nlrow = nlrows[nlrowsidx[i]];
    370 convexside = convexsides[nlrowsidx[i]];
    371
    372 /* compute activity of nlrow at point */
    373 SCIP_CALL( SCIPgetNlRowSolActivity(scip, nlrow, point, &activity) );
    374 if( activity == SCIP_INVALID ) /*lint !e777*/
    375 {
    376 *position = EXTERIOR;
    377 SCIPdebugMsg(scip, "exterior because cons <%s> cannot be evaluated\n", SCIPnlrowGetName(nlrow));
    378 SCIPdebug( SCIPprintNlRow(scip, nlrow, NULL) );
    379 return SCIP_OKAY;
    380 }
    381
    382 if( convexside == RHS )
    383 {
    384 assert(!SCIPisInfinity(scip, SCIPnlrowGetRhs(nlrow)));
    385
    386 /* if nlrow <= rhs is violated, then we are in the exterior */
    387 if( SCIPisFeasGT(scip, activity, SCIPnlrowGetRhs(nlrow)) )
    388 {
    389 *position = EXTERIOR;
    390 SCIPdebugMsg(scip, "exterior because cons <%s> has activity %g. rhs: %g\n", SCIPnlrowGetName(nlrow),
    391 activity, SCIPnlrowGetRhs(nlrow));
    392 SCIPdebug( SCIPprintNlRow(scip, nlrow, NULL) );
    393
    394 return SCIP_OKAY;
    395 }
    396
    397 /* if nlrow(point) == rhs, then we are currently at the boundary */
    398 if( SCIPisFeasEQ(scip, activity, SCIPnlrowGetRhs(nlrow)) )
    399 *position = BOUNDARY;
    400 }
    401 else
    402 {
    403 assert(!SCIPisInfinity(scip, -SCIPnlrowGetLhs(nlrow)));
    404 assert(convexside == LHS);
    405
    406 /* if lhs <= nlrow is violated, then we are in the exterior */
    407 if( SCIPisFeasLT(scip, activity, SCIPnlrowGetLhs(nlrow)) )
    408 {
    409 *position = EXTERIOR;
    410 return SCIP_OKAY;
    411 }
    412
    413 /* if lhs == nlrow(point), then we are currently at the boundary */
    414 if( SCIPisFeasEQ(scip, activity, SCIPnlrowGetLhs(nlrow)) )
    415 *position = BOUNDARY;
    416 }
    417 }
    418
    419 return SCIP_OKAY;
    420}
    421
    422
    423/** returns, in convexcomb, the convex combination
    424 * \f$ \lambda\, \text{endpoint} + (1 - \lambda) \text{startpoint} = \text{startpoint} + \lambda (\text{endpoint} - \text{startpoint})\f$
    425 */
    426static
    428 SCIP* scip, /**< SCIP data structure */
    429 SCIP_Real lambda, /**< convex combination multiplier */
    430 SCIP_SOL* startpoint, /**< point corresponding to \f$ \lambda = 0 \f$ */
    431 SCIP_SOL* endpoint, /**< point corresponding to \f$ \lambda = 1 \f$ */
    432 SCIP_SOL* convexcomb /**< solution to store convex combination of intsol and tosepasol */
    433 )
    434{
    435 SCIP_VAR** vars;
    436 int nvars;
    437 int i;
    438
    439 assert(scip != NULL);
    440 assert(startpoint != NULL);
    441 assert(endpoint != NULL);
    442 assert(convexcomb != NULL);
    443
    444 vars = SCIPgetVars(scip);
    445 nvars = SCIPgetNVars(scip);
    446
    447 for( i = 0; i < nvars; i++ )
    448 {
    449 SCIP_Real val;
    450 SCIP_VAR* var;
    451
    452 var = vars[i];
    453 val = lambda * SCIPgetSolVal(scip, endpoint, var) + (1.0 - lambda) * SCIPgetSolVal(scip, startpoint, var);
    454
    455 if( !SCIPisZero(scip, val) )
    456 {
    457 SCIP_CALL( SCIPsetSolVal(scip, convexcomb, var, val) );
    458 }
    459 else
    460 {
    461 SCIP_CALL( SCIPsetSolVal(scip, convexcomb, var, 0.0) );
    462 }
    463 }
    464
    465 return SCIP_OKAY;
    466}
    467
    468
    469/** performs binary search to find the point belonging to the segment [`intsol`, `tosepasol`] that intersects the boundary
    470 * of the region described by the intersection of `nlrows[i]` &le; rhs if `convexsides[i] = RHS` or lhs &le; `nlrows[i]` if not,
    471 * for i in `nlrowsidx`
    472 */
    473static
    475 SCIP* scip, /**< SCIP data structure */
    476 SCIP_NLROW** nlrows, /**< nlrows defining the region */
    477 int* nlrowsidx, /**< indices of nlrows defining the region */
    478 int nnlrowsidx, /**< number of nlrows indices */
    479 CONVEXSIDE* convexsides, /**< sides of the nlrows involved in the region */
    480 SCIP_SOL* intsol, /**< point acting as 'interior point' */
    481 SCIP_SOL* tosepasol, /**< solution that should be separated */
    482 SCIP_SOL* sol, /**< convex combination of intsol and lpsol */
    483 POSITION* position /**< buffer to store position of sol */
    484 )
    485{
    486 SCIP_Real lb;
    487 SCIP_Real ub;
    488 int i;
    489
    490 assert(scip != NULL);
    491 assert(nlrows != NULL);
    492 assert(nlrowsidx != NULL);
    493 assert(convexsides != NULL);
    494 assert(intsol != NULL);
    495 assert(tosepasol != NULL);
    496 assert(sol != NULL);
    497 assert(position != NULL);
    498
    499 SCIPdebugMsg(scip, "starting binary search\n");
    500 lb = 0.0; /* corresponds to intsol */
    501 ub = 1.0; /* corresponds to tosepasol */
    502 for( i = 0; i < MAX_ITER; i++ )
    503 {
    504 /* sol = (ub+lb)/2 * lpsol + (1 - (ub+lb)/2) * intsol */
    505 SCIP_CALL( buildConvexCombination(scip, (ub + lb)/2.0, intsol, tosepasol, sol) );
    506
    507 /* find poisition of point: boundary, interior, exterior */
    508 SCIP_CALL( findPointPosition(scip, nlrows, nlrowsidx, nnlrowsidx, convexsides, sol, position) );
    509 SCIPdebugMsg(scip, "Position: %d, lambda: %g\n", *position, (ub + lb)/2.0);
    510
    511 switch( *position )
    512 {
    513 case BOUNDARY:
    514 SCIPdebugMsg(scip, "Done\n");
    515 return SCIP_OKAY;
    516
    517 case INTERIOR:
    518 /* want to be closer to tosepasol */
    519 lb = (ub + lb)/2.0;
    520 break;
    521
    522 case EXTERIOR:
    523 /* want to be closer to intsol */
    524 ub = (ub + lb)/2.0;
    525 break;
    526 }
    527 }
    528 SCIPdebugMsg(scip, "Done\n");
    529 return SCIP_OKAY;
    530}
    531
    532
    533/** computes gradient cut (linearization) of nlrow at sol */
    534static
    536 SCIP* scip, /**< SCIP data structure */
    537 SCIP_SOL* sol, /**< point used to construct gradient cut (x_0) */
    538 SCIP_NLROW* nlrow, /**< constraint */
    539 CONVEXSIDE convexside, /**< whether we use rhs or lhs of nlrow */
    540 SCIP_EXPRITER* exprit, /**< expression iterator that can be used */
    541 SCIP_ROW* row, /**< storage for cut */
    542 SCIP_Bool* success /**< buffer to store whether the gradient was finite */
    543 )
    544{
    545 SCIP_EXPR* expr;
    546 SCIP_Real exprval;
    547 SCIP_Real gradx0; /* <grad f(x_0), x_0> */
    548 int i;
    549
    550 assert(scip != NULL);
    551 assert(nlrow != NULL);
    552 assert(row != NULL);
    553
    554 gradx0 = 0.0;
    555 *success = TRUE;
    556
    558
    559#ifdef CUT_DEBUG
    561#endif
    562
    563 /* linear part */
    564 for( i = 0; i < SCIPnlrowGetNLinearVars(nlrow); i++ )
    565 {
    567 }
    568
    569 expr = SCIPnlrowGetExpr(nlrow);
    570 assert(expr != NULL);
    571
    572 SCIP_CALL( SCIPevalExprGradient(scip, expr, sol, 0L) );
    573
    575 for( ; !SCIPexpriterIsEnd(exprit); expr = SCIPexpriterGetNext(exprit) ) /*lint !e441*/ /*lint !e440*/
    576 {
    577 SCIP_Real grad;
    578 SCIP_VAR* var;
    579
    580 if( !SCIPisExprVar(scip, expr) )
    581 continue;
    582
    583 grad = SCIPexprGetDerivative(expr);
    584 var = SCIPgetVarExprVar(expr);
    585 assert(var != NULL);
    586
    587 /* check gradient entries: function might not be differentiable */
    588 if( !SCIPisFinite(grad) || grad == SCIP_INVALID ) /*lint !e777*/
    589 {
    590 *success = FALSE;
    591 break;
    592 }
    593 /* SCIPdebugMsg(scip, "grad w.r.t. <%s> (%g) = %g, gradx0 += %g\n", SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), grad, grad * SCIPgetSolVal(scip, sol, var)); */
    594
    595 gradx0 += grad * SCIPgetSolVal(scip, sol, var);
    596 SCIP_CALL( SCIPaddVarToRow(scip, row, var, grad) );
    597 }
    598
    600
    601 /* if there was a problem computing the cut -> return */
    602 if( ! *success )
    603 return SCIP_OKAY;
    604
    605#ifdef CUT_DEBUG
    606 SCIPdebugMsg(scip, "gradient: ");
    608 SCIPdebugMsg(scip, "gradient dot x_0: %g\n", gradx0);
    609#endif
    610
    611 /* gradient cut is linear part + f(x_0) - <grad f(x_0), x_0> + <grad f(x_0), x> <= rhs or >= lhs */
    612 exprval = SCIPexprGetEvalValue(SCIPnlrowGetExpr(nlrow));
    613 assert(exprval != SCIP_INVALID); /* we should have noticed a domain error above */ /*lint !e777*/
    614 if( convexside == RHS )
    615 {
    616 assert(!SCIPisInfinity(scip, SCIPnlrowGetRhs(nlrow)));
    617 SCIP_CALL( SCIPchgRowRhs(scip, row, SCIPnlrowGetRhs(nlrow) - SCIPnlrowGetConstant(nlrow) - exprval + gradx0) );
    618 }
    619 else
    620 {
    621 assert(convexside == LHS);
    622 assert(!SCIPisInfinity(scip, -SCIPnlrowGetLhs(nlrow)));
    623 SCIP_CALL( SCIPchgRowLhs(scip, row, SCIPnlrowGetLhs(nlrow) - SCIPnlrowGetConstant(nlrow) - exprval + gradx0) );
    624 }
    625
    626#ifdef CUT_DEBUG
    627 SCIPdebugMsg(scip, "gradient cut: ");
    629#endif
    630
    631 return SCIP_OKAY;
    632}
    633
    634/** tries to generate gradient cuts at the point on the segment [`intsol`, `tosepasol`] that intersecs the boundary of the
    635 * convex relaxation
    636 *
    637 * -# checks that the relative interior of the segment actually intersects the boundary
    638 * (this check is needed since `intsol` is not necessarily an interior point)
    639 * -# finds point on the boundary
    640 * -# generates gradient cut at point on the boundary
    641 */
    642static
    644 SCIP* scip, /**< SCIP data structure */
    645 SCIP_SEPA* sepa, /**< the cut separator itself */
    646 SCIP_SOL* tosepasol, /**< solution that should be separated */
    647 SCIP_RESULT* result /**< pointer to store the result of the separation call */
    648 )
    649{
    650 SCIP_SEPADATA* sepadata;
    651 SCIP_NLROW** nlrows;
    652 CONVEXSIDE* convexsides;
    653 SCIP_SOL* sol;
    654 SCIP_SOL* intsol;
    655 POSITION position;
    656 int* nlrowsidx;
    657 int nnlrowsidx;
    658 int i;
    659 SCIP_EXPRITER* exprit;
    660
    661 assert(sepa != NULL);
    662
    663 sepadata = SCIPsepaGetData(sepa);
    664 assert(sepadata != NULL);
    665
    666 intsol = sepadata->intsol;
    667 nlrows = sepadata->nlrows;
    668 nlrowsidx = sepadata->nlrowsidx;
    669 nnlrowsidx = sepadata->nnlrowsidx;
    670 convexsides = sepadata->convexsides;
    671
    672 assert(intsol != NULL);
    673 assert(nlrows != NULL);
    674 assert(nlrowsidx != NULL);
    675 assert(nnlrowsidx > 0);
    676 assert(convexsides != NULL);
    677
    678 /* to evaluate the nlrow one needs a solution */
    679 SCIP_CALL( SCIPcreateSol(scip, &sol, NULL) );
    680
    681 /* don't separate if, under SCIP tolerances, only a slight perturbation of the interior point in the direction of
    682 * tosepasol gives a point that is in the exterior */
    683 SCIP_CALL( buildConvexCombination(scip, VIOLATIONFAC * SCIPfeastol(scip), intsol, tosepasol, sol) );
    684 SCIP_CALL( findPointPosition(scip, nlrows, nlrowsidx, nnlrowsidx, convexsides, sol, &position) );
    685
    686 if( position == EXTERIOR )
    687 {
    688#ifdef SCIP_DEBUG
    689 SCIPdebugMsg(scip, "segment joining intsol and tosepasol seems to be contained in the exterior of the region, can't separate\n");
    690 /* move from intsol in the direction of -tosepasol to check if we are really tangent to the region */
    691 SCIP_CALL( buildConvexCombination(scip, -1e-3, intsol, tosepasol, sol) );
    692 SCIP_CALL( findPointPosition(scip, nlrows, nlrowsidx, nnlrowsidx, convexsides, sol, &position) );
    693 if( position == EXTERIOR )
    694 {
    695 SCIPdebugMsg(scip, "line through intsol and tosepasol is tangent to region; can't separate\n");
    696 }
    697 SCIP_CALL( findPointPosition(scip, nlrows, nlrowsidx, nnlrowsidx, convexsides, intsol, &position) );
    698 printf("Position of intsol is %s\n",
    699 position == EXTERIOR ? "exterior" : position == INTERIOR ? "interior": "boundary");
    700 SCIP_CALL( findPointPosition(scip, nlrows, nlrowsidx, nnlrowsidx, convexsides, tosepasol, &position) );
    701 printf("Position of tosepasol is %s\n",
    702 position == EXTERIOR ? "exterior" : position == INTERIOR ? "interior": "boundary");
    703
    704 /* slightly move from intsol in the direction of +-tosepasol */
    705 SCIP_CALL( buildConvexCombination(scip, 1e-5, intsol, tosepasol, sol) );
    706 SCIP_CALL( findPointPosition(scip, nlrows, nlrowsidx, nnlrowsidx, convexsides, sol, &position) );
    707 printf("Position of intsol + 0.00001(tosepasol - inisol) is %s\n",
    708 position == EXTERIOR ? "exterior" : position == INTERIOR ? "interior": "boundary");
    710
    711 SCIP_CALL( buildConvexCombination(scip, -1e-5, intsol, tosepasol, sol) );
    712 SCIP_CALL( findPointPosition(scip, nlrows, nlrowsidx, nnlrowsidx, convexsides, sol, &position) );
    713 printf("Position of intsol - 0.00001(tosepasol - inisol) is %s\n",
    714 position == EXTERIOR ? "exterior" : position == INTERIOR ? "interior": "boundary");
    716#endif
    717 *result = SCIP_DIDNOTFIND;
    718 goto CLEANUP;
    719 }
    720
    721 /* find point on boundary */
    722 if( position != BOUNDARY )
    723 {
    724 SCIP_CALL( findBoundaryPoint(scip, nlrows, nlrowsidx, nnlrowsidx, convexsides, intsol, tosepasol, sol,
    725 &position) );
    726
    727 /* if MAX_ITER weren't enough to find a point in the boundary we don't separate */
    728 if( position != BOUNDARY )
    729 {
    730 SCIPdebugMsg(scip, "couldn't find boundary point, don't separate\n");
    731 goto CLEANUP;
    732 }
    733 }
    734
    735 /** @todo: could probably be moved inside generateCut */
    736 SCIP_CALL( SCIPcreateExpriter(scip, &exprit) );
    737
    738 /* generate cuts at sol */
    739 for( i = 0; i < nnlrowsidx; i++ )
    740 {
    741 SCIP_NLROW* nlrow;
    742 SCIP_ROW* row;
    743 SCIP_Real activity;
    744 CONVEXSIDE convexside;
    745 SCIP_Bool success;
    746 char rowname[SCIP_MAXSTRLEN];
    747
    748 nlrow = nlrows[nlrowsidx[i]];
    749 convexside = convexsides[nlrowsidx[i]];
    750
    751 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%u", SCIPnlrowGetName(nlrow), ++(sepadata->ncuts));
    752
    753 /* only separate nlrows that are tight at the boundary point */
    754 SCIP_CALL( SCIPgetNlRowSolActivity(scip, nlrow, sol, &activity) );
    755 SCIPdebugMsg(scip, "cons <%s> at boundary point has activity: %g\n", SCIPnlrowGetName(nlrow), activity);
    756
    757 if( activity == SCIP_INVALID /*lint !e777*/
    758 || (convexside == RHS && !SCIPisFeasEQ(scip, activity, SCIPnlrowGetRhs(nlrow))) /*lint !e777*/
    759 || (convexside == LHS && !SCIPisFeasEQ(scip, activity, SCIPnlrowGetLhs(nlrow))) )
    760 continue;
    761
    762 /* cut is globally valid, since we work on nlrows from the NLP built at the root node, which are globally valid */
    763 /* @todo: when local nlrows get supported in SCIP, one can think of recomputing the interior point */
    765 FALSE, FALSE , TRUE) );
    766 SCIP_CALL( generateCut(scip, sol, nlrow, convexside, exprit, row, &success) );
    767
    768 /* add cut */
    769 SCIPdebugMsg(scip, "cut <%s> has efficacy %g\n", SCIProwGetName(row), SCIPgetCutEfficacy(scip, NULL, row));
    770 if( success && SCIPisCutEfficacious(scip, NULL, row) )
    771 {
    772 SCIP_Bool infeasible;
    773
    774 SCIPdebugMsg(scip, "adding cut\n");
    775 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
    776
    777 if( infeasible )
    778 {
    779 *result = SCIP_CUTOFF;
    780 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    781 break;
    782 }
    783 else
    784 {
    785 *result = SCIP_SEPARATED;
    786 }
    787 }
    788
    789 /* release the row */
    790 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    791 }
    792
    793 SCIPfreeExpriter(&exprit);
    794
    795CLEANUP:
    796 SCIP_CALL( SCIPfreeSol(scip, &sol) );
    797
    798 return SCIP_OKAY;
    799}
    800
    801/*
    802 * Callback methods of separator
    803 */
    804
    805/** copy method for separator plugins (called when SCIP copies plugins) */
    806static
    807SCIP_DECL_SEPACOPY(sepaCopyGauge)
    808{ /*lint --e{715}*/
    809 assert(scip != NULL);
    810 assert(sepa != NULL);
    811 assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
    812
    813 /* call inclusion method of separator */
    815
    816 return SCIP_OKAY;
    817}
    818
    819/** destructor of separator to free user data (called when SCIP is exiting) */
    820static
    821SCIP_DECL_SEPAFREE(sepaFreeGauge)
    822{ /*lint --e{715}*/
    823 SCIP_SEPADATA* sepadata;
    824
    825 assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
    826
    827 /* free separator data */
    828 sepadata = SCIPsepaGetData(sepa);
    829 assert(sepadata != NULL);
    830
    831 SCIPfreeBlockMemory(scip, &sepadata);
    832
    833 SCIPsepaSetData(sepa, NULL);
    834
    835 return SCIP_OKAY;
    836}
    837
    838
    839/** solving process deinitialization method of separator (called before branch and bound process data is freed) */
    840static
    841SCIP_DECL_SEPAEXITSOL(sepaExitsolGauge)
    842{ /*lint --e{715}*/
    843 SCIP_SEPADATA* sepadata;
    844
    845 assert(sepa != NULL);
    846
    847 sepadata = SCIPsepaGetData(sepa);
    848
    849 assert(sepadata != NULL);
    850
    851 /* free memory and reset data */
    852 if( sepadata->isintsolavailable )
    853 {
    854 SCIPfreeBlockMemoryArray(scip, &sepadata->nlrowsidx, sepadata->nlrowssize);
    855 SCIPfreeBlockMemoryArray(scip, &sepadata->convexsides, sepadata->nlrowssize);
    856 SCIPfreeBlockMemoryArray(scip, &sepadata->nlrows, sepadata->nlrowssize);
    857 SCIP_CALL( SCIPfreeSol(scip, &sepadata->intsol) );
    858
    859 sepadata->nnlrows = 0;
    860 sepadata->nnlrowsidx = 0;
    861 sepadata->nlrowssize = 0;
    862 sepadata->isintsolavailable = FALSE;
    863 }
    864 assert(sepadata->nnlrows == 0);
    865 assert(sepadata->nnlrowsidx == 0);
    866 assert(sepadata->nlrowssize == 0);
    867 assert(sepadata->isintsolavailable == FALSE);
    868
    869 sepadata->skipsepa = FALSE;
    870
    871 return SCIP_OKAY;
    872}
    873
    874
    875/** LP solution separation method of separator */
    876static
    877SCIP_DECL_SEPAEXECLP(sepaExeclpGauge)
    878{ /*lint --e{715}*/
    879 SCIP_SEPADATA* sepadata;
    880 SCIP_SOL* lpsol;
    881 int i;
    882
    883 assert(scip != NULL);
    884 assert(sepa != NULL);
    885
    886 sepadata = SCIPsepaGetData(sepa);
    887
    888 assert(sepadata != NULL);
    889
    890 *result = SCIP_DIDNOTRUN;
    891
    892 /* do not run if there is no interesting convex relaxation (with at least two nonlinear convex constraint) */
    893 if( sepadata->skipsepa )
    894 {
    895 SCIPdebugMsg(scip, "not running because convex relaxation is uninteresting\n");
    896 return SCIP_OKAY;
    897 }
    898
    899 /* do not run if SCIP has not constructed an NLP */
    901 {
    902 SCIPdebugMsg(scip, "NLP not constructed, skipping gauge separator\n");
    903 return SCIP_OKAY;
    904 }
    905
    906 /* do not run if SCIP has no way of solving nonlinear problems */
    907 if( SCIPgetNNlpis(scip) == 0 )
    908 {
    909 SCIPdebugMsg(scip, "Skip gauge separator: no nlpi and SCIP can't solve nonlinear problems without a nlpi\n");
    910 return SCIP_OKAY;
    911 }
    912
    913 /* if we don't have an interior point compute one; if we fail to compute one, then separator will not be run again;
    914 * otherwise, we also store the convex nlrows in sepadata
    915 */
    916 if( !sepadata->isintsolavailable )
    917 {
    918 /* @todo: one could store the convex nonlinear rows inside computeInteriorPoint */
    919 SCIP_CALL( computeInteriorPoint(scip, sepadata) );
    920 assert(sepadata->skipsepa || sepadata->isintsolavailable);
    921
    922 if( sepadata->skipsepa )
    923 return SCIP_OKAY;
    924
    926 }
    927
    928#ifdef SCIP_DISABLED_CODE
    929 /* get interior point: try to compute an interior point, otherwise use primal solution, otherwise use NLP solution */
    930 /* @todo: - decide order:
    931 * - we can also use convex combination of solutions; there is a function SCIPvarGetAvgSol!
    932 * - can add an event handler to only update when a new solution has been found
    933 */
    934 if( !sepadata->isintsolavailable )
    935 {
    936 if( SCIPgetNSols(scip) > 0 )
    937 {
    938 SCIPdebugMsg(scip, "Using current primal solution as interior point!\n");
    939 SCIP_CALL( SCIPcreateSolCopy(scip, &sepadata->intsol, SCIPgetBestSol(scip)) );
    940 sepadata->isintsolavailable = TRUE;
    941 }
    943 {
    944 SCIPdebugMsg(scip, "Using NLP solution as interior point!\n");
    945 SCIP_CALL( SCIPcreateNLPSol(scip, &sepadata->intsol, NULL) );
    946 sepadata->isintsolavailable = TRUE;
    947 }
    948 else
    949 {
    950 SCIPdebugMsg(scip, "We couldn't find an interior point, don't have a feasible nor an NLP solution; skip separator\n");
    951 return SCIP_OKAY;
    952 }
    953 }
    954#endif
    955
    956 /* store lp sol (or pseudo sol when lp is not solved) to be able to use it to compute nlrows' activities */
    958
    959 /* store indices of relevant constraints, ie, the ones that violate the lp sol */
    960 sepadata->nnlrowsidx = 0;
    961 for( i = 0; i < sepadata->nnlrows; i++ )
    962 {
    963 SCIP_NLROW* nlrow;
    964 SCIP_Real activity;
    965
    966 nlrow = sepadata->nlrows[i];
    967
    968 SCIP_CALL( SCIPgetNlRowSolActivity(scip, nlrow, lpsol, &activity) );
    969 if( activity == SCIP_INVALID ) /*lint !e777*/
    970 continue;
    971
    972 if( sepadata->convexsides[i] == RHS )
    973 {
    974 assert(!SCIPisInfinity(scip, SCIPnlrowGetRhs(nlrow)));
    975
    976 if( activity - SCIPnlrowGetRhs(nlrow) < VIOLATIONFAC * SCIPfeastol(scip) )
    977 continue;
    978 }
    979 else
    980 {
    981 assert(sepadata->convexsides[i] == LHS);
    982 assert(!SCIPisInfinity(scip, -SCIPnlrowGetLhs(nlrow)));
    983
    984 if( SCIPnlrowGetLhs(nlrow) - activity < VIOLATIONFAC * SCIPfeastol(scip) )
    985 continue;
    986 }
    987
    988 sepadata->nlrowsidx[sepadata->nnlrowsidx] = i;
    989 ++(sepadata->nnlrowsidx);
    990 }
    991
    992 /* separate only if there are violated nlrows */
    993 SCIPdebugMsg(scip, "there are %d violated nlrows\n", sepadata->nnlrowsidx);
    994 if( sepadata->nnlrowsidx > 0 )
    995 {
    996 SCIP_CALL( separateCuts(scip, sepa, lpsol, result) );
    997 }
    998
    999 /* free lpsol */
    1000 SCIP_CALL( SCIPfreeSol(scip, &lpsol) );
    1001
    1002 return SCIP_OKAY;
    1003}
    1004
    1005
    1006/*
    1007 * separator specific interface methods
    1008 */
    1009
    1010/** creates the gauge separator and includes it in SCIP */
    1012 SCIP* scip /**< SCIP data structure */
    1013 )
    1014{
    1015 SCIP_SEPADATA* sepadata;
    1016 SCIP_SEPA* sepa;
    1017
    1018 /* create gauge separator data */
    1019 SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
    1020
    1021 /* this sets all data in sepadata to 0 */
    1022 BMSclearMemory(sepadata);
    1023
    1024 /* include separator */
    1027 sepaExeclpGauge, NULL,
    1028 sepadata) );
    1029
    1030 assert(sepa != NULL);
    1031
    1032 /* set non fundamental callbacks via setter functions */
    1033 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyGauge) );
    1034 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeGauge) );
    1035 SCIP_CALL( SCIPsetSepaExitsol(scip, sepa, sepaExitsolGauge) );
    1036
    1037 /* add gauge separator parameters */
    1038 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/nlpiterlimit",
    1039 "iteration limit of NLP solver; 0 for no limit",
    1040 &sepadata->nlpiterlimit, TRUE, DEFAULT_NLPITERLIM, 0, INT_MAX, NULL, NULL) );
    1041
    1042 return SCIP_OKAY;
    1043}
    #define NULL
    Definition: def.h:248
    #define SCIP_MAXSTRLEN
    Definition: def.h:269
    #define SCIP_INVALID
    Definition: def.h:178
    #define SCIP_Bool
    Definition: def.h:91
    #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
    int SCIPgetNVars(SCIP *scip)
    Definition: scip_prob.c:2246
    SCIP_VAR ** SCIPgetVars(SCIP *scip)
    Definition: scip_prob.c:2201
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3304
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    #define SCIPdebugMsg
    Definition: scip_message.h:78
    SCIP_Bool SCIPnlpiOracleIsConstraintNonlinear(SCIP_NLPIORACLE *oracle, int considx)
    Definition: nlpioracle.c:2084
    SCIP_RETCODE SCIPnlpiOraclePrintProblem(SCIP *scip, SCIP_NLPIORACLE *oracle, FILE *file)
    Definition: nlpioracle.c:2848
    int SCIPnlpiOracleGetNVars(SCIP_NLPIORACLE *oracle)
    Definition: nlpioracle.c:1933
    int SCIPnlpiOracleGetNConstraints(SCIP_NLPIORACLE *oracle)
    Definition: nlpioracle.c:1943
    void * SCIPgetNlpiOracleIpopt(SCIP_NLPIPROBLEM *nlpiproblem)
    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_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:94
    SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
    Definition: scip_cut.c:117
    SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
    Definition: scip_cut.c:225
    SCIP_RETCODE SCIPevalExprGradient(SCIP *scip, SCIP_EXPR *expr, SCIP_SOL *sol, SCIP_Longint soltag)
    Definition: scip_expr.c:1692
    SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
    Definition: expriter.c:969
    SCIP_Real SCIPexprGetDerivative(SCIP_EXPR *expr)
    Definition: expr.c:3972
    SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
    Definition: scip_expr.c:1457
    SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2362
    SCIP_Real SCIPexprGetEvalValue(SCIP_EXPR *expr)
    Definition: expr.c:3946
    SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
    Definition: expriter.c:858
    SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
    Definition: expr_var.c:424
    void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
    Definition: scip_expr.c:2376
    SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
    Definition: expriter.c:501
    SCIP_ROW ** SCIPgetLPRows(SCIP *scip)
    Definition: scip_lp.c:611
    int SCIPgetNLPRows(SCIP *scip)
    Definition: scip_lp.c:632
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_RETCODE SCIPaddNlpiProblemRows(SCIP *scip, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *nlpiprob, SCIP_HASHMAP *var2idx, SCIP_ROW **rows, int nrows)
    Definition: scip_nlpi.c:787
    #define SCIPsolveNlpi(scip, nlpi,...)
    Definition: scip_nlpi.h:208
    const char * SCIPnlpiGetName(SCIP_NLPI *nlpi)
    Definition: nlpi.c:722
    SCIP_RETCODE SCIPcreateNlpiProblemFromNlRows(SCIP *scip, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM **nlpiprob, const char *name, SCIP_NLROW **nlrows, int nnlrows, SCIP_HASHMAP *var2idx, SCIP_HASHMAP *nlrow2idx, SCIP_Real *nlscore, SCIP_Real cutoffbound, SCIP_Bool setobj, SCIP_Bool onlyconvex)
    Definition: scip_nlpi.c:449
    int SCIPgetNNlpis(SCIP *scip)
    Definition: scip_nlpi.c:205
    SCIP_NLPI ** SCIPgetNlpis(SCIP *scip)
    Definition: scip_nlpi.c:192
    SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
    Definition: scip_nlp.c:110
    int SCIPgetNNLPNlRows(SCIP *scip)
    Definition: scip_nlp.c:341
    SCIP_NLROW ** SCIPgetNLPNlRows(SCIP *scip)
    Definition: scip_nlp.c:319
    const char * SCIPnlrowGetName(SCIP_NLROW *nlrow)
    Definition: nlp.c:1933
    SCIP_Real SCIPnlrowGetRhs(SCIP_NLROW *nlrow)
    Definition: nlp.c:1914
    SCIP_Real SCIPnlrowGetLhs(SCIP_NLROW *nlrow)
    Definition: nlp.c:1904
    SCIP_EXPRCURV SCIPnlrowGetCurvature(SCIP_NLROW *nlrow)
    Definition: nlp.c:1924
    int SCIPnlrowGetNLinearVars(SCIP_NLROW *nlrow)
    Definition: nlp.c:1864
    SCIP_VAR ** SCIPnlrowGetLinearVars(SCIP_NLROW *nlrow)
    Definition: nlp.c:1874
    SCIP_Real SCIPnlrowGetConstant(SCIP_NLROW *nlrow)
    Definition: nlp.c:1854
    SCIP_EXPR * SCIPnlrowGetExpr(SCIP_NLROW *nlrow)
    Definition: nlp.c:1894
    SCIP_Real * SCIPnlrowGetLinearCoefs(SCIP_NLROW *nlrow)
    Definition: nlp.c:1884
    SCIP_RETCODE SCIPprintNlRow(SCIP *scip, SCIP_NLROW *nlrow, FILE *file)
    Definition: scip_nlp.c:1617
    SCIP_RETCODE SCIPgetNlRowSolActivity(SCIP *scip, SCIP_NLROW *nlrow, SCIP_SOL *sol, SCIP_Real *activity)
    Definition: scip_nlp.c:1522
    SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1581
    SCIP_RETCODE SCIPchgRowLhs(SCIP *scip, SCIP_ROW *row, SCIP_Real lhs)
    Definition: scip_lp.c:1529
    SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1604
    SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_lp.c:1646
    SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
    Definition: scip_lp.c:2176
    const char * SCIProwGetName(SCIP_ROW *row)
    Definition: lp.c:17745
    SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1429
    SCIP_RETCODE SCIPchgRowRhs(SCIP *scip, SCIP_ROW *row, SCIP_Real rhs)
    Definition: scip_lp.c:1553
    SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
    Definition: scip_sepa.c:115
    const char * SCIPsepaGetName(SCIP_SEPA *sepa)
    Definition: sepa.c:746
    SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
    Definition: scip_sepa.c:173
    SCIP_RETCODE SCIPsetSepaExitsol(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAEXITSOL((*sepaexitsol)))
    Definition: scip_sepa.c:237
    SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
    Definition: sepa.c:636
    void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
    Definition: sepa.c:646
    SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
    Definition: scip_sepa.c:157
    SCIP_SOL * SCIPgetBestSol(SCIP *scip)
    Definition: scip_sol.c:2981
    SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:516
    SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
    Definition: scip_sol.c:884
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1252
    SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
    Definition: scip_sol.c:2349
    SCIP_RETCODE SCIPcreateCurrentSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:749
    SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:664
    int SCIPgetNSols(SCIP *scip)
    Definition: scip_sol.c:2882
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1571
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Real SCIPdualfeastol(SCIP *scip)
    SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
    SCIP_RETCODE SCIPincludeSepaGauge(SCIP *scip)
    Definition: sepa_gauge.c:1011
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    memory allocation routines
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    SCIP_NLPSOLSTAT SCIPnlpGetSolstat(SCIP_NLP *nlp)
    Definition: nlp.c:4503
    Ipopt NLP interface.
    methods to store an NLP and request function, gradient, and Hessian values
    public functions to work with algebraic expressions
    public methods for LP management
    public methods for message output
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    public data structures and miscellaneous methods
    #define SCIPisFinite(x)
    Definition: pub_misc.h:82
    public methods for NLP management
    public methods for separators
    public methods for problem variables
    public methods for cuts and aggregation rows
    public functions to work with algebraic expressions
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for nonlinear relaxation
    public methods for NLPI solver interfaces
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for separator plugins
    public methods for solutions
    public methods for querying solving statistics
    public methods for timing
    ConvexSide
    enum ConvexSide CONVEXSIDE
    #define SEPA_PRIORITY
    Definition: sepa_gauge.c:70
    #define SEPA_DELAY
    Definition: sepa_gauge.c:74
    static SCIP_RETCODE generateCut(SCIP *scip, SCIP_SOL *sol, SCIP_NLROW *nlrow, CONVEXSIDE convexside, SCIP_EXPRITER *exprit, SCIP_ROW *row, SCIP_Bool *success)
    Definition: sepa_gauge.c:535
    enum Position POSITION
    Definition: sepa_gauge.c:104
    @ LHS
    Definition: sepa_gauge.c:92
    @ RHS
    Definition: sepa_gauge.c:93
    static SCIP_DECL_SEPAEXITSOL(sepaExitsolGauge)
    Definition: sepa_gauge.c:841
    static SCIP_RETCODE findBoundaryPoint(SCIP *scip, SCIP_NLROW **nlrows, int *nlrowsidx, int nnlrowsidx, CONVEXSIDE *convexsides, SCIP_SOL *intsol, SCIP_SOL *tosepasol, SCIP_SOL *sol, POSITION *position)
    Definition: sepa_gauge.c:474
    #define SEPA_DESC
    Definition: sepa_gauge.c:69
    static SCIP_RETCODE computeInteriorPoint(SCIP *scip, SCIP_SEPADATA *sepadata)
    Definition: sepa_gauge.c:192
    #define INTERIOROBJVARLB
    Definition: sepa_gauge.c:83
    #define SEPA_USESSUBSCIP
    Definition: sepa_gauge.c:73
    static SCIP_DECL_SEPACOPY(sepaCopyGauge)
    Definition: sepa_gauge.c:807
    static SCIP_DECL_SEPAFREE(sepaFreeGauge)
    Definition: sepa_gauge.c:821
    static SCIP_RETCODE separateCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *tosepasol, SCIP_RESULT *result)
    Definition: sepa_gauge.c:643
    #define NLPFEASFAC
    Definition: sepa_gauge.c:81
    static SCIP_RETCODE buildConvexCombination(SCIP *scip, SCIP_Real lambda, SCIP_SOL *startpoint, SCIP_SOL *endpoint, SCIP_SOL *convexcomb)
    Definition: sepa_gauge.c:427
    static SCIP_RETCODE findPointPosition(SCIP *scip, SCIP_NLROW **nlrows, int *nlrowsidx, int nnlrowsidx, CONVEXSIDE *convexsides, SCIP_SOL *point, POSITION *position)
    Definition: sepa_gauge.c:343
    enum ConvexSide CONVEXSIDE
    Definition: sepa_gauge.c:95
    #define SEPA_MAXBOUNDDIST
    Definition: sepa_gauge.c:72
    #define SEPA_FREQ
    Definition: sepa_gauge.c:71
    Position
    Definition: sepa_gauge.c:99
    @ EXTERIOR
    Definition: sepa_gauge.c:102
    @ INTERIOR
    Definition: sepa_gauge.c:100
    @ BOUNDARY
    Definition: sepa_gauge.c:101
    #define DEFAULT_NLPITERLIM
    Definition: sepa_gauge.c:79
    #define SEPA_NAME
    Definition: sepa_gauge.c:68
    #define MAX_ITER
    Definition: sepa_gauge.c:77
    #define VIOLATIONFAC
    Definition: sepa_gauge.c:76
    static SCIP_DECL_SEPAEXECLP(sepaExeclpGauge)
    Definition: sepa_gauge.c:877
    static SCIP_RETCODE storeNonlinearConvexNlrows(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_NLROW **nlrows, int nnlrows)
    Definition: sepa_gauge.c:132
    gauge separator
    SCIP_Real totaltime
    Definition: type_nlpi.h:190
    @ SCIP_EXPRCURV_CONVEX
    Definition: type_expr.h:63
    @ SCIP_EXPRCURV_LINEAR
    Definition: type_expr.h:65
    @ SCIP_EXPRCURV_CONCAVE
    Definition: type_expr.h:64
    @ SCIP_EXPRITER_DFS
    Definition: type_expr.h:718
    @ SCIP_NLPSOLSTAT_FEASIBLE
    Definition: type_nlpi.h:162
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    struct SCIP_SepaData SCIP_SEPADATA
    Definition: type_sepa.h:52