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