Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
nearp_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 NEARPLIB instances. The base files are available online, as well
15// as a description of the format:
16// https://www.sintef.no/projectweb/top/nearp/documentation/
17//
18// The goal is to find routes starting and ending at a depot which visit a
19// set of arcs (directed), edges (undirected), and nodes, whereas a VRP only
20// visits nodes. The objective is to minimize the total cost, which is due to
21// either servicing a part of the graph (i.e. performing the required action)
22// or traversing an edge (to get to another point in space). Not all arcs/edges
23// in the graph must be serviced. These components are summarized in NEARP:
24// node-edge-arc routing problem. The problem is sometimes also called MCGRP:
25// mixed capacitated generalized routing problem.
26//
27// All vehicles start at the same node, the depot. Its index is often 1, but
28// many instances have another depot.
29// Servicing a part of the graph requires resources, vehicles have a limited
30// capacity. All vehicles have the same capacity.
31//
32// The format of the data is the following (from
33// https://www.sintef.no/projectweb/top/nearp/documentation/):
34//
35// Name: <Instance name>
36// Optimal value: <Optimal value, -1 if unknown>
37// #Vehicles: <Max. number of vehicles, -1 if unconstrained>
38// Capacity: <Vehicle capacity Q>
39// Depot: <Index of depot node>
40// #Nodes: <number of nodes>
41// #Edges: <number of edges>
42// #Arcs: <number of arcs>
43// #Required N: <number of required nodes>
44// #Required E: <number of required edges>
45// #Required A: <number of required arcs>
46//
47// % Required nodes: Ni q_i s_i
48// NODE INDEX, DEMAND, SERVICE COST
49//
50// % Required edges: Ek i j q_ij c_ij s_ij
51// EDGE INDEX, FROM NODE, TO NODE, TRAVERSAL COST, DEMAND, SERVICE COST
52//
53// % Non-required edges: NrEl i j c_ij
54// EDGE INDEX, FROM NODE, TO NODE, TRAVERSAL COST
55//
56// % Required arcs: Ar i j q_ij c_ij
57// ARC INDEX, FROM NODE, TO NODE, TRAVERSAL COST, DEMAND, SERVICE COST
58//
59// % Non-required arcs: NrAs i j c_ij
60// ARC INDEX, FROM NODE, TO NODE, TRAVERSAL COST
61//
62// For nodes, the index is of the form NX, where X is the node index (for
63// instance, N1 is the first node that requires servicing). The elements of
64// each section are not necessarily sorted. Nodes are indexed together, with no
65// separation between those that require servicing and those that do not,
66// from 1 to the number of nodes. Conversely, arcs and edges have separate
67// indexing depending on whether they require indexing: E1 to EM all require
68// servicing, NrE1 to NrEN do not, for a total of M + N edges (respectively,
69// for arcs, A1 to AK and NrA1 to NrAL for K + L arcs).
70//
71// While the file format is defined with 1-based indexing, the output of the
72// parser is always 0-based. Users of this parser should never see any 1-based
73// index; only 0-based index should be used to query values.
74
75#ifndef OR_TOOLS_ROUTING_PARSERS_NEARP_PARSER_H_
76#define OR_TOOLS_ROUTING_PARSERS_NEARP_PARSER_H_
77
78#include <algorithm>
79#include <string>
80#include <string_view>
81#include <vector>
82
86
87namespace operations_research {
89 public:
91
92#ifndef SWIG
93 NearpParser(const NearpParser&) = delete;
94 const NearpParser& operator=(const NearpParser&) = delete;
95#endif
96
97 // Loads instance from a file into this parser object.
98 bool LoadFile(const std::string& file_name);
99
100 // Returns the name of the instance being solved.
101 const std::string& name() const { return name_; }
102 // Returns the comment of the instance being solved, typically an upper bound.
103 const std::string& comment() const { return comment_; }
104 // Returns the index of the depot.
105 int64_t depot() const { return depot_; }
106
107 // Returns the maximum number of vehicles to use.
108 int NumberOfVehicles() const { return num_vehicles_; }
109 // Returns the capacity of the vehicles.
110 int64_t capacity() const { return capacity_; }
111
112 // Returns the number of nodes in the current routing problem.
113 int NumberOfNodes() const { return num_nodes_; }
114 // Returns the number of arc in the current routing problem, with or
115 // without servicing required.
116 int NumberOfArcs() const { return num_arcs_; }
117 // Returns the number of edges in the current routing problem, with or
118 // without servicing required.
119 int NumberOfEdges() const { return num_edges_; }
120
121 // Returns the number of arcs in the current routing problem that require
122 // servicing.
123 int NumberOfArcsWithServicing() const { return num_arcs_with_servicing_; }
124 // Returns the number of edges in the current routing problem that require
125 // servicing.
126 int NumberOfEdgesWithServicing() const { return num_edges_with_servicing_; }
127 // Returns the number of nodes in the current routing problem that require
128 // servicing.
129 int NumberOfNodesWithServicing() const { return num_nodes_with_servicing_; }
130
131 // Returns the number of arcs in the current routing problem that do not
132 // require servicing.
136 // Returns the number of edges in the current routing problem that do not
137 // require servicing.
141 // Returns the number of nodes in the current routing problem that do not
142 // require servicing.
146
147 // Returns the servicing demands of the arcs in the current routing problem.
149 return arc_servicing_demands_;
150 }
151 // Returns the servicing demands of the edges in the current routing problem.
153 return edge_servicing_demands_;
154 }
155 // Returns the servicing demands of the nodes in the current routing problem.
157 return node_servicing_demands_;
158 }
159
160 // Returns the servicing costs of the arcs in the current routing problem.
162 return arc_servicing_costs_;
163 }
164 // Returns the servicing costs of the edges in the current routing problem.
166 return edge_servicing_costs_;
167 }
168 // Returns the servicing costs of the nodes in the current routing problem.
170 return node_servicing_costs_;
171 }
172
173 // Returns the traversing costs of the arcs in the current routing problem.
175 return arc_traversing_costs_;
176 }
177 // Returns the traversing costs of the edges in the current routing problem.
179 return edge_traversing_costs_;
180 }
181
182 // Returns the name of graph objects. The implementations should fit all
183 // instances of NEARP files,
184 std::string GetArcName(Arc arc) const;
185 std::string GetArcName(int64_t tail, int64_t head) const {
186 return GetArcName({tail, head});
187 }
188 std::string GetEdgeName(Edge edge) const;
189 std::string GetEdgeName(int64_t tail, int64_t head) const {
190 return GetEdgeName({tail, head});
191 }
192 std::string GetNodeName(int64_t node) const {
193 CHECK_GE(node, 0);
194 CHECK_LT(node, NumberOfNodes());
195 return absl::StrCat("N", node + 1);
196 }
197
198 private:
199 // Parsing.
200 enum Section {
201 METADATA,
202 ARCS_WITH_SERVICING,
203 ARCS_WITHOUT_SERVICING,
204 EDGES_WITH_SERVICING,
205 EDGES_WITHOUT_SERVICING,
206 NODES_WITH_SERVICING,
207 // No need for a state to parse nodes without servicing demands: they do
208 // not have any data associated with them (their number is known in the
209 // header of the data file).
210 UNDEFINED_SECTION
211 };
212
213 void Initialize();
214 bool ParseFile(const std::string& file_name);
215 bool ParseMetadataLine(const std::vector<std::string>& words);
216 bool ParseArc(std::string_view line, bool with_servicing);
217 bool ParseEdge(std::string_view line, bool with_servicing);
218 bool ParseNode(std::string_view line);
219
220 // Parsing data.
221 Section section_;
222
223 // Instance data:
224 // - metadata
225 std::string name_;
226 std::string comment_;
227 int num_arcs_;
228 int num_edges_;
229 int num_nodes_;
230 int num_arcs_with_servicing_;
231 int num_edges_with_servicing_;
232 int num_nodes_with_servicing_;
233 int64_t depot_;
234
235 // - graph costs and servicing demands. Keep track of the order of the
236 // demands: the output format requires to use the servicing-demands IDs,
237 // which are indices when iterating through these maps.
238 // Specifically, for nodes, a vector is not suitable, as indices are not
239 // necessarily contiguous.
240 gtl::linked_hash_map<Arc, int64_t> arc_traversing_costs_;
241 gtl::linked_hash_map<Edge, int64_t> edge_traversing_costs_;
242
243 gtl::linked_hash_map<Arc, int64_t> arc_servicing_demands_;
244 gtl::linked_hash_map<Edge, int64_t> edge_servicing_demands_;
245 gtl::linked_hash_map<int64_t, int64_t> node_servicing_demands_;
246
247 gtl::linked_hash_map<Arc, int64_t> arc_servicing_costs_;
248 gtl::linked_hash_map<Edge, int64_t> edge_servicing_costs_;
249 gtl::linked_hash_map<int64_t, int64_t> node_servicing_costs_;
250
251 // - vehicles
252 int num_vehicles_;
253 int64_t capacity_;
254};
255} // namespace operations_research
256
257#endif // OR_TOOLS_ROUTING_PARSERS_NEARP_PARSER_H_
bool LoadFile(const std::string &file_name)
Loads instance from a file into this parser object.
int NumberOfVehicles() const
Returns the maximum number of vehicles to use.
const gtl::linked_hash_map< int64_t, int64_t > & node_servicing_demands() const
Returns the servicing demands of the nodes in the current routing problem.
std::string GetEdgeName(Edge edge) const
std::string GetEdgeName(int64_t tail, int64_t head) const
int NumberOfNodes() const
Returns the number of nodes in the current routing problem.
std::string GetArcName(Arc arc) const
int64_t depot() const
Returns the index of the depot.
const std::string & comment() const
Returns the comment of the instance being solved, typically an upper bound.
const gtl::linked_hash_map< Edge, int64_t > & edge_servicing_costs() const
Returns the servicing costs of the edges in the current routing problem.
std::string GetNodeName(int64_t node) const
const gtl::linked_hash_map< Arc, int64_t > & arc_servicing_demands() const
Returns the servicing demands of the arcs in the current routing problem.
const NearpParser & operator=(const NearpParser &)=delete
int64_t NumberOfNodesWithoutServicing() const
NearpParser(const NearpParser &)=delete
const gtl::linked_hash_map< int64_t, int64_t > & node_servicing_costs() const
Returns the servicing costs of the nodes in the current routing problem.
const gtl::linked_hash_map< Edge, int64_t > & edge_servicing_demands() const
Returns the servicing demands of the edges in the current routing problem.
int64_t capacity() const
Returns the capacity of the vehicles.
const gtl::linked_hash_map< Edge, int64_t > & edge_traversing_costs() const
Returns the traversing costs of the edges in the current routing problem.
const std::string & name() const
Returns the name of the instance being solved.
const gtl::linked_hash_map< Arc, int64_t > & arc_traversing_costs() const
Returns the traversing costs of the arcs in the current routing problem.
const gtl::linked_hash_map< Arc, int64_t > & arc_servicing_costs() const
Returns the servicing costs of the arcs in the current routing problem.
std::string GetArcName(int64_t tail, int64_t head) const
Edge edge
int arc
In SWIG mode, we don't want anything besides these top-level includes.
int line
int head
int tail