Scippy

    SCIP

    Solving Constraint Integer Programs

    ConshdlrSubtour.cpp
    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 ConshdlrSubtour.cpp
    26 * @brief Subtour elimination constraint handler for TSP problems, written in C++
    27 * @author Timo Berthold
    28 */
    29
    30/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    31
    32#include <cassert>
    33#include <string>
    34#include <iostream>
    35#include "ConshdlrSubtour.h"
    36#include "GomoryHuTree.h"
    37
    38#include "objscip/objscip.h"
    39
    40#include "scip/cons_linear.h"
    41
    42#include "GomoryHuTree.h"
    43
    44using namespace tsp;
    45using namespace scip;
    46using namespace std;
    47
    48/** data structure for subtour elimination constraints */
    49struct SCIP_ConsData
    50{
    51 GRAPH* graph;
    52};
    53
    54
    55/** checks whether proposed solution contains a subtour
    56 *
    57 * We assume that the solution is binary.
    58 */
    59static
    61 SCIP* scip, /**< SCIP data structure */
    62 GRAPH* graph, /**< underlying graph */
    63 SCIP_SOL* sol /**< proposed solution */
    64 )
    65{
    66 GRAPHNODE* node;
    67 GRAPHNODE* startnode;
    68 GRAPHEDGE* edge;
    69 GRAPHEDGE* nextedge;
    70 GRAPHEDGE* lastedge = NULL;
    71 int tourlength = 0;
    72
    73 assert(scip != NULL);
    74 assert(graph != NULL);
    75
    76 if( graph->nnodes <= 1 )
    77 return FALSE;
    78
    79 startnode = &graph->nodes[0];
    80 node = startnode;
    81
    82 /* follow the (sub?)tour until you come back to the startnode */
    83 do
    84 {
    85 edge = node->first_edge;
    86 nextedge = NULL;
    87
    88 /* look for an outgoing edge to proceed */
    89 while( edge != NULL )
    90 {
    91 /* if a new edge with value 1 is found, we proceed */
    92 if( edge->back != lastedge && SCIPgetSolVal(scip, sol, edge->var) > 0.5 )
    93 {
    94 ++tourlength;
    95
    96 /* if we found a subtour without the starting node, e.g. 0 - 1 - 2 - 3 - 1 - 2 - ...;
    97 * this can only happen, if the degree constraints are violated; */
    98 if( nextedge != NULL || tourlength > graph->nnodes )
    99 return TRUE;
    100
    101 nextedge = edge;
    102
    103 /* only use the first edge for the start node */
    104 if( node == startnode )
    105 break;
    106 }
    107
    108 edge = edge->next;
    109 }
    110
    111 /* no outgoing edge found in the solution: the degree constraints must be violated; abort! */
    112 if( nextedge == NULL )
    113 return TRUE;
    114
    115 node = nextedge->adjac;
    116 lastedge = nextedge;
    117 }
    118 while( node != startnode );
    119
    120 assert(tourlength <= graph->nnodes);
    121
    122 return ( graph->nnodes != tourlength );
    123}
    124
    125
    126/** separates subtour elemination cuts */
    127static
    129 SCIP* scip, /**< SCIP data structure */
    130 SCIP_CONSHDLR* conshdlr, /**< the constraint handler itself */
    131 SCIP_CONS** conss, /**< array of constraints to process */
    132 int nconss, /**< number of constraints to process */
    133 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
    134 SCIP_SOL* sol, /**< primal solution that should be separated */
    135 SCIP_Bool enforce, /**< whether we are in enforcing */
    136 SCIP_RESULT* result /**< pointer to store the result of the separation call */
    137 )
    138{ /*lint --e{715}*/
    139 assert(result != NULL);
    140
    141 *result = SCIP_DIDNOTFIND;
    142
    143 for(int c = 0; c < nusefulconss && *result != SCIP_CUTOFF; ++c)
    144 {
    145 // get all required structures
    146 SCIP_CONSDATA* consdata;
    147 GRAPH* graph;
    148
    149 consdata = SCIPconsGetData(conss[c]);
    150 assert(consdata != NULL);
    151
    152 graph = consdata->graph;
    153 assert(graph != NULL);
    154
    155 // store the suggested, but infeasible solution into the capacity of the edges
    156 for(int i = 0; i < graph->nedges; i++)
    157 {
    158 double cap = SCIPgetSolVal(scip, sol, graph->edges[i].var);
    159 graph->edges[i].rcap = cap;
    160 graph->edges[i].cap = cap;
    161 graph->edges[i].back->rcap = cap;
    162 graph->edges[i].back->cap = cap;
    163 }
    164
    165 SCIP_Bool** cuts = NULL;
    166 int ncuts;
    167
    168 SCIP_CALL( SCIPallocBufferArray(scip, &cuts, graph->nnodes) );
    169 for(int i = 0; i < graph->nnodes; i++)
    170 {
    171 SCIP_CALL( SCIPallocBufferArray(scip, &cuts[i], graph->nnodes) ); /*lint !e866*/
    172 }
    173
    174 // try to find cuts
    175 if( ghc_tree(graph, cuts, &ncuts, SCIPfeastol(scip)) )
    176 {
    177 // create a new cutting plane for every suitable arc (representing a cut with value < 2) of the Gomory Hu Tree
    178 for(int i = 0; i < ncuts && *result != SCIP_CUTOFF; ++i)
    179 {
    180 SCIP_ROW* row;
    181 SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, "subtour", 2.0, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
    182
    184
    185 for(int j = 0; j < graph->nnodes; j++)
    186 {
    187 // in gmincut the graph has been partitioned into two parts, represented by bools
    188 if( cuts[i][j] )
    189 {
    190 GRAPHEDGE* edge = graph->nodes[j].first_edge;
    191
    192 // take every edge with nodes in different parts into account
    193 while( edge != NULL )
    194 {
    195 if( ! cuts[i][edge->adjac->id] )
    196 {
    197 SCIP_CALL( SCIPaddVarToRow(scip, row, edge->var, 1.0) );
    198 }
    199 edge = edge->next;
    200 }
    201 }
    202 }
    203
    205
    206 // Add violated cut. The cuts produced by ghc_tree are violated by at least the feasibility tolerance. If we
    207 // are enforcing, then this is enough to add the cut. Otherwise (we are separating), we check whether the
    208 // cut is efficacious.
    209 if( enforce || SCIPisCutEfficacious(scip, sol, row) )
    210 {
    211 SCIP_Bool infeasible;
    212 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
    213 if ( infeasible )
    214 *result = SCIP_CUTOFF;
    215 else
    216 *result = SCIP_SEPARATED;
    217 }
    218 SCIP_CALL( SCIPreleaseRow(scip, &row) );
    219 }
    220 }
    221
    222 for(int i = graph->nnodes - 1; i >= 0; i--)
    223 SCIPfreeBufferArray(scip, &cuts[i]);
    225 }
    226
    227 return SCIP_OKAY;
    228}
    229
    230
    231/** frees specific constraint data */
    232SCIP_DECL_CONSDELETE(ConshdlrSubtour::scip_delete)
    233{ /*lint --e{715}*/
    234 assert(consdata != NULL);
    235
    236 release_graph(&(*consdata)->graph);
    237 SCIPfreeBlockMemory(scip, consdata);
    238
    239 return SCIP_OKAY;
    240}
    241
    242
    243/** transforms constraint data into data belonging to the transformed problem */
    244SCIP_DECL_CONSTRANS(ConshdlrSubtour::scip_trans)
    245{
    246 SCIP_CONSDATA* sourcedata;
    247 SCIP_CONSDATA* targetdata = NULL;
    248
    249 sourcedata = SCIPconsGetData(sourcecons);
    250 assert( sourcedata != NULL );
    251
    252 SCIP_CALL( SCIPallocBlockMemory(scip, &targetdata) );
    253 targetdata->graph = sourcedata->graph;
    254 capture_graph(targetdata->graph);
    255
    256 /* create target constraint */
    257 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
    258 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
    259 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
    260 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
    261 SCIPconsIsStickingAtNode(sourcecons)) );
    262
    263 return SCIP_OKAY;
    264}
    265
    266
    267/** separation method of constraint handler for LP solution
    268 *
    269 * Separates all constraints of the constraint handler. The method is called in the LP solution loop,
    270 * which means that a valid LP solution exists.
    271 *
    272 * The first nusefulconss constraints are the ones, that are identified to likely be violated. The separation
    273 * method should process only the useful constraints in most runs, and only occasionally the remaining
    274 * nconss - nusefulconss constraints.
    275 *
    276 * possible return values for *result (if more than one applies, the first in the list should be used):
    277 * - SCIP_CUTOFF : the node is infeasible in the variable's bounds and can be cut off
    278 * - SCIP_CONSADDED : an additional constraint was generated
    279 * - SCIP_REDUCEDDOM : a variable's domain was reduced
    280 * - SCIP_SEPARATED : a cutting plane was generated
    281 * - SCIP_DIDNOTFIND : the separator searched, but did not find domain reductions, cutting planes, or cut constraints
    282 * - SCIP_DIDNOTRUN : the separator was skipped
    283 * - SCIP_DELAYED : the separator was skipped, but should be called again
    284 */
    285SCIP_DECL_CONSSEPALP(ConshdlrSubtour::scip_sepalp)
    286{
    287 SCIP_CALL( sepaSubtour(scip, conshdlr, conss, nconss, nusefulconss, NULL, FALSE, result) );
    288
    289 return SCIP_OKAY;
    290}
    291
    292
    293/** separation method of constraint handler for arbitrary primal solution
    294 *
    295 * Separates all constraints of the constraint handler. The method is called outside the LP solution loop (e.g., by
    296 * a relaxator or a primal heuristic), which means that there is no valid LP solution.
    297 * Instead, the method should produce cuts that separate the given solution.
    298 *
    299 * The first nusefulconss constraints are the ones, that are identified to likely be violated. The separation
    300 * method should process only the useful constraints in most runs, and only occasionally the remaining
    301 * nconss - nusefulconss constraints.
    302 *
    303 * possible return values for *result (if more than one applies, the first in the list should be used):
    304 * - SCIP_CUTOFF : the node is infeasible in the variable's bounds and can be cut off
    305 * - SCIP_CONSADDED : an additional constraint was generated
    306 * - SCIP_REDUCEDDOM : a variable's domain was reduced
    307 * - SCIP_SEPARATED : a cutting plane was generated
    308 * - SCIP_DIDNOTFIND : the separator searched, but did not find domain reductions, cutting planes, or cut constraints
    309 * - SCIP_DIDNOTRUN : the separator was skipped
    310 * - SCIP_DELAYED : the separator was skipped, but should be called again
    311 */
    312SCIP_DECL_CONSSEPASOL(ConshdlrSubtour::scip_sepasol)
    313{
    314 SCIP_CALL( sepaSubtour(scip, conshdlr, conss, nconss, nusefulconss, sol, FALSE, result) );
    315
    316 return SCIP_OKAY;
    317}
    318
    319
    320/** constraint enforcing method of constraint handler for LP solutions
    321 *
    322 * The method is called at the end of the node processing loop for a node where the LP was solved.
    323 * The LP solution has to be checked for feasibility. If possible, an infeasibility should be resolved by
    324 * branching, reducing a variable's domain to exclude the solution or separating the solution with a valid
    325 * cutting plane.
    326 *
    327 * The enforcing methods of the active constraint handlers are called in decreasing order of their enforcing
    328 * priorities until the first constraint handler returned with the value SCIP_CUTOFF, SCIP_SEPARATED,
    329 * SCIP_REDUCEDDOM, SCIP_CONSADDED, or SCIP_BRANCHED.
    330 * The integrality constraint handler has an enforcing priority of zero. A constraint handler which can
    331 * (or wants) to enforce its constraints only for integral solutions should have a negative enforcing priority
    332 * (e.g. the alldiff-constraint can only operate on integral solutions).
    333 * A constraint handler which wants to incorporate its own branching strategy even on non-integral
    334 * solutions must have an enforcing priority greater than zero (e.g. the SOS-constraint incorporates
    335 * SOS-branching on non-integral solutions).
    336 *
    337 * The first nusefulconss constraints are the ones, that are identified to likely be violated. The enforcing
    338 * method should process the useful constraints first. The other nconss - nusefulconss constraints should only
    339 * be enforced, if no violation was found in the useful constraints.
    340 *
    341 * possible return values for *result (if more than one applies, the first in the list should be used):
    342 * - SCIP_CUTOFF : the node is infeasible in the variable's bounds and can be cut off
    343 * - SCIP_CONSADDED : an additional constraint was generated
    344 * - SCIP_REDUCEDDOM : a variable's domain was reduced
    345 * - SCIP_SEPARATED : a cutting plane was generated
    346 * - SCIP_BRANCHED : no changes were made to the problem, but a branching was applied to resolve an infeasibility
    347 * - SCIP_INFEASIBLE : at least one constraint is infeasible, but it was not resolved
    348 * - SCIP_FEASIBLE : all constraints of the handler are feasible
    349 */
    350SCIP_DECL_CONSENFOLP(ConshdlrSubtour::scip_enfolp)
    351{ /*lint --e{715}*/
    352 assert(result != NULL);
    353
    354 // search for subtour elimination cuts
    355 SCIP_CALL( sepaSubtour(scip, conshdlr, conss, nconss, nusefulconss, NULL, TRUE, result) );
    356
    357 // if separation could not find a subtour, then the solution is feasible for this constraint
    358 if( *result == SCIP_DIDNOTFIND )
    359 *result = SCIP_FEASIBLE;
    360
    361 return SCIP_OKAY;
    362}
    363
    364/** constraint enforcing method of constraint handler for pseudo solutions
    365 *
    366 * The method is called at the end of the node processing loop for a node where the LP was not solved.
    367 * The pseudo solution has to be checked for feasibility. If possible, an infeasibility should be resolved by
    368 * branching, reducing a variable's domain to exclude the solution or adding an additional constraint.
    369 * Separation is not possible, since the LP is not processed at the current node. All LP informations like
    370 * LP solution, slack values, or reduced costs are invalid and must not be accessed.
    371 *
    372 * Like in the enforcing method for LP solutions, the enforcing methods of the active constraint handlers are
    373 * called in decreasing order of their enforcing priorities until the first constraint handler returned with
    374 * the value SCIP_CUTOFF, SCIP_REDUCEDDOM, SCIP_CONSADDED, SCIP_BRANCHED, or SCIP_SOLVELP.
    375 *
    376 * The first nusefulconss constraints are the ones, that are identified to likely be violated. The enforcing
    377 * method should process the useful constraints first. The other nconss - nusefulconss constraints should only
    378 * be enforced, if no violation was found in the useful constraints.
    379 *
    380 * If the pseudo solution's objective value is lower than the lower bound of the node, it cannot be feasible
    381 * and the enforcing method may skip it's check and set *result to SCIP_DIDNOTRUN. However, it can also process
    382 * its constraints and return any other possible result code.
    383 *
    384 * possible return values for *result (if more than one applies, the first in the list should be used):
    385 * - SCIP_CUTOFF : the node is infeasible in the variable's bounds and can be cut off
    386 * - SCIP_CONSADDED : an additional constraint was generated
    387 * - SCIP_REDUCEDDOM : a variable's domain was reduced
    388 * - SCIP_BRANCHED : no changes were made to the problem, but a branching was applied to resolve an infeasibility
    389 * - SCIP_SOLVELP : at least one constraint is infeasible, and this can only be resolved by solving the SCIP_LP
    390 * - SCIP_INFEASIBLE : at least one constraint is infeasible, but it was not resolved
    391 * - SCIP_FEASIBLE : all constraints of the handler are feasible
    392 * - SCIP_DIDNOTRUN : the enforcement was skipped (only possible, if objinfeasible is true)
    393 */
    394SCIP_DECL_CONSENFOPS(ConshdlrSubtour::scip_enfops)
    395{ /*lint --e{715}*/
    396 assert(result != NULL);
    397
    398 // search for subtour elimination cuts
    399 SCIP_CALL( sepaSubtour(scip, conshdlr, conss, nconss, nusefulconss, NULL, TRUE, result) );
    400
    401 // if separation could not find a subtour, then the solution is feasible for this constraint
    402 if( *result == SCIP_DIDNOTFIND )
    403 *result = SCIP_FEASIBLE;
    404
    405 return SCIP_OKAY;
    406}
    407
    408/** feasibility check method of constraint handler for primal solutions
    409 *
    410 * The given solution has to be checked for feasibility.
    411 *
    412 * The check methods of the active constraint handlers are called in decreasing order of their check
    413 * priorities until the first constraint handler returned with the result SCIP_INFEASIBLE.
    414 * The integrality constraint handler has a check priority of zero. A constraint handler which can
    415 * (or wants) to check its constraints only for integral solutions should have a negative check priority
    416 * (e.g. the alldiff-constraint can only operate on integral solutions).
    417 * A constraint handler which wants to check feasibility even on non-integral solutions must have a
    418 * check priority greater than zero (e.g. if the check is much faster than testing all variables for
    419 * integrality).
    420 *
    421 * In some cases, integrality conditions or rows of the current LP don't have to be checked, because their
    422 * feasibility is already checked or implicitly given. In these cases, 'checkintegrality' or
    423 * 'checklprows' is FALSE.
    424 *
    425 * possible return values for *result:
    426 * - SCIP_INFEASIBLE : at least one constraint of the handler is infeasible
    427 * - SCIP_FEASIBLE : all constraints of the handler are feasible
    428 */
    429SCIP_DECL_CONSCHECK(ConshdlrSubtour::scip_check)
    430{ /*lint --e{715}*/
    431 assert(result != NULL);
    432 *result = SCIP_FEASIBLE;
    433
    434 for( int i = 0; i < nconss; ++i )
    435 {
    436 SCIP_CONSDATA* consdata;
    437 GRAPH* graph;
    438 SCIP_Bool found;
    439
    440 assert(conss != NULL);
    441 assert(conss[i] != NULL);
    442 consdata = SCIPconsGetData(conss[i]);
    443 assert(consdata != NULL);
    444 graph = consdata->graph;
    445 assert(graph != NULL);
    446
    447 // if a subtour is found, the solution must be infeasible
    448 found = findSubtour(scip, graph, sol);
    449 if( found )
    450 {
    451 *result = SCIP_INFEASIBLE;
    452 if( printreason )
    453 {
    454 SCIP_CALL( SCIPprintCons(scip, conss[i], NULL) );
    455 SCIPinfoMessage(scip, NULL, "violation: graph has a subtour\n");
    456 }
    457 }
    458 }
    459
    460 return SCIP_OKAY;
    461}
    462
    463/** domain propagation method of constraint handler
    464 *
    465 * The first nusefulconss constraints are the ones, that are identified to likely be violated. The propagation
    466 * method should process only the useful constraints in most runs, and only occasionally the remaining
    467 * nconss - nusefulconss constraints.
    468 *
    469 * possible return values for *result:
    470 * - SCIP_CUTOFF : the node is infeasible in the variable's bounds and can be cut off
    471 * - SCIP_REDUCEDDOM : at least one domain reduction was found
    472 * - SCIP_DIDNOTFIND : the propagator searched, but did not find any domain reductions
    473 * - SCIP_DIDNOTRUN : the propagator was skipped
    474 * - SCIP_DELAYED : the propagator was skipped, but should be called again
    475 */
    476SCIP_DECL_CONSPROP(ConshdlrSubtour::scip_prop)
    477{ /*lint --e{715}*/
    478 assert(result != NULL);
    479
    480 *result = SCIP_DIDNOTRUN;
    481 return SCIP_OKAY;
    482}
    483
    484/** variable rounding lock method of constraint handler
    485 *
    486 * This method is called, after a constraint is added or removed from the transformed problem.
    487 * It should update the rounding locks of all associated variables with calls to SCIPaddVarLocksType(),
    488 * depending on the way, the variable is involved in the constraint:
    489 * - If the constraint may get violated by decreasing the value of a variable, it should call
    490 * SCIPaddVarLocksType(scip, var, SCIP_LOCKTYPE_MODEL, nlockspos, nlocksneg), saying that rounding down is
    491 * potentially rendering the (positive) constraint infeasible and rounding up is potentially rendering the
    492 * negation of the constraint infeasible.
    493 * - If the constraint may get violated by increasing the value of a variable, it should call
    494 * SCIPaddVarLocksType(scip, var, SCIP_LOCKTYPE_MODEL, nlocksneg, nlockspos), saying that rounding up is
    495 * potentially rendering the constraint's negation infeasible and rounding up is potentially rendering the
    496 * constraint itself infeasible.
    497 * - If the constraint may get violated by changing the variable in any direction, it should call
    498 * SCIPaddVarLocksType(scip, var, SCIP_LOCKTYPE_MODEL, nlockspos + nlocksneg, nlockspos + nlocksneg).
    499 *
    500 * Consider the linear constraint "3x -5y +2z <= 7" as an example. The variable rounding lock method of the
    501 * linear constraint handler should call SCIPaddVarLocksType(scip, x, SCIP_LOCKTYPE_MODEL, nlocksneg, nlockspos),
    502 * SCIPaddVarLocksType(scip, y, SCIP_LOCKTYPE_MODEL, nlockspos, nlocksneg) and
    503 * SCIPaddVarLocksType(scip, z, SCIP_LOCKTYPE_MODEL, nlocksneg, nlockspos) to tell SCIP,
    504 * that rounding up of x and z and rounding down of y can destroy the feasibility of the constraint, while rounding
    505 * down of x and z and rounding up of y can destroy the feasibility of the constraint's negation "3x -5y +2z > 7".
    506 * A linear constraint "2 <= 3x -5y +2z <= 7" should call
    507 * SCIPaddVarLocksType(scip, ..., SCIP_LOCKTYPE_MODEL, nlockspos + nlocksneg, nlockspos + nlocksneg) on all variables,
    508 * since rounding in both directions of each variable can destroy both the feasibility of the constraint and it's negation
    509 * "3x -5y +2z < 2 or 3x -5y +2z > 7".
    510 *
    511 * If the constraint itself contains other constraints as sub constraints (e.g. the "or" constraint concatenation
    512 * "c(x) or d(x)"), the rounding lock methods of these constraints should be called in a proper way.
    513 * - If the constraint may get violated by the violation of the sub constraint c, it should call
    514 * SCIPaddConsLocks(scip, c, nlockspos, nlocksneg), saying that infeasibility of c may lead to infeasibility of
    515 * the (positive) constraint, and infeasibility of c's negation (i.e. feasibility of c) may lead to infeasibility
    516 * of the constraint's negation (i.e. feasibility of the constraint).
    517 * - If the constraint may get violated by the feasibility of the sub constraint c, it should call
    518 * SCIPaddConsLocks(scip, c, nlocksneg, nlockspos), saying that infeasibility of c may lead to infeasibility of
    519 * the constraint's negation (i.e. feasibility of the constraint), and infeasibility of c's negation (i.e. feasibility
    520 * of c) may lead to infeasibility of the (positive) constraint.
    521 * - If the constraint may get violated by any change in the feasibility of the sub constraint c, it should call
    522 * SCIPaddConsLocks(scip, c, nlockspos + nlocksneg, nlockspos + nlocksneg).
    523 *
    524 * Consider the or concatenation "c(x) or d(x)". The variable rounding lock method of the or constraint handler
    525 * should call SCIPaddConsLocks(scip, c, nlockspos, nlocksneg) and SCIPaddConsLocks(scip, d, nlockspos, nlocksneg)
    526 * to tell SCIP, that infeasibility of c and d can lead to infeasibility of "c(x) or d(x)".
    527 *
    528 * As a second example, consider the equivalence constraint "y <-> c(x)" with variable y and constraint c. The
    529 * constraint demands, that y == 1 if and only if c(x) is satisfied. The variable lock method of the corresponding
    530 * constraint handler should call SCIPaddVarLocksType(scip, y, SCIP_LOCKTYPE_MODEL, nlockspos + nlocksneg, nlockspos + nlocksneg) and
    531 * SCIPaddConsLocks(scip, c, nlockspos + nlocksneg, nlockspos + nlocksneg), because any modification to the
    532 * value of y or to the feasibility of c can alter the feasibility of the equivalence constraint.
    533 */
    534SCIP_DECL_CONSLOCK(ConshdlrSubtour::scip_lock)
    535{ /*lint --e{715}*/
    536 SCIP_CONSDATA* consdata;
    537 GRAPH* g;
    538
    539 consdata = SCIPconsGetData(cons);
    540 assert(consdata != NULL);
    541
    542 g = consdata->graph;
    543 assert(g != NULL);
    544
    545 for( int i = 0; i < g->nedges; ++i )
    546 {
    547 SCIP_CALL( SCIPaddVarLocksType(scip, g->edges[i].var, SCIP_LOCKTYPE_MODEL, nlocksneg, nlockspos) );
    548 }
    549
    550 return SCIP_OKAY;
    551}
    552
    553/** variable deletion method of constraint handler
    554 *
    555 * This method should iterate over all constraints of the constraint handler and delete all variables
    556 * that were marked for deletion by SCIPdelVar().
    557 *
    558 * input:
    559 * - scip : SCIP main data structure
    560 * - conshdlr : the constraint handler itself
    561 * - conss : array of constraints in transformed problem
    562 * - nconss : number of constraints in transformed problem
    563 */
    564SCIP_DECL_CONSDELVARS(ConshdlrSubtour::scip_delvars)
    565{ /*lint --e{715}*/
    566 return SCIP_OKAY;
    567}
    568
    569
    570/** constraint display method of constraint handler
    571 *
    572 * The constraint handler should store a representation of the constraint into the given text file.
    573 */
    574SCIP_DECL_CONSPRINT(ConshdlrSubtour::scip_print)
    575{ /*lint --e{715}*/
    576 SCIP_CONSDATA* consdata;
    577 GRAPH* g;
    578
    579 consdata = SCIPconsGetData(cons);
    580 assert(consdata != NULL);
    581
    582 g = consdata->graph;
    583 assert(g != NULL);
    584
    585 SCIPinfoMessage(scip, file, "subtour of Graph G with %d nodes and %d edges\n", g->nnodes, g->nedges);
    586
    587 return SCIP_OKAY;
    588}
    589
    590/** clone method which will be used to copy a objective plugin */
    591SCIP_DECL_CONSHDLRCLONE(ObjProbCloneable* ConshdlrSubtour::clone) /*lint !e665*/
    592{
    593 assert(valid != NULL);
    594 *valid = TRUE;
    595 return new ConshdlrSubtour(scip);
    596}
    597
    598/** constraint copying method of constraint handler
    599 *
    600 * The constraint handler can provide a copy method, which copies a constraint from one SCIP data structure into a other
    601 * SCIP data structure.
    602 */
    603SCIP_DECL_CONSCOPY(ConshdlrSubtour::scip_copy)
    604{ /*lint --e{715}*/
    605 SCIP_CONSHDLR* conshdlr;
    606 SCIP_CONSDATA* consdata = NULL;
    607
    608 assert(valid != NULL);
    609
    610 /* find the subtour constraint handler */
    611 conshdlr = SCIPfindConshdlr(scip, "subtour");
    612 if( conshdlr == NULL )
    613 {
    614 SCIPerrorMessage("subtour constraint handler not found\n");
    615 return SCIP_PLUGINNOTFOUND;
    616 }
    617
    618 /* create constraint data */
    619 SCIP_CALL( SCIPallocBlockMemory( scip, &consdata) );
    620 ProbDataTSP* probdatatsp;
    621 probdatatsp = dynamic_cast<ProbDataTSP*>(SCIPgetObjProbData(scip));
    622 assert( probdatatsp != NULL );
    623
    624 GRAPH * graph = probdatatsp->getGraph();
    625 consdata->graph = graph;
    626 capture_graph( consdata->graph );
    627
    628 /* create constraint */
    629 SCIP_CALL( SCIPcreateCons(scip, cons, (name == NULL) ? SCIPconsGetName(sourcecons) : name,
    630 conshdlr, consdata, initial, separate, enforce, check,
    631 propagate, local, modifiable, dynamic, removable, FALSE) );
    632
    633 *valid = TRUE;
    634
    635 return SCIP_OKAY;
    636}
    637
    638/** creates and captures a TSP subtour constraint */
    640 SCIP* scip, /**< SCIP data structure */
    641 SCIP_CONS** cons, /**< pointer to hold the created constraint */
    642 const char* name, /**< name of constraint */
    643 GRAPH* graph, /**< the underlying graph */
    644 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
    645 SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
    646 SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
    647 SCIP_Bool check, /**< should the constraint be checked for feasibility? */
    648 SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
    649 SCIP_Bool local, /**< is constraint only valid locally? */
    650 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
    651 SCIP_Bool dynamic, /**< is constraint dynamic? */
    652 SCIP_Bool removable /**< should the constraint be removed from the LP due to aging or cleanup? */
    653 )
    654{
    655 SCIP_CONSHDLR* conshdlr;
    656 SCIP_CONSDATA* consdata;
    657
    658 /* find the subtour constraint handler */
    659 conshdlr = SCIPfindConshdlr(scip, "subtour");
    660 if( conshdlr == NULL )
    661 {
    662 SCIPerrorMessage("subtour constraint handler not found\n");
    663 return SCIP_PLUGINNOTFOUND;
    664 }
    665
    666 /* create constraint data */
    667 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) ); /*lint !e530*/
    668 consdata->graph = graph;
    669 capture_graph(consdata->graph);
    670
    671 /* create constraint */
    672 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
    673 local, modifiable, dynamic, removable, FALSE) );
    674
    675 return SCIP_OKAY;
    676}
    SCIP_DECL_CONSENFOPS(ConshdlrSubtour::scip_enfops)
    SCIP_DECL_CONSSEPASOL(ConshdlrSubtour::scip_sepasol)
    SCIP_DECL_CONSLOCK(ConshdlrSubtour::scip_lock)
    static SCIP_Bool findSubtour(SCIP *scip, GRAPH *graph, SCIP_SOL *sol)
    SCIP_DECL_CONSHDLRCLONE(ObjProbCloneable *ConshdlrSubtour::clone)
    SCIP_DECL_CONSDELETE(ConshdlrSubtour::scip_delete)
    static SCIP_RETCODE sepaSubtour(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool enforce, SCIP_RESULT *result)
    SCIP_DECL_CONSCOPY(ConshdlrSubtour::scip_copy)
    SCIP_DECL_CONSSEPALP(ConshdlrSubtour::scip_sepalp)
    SCIP_DECL_CONSTRANS(ConshdlrSubtour::scip_trans)
    SCIP_DECL_CONSDELVARS(ConshdlrSubtour::scip_delvars)
    SCIP_DECL_CONSPRINT(ConshdlrSubtour::scip_print)
    SCIP_DECL_CONSCHECK(ConshdlrSubtour::scip_check)
    SCIP_DECL_CONSPROP(ConshdlrSubtour::scip_prop)
    SCIP_DECL_CONSENFOLP(ConshdlrSubtour::scip_enfolp)
    C++ constraint handler for TSP subtour elimination constraints.
    void capture_graph(GRAPH *gr)
    SCIP_Bool ghc_tree(GRAPH *gr, SCIP_Bool **cuts, int *ncuts, double minviol)
    void release_graph(GRAPH **gr)
    generator for global cuts in undirected graphs
    GRAPH * getGraph()
    Definition: ProbDataTSP.h:97
    Constraint handler for linear constraints in their most general form, .
    #define NULL
    Definition: def.h:248
    #define SCIP_Bool
    Definition: def.h:91
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_CALL(x)
    Definition: def.h:355
    #define nnodes
    Definition: gastrans.c:74
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
    Definition: cons.c:8419
    SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
    Definition: cons.c:8648
    SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
    Definition: cons.c:8558
    SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
    Definition: scip_cons.c:2536
    SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
    Definition: cons.c:8588
    SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
    Definition: cons.c:8578
    SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
    Definition: scip_cons.c:997
    SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
    Definition: cons.c:8608
    SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
    Definition: cons.c:8628
    const char * SCIPconsGetName(SCIP_CONS *cons)
    Definition: cons.c:8389
    SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
    Definition: cons.c:8638
    SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
    Definition: cons.c:8668
    SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
    Definition: cons.c:8568
    SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
    Definition: cons.c:8658
    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
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1581
    SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
    Definition: scip_lp.c:1604
    SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
    Definition: scip_lp.c:1367
    SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
    Definition: scip_lp.c:1646
    SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
    Definition: scip_lp.c:1508
    SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
    Definition: scip_sol.c:1765
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_Real SCIPfeastol(SCIP *scip)
    SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
    Definition: scip_var.c:5118
    Definition: pqueue.h:38
    SCIP_RETCODE SCIPcreateConsSubtour(SCIP *scip, SCIP_CONS **cons, const char *name, GRAPH *graph, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable)
    scip::ObjProbData * SCIPgetObjProbData(SCIP *scip)
    C++ wrapper classes for SCIP.
    #define SCIPerrorMessage
    Definition: pub_message.h:64
    static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
    Main separation function.
    Definition: sepa_flower.c:1221
    struct GraphEdge * back
    Definition: GomoryHuTree.h:70
    double rcap
    Definition: GomoryHuTree.h:66
    double cap
    Definition: GomoryHuTree.h:65
    GRAPHNODE * adjac
    Definition: GomoryHuTree.h:72
    SCIP_VAR * var
    Definition: GomoryHuTree.h:74
    struct GraphEdge * next
    Definition: GomoryHuTree.h:69
    struct GraphEdge * first_edge
    Definition: GomoryHuTree.h:53
    GRAPHNODE * nodes
    Definition: GomoryHuTree.h:86
    int nedges
    Definition: GomoryHuTree.h:83
    int nnodes
    Definition: GomoryHuTree.h:82
    GRAPHEDGE * edges
    Definition: GomoryHuTree.h:87
    Definition of base class for all clonable classes which define problem data.
    struct SCIP_ConsData SCIP_CONSDATA
    Definition: type_cons.h:65
    @ SCIP_DIDNOTRUN
    Definition: type_result.h:42
    @ SCIP_CUTOFF
    Definition: type_result.h:48
    @ SCIP_FEASIBLE
    Definition: type_result.h:45
    @ SCIP_DIDNOTFIND
    Definition: type_result.h:44
    @ SCIP_SEPARATED
    Definition: type_result.h:49
    @ SCIP_INFEASIBLE
    Definition: type_result.h:46
    enum SCIP_Result SCIP_RESULT
    Definition: type_result.h:61
    @ SCIP_PLUGINNOTFOUND
    Definition: type_retcode.h:54
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_LOCKTYPE_MODEL
    Definition: type_var.h:141