Scippy

    SCIP

    Solving Constraint Integer Programs

    main_vrp.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
    26 * @brief main file for VRP pricer example
    27 * @author Andreas Bley
    28 * @author Marc Pfetsch
    29 *
    30 * We want to solve the vehicle routing problem on a graph \f$G = (V,E)\f$ with
    31 * \f$V = J \cup \{d\}\f$, where d is the depot and the distances are given by the
    32 * length function \f$l_e: E \rightarrow R_{\geq 0}\f$.
    33 *
    34 * Consider the MIP formulation
    35 *
    36 * \f[
    37 * \begin{array}[t]{rll}
    38 * \min & \displaystyle \sum_{e \in E} l_e y_e \\
    39 * & & \\
    40 * s.t. & -y_e + \sum_{t \in T_k} a^t_e x_t \leq 0, & \forall e \in E\\
    41 * & \displaystyle \sum_{t \in T_k} a^t_j x_t = 1, & \forall j \in J \\
    42 * & y(\delta(j)) = 2, & \forall j \in J \\
    43 * & y_e \in \{0,1,2\}, & \forall e \in E \\
    44 * & x_t \in [0,1], & \forall t \in T_k
    45 * \end{array}
    46 * \f]
    47 *
    48 * where \f$T_k\f$ is the set of tours visiting at most k customers
    49 * with repetitions of customers allowed and \f$a^t_e\f$ (\f$a^t_j\f$) counts how often
    50 * edge e (node j) is traversed in \f$t \in T_k\f$.
    51 *
    52 * Examples and the file format are given at https://neo.lcc.uma.es/vrp/vrp-instances/capacitated-vrp-instances/.
    53 */
    54
    55/* standard library includes */
    56#include <stdio.h>
    57#include <iostream>
    58#include <fstream>
    59#include <vector>
    60#include <string>
    61
    62/* scip includes */
    63#include "objscip/objscip.h"
    65
    66/* user defined includes */
    67#include "pricer_vrp.h"
    68
    69
    70/* namespace usage */
    71using namespace std;
    72using namespace scip;
    73
    74
    75/** read VRP problem */
    76static
    78 const char* filename, /**< filename */
    79 int& num_nodes, /**< number of nodes in instance */
    80 int& capacity, /**< capacity in instance */
    81 vector<int>& demand, /**< array of demands of instance */
    82 vector<vector<int> >& dist /**< distances between nodes */
    83 )
    84{
    85 const string DIMENSION = "DIMENSION";
    86 const string DEMAND_SECTION = "DEMAND_SECTION";
    87 const string DEPOT_SECTION = "DEPOT_SECTION";
    88 const string EDGE_WEIGHT_TYPE = "EDGE_WEIGHT_TYPE";
    89 const string EUC_2D = "EUC_2D";
    90 const string EXPLICIT = "EXPLICIT";
    91 const string LOWER_DIAG_ROW = "LOWER_DIAG_ROW";
    92 const string EDGE_WEIGHT_FORMAT = "EDGE_WEIGHT_FORMAT";
    93 const string EDGE_WEIGHT_SECTION = "EDGE_WEIGHT_SECTION";
    94 const string NODE_COORD_SECTION = "NODE_COORD_SECTION";
    95 const string CAPACITY = "CAPACITY";
    96
    97 ifstream file(filename);
    98
    99 num_nodes = -1;
    100 capacity = -1;
    101
    102 if ( ! file )
    103 {
    104 cerr << "Cannot open file " << filename << endl;
    105 return 1;
    106 }
    107
    108 string edge_weight_type = "";
    109 string edge_weight_format = "";
    110 vector<int> x;
    111 vector<int> y;
    112
    113 while ( file )
    114 {
    115 //--------------------
    116 // Read keyword.
    117 //--------------------
    118 string key;
    119 string dummy;
    120 file >> key;
    121
    122 if ( key == DIMENSION )
    123 {
    124 file >> dummy;
    125 file >> num_nodes;
    126
    127 assert( num_nodes >= 0 );
    128 demand.resize(num_nodes, 0); /*lint !e732 !e747*/
    129 dist.resize(num_nodes); /*lint !e732 !e747*/
    130 for (int i = 0; i < num_nodes; ++i)
    131 dist[i].resize(i, 0); /*lint !e732 !e747*/
    132 }
    133
    134 if ( key == CAPACITY )
    135 {
    136 file >> dummy;
    137 file >> capacity;
    138 }
    139 else if ( key == EDGE_WEIGHT_TYPE )
    140 {
    141 file >> dummy;
    142 file >> edge_weight_type;
    143 if ( edge_weight_type != EUC_2D && edge_weight_type != EXPLICIT )
    144 {
    145 cerr << "Wrong " << EDGE_WEIGHT_TYPE << " " << edge_weight_type << endl;
    146 return 1;
    147 }
    148 if ( edge_weight_type == EUC_2D )
    149 {
    150 assert( num_nodes >= 0 );
    151 x.resize(num_nodes, 0); /*lint !e732 !e747*/
    152 y.resize(num_nodes, 0); /*lint !e732 !e747*/
    153 }
    154 }
    155 else if ( key == EDGE_WEIGHT_FORMAT )
    156 {
    157 file >> dummy;
    158 file >> edge_weight_format;
    159 }
    160 else if ( key == EDGE_WEIGHT_FORMAT + ":" )
    161 {
    162 file >> edge_weight_format;
    163 }
    164 else if ( key == EDGE_WEIGHT_SECTION )
    165 {
    166 if ( edge_weight_type != EXPLICIT || edge_weight_format != LOWER_DIAG_ROW )
    167 {
    168 cerr << "Error. Unsupported edge length type." << endl;
    169 return 1;
    170 }
    171 assert( num_nodes >= 0 );
    172 for (int i = 0; i < num_nodes; ++i)
    173 {
    174 for (int j = 0; j < i; ++j)
    175 {
    176 int l;
    177 file >> l;
    178 dist[i][j] = l; /*lint !e732 !e747*/
    179 }
    180 }
    181 }
    182 else if ( key == NODE_COORD_SECTION )
    183 {
    184 if ( edge_weight_type != EUC_2D )
    185 {
    186 cerr << "Error. Data file contains " << EDGE_WEIGHT_TYPE << " " << edge_weight_type << " and " << NODE_COORD_SECTION << endl;
    187 return 1;
    188 }
    189 assert( num_nodes >= 0 );
    190 for (int i = 0; i < num_nodes; ++i)
    191 {
    192 int j, xi, yi;
    193 file >> j;
    194 file >> xi;
    195 file >> yi;
    196 if ( j != i+1 )
    197 {
    198 cerr << "Error reading " << NODE_COORD_SECTION << endl;
    199 return 1;
    200 }
    201 x[i] = xi; /*lint !e732 !e747*/
    202 y[i] = yi; /*lint !e732 !e747*/
    203 }
    204 for (int i = 0; i < num_nodes; ++i)
    205 {
    206 for (int j = 0; j < i; ++j)
    207 {
    208 int dx = x[i] - x[j]; /*lint !e732 !e747 !e864*/
    209 int dy = y[i] - y[j]; /*lint !e732 !e747 !e864*/
    210 dist[i][j] = int( sqrt((double)dx*dx + dy*dy) + 0.5 ); /*lint !e732 !e747 !e790*/
    211 }
    212 }
    213 }
    214 else if ( key == DEMAND_SECTION )
    215 {
    216 assert( num_nodes >= 0 );
    217 for (int i = 0; i < num_nodes; ++i)
    218 {
    219 int j, d;
    220 file >> j;
    221 file >> d;
    222 if ( j != i+1 )
    223 {
    224 cerr << "Error reading " << DEMAND_SECTION << endl;
    225 return 1;
    226 }
    227 demand[i] = d; /*lint !e732 !e747*/
    228 }
    229 }
    230 else if ( key == DEPOT_SECTION )
    231 {
    232 for (int i = 0; i != -1 ;)
    233 {
    234 file >> i;
    235 if ( i != -1 && i != 1 )
    236 {
    237 cerr << "Error: This file specifies other depots than 1." << endl;
    238 return 1;
    239 }
    240 }
    241 }
    242 else
    243 {
    244 (void) getline(file, dummy);
    245 }
    246 }
    247
    248 return 0;
    249}
    250
    251
    252//------------------------------------------------------------
    253static
    254SCIP_RETCODE execmain(int argc, char** argv)
    255{
    256 SCIP* scip = NULL;
    257
    258 cout << "Solving the vehicle routing problem using SCIP." << endl;
    259 cout << "Implemented by Andreas Bley." << endl << endl;
    260
    261 if ( argc != 2 && argc != 3 )
    262 {
    263 cerr << "Usage: vrp [-h] datafile" << endl;
    264 cerr << "Options:" << endl;
    265 cerr << " -h Uses hop limit instead of capacity limit for tours."<< endl;
    266 return SCIP_INVALIDDATA;
    267 }
    268
    269
    270 /**********************
    271 * Setup problem data *
    272 **********************/
    273
    274 const char* VRP_PRICER_NAME = "VRP_Pricer";
    275
    276 vector<vector<int> > dist;
    277 vector<int> demand;
    278 int capacity;
    279 int num_nodes;
    280
    281 if ( read_problem(argv[argc-1], num_nodes, capacity, demand, dist) )
    282 {
    283 cerr << "Error reading data file " << argv[argc-1] << endl;
    284 return SCIP_READERROR;
    285 }
    286 assert( num_nodes >= 0 );
    287 assert( capacity >= 0 );
    288
    289 cout << "Number of nodes: " << num_nodes << endl;
    290
    291 if ( argc == 3 )
    292 {
    293 if ( string("-h") != argv[1] )
    294 {
    295 cerr << "Unknow option " << argv[2] << endl;
    297 }
    298
    299 int total_demand = 0;
    300 for (int i = 1; i< num_nodes; ++i)
    301 total_demand += demand[i]; /*lint !e732 !e747*/
    302
    303 if( total_demand == 0.0 )
    304 {
    305 cerr << "Total demand is zero!" << endl;
    306 return SCIP_INVALIDDATA;
    307 }
    308
    309 capacity = (num_nodes - 1) * capacity / total_demand;
    310 demand.assign(num_nodes, 1);
    311 demand[0] = 0; /*lint !e747*/
    312 cout << "Max customers per tour: " << capacity << endl << endl;
    313 }
    314 else
    315 cout << "Max demand per tour: " << capacity << endl << endl;
    316
    317 /**************
    318 * Setup SCIP *
    319 **************/
    320
    321 /* initialize SCIP environment */
    323
    324 /***********************
    325 * Version information *
    326 ***********************/
    327
    329 SCIPinfoMessage(scip, NULL, "\n");
    330
    331 /* include default plugins */
    333
    334 /* set verbosity parameter */
    335 SCIP_CALL( SCIPsetIntParam(scip, "display/verblevel", 5) );
    336 /* SCIP_CALL( SCIPsetBoolParam(scip, "display/lpinfo", TRUE) ); */
    337
    338 /* create empty problem */
    339 SCIP_CALL( SCIPcreateProb(scip, "VRP", 0, 0, 0, 0, 0, 0, 0) );
    340
    341 /* add arc-routing variables */
    342 char var_name[255];
    343 vector< vector<SCIP_VAR*> > arc_var( num_nodes ); /*lint !e732 !e747*/
    344 for (size_t i = 0; i < (size_t)num_nodes; ++i)
    345 {
    346 arc_var[i].resize(i, (SCIP_VAR*) NULL); /*lint !e732 !e747*/
    347 for (size_t j = 0; j < i; ++j)
    348 {
    349 SCIP_VAR* var;
    350 (void) SCIPsnprintf(var_name, 255, "E%d_%d", i, j );
    351
    353 &var, // returns new index
    354 var_name, // name
    355 0.0, // lower bound
    356 2.0, // upper bound
    357 dist[i][j], // objective
    358 SCIP_VARTYPE_INTEGER, // variable type
    359 TRUE, // initial
    360 FALSE, // forget the rest ...
    361 NULL, NULL, NULL, NULL, NULL) ); /*lint !e732 !e747*/
    362 SCIP_CALL( SCIPaddVar(scip, var) );
    363 arc_var[i][j] = var; /*lint !e732 !e747*/
    364 }
    365 }
    366
    367 /* add arc-routing - tour constraints */
    368 char con_name[255];
    369 vector< vector<SCIP_CONS*> > arc_con( num_nodes ); /*lint !e732 !e747*/
    370 for (size_t i = 0; i < (size_t)num_nodes; ++i)
    371 {
    372 arc_con[i].resize(i, (SCIP_CONS*)NULL); /*lint !e732 !e747*/
    373 for (size_t j = 0; j < i; ++j)
    374 {
    375 SCIP_CONS* con;
    376 (void) SCIPsnprintf(con_name, 255, "A%d_%d", i, j);
    377 SCIP_VAR* idx = arc_var[i][j]; /*lint !e732 !e747*/
    378 SCIP_Real coeff = -1;
    379 SCIP_CALL( SCIPcreateConsLinear(scip, &con, con_name, 1, &idx, &coeff,
    380 -SCIPinfinity(scip), /* lhs */
    381 0.0, /* rhs */
    382 TRUE, /* initial */
    383 FALSE, /* separate */
    384 TRUE, /* enforce */
    385 TRUE, /* check */
    386 TRUE, /* propagate */
    387 FALSE, /* local */
    388 TRUE, /* modifiable */
    389 FALSE, /* dynamic */
    390 FALSE, /* removable */
    391 FALSE) ); /* stickingatnode */
    392 SCIP_CALL( SCIPaddCons(scip, con) );
    393 arc_con[i][j] = con; /*lint !e732 !e747*/
    394 }
    395 }
    396
    397 /* add arc-routing - degree constraints */
    398 for (size_t i = 1; i < (size_t)num_nodes; ++i)
    399 {
    400 SCIP_CONS* con;
    401 (void) SCIPsnprintf(con_name, 255, "D%d", i);
    402 SCIP_CALL( SCIPcreateConsLinear(scip, &con, con_name, 0, 0, 0,
    403 2.0, /* lhs */
    404 2.0, /* rhs */
    405 TRUE, /* initial */
    406 FALSE, /* separate */
    407 TRUE, /* enforce */
    408 TRUE, /* check */
    409 TRUE, /* propagate */
    410 FALSE, /* local */
    411 FALSE, /* modifiable */
    412 FALSE, /* dynamic */
    413 FALSE, /* removable */
    414 FALSE) ); /* stickingatnode */
    415 SCIP_CALL( SCIPaddCons(scip, con) );
    416 for (size_t j = 0; j < (size_t)num_nodes; ++j)
    417 {
    418 if ( j != i )
    419 {
    420 SCIP_CALL( SCIPaddCoefLinear(scip, con, i > j ? arc_var[i][j] : arc_var[j][i], 1.0) ); /*lint !e732 !e747*/
    421 }
    422 }
    424 }
    425
    426 /* add set packing constraints (Node 0 is the depot) */
    427 vector<SCIP_CONS*> part_con(num_nodes, (SCIP_CONS*)NULL); /*lint !e732 !e747*/
    428 for (size_t i = 1; i < (size_t)num_nodes; ++i)
    429 {
    430 SCIP_CONS* con = NULL;
    431 (void) SCIPsnprintf(con_name, 255, "C%d", i);
    432 SCIP_CALL( SCIPcreateConsLinear( scip, &con, con_name, 0, NULL, NULL,
    433 1.0, /* lhs */
    434 SCIPinfinity(scip), /* rhs */
    435 TRUE, /* initial */
    436 FALSE, /* separate */
    437 TRUE, /* enforce */
    438 TRUE, /* check */
    439 TRUE, /* propagate */
    440 FALSE, /* local */
    441 TRUE, /* modifiable */
    442 FALSE, /* dynamic */
    443 FALSE, /* removable */
    444 FALSE /* stickingatnode */ ) );
    445 SCIP_CALL( SCIPaddCons(scip, con) );
    446 part_con[i] = con; /*lint !e732 !e747*/
    447 }
    448
    449 /* include VRP pricer */
    450 ObjPricerVRP* vrp_pricer_ptr = new ObjPricerVRP(scip, VRP_PRICER_NAME, num_nodes, capacity, demand, dist,
    451 arc_var, arc_con, part_con);
    452
    453 SCIP_CALL( SCIPincludeObjPricer(scip, vrp_pricer_ptr, TRUE) );
    454
    455 /* activate pricer */
    456 SCIP_CALL( SCIPactivatePricer(scip, SCIPfindPricer(scip, VRP_PRICER_NAME)) );
    457
    458 // SCIP_CALL( SCIPwriteOrigProblem(scip, "vrp_init.lp", "lp", FALSE) );
    459
    460
    461 /*************
    462 * Solve *
    463 *************/
    464
    466
    467
    468 /**************
    469 * Statistics *
    470 *************/
    472
    474
    475
    476
    477 /********************
    478 * Deinitialization *
    479 ********************/
    480
    481 /* release variables */
    482 for (size_t i = 0; i < (size_t)num_nodes; ++i)
    483 {
    484 if ( i > 0 )
    485 {
    486 SCIP_CALL( SCIPreleaseCons(scip, &part_con[i]) );
    487 }
    488 for (size_t j = 0; j < i; ++j)
    489 {
    490 SCIP_CALL( SCIPreleaseVar(scip, &arc_var[i][j]) );
    491 SCIP_CALL( SCIPreleaseCons(scip, &arc_con[i][j]) );
    492 }
    493 }
    494
    495
    497
    499
    500 return SCIP_OKAY;
    501}
    502
    503int main(int argc, char** argv)
    504{
    505 return execmain(argc, argv) != SCIP_OKAY ? 1 : 0;
    506}
    SCIP_VAR ** y
    Definition: circlepacking.c:64
    SCIP_VAR ** x
    Definition: circlepacking.c:63
    #define NULL
    Definition: def.h:248
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_CALL(x)
    Definition: def.h:355
    SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
    SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, 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)
    SCIP_RETCODE SCIPfree(SCIP **scip)
    Definition: scip_general.c:402
    SCIP_RETCODE SCIPcreate(SCIP **scip)
    Definition: scip_general.c:370
    SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_prob.c:1907
    SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
    Definition: scip_prob.c:3274
    SCIP_RETCODE SCIPcreateProb(SCIP *scip, const char *name, SCIP_DECL_PROBDELORIG((*probdelorig)), SCIP_DECL_PROBTRANS((*probtrans)), SCIP_DECL_PROBDELTRANS((*probdeltrans)), SCIP_DECL_PROBINITSOL((*probinitsol)), SCIP_DECL_PROBEXITSOL((*probexitsol)), SCIP_DECL_PROBCOPY((*probcopy)), SCIP_PROBDATA *probdata)
    Definition: scip_prob.c:119
    void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:208
    void SCIPprintVersion(SCIP *scip, FILE *file)
    Definition: scip_general.c:169
    SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
    Definition: scip_param.c:487
    SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
    Definition: scip_cons.c:1173
    SCIP_PRICER * SCIPfindPricer(SCIP *scip, const char *name)
    Definition: scip_pricer.c:311
    SCIP_RETCODE SCIPactivatePricer(SCIP *scip, SCIP_PRICER *pricer)
    Definition: scip_pricer.c:384
    SCIP_RETCODE SCIPprintBestSol(SCIP *scip, FILE *file, SCIP_Bool printzeros)
    Definition: scip_sol.c:3047
    SCIP_RETCODE SCIPsolve(SCIP *scip)
    Definition: scip_solve.c:2635
    SCIP_RETCODE SCIPprintStatistics(SCIP *scip, FILE *file)
    SCIP_Real SCIPinfinity(SCIP *scip)
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
    Definition: scip_var.c:120
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    int main(int argc, char **argv)
    Definition: main_vrp.cpp:503
    static SCIP_RETCODE execmain(int argc, char **argv)
    Definition: main_vrp.cpp:254
    static int read_problem(const char *filename, int &num_nodes, int &capacity, vector< int > &demand, vector< vector< int > > &dist)
    Definition: main_vrp.cpp:77
    #define BMScheckEmptyMemory()
    Definition: memory.h:155
    Definition: pqueue.h:38
    SCIP_RETCODE SCIPincludeObjPricer(SCIP *scip, scip::ObjPricer *objpricer, SCIP_Bool deleteobject)
    Definition: objpricer.cpp:221
    C++ wrapper classes for SCIP.
    C++ wrapper for default SCIP plugins.
    VRP pricer plugin.
    SCIP_RETCODE SCIPincludeDefaultPlugins(SCIP *scip)
    @ SCIP_READERROR
    Definition: type_retcode.h:45
    @ SCIP_INVALIDDATA
    Definition: type_retcode.h:52
    @ SCIP_PARAMETERUNKNOWN
    Definition: type_retcode.h:55
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    @ SCIP_VARTYPE_INTEGER
    Definition: type_var.h:65