Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
carp_parser.h
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14// A parser for CARPLIB instances. The base files are available online, as well
15// as a description of the (Spanish-based) format:
16// https://www.uv.es/belengue/carp.html ("CARPLIB")
17// https://www.uv.es/~belengue/carp/READ_ME
18//
19// The goal is to find routes starting and ending at a depot which visit a
20// set of arcs (whereas a VRP visits nodes). The objective is to minimize the
21// total cost, which is due to either servicing an edge (i.e. performing the
22// required action) or traversing an edge (to get to another point in space).
23// Not all arcs/edges in the graph must be serviced.
24//
25// By this formulation, the total cost of servicing is known in advance.
26// All vehicles start at the same node, the depot, having index 1.
27// Servicing an edge requires resources, vehicles have a limited capacity. All
28// vehicles have the same capacity.
29//
30// The format of the data is the following:
31//
32// NOMBRE : <INSTANCE-NAME>
33// COMENTARIO : <ARBITRARY-COMMENT>
34// VERTICES : <NUMBER-OF-NODES, int>
35// ARISTAS_REQ : <NUMBER-OF-EDGES-WITH-NONZERO-SERVICING, int>
36// ARISTAS_NOREQ : <NUMBER-OF-EDGES-WITH-ZERO-SERVICING, int>
37// VEHICULOS : <NUMBER-OF-VEHICLES, int>
38// CAPACIDAD : <CAPACITY-OF-EACH-VEHICLE, int>
39// TIPO_COSTES_ARISTAS : EXPLICITOS
40// COSTE_TOTAL_REQ : <TOTAL-SERVICING-COST>
41// LISTA_ARISTAS_REQ :
42// ( <HEAD-NODE-OF-EDGE, int>, <TAIL-NODE-OF-EDGE, int> )
43// coste <TRAVERSING-COST, int> demanda <SERVICING, int>
44// <repeated, one edge per line>
45// LISTA_ARISTAS_NOREQ :
46// ( <HEAD-NODE-OF-EDGE, int>, <TAIL-NODE-OF-EDGE, int> )
47// coste <TRAVERSING-COST, int>
48// <repeated, one edge per line>
49// DEPOSITO : 1
50//
51// While the file format is defined with 1-based indexing, the output of the
52// parser is always 0-based. Users of this parser should never see any 1-based
53// index; only 0-based index should be used to query values.
54
55#ifndef OR_TOOLS_ROUTING_PARSERS_CARP_PARSER_H_
56#define OR_TOOLS_ROUTING_PARSERS_CARP_PARSER_H_
57
58#include <algorithm>
59#include <string>
60#include <string_view>
61#include <vector>
62
63#include "absl/types/span.h"
67
68namespace operations_research {
70 public:
71 CarpParser();
72
73#ifndef SWIG
74 CarpParser(const CarpParser&) = delete;
75 const CarpParser& operator=(const CarpParser&) = delete;
76#endif
77
78 // Loads instance from a file into this parser object.
79 bool LoadFile(const std::string& file_name);
80
81 // Returns the name of the instance being solved.
82 const std::string& name() const { return name_; }
83 // Returns the comment of the instance being solved, typically an upper bound.
84 const std::string& comment() const { return comment_; }
85 // Returns the index of the depot.
86 int64_t depot() const { return depot_; }
87 // Returns the number of nodes in the current routing problem.
88 int64_t NumberOfNodes() const { return number_of_nodes_; }
89 // Returns the number of edges in the current routing problem, with or
90 // without servicing required.
94 // Returns the number of edges in the current routing problem that require
95 // servicing.
97 return number_of_edges_with_servicing_;
98 }
99 // Returns the number of edges in the current routing problem that do not
100 // require servicing.
102 return number_of_edges_without_servicing_;
103 }
104 // Returns the total servicing cost for all arcs.
105 int64_t TotalServicingCost() const { return total_servicing_cost_; }
106 // Returns the servicing of the edges in the current routing problem.
108 return servicing_demands_;
109 }
110 // Returns the traversing costs of the edges in the current routing problem.
112 return traversing_costs_;
113 }
114 // Returns the maximum number of vehicles to use.
115 int64_t NumberOfVehicles() const { return n_vehicles_; }
116 // Returns the capacity of the vehicles.
117 int64_t capacity() const { return capacity_; }
118
119 // Returns the traversing cost for an edge. All edges are supposed to have
120 // a traversing cost.
121 int64_t GetTraversingCost(Edge edge) const {
122 CHECK(traversing_costs_.contains(edge))
123 << "Unknown edge: " << edge.tail() << " - " << edge.head();
124 return traversing_costs_.at(edge);
125 }
126 int64_t GetTraversingCost(int64_t tail, int64_t head) const {
127 return GetTraversingCost({tail, head});
128 }
129
130 // Checks whether this edge requires servicing.
131 int64_t HasServicingNeed(Edge edge) const {
132 return servicing_demands_.contains(edge);
133 }
134 int64_t HasServicingNeed(int64_t tail, int64_t head) const {
135 return HasServicingNeed({tail, head});
136 }
137
138 // Returns the servicing for an edge. Only a subset of edges have a servicing
139 // need.
140 int64_t GetServicing(Edge edge) const {
141 CHECK(HasServicingNeed(edge))
142 << "Unknown edge: " << edge.tail() << " - " << edge.head();
143 return servicing_demands_.at(edge);
144 }
145 int64_t GetServicing(int64_t tail, int64_t head) const {
146 return GetServicing({tail, head});
147 }
148
149 private:
150 // Parsing.
151 enum Section {
152 METADATA,
153 ARCS_WITH_SERVICING,
154 ARCS_WITHOUT_SERVICING,
155 UNDEFINED_SECTION
156 };
157
158 void Initialize();
159 bool ParseFile(const std::string& file_name);
160 bool ParseMetadataLine(absl::Span<const std::string> words);
161 bool ParseEdge(std::string_view line, bool with_servicing);
162
163 // Parsing data.
164 Section section_;
165
166 // Instance data:
167 // - metadata
168 std::string name_;
169 std::string comment_;
170 int64_t number_of_nodes_;
171 int64_t number_of_edges_with_servicing_;
172 int64_t number_of_edges_without_servicing_;
173 int64_t total_servicing_cost_;
174 int64_t depot_;
175 // - graph costs and servicing demands. Keep track of the order of the
176 // demands: the output format requires to use the servicing-demands IDs,
177 // which are indices when iterating over this map.
178 gtl::linked_hash_map<Edge, int64_t> traversing_costs_;
179 gtl::linked_hash_map<Edge, int64_t> servicing_demands_;
180 // - vehicles
181 int64_t n_vehicles_;
182 int64_t capacity_;
183};
184} // namespace operations_research
185
186#endif // OR_TOOLS_ROUTING_PARSERS_CARP_PARSER_H_
bool LoadFile(const std::string &file_name)
Loads instance from a file into this parser object.
int64_t GetServicing(Edge edge) const
int64_t NumberOfVehicles() const
Returns the maximum number of vehicles to use.
int64_t GetTraversingCost(Edge edge) const
int64_t NumberOfEdgesWithServicing() const
Definition carp_parser.h:96
int64_t capacity() const
Returns the capacity of the vehicles.
const CarpParser & operator=(const CarpParser &)=delete
const std::string & name() const
Returns the name of the instance being solved.
Definition carp_parser.h:82
int64_t GetServicing(int64_t tail, int64_t head) const
int64_t depot() const
Returns the index of the depot.
Definition carp_parser.h:86
int64_t TotalServicingCost() const
Returns the total servicing cost for all arcs.
const std::string & comment() const
Returns the comment of the instance being solved, typically an upper bound.
Definition carp_parser.h:84
const gtl::linked_hash_map< Edge, int64_t > & traversing_costs() const
Returns the traversing costs of the edges in the current routing problem.
int64_t NumberOfNodes() const
Returns the number of nodes in the current routing problem.
Definition carp_parser.h:88
int64_t HasServicingNeed(Edge edge) const
Checks whether this edge requires servicing.
int64_t GetTraversingCost(int64_t tail, int64_t head) const
int64_t HasServicingNeed(int64_t tail, int64_t head) const
CarpParser(const CarpParser &)=delete
int64_t NumberOfEdgesWithoutServicing() const
const gtl::linked_hash_map< Edge, int64_t > & servicing_demands() const
Returns the servicing of the edges in the current routing problem.
Edge edge
In SWIG mode, we don't want anything besides these top-level includes.
int line
int head
int tail