SCIP

    Solving Constraint Integer Programs

    sepa_convexproj.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2026 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file sepa_convexproj.c
    26 * @ingroup DEFPLUGINS_SEPA
    27 * @brief convexproj separator
    28 * @author Felipe Serrano
    29 *
    30 * @todo should separator only be run when SCIPallColsInLP is true?
    31 * @todo check if it makes sense to implement the copy callback
    32 * @todo add SCIPisStopped(scip) to the condition of time consuming loops
    33 */
    34/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    35
    37#include "scip/scip_expr.h"
    38#include "scip/scip_nlpi.h"
    39#include "scip/expr_varidx.h"
    40#include "scip/expr_pow.h"
    41#include "scip/expr_sum.h"
    42#include "scip/pub_message.h"
    43#include "scip/pub_misc.h"
    44#include "scip/pub_nlp.h"
    45#include "scip/pub_sepa.h"
    46#include "scip/pub_var.h"
    47#include "scip/scip_cut.h"
    48#include "scip/scip_general.h"
    49#include "scip/scip_lp.h"
    50#include "scip/scip_mem.h"
    51#include "scip/scip_message.h"
    52#include "scip/scip_nlp.h"
    53#include "scip/scip_numerics.h"
    54#include "scip/scip_param.h"
    55#include "scip/scip_prob.h"
    56#include "scip/scip_sepa.h"
    57#include "scip/scip_sol.h"
    59#include "scip/scip_timing.h"
    60#include "scip/scip_tree.h"
    62
    63
    64#define SEPA_NAME "convexproj"
    65#define SEPA_DESC "separate at projection of point onto convex region"
    66#define SEPA_PRIORITY 0
    67#define SEPA_FREQ -1
    68#define SEPA_MAXBOUNDDIST 1.0
    69#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
    70#define SEPA_DELAY TRUE /**< should separation method be delayed, if other separators found cuts? */
    71
    72#define DEFAULT_MAXDEPTH -1 /**< maximum depth at which the separator is applied; -1 means no limit */
    73#define DEFAULT_NLPITERLIM 250 /**< default NLP iteration limit */
    74
    75#define VIOLATIONFAC 100 /**< points regarded violated if max violation > VIOLATIONFAC*SCIPfeastol() */
    76
    77/*
    78 * Data structures
    79 */
    80
    81/** side that makes an nlrow convex */
    83{
    84 LHS = 0, /**< left hand side */
    85 RHS = 1 /**< right hand side */
    86};
    88
    89/** separator data
    90 * it keeps the nlpi which represents the projection problem (see sepa_convexproj.h); it also keeps the convex nlrows
    91 * and the side which actually makes them convex; when separating, we use the nlpi to compute the projection and then
    92 * the convex nlrows to compute the actual gradient cuts */
    93struct SCIP_SepaData
    94{
    95 SCIP_NLPI* nlpi; /**< nlpi used to create the nlpi problem */
    96 SCIP_NLPIPROBLEM* nlpiprob; /**< nlpi problem representing the convex NLP relaxation */
    97 SCIP_VAR** nlpivars; /**< array containing all variables of the nlpi */
    98 SCIP_HASHMAP* var2nlpiidx; /**< mapping between variables and nlpi indices */
    99 int nlpinvars; /**< total number of nlpi variables */
    100
    101 SCIP_Bool skipsepa; /**< should separator be skipped? */
    102
    103 SCIP_NLROW** nlrows; /**< convex nlrows */
    104 CONVEXSIDE* convexsides; /**< which sides make the nlrows convex */
    105 SCIP_Real* constraintviolation;/**< array storing the violation of constraint by current solution; 0.0 if it is not violated */
    106 int nnlrows; /**< total number of nlrows */
    107 int nlrowssize; /**< memory allocated for nlrows, convexsides and nlrowsidx */
    108
    109 /* parameter */
    110 int nlpiterlimit; /**< iteration limit of NLP solver; 0 for no limit */
    111 int maxdepth; /**< maximal depth at which the separator is applied */
    112
    113 int ncuts; /**< number of cuts generated */
    114};
    115
    116
    117/*
    118 * Local methods
    119 */
    120
    121/** clears the sepadata data */
    122static
    124 SCIP* scip, /**< SCIP data structure */
    125 SCIP_SEPADATA* sepadata /**< separator data */
    126 )
    127{
    128 assert(sepadata != NULL);
    129
    130 /* nlrowssize gets allocated first and then its decided whether to create the nlpiprob */
    131 if( sepadata->nlrowssize > 0 )
    132 {
    133 SCIPfreeBlockMemoryArray(scip, &sepadata->constraintviolation, sepadata->nlrowssize);
    134 SCIPfreeBlockMemoryArray(scip, &sepadata->convexsides, sepadata->nlrowssize);
    135 SCIPfreeBlockMemoryArray(scip, &sepadata->nlrows, sepadata->nlrowssize);
    136 sepadata->nlrowssize = 0;
    137 }
    138
    139 if( sepadata->nlpiprob != NULL )
    140 {
    141 assert(sepadata->nlpi != NULL);
    142
    143 SCIPfreeBlockMemoryArray(scip, &sepadata->nlpivars, sepadata->nlpinvars);
    144
    145 SCIPhashmapFree(&sepadata->var2nlpiidx);
    146 SCIP_CALL( SCIPfreeNlpiProblem(scip, sepadata->nlpi, &sepadata->nlpiprob) );
    147
    148 sepadata->nlpinvars = 0;
    149 sepadata->nnlrows = 0;
    150 }
    151 assert(sepadata->nlpinvars == 0);
    152 assert(sepadata->nnlrows == 0);
    153 assert(sepadata->nlrowssize == 0);
    154
    155 sepadata->skipsepa = FALSE;
    156
    157 return SCIP_OKAY;
    158}
    159
    160/** computes gradient cut (linearization) of nlrow at projection */
    161static
    163 SCIP* scip, /**< SCIP data structure */
    164 SCIP_SEPA* sepa, /**< the cut separator itself */
    165 SCIP_SOL* projection, /**< point where we compute gradient cut */
    166 SCIP_NLROW* nlrow, /**< constraint for which we generate gradient cut */
    167 CONVEXSIDE convexside, /**< which side makes the nlrow convex */
    168 SCIP_Real activity, /**< activity of constraint at projection */
    169 SCIP_EXPRITER* exprit, /**< expression iterator that can be used */
    170 SCIP_ROW** row /**< storage for cut */
    171 )
    172{
    173 char rowname[SCIP_MAXSTRLEN];
    174 SCIP_SEPADATA* sepadata;
    175 SCIP_Real gradx0; /* <grad f(x_0), x_0> */
    176 SCIP_EXPR* expr;
    177 int i;
    178
    179 assert(scip != NULL);
    180 assert(sepa != NULL);
    181 assert(nlrow != NULL);
    182 assert(row != NULL);
    183
    184 sepadata = SCIPsepaGetData(sepa);
    185
    186 assert(sepadata != NULL);
    187
    188 gradx0 = 0.0;
    189
    190 /* an nlrow has a linear part and expression; ideally one would just build the gradient but we
    191 * do not know if the different parts share variables or not, so we can't just build the gradient; for this reason
    192 * we create the row right away and compute the gradients of each part independently and add them to the row; the
    193 * row takes care to add coeffs corresponding to the same variable when they appear in different parts of the nlrow
    194 * NOTE: a gradient cut is globally valid whenever the constraint from which it is deduced is globally valid; since
    195 * we build the convex relaxation using only globally valid constraints, the cuts are globally valid
    196 */
    197 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "proj_cut_%s_%u", SCIPnlrowGetName(nlrow), ++(sepadata->ncuts));
    199 TRUE) );
    200
    202
    203 /* linear part */
    204 for( i = 0; i < SCIPnlrowGetNLinearVars(nlrow); i++ )
    205 {
    206 gradx0 += SCIPgetSolVal(scip, projection, SCIPnlrowGetLinearVars(nlrow)[i]) * SCIPnlrowGetLinearCoefs(nlrow)[i];
    208 }
    209
    210 expr = SCIPnlrowGetExpr(nlrow);
    211 assert(expr != NULL);
    212
    213 SCIP_CALL( SCIPevalExprGradient(scip, expr, projection, 0L) );
    214
    216 for( ; !SCIPexpriterIsEnd(exprit); expr = SCIPexpriterGetNext(exprit) ) /*lint !e441*/ /*lint !e440*/
    217 {
    218 SCIP_Real grad;
    219 SCIP_VAR* var;
    220
    221 if( !SCIPisExprVar(scip, expr) )
    222 continue;
    223
    224 grad = SCIPexprGetDerivative(expr);
    225 var = SCIPgetVarExprVar(expr);
    226 assert(var != NULL);
    227
    228 gradx0 += grad * SCIPgetSolVal(scip, projection, var);
    229 SCIP_CALL( SCIPaddVarToRow(scip, *row, var, grad) );
    230 }
    231
    233
    234 SCIPdebugPrintf("gradient: ");
    236 SCIPdebugPrintf("gradient dot x_0: %g\n", gradx0);
    237
    238 /* gradient cut is f(x_0) - <grad f(x_0), x_0> + <grad f(x_0), x> <= rhs or >= lhs */
    239 if( convexside == RHS )
    240 {
    241 assert(!SCIPisInfinity(scip, SCIPnlrowGetRhs(nlrow)));
    242 SCIP_CALL( SCIPchgRowRhs(scip, *row, SCIPnlrowGetRhs(nlrow) - activity + gradx0) );
    243 }
    244 else
    245 {
    246 assert(convexside == LHS);
    247 assert(!SCIPisInfinity(scip, -SCIPnlrowGetLhs(nlrow)));
    248 SCIP_CALL( SCIPchgRowLhs(scip, *row, SCIPnlrowGetLhs(nlrow) - activity + gradx0) );
    249 }
    250
    251 SCIPdebugPrintf("gradient cut: ");
    253
    254 return SCIP_OKAY;
    255}
    256
    257/** set quadratic part of objective function: \f$ \sum_i x_i^2 \f$
    258 *
    259 * the objective function is \f$ ||x - x_0||^2 \f$,
    260 * where \f$ x_0 \f$ is the point to separate; the only part that changes is the term \f$ -2 \langle x_0, x \rangle \f$
    261 * which is linear and is set every time we want to separate a point, see separateCuts()
    262 */
    263static
    265 SCIP* scip, /**< SCIP data structure */
    266 SCIP_SEPADATA* sepadata /**< the cut separator data */
    267 )
    268{
    269 SCIP_EXPR* exprsum;
    270 SCIP_EXPR** exprspow;
    271 int i;
    272
    273 assert(scip != NULL);
    274 assert(sepadata != NULL);
    275 assert(sepadata->nlpi != NULL);
    276 assert(sepadata->nlpiprob != NULL);
    277 assert(sepadata->var2nlpiidx != NULL);
    278 assert(sepadata->nlpinvars > 0);
    279
    280 SCIP_CALL( SCIPallocBufferArray(scip, &exprspow, sepadata->nlpinvars) );
    281 for( i = 0; i < sepadata->nlpinvars; i++ )
    282 {
    283 SCIP_VAR* var;
    284 SCIP_EXPR* varexpr;
    285
    286 var = sepadata->nlpivars[i];
    287 assert(SCIPhashmapExists(sepadata->var2nlpiidx, (void*)var) );
    288
    289 SCIP_CALL( SCIPcreateExprVaridx(scip, &varexpr, SCIPhashmapGetImageInt(sepadata->var2nlpiidx, (void*)var), NULL, NULL) );
    290 SCIP_CALL( SCIPcreateExprPow(scip, &exprspow[i], varexpr, 2.0, NULL, NULL) );
    291 SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
    292 }
    293
    294 SCIP_CALL( SCIPcreateExprSum(scip, &exprsum, sepadata->nlpinvars, exprspow, NULL, 0.0, NULL, NULL) );
    295
    296 /* set quadratic part of objective function */
    297 SCIP_CALL( SCIPsetNlpiObjective(scip, sepadata->nlpi, sepadata->nlpiprob, 0, NULL, NULL, exprsum, 0.0) );
    298
    299 /* free memory */
    300 SCIP_CALL( SCIPreleaseExpr(scip, &exprsum) );
    301 for( i = sepadata->nlpinvars-1; i >= 0; --i )
    302 {
    303 SCIP_CALL( SCIPreleaseExpr(scip, &exprspow[i]) );
    304 }
    305 SCIPfreeBufferArray(scip, &exprspow);
    306
    307 return SCIP_OKAY;
    308}
    309
    310/** projects sol onto convex relaxation (stored in sepadata) and tries to generate gradient cuts at the projection
    311 *
    312 * it generates cuts only for the constraints that were violated by the LP solution and are now active or still
    313 * violated (in case we don't solve to optimality).
    314 * @todo: store a feasible solution if one is found to use as warmstart
    315 */
    316static
    318 SCIP* scip, /**< SCIP data structure */
    319 SCIP_SEPA* sepa, /**< the cut separator itself */
    320 SCIP_SOL* sol, /**< solution that should be separated */
    321 SCIP_RESULT* result /**< pointer to store the result of the separation call */
    322 )
    323{
    324 SCIP_SEPADATA* sepadata;
    325 SCIP_SOL* projection;
    326 SCIP_Real* linvals;
    327 SCIP_Real* nlpisol;
    328 int nlpinvars;
    329 int i;
    330 int* lininds;
    331 SCIP_Bool nlpunstable;
    332 SCIP_EXPRITER* exprit;
    333
    334 nlpunstable = FALSE;
    335
    336 assert(sepa != NULL);
    337
    338 sepadata = SCIPsepaGetData(sepa);
    339
    340 assert(result != NULL);
    341 assert(sepadata != NULL);
    342 assert(sepadata->nnlrows > 0);
    343 assert(sepadata->nlpi != NULL);
    344 assert(sepadata->nlpinvars > 0);
    345 assert(sepadata->nlrows != NULL);
    346 assert(sepadata->nlpiprob != NULL);
    347 assert(sepadata->var2nlpiidx != NULL);
    348 assert(sepadata->convexsides != NULL);
    349 assert(sepadata->constraintviolation != NULL);
    350
    351 nlpinvars = sepadata->nlpinvars;
    352 /* set linear part of objective function: \norm(x - x^0)^2 = \norm(x)^2 - \sum 2 * x_i * x^0_i + const
    353 * we ignore the constant; x0 is `sol`
    354 */
    355 SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nlpinvars) );
    356 SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nlpinvars) );
    357 for( i = 0; i < nlpinvars; i++ )
    358 {
    359 SCIP_VAR* var;
    360
    361 var = sepadata->nlpivars[i];
    362 assert(SCIPhashmapExists(sepadata->var2nlpiidx, (void*)var) );
    363
    364 lininds[i] = SCIPhashmapGetImageInt(sepadata->var2nlpiidx, (void*)var);
    365 linvals[i] = - 2.0 * SCIPgetSolVal(scip, sol, var);
    366
    367 /* if coefficient is too large, don't separate */
    368 if( SCIPisHugeValue(scip, REALABS(linvals[i])) )
    369 {
    370 SCIPdebugMsg(scip, "Don't separate points too close to infinity\n");
    371 goto CLEANUP;
    372 }
    373 }
    374
    375 /* set linear part of objective function */
    376 SCIP_CALL( SCIPchgNlpiLinearCoefs(scip, sepadata->nlpi, sepadata->nlpiprob, -1, nlpinvars, lininds, linvals) );
    377
    378 /* compute the projection onto the convex NLP relaxation */
    379 SCIP_CALL( SCIPsolveNlpi(scip, sepadata->nlpi, sepadata->nlpiprob,
    380 .iterlimit = sepadata->nlpiterlimit > 0 ? sepadata->nlpiterlimit : INT_MAX,
    381 .feastol = SCIPfeastol(scip) / 10.0, /* use tighter tolerances for the NLP solver */
    382 .opttol = MAX(SCIPfeastol(scip), SCIPdualfeastol(scip))) ); /*lint !e666*/
    383 SCIPdebugMsg(scip, "NLP solstat = %d\n", SCIPgetNlpiSolstat(scip, sepadata->nlpi, sepadata->nlpiprob));
    384
    385 /* if solution is feasible, add cuts */
    386 switch( SCIPgetNlpiSolstat(scip, sepadata->nlpi, sepadata->nlpiprob) )
    387 {
    390 /* @todo: if solution is optimal, we might as well add the cut <x - P(x_0), x_0 - P(x_0)> <= 0
    391 * even though this cut is implied by all the gradient cuts of the rows active at the projection,
    392 * we do not add them all (only the gradient cuts of constraints that violated the LP solution */
    394 /* generate cuts for violated constraints (at sol) that are active or still violated at the projection, since
    395 * a suboptimal solution or numerical issues could give a solution of the projection problem where constraints
    396 * are not active; if the solution of the projection problem is in the interior of the region, we do nothing
    397 */
    398
    399 /* get solution: build SCIP_SOL out of nlpi sol */
    400 SCIP_CALL( SCIPgetNlpiSolution(scip, sepadata->nlpi, sepadata->nlpiprob, &nlpisol, NULL, NULL, NULL, NULL) );
    401 assert(nlpisol != NULL);
    402
    403 SCIP_CALL( SCIPcreateSol(scip, &projection, NULL) );
    404 for( i = 0; i < nlpinvars; i++ )
    405 {
    406 SCIP_VAR* var;
    407
    408 var = sepadata->nlpivars[i];
    409 assert(SCIPhashmapExists(sepadata->var2nlpiidx, (void*)var) );
    410
    411 SCIP_CALL( SCIPsetSolVal(scip, projection, var,
    412 nlpisol[SCIPhashmapGetImageInt(sepadata->var2nlpiidx, (void *)var)]) );
    413 }
    414 SCIPdebug( SCIPprintSol(scip, projection, NULL, TRUE) );
    415
    416 /** @todo this could just be created inside generateCut and the extra argument removed */
    417 SCIP_CALL( SCIPcreateExpriter(scip, &exprit) );
    418
    419 /* check for active or violated constraints */
    420 for( i = 0; i < sepadata->nnlrows; ++i )
    421 {
    422 SCIP_NLROW* nlrow;
    423 CONVEXSIDE convexside;
    424 SCIP_Real activity;
    425
    426 /* ignore constraints that are not violated by `sol` */
    427 if( SCIPisFeasZero(scip, sepadata->constraintviolation[i]) )
    428 continue;
    429
    430 convexside = sepadata->convexsides[i];
    431 nlrow = sepadata->nlrows[i];
    432 assert(nlrow != NULL);
    433
    434 /* check for currently active constraints at projected point */
    435 SCIP_CALL( SCIPgetNlRowSolActivity(scip, nlrow, projection, &activity) );
    436
    437 /* if row cannot be evaluated, then skip it */
    438 if( activity == SCIP_INVALID ) /*lint !e777*/
    439 continue;
    440
    441 SCIPdebugMsg(scip, "NlRow activity at nlpi solution: %g <= %g <= %g\n", SCIPnlrowGetLhs(nlrow), activity,
    442 SCIPnlrowGetRhs(nlrow) );
    443
    444 /* if nlrow is active or violates the projection, build gradient cut at projection */
    445 if( (convexside == RHS && SCIPisFeasGE(scip, activity, SCIPnlrowGetRhs(nlrow)))
    446 || (convexside == LHS && SCIPisFeasLE(scip, activity, SCIPnlrowGetLhs(nlrow))) )
    447 {
    448 SCIP_ROW* row;
    449
    450 SCIP_CALL( generateCut(scip, sepa, projection, nlrow, convexside, activity, exprit,
    451 &row) );
    452
    453 SCIPdebugMsg(scip, "active or violated nlrow: (sols vio: %e)\n", sepadata->constraintviolation[i]);
    455 SCIPdebugMsg(scip, "cut with efficacy %g generated\n", SCIPgetCutEfficacy(scip, sol, row));
    457
    458 /* add cut if it is efficacious for the point we want to separate (sol) */
    459 if( SCIPisCutEfficacious(scip, sol, row) )
    460 {
    461 SCIP_Bool infeasible;
    462
    463 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
    464
    465 if( infeasible )
    466 {
    467 *result = SCIP_CUTOFF;
    468 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    469 break;
    470 }
    471 else
    472 {
    473 *result = SCIP_SEPARATED;
    474 }
    475 }
    476
    477 /* release the row */
    478 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    479 }
    480 }
    481
    482 SCIPfreeExpriter(&exprit);
    483
    484#ifdef SCIP_DEBUG
    485 {
    486 SCIP_Real distance;
    487
    488 /* compute distance between LP sol and its projection (only makes sense when it is optimal) */
    489 distance = 0.0;
    490 for( i = 0; i < SCIPgetNNLPVars(scip); ++i )
    491 {
    492 SCIP_VAR* var;
    493
    494 var = SCIPgetNLPVars(scip)[i];
    495 assert(var != NULL);
    496
    497 /* assert NLP solution is within the bounds of the variable (only make sense when sol is optimal) */
    502
    503 /*SCIPdebugMsg(scip, "NLP sol (LP sol): %s = %f (%g)\n", SCIPvarGetName(var),
    504 * SCIPvarGetNLPSol(var), SCIPgetSolVal(scip, sol, var));
    505 */
    506
    507 distance += SQR( SCIPvarGetNLPSol(var) - SCIPgetSolVal(scip, sol, var) );
    508 }
    509
    510 SCIPdebugMsg(scip, "NLP objval: %e, distance: %e\n", SCIPgetNLPObjval(scip), distance);
    511 }
    512#endif
    513
    514 /* free solution */
    515 SCIP_CALL( SCIPfreeSol(scip, &projection) );
    516 break;
    517
    520 /* fallthrough;
    521 * @todo: write what it means to be locinfeasible and why it can't be used to cutoff the node */
    523 /* unknown... assume numerical issues */
    524 nlpunstable = TRUE;
    525 break;
    526
    528 default:
    529 SCIPerrorMessage("Projection NLP is not unbounded by construction, should not get here!\n");
    530 SCIPABORT();
    531 nlpunstable = TRUE;
    532 }
    533
    534 /* if nlp is detected to be unstable, don't try to separate again */
    535 if( nlpunstable )
    536 {
    537 /* @todo: maybe change objective function to \sum [(x_i - x_i^*)/max(|x_i^*|, 1)]^2
    538 * or some other scaling when unstable and try again.
    539 * maybe free it here */
    540 sepadata->skipsepa = TRUE;
    541 }
    542
    543 /* reset objective */
    544 BMSclearMemoryArray(linvals, nlpinvars);
    545 SCIP_CALL( SCIPchgNlpiLinearCoefs(scip, sepadata->nlpi, sepadata->nlpiprob, -1, nlpinvars, lininds, linvals) );
    546
    547CLEANUP:
    548 /* free memory */
    549 SCIPfreeBufferArray(scip, &lininds);
    550 SCIPfreeBufferArray(scip, &linvals);
    551
    552 return SCIP_OKAY;
    553}
    554
    555/** computes the violation and maximum violation of the convex nlrows stored in sepadata wrt sol */
    556static
    558 SCIP* scip, /**< SCIP data structure */
    559 SCIP_SEPADATA* sepadata, /**< separator data */
    560 SCIP_SOL* sol, /**< solution that should be separated */
    561 SCIP_Real* maxviolation /**< buffer to store maximum violation */
    562 )
    563{
    564 SCIP_NLROW* nlrow;
    565 int i;
    566
    567 assert(sepadata != NULL);
    568 assert(sepadata->nnlrows > 0);
    569 assert(sepadata->nlrows != NULL);
    570 assert(sepadata->convexsides != NULL);
    571 assert(sepadata->constraintviolation != NULL);
    572
    573 *maxviolation = 0.0;
    574 for( i = 0; i < sepadata->nnlrows; i++ )
    575 {
    576 SCIP_Real activity;
    577 SCIP_Real violation;
    578
    579 nlrow = sepadata->nlrows[i];
    580
    581 /* get activity of nlrow */
    582 SCIP_CALL( SCIPgetNlRowSolActivity(scip, nlrow, sol, &activity) );
    583
    584 if( activity == SCIP_INVALID ) /*lint !e777*/
    585 {
    586 *maxviolation = SCIP_INVALID;
    587 break;
    588 }
    589
    590 /* violation = max{activity - rhs, 0.0} when convex and max{lhs - activity, 0.0} when concave */
    591 if( sepadata->convexsides[i] == RHS )
    592 {
    594 assert(!SCIPisInfinity(scip, SCIPnlrowGetRhs(nlrow)));
    595
    596 violation = activity - SCIPnlrowGetRhs(nlrow);
    597 sepadata->constraintviolation[i] = MAX(violation, 0.0);
    598 }
    599 if( sepadata->convexsides[i] == LHS )
    600 {
    602 assert(!SCIPisInfinity(scip, -SCIPnlrowGetLhs(nlrow)));
    603
    604 violation = SCIPnlrowGetLhs(nlrow) - activity;
    605 sepadata->constraintviolation[i] = MAX(violation, 0.0);
    606 }
    607
    608 /* compute maximum */
    609 if( *maxviolation < sepadata->constraintviolation[i] )
    610 *maxviolation = sepadata->constraintviolation[i];
    611 }
    612
    613 SCIPdebugMsg(scip, "Maximum violation %g\n", *maxviolation);
    614
    615 return SCIP_OKAY;
    616}
    617
    618
    619/** stores, from the constraints represented by nlrows, the nonlinear convex ones in sepadata */
    620static
    622 SCIP* scip, /**< SCIP data structure */
    623 SCIP_SEPADATA* sepadata, /**< separator data */
    624 SCIP_NLROW** nlrows, /**< nlrows from which to store convex ones */
    625 int nnlrows /**< number of nlrows */
    626 )
    627{
    628 int i;
    629
    630 assert(scip != NULL);
    631 assert(sepadata != NULL);
    632
    633 SCIPdebugMsg(scip, "storing convex nlrows\n");
    634
    635 sepadata->nlrowssize = nnlrows;
    636 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(sepadata->nlrows), nnlrows) );
    637 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(sepadata->convexsides), nnlrows) );
    638 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(sepadata->constraintviolation), nnlrows) );
    639
    640 /* count the number of nonlinear convex rows and store them */
    641 sepadata->nnlrows = 0;
    642 for( i = 0; i < nnlrows; ++i )
    643 {
    644 SCIP_NLROW* nlrow;
    645
    646 nlrow = nlrows[i];
    647 assert(nlrow != NULL);
    648
    649 /* linear case */
    651 continue;
    652
    653 /* nonlinear case */
    655 {
    656 sepadata->convexsides[sepadata->nnlrows] = RHS;
    657 sepadata->nlrows[sepadata->nnlrows] = nlrow;
    658 ++(sepadata->nnlrows);
    659 }
    661 {
    662 sepadata->convexsides[sepadata->nnlrows] = LHS;
    663 sepadata->nlrows[sepadata->nnlrows] = nlrow;
    664 ++(sepadata->nnlrows);
    665 }
    666 }
    667
    668 return SCIP_OKAY;
    669}
    670
    671/*
    672 * Callback methods of separator
    673 */
    674
    675/** copy method for separator plugins (called when SCIP copies plugins) */
    676static
    677SCIP_DECL_SEPACOPY(sepaCopyConvexproj)
    678{ /*lint --e{715}*/
    679 assert(scip != NULL);
    680 assert(sepa != NULL);
    681
    683
    684 /* call inclusion method of separator */
    686
    687 return SCIP_OKAY;
    688}
    689
    690/** destructor of separator to free user data (called when SCIP is exiting) */
    691static
    692SCIP_DECL_SEPAFREE(sepaFreeConvexproj)
    693{ /*lint --e{715}*/
    694 SCIP_SEPADATA* sepadata;
    695
    697
    698 /* free separator data */
    699 sepadata = SCIPsepaGetData(sepa);
    700 assert(sepadata != NULL);
    701
    702 SCIP_CALL( sepadataClear(scip, sepadata) );
    703
    704 SCIPfreeBlockMemory(scip, &sepadata);
    705
    706 SCIPsepaSetData(sepa, NULL);
    707
    708 return SCIP_OKAY;
    709}
    710
    711/** solving process deinitialization method of separator (called before branch and bound process data is freed) */
    712static
    713SCIP_DECL_SEPAEXITSOL(sepaExitsolConvexproj)
    714{ /*lint --e{715}*/
    715 SCIP_SEPADATA* sepadata;
    716
    717 assert(sepa != NULL);
    718
    719 sepadata = SCIPsepaGetData(sepa);
    720
    721 assert(sepadata != NULL);
    722
    723 SCIP_CALL( sepadataClear(scip, sepadata) );
    724
    725 return SCIP_OKAY;
    726}
    727
    728
    729/** LP solution separation method of separator */
    730static
    731SCIP_DECL_SEPAEXECLP(sepaExeclpConvexproj)
    732{ /*lint --e{715}*/
    733 SCIP_Real maxviolation;
    734 SCIP_SOL* lpsol;
    735 SCIP_SEPADATA* sepadata;
    736
    737 *result = SCIP_DIDNOTRUN;
    738
    739 sepadata = SCIPsepaGetData(sepa);
    740 assert(sepadata != NULL);
    741
    742 /* do not run if there is no interesting convex relaxation (with at least one nonlinear convex constraint),
    743 * or if we have found it to be numerically unstable
    744 * @todo: should it be with at least 2 nonlinear convex constraints?
    745 */
    746 if( sepadata->skipsepa )
    747 {
    748 SCIPdebugMsg(scip, "not running because convex relaxation is uninteresting or numerically unstable\n");
    749 return SCIP_OKAY;
    750 }
    751
    752 /* the separator needs an NLP solver */
    753 if( SCIPgetNNlpis(scip) == 0 )
    754 return SCIP_OKAY;
    755
    756 /* only call separator up to a maximum depth */
    757 if( sepadata->maxdepth >= 0 && depth > sepadata->maxdepth )
    758 return SCIP_OKAY;
    759
    760 /* only call separator, if we are not close to terminating */
    761 if( SCIPisStopped(scip) )
    762 return SCIP_OKAY;
    763
    764 /* do not run if SCIP does not have constructed an NLP */
    766 {
    767 SCIPdebugMsg(scip, "NLP not constructed, skipping convex projection separator\n");
    768 return SCIP_OKAY;
    769 }
    770
    771 /* recompute convex NLP relaxation if the variable set changed and we are still at the root node */
    772 if( sepadata->nlpiprob != NULL && SCIPgetNVars(scip) != sepadata->nlpinvars && SCIPgetDepth(scip) == 0 )
    773 {
    774 SCIP_CALL( sepadataClear(scip, sepadata) );
    775 assert(sepadata->nlpiprob == NULL);
    776 }
    777
    778 /* create or update convex NLP relaxation */
    779 if( sepadata->nlpiprob == NULL )
    780 {
    781 /* store convex nonlinear constraints */
    783
    784 /* check that convex NLP relaxation is interesting (more than one nonlinear constraint) */
    785 if( sepadata->nnlrows < 1 )
    786 {
    787 SCIPdebugMsg(scip, "convex relaxation uninteresting, don't run\n");
    788 sepadata->skipsepa = TRUE;
    789 return SCIP_OKAY;
    790 }
    791
    792 sepadata->nlpinvars = SCIPgetNVars(scip);
    793 sepadata->nlpi = SCIPgetNlpis(scip)[0];
    794 assert(sepadata->nlpi != NULL);
    795
    796 SCIP_CALL( SCIPhashmapCreate(&sepadata->var2nlpiidx, SCIPblkmem(scip), sepadata->nlpinvars) );
    797 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &sepadata->nlpivars, SCIPgetVars(scip), sepadata->nlpinvars) ); /*lint !e666*/
    798
    799 SCIP_CALL( SCIPcreateNlpiProblemFromNlRows(scip, sepadata->nlpi, &sepadata->nlpiprob, "convexproj-nlp", SCIPgetNLPNlRows(scip), SCIPgetNNLPNlRows(scip),
    800 sepadata->var2nlpiidx, NULL, NULL, SCIPgetCutoffbound(scip), FALSE, TRUE) );
    801
    802 /* add rows of the LP
    803 * we do not sue the depth argument of the callback because we want to build a globally valid initia lrelaxation
    804 */
    805 if( SCIPgetDepth(scip) == 0 )
    806 {
    807 SCIP_CALL( SCIPaddNlpiProblemRows(scip, sepadata->nlpi, sepadata->nlpiprob, sepadata->var2nlpiidx,
    809 }
    810
    811 /* set quadratic part of objective function */
    812 SCIP_CALL( setQuadraticObj(scip, sepadata) );
    813 }
    814 else
    815 {
    816 SCIP_CALL( SCIPupdateNlpiProblem(scip, sepadata->nlpi, sepadata->nlpiprob, sepadata->var2nlpiidx,
    817 sepadata->nlpivars, sepadata->nlpinvars, SCIPgetCutoffbound(scip)) );
    818 }
    819
    820 /* assert that the lp solution satisfies the cutoff bound; if this fails then we shouldn't have a cutoff bound in the
    821 * nlpi, since then the projection could be in the interior of the actual convex relaxation */
    824
    825 /* get current sol: LP or pseudo solution if LP sol is not available */
    827
    828 /* do not run if current solution cannot be evaluated or the violation is small */
    829 SCIP_CALL( computeMaxViolation(scip, sepadata, lpsol, &maxviolation) );
    830 if( maxviolation == SCIP_INVALID ) /*lint !e777*/
    831 {
    832 SCIPdebugMsg(scip, "constraints cannot be evaluated at solution, do not separate\n");
    833 SCIP_CALL( SCIPfreeSol(scip, &lpsol) );
    834 return SCIP_OKAY;
    835 }
    836 if( maxviolation < VIOLATIONFAC * SCIPfeastol(scip) )
    837 {
    838 SCIPdebugMsg(scip, "solution doesn't violate constraints enough, do not separate\n");
    839 SCIP_CALL( SCIPfreeSol(scip, &lpsol) );
    840 return SCIP_OKAY;
    841 }
    842
    843 /* run the separator */
    844 *result = SCIP_DIDNOTFIND;
    845
    846 /* separateCuts computes the projection and then gradient cuts on each constraint that was originally violated */
    847 SCIP_CALL( separateCuts(scip, sepa, lpsol, result) );
    848
    849 /* free memory */
    850 SCIP_CALL( SCIPfreeSol(scip, &lpsol) );
    851
    852 return SCIP_OKAY;
    853}
    854
    855
    856/*
    857 * separator specific interface methods
    858 */
    859
    860/** creates the convexproj separator and includes it in SCIP */
    862 SCIP* scip /**< SCIP data structure */
    863 )
    864{
    865 SCIP_SEPADATA* sepadata;
    866 SCIP_SEPA* sepa;
    867
    868 /* create convexproj separator data */
    869 SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
    870
    871 /* this sets all data in sepadata to 0 */
    872 BMSclearMemory(sepadata);
    873
    874 /* include separator */
    877 sepaExeclpConvexproj, NULL,
    878 sepadata) );
    879 assert(sepa != NULL);
    880
    881 /* set non fundamental callbacks via setter functions */
    882 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyConvexproj) );
    883 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeConvexproj) );
    884 SCIP_CALL( SCIPsetSepaExitsol(scip, sepa, sepaExitsolConvexproj) );
    885
    886 /* add convexproj separator parameters */
    887 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxdepth",
    888 "maximal depth at which the separator is applied (-1: unlimited)",
    889 &sepadata->maxdepth, FALSE, DEFAULT_MAXDEPTH, -1, INT_MAX, NULL, NULL) );
    890
    891 SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/nlpiterlimit",
    892 "iteration limit of NLP solver; 0 for no limit",
    893 &sepadata->nlpiterlimit, TRUE, DEFAULT_NLPITERLIM, 0, INT_MAX, NULL, NULL) );
    894
    895 return SCIP_OKAY;
    896}
    #define NULL
    Definition: def.h:257
    #define SCIP_MAXSTRLEN
    Definition: def.h:278
    #define SCIP_INVALID
    Definition: def.h:187
    #define SCIP_Bool
    Definition: def.h:100
    #define SCIP_STRINGEQ(name, reference, retcode)
    Definition: def.h:454
    #define SCIP_Real
    Definition: def.h:165
    #define SQR(x)
    Definition: def.h:208
    #define TRUE
    Definition: def.h:102
    #define FALSE
    Definition: def.h:103
    #define MAX(x, y)
    Definition: def.h:229
    #define SCIPABORT()
    Definition: def.h:336
    #define REALABS(x)
    Definition: def.h:191
    #define SCIP_CALL(x)
    Definition: def.h:364
    power and signed power expression handlers
    sum expression handler
    handler for variable index expressions
    SCIP_RETCODE SCIPcreateExprVaridx(SCIP *scip, SCIP_EXPR **expr, int varidx, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_varidx.c:220
    SCIP_RETCODE SCIPcreateExprSum(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefficients, SCIP_Real constant, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_sum.c:1117
    SCIP_RETCODE SCIPcreateExprPow(SCIP *scip, SCIP_EXPR **expr, SCIP_EXPR *child, SCIP_Real exponent, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
    Definition: expr_pow.c:3186
    SCIP_Bool SCIPisStopped(SCIP *scip)
    Definition: scip_general.c:767
    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_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_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
    Definition: scip_expr.c:1443
    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_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
    Definition: expriter.c:858
    SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
    Definition: expr_var.c:423
    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
    SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
    Definition: scip_lp.c:174
    SCIP_Real SCIPgetLPObjval(SCIP *scip)
    Definition: scip_lp.c:253
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #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
    #define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
    Definition: scip_mem.h:105
    SCIP_RETCODE SCIPaddNlpiProblemRows(SCIP *scip, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *nlpiprob, SCIP_HASHMAP *var2idx, SCIP_ROW **rows, int nrows)
    Definition: scip_nlpi.c:787
    SCIP_RETCODE SCIPupdateNlpiProblem(SCIP *scip, SCIP_NLPI *nlpi, SCIP_NLPIPROBLEM *nlpiprob, SCIP_HASHMAP *var2nlpiidx, SCIP_VAR **nlpivars, int nlpinvars, SCIP_Real cutoffbound)
    Definition: scip_nlpi.c:735
    #define SCIPsolveNlpi(scip, nlpi,...)
    Definition: scip_nlpi.h:208
    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
    SCIP_Real SCIPgetNLPObjval(SCIP *scip)
    Definition: scip_nlp.c:645
    int SCIPgetNNLPVars(SCIP *scip)
    Definition: scip_nlp.c:201
    int SCIPgetNNLPNlRows(SCIP *scip)
    Definition: scip_nlp.c:341
    SCIP_VAR ** SCIPgetNLPVars(SCIP *scip)
    Definition: scip_nlp.c:179
    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_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
    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_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:514
    SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
    Definition: scip_sol.c:1250
    SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
    Definition: scip_sol.c:2351
    SCIP_RETCODE SCIPcreateCurrentSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
    Definition: scip_sol.c:747
    SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_sol.c:1569
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1763
    SCIP_Real SCIPgetCutoffbound(SCIP *scip)
    SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisHugeValue(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_Real SCIPdualfeastol(SCIP *scip)
    int SCIPgetDepth(SCIP *scip)
    Definition: scip_tree.c:672
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24300
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24266
    SCIP_Real SCIPvarGetNLPSol(SCIP_VAR *var)
    Definition: var.c:24723
    SCIP_RETCODE SCIPincludeSepaConvexproj(SCIP *scip)
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    memory allocation routines
    #define BMSclearMemory(ptr)
    Definition: memory.h:129
    #define BMSclearMemoryArray(ptr, num)
    Definition: memory.h:130
    public methods for message output
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    #define SCIPdebug(x)
    Definition: pub_message.h:93
    #define SCIPdebugPrintf
    Definition: pub_message.h:99
    public data structures and miscellaneous methods
    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
    general public methods
    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
    public methods for the branch-and-bound tree
    #define SEPA_PRIORITY
    #define SEPA_DELAY
    static SCIP_RETCODE sepadataClear(SCIP *scip, SCIP_SEPADATA *sepadata)
    ConvexSide
    @ LHS
    @ RHS
    #define SEPA_DESC
    static SCIP_DECL_SEPACOPY(sepaCopyConvexproj)
    #define SEPA_USESSUBSCIP
    static SCIP_RETCODE generateCut(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *projection, SCIP_NLROW *nlrow, CONVEXSIDE convexside, SCIP_Real activity, SCIP_EXPRITER *exprit, SCIP_ROW **row)
    #define DEFAULT_MAXDEPTH
    static SCIP_DECL_SEPAEXECLP(sepaExeclpConvexproj)
    static SCIP_RETCODE separateCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
    enum ConvexSide CONVEXSIDE
    #define SEPA_MAXBOUNDDIST
    #define SEPA_FREQ
    #define DEFAULT_NLPITERLIM
    static SCIP_RETCODE setQuadraticObj(SCIP *scip, SCIP_SEPADATA *sepadata)
    #define SEPA_NAME
    #define VIOLATIONFAC
    static SCIP_DECL_SEPAEXITSOL(sepaExitsolConvexproj)
    static SCIP_RETCODE computeMaxViolation(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_SOL *sol, SCIP_Real *maxviolation)
    static SCIP_DECL_SEPAFREE(sepaFreeConvexproj)
    static SCIP_RETCODE storeNonlinearConvexNlrows(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_NLROW **nlrows, int nnlrows)
    convexproj separator
    @ 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_LPSOLSTAT_OPTIMAL
    Definition: type_lp.h:44
    @ SCIP_NLPSOLSTAT_UNBOUNDED
    Definition: type_nlpi.h:165
    @ SCIP_NLPSOLSTAT_GLOBINFEASIBLE
    Definition: type_nlpi.h:164
    @ SCIP_NLPSOLSTAT_LOCINFEASIBLE
    Definition: type_nlpi.h:163
    @ SCIP_NLPSOLSTAT_FEASIBLE
    Definition: type_nlpi.h:162
    @ SCIP_NLPSOLSTAT_LOCOPT
    Definition: type_nlpi.h:161
    @ SCIP_NLPSOLSTAT_GLOBOPT
    Definition: type_nlpi.h:160
    @ SCIP_NLPSOLSTAT_UNKNOWN
    Definition: type_nlpi.h:166
    @ 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
    @ SCIP_INVALIDCALL
    Definition: type_retcode.h:51
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    struct SCIP_SepaData SCIP_SEPADATA
    Definition: type_sepa.h:52