Google OR-Tools v9.12
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-2025 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
83#include "absl/strings/string_view.h"
87
90 public:
92
93#ifndef SWIG
94 NearpParser(const NearpParser&) = delete;
95 const NearpParser& operator=(const NearpParser&) = delete;
96#endif
97
98 // Loads instance from a file into this parser object.
99 bool LoadFile(absl::string_view file_name);
100
101 // Returns the name of the instance being solved.
102 const std::string& name() const { return name_; }
103 // Returns the comment of the instance being solved, typically an upper bound.
104 const std::string& comment() const { return comment_; }
105 // Returns the index of the depot.
106 int64_t depot() const { return depot_; }
107
108 // Returns the maximum number of vehicles to use.
109 int NumberOfVehicles() const { return num_vehicles_; }
110 // Returns the capacity of the vehicles.
111 int64_t capacity() const { return capacity_; }
112
113 // Returns the number of nodes in the current routing problem.
114 int NumberOfNodes() const { return num_nodes_; }
115 // Returns the number of arc in the current routing problem, with or
116 // without servicing required.
117 int NumberOfArcs() const { return num_arcs_; }
118 // Returns the number of edges in the current routing problem, with or
119 // without servicing required.
120 int NumberOfEdges() const { return num_edges_; }
121
122 // Returns the number of arcs in the current routing problem that require
123 // servicing.
124 int NumberOfArcsWithServicing() const { return num_arcs_with_servicing_; }
125 // Returns the number of edges in the current routing problem that require
126 // servicing.
127 int NumberOfEdgesWithServicing() const { return num_edges_with_servicing_; }
128 // Returns the number of nodes in the current routing problem that require
129 // servicing.
130 int NumberOfNodesWithServicing() const { return num_nodes_with_servicing_; }
131
132 // Returns the number of arcs in the current routing problem that do not
133 // require servicing.
137 // Returns the number of edges in the current routing problem that do not
138 // require servicing.
142 // Returns the number of nodes in the current routing problem that do not
143 // require servicing.
147
148 // Returns the servicing demands of the arcs in the current routing problem.
150 return arc_servicing_demands_;
151 }
152 // Returns the servicing demands of the edges in the current routing problem.
154 return edge_servicing_demands_;
155 }
156 // Returns the servicing demands of the nodes in the current routing problem.
158 return node_servicing_demands_;
159 }
160
161 // Returns the servicing costs of the arcs in the current routing problem.
163 return arc_servicing_costs_;
164 }
165 // Returns the servicing costs of the edges in the current routing problem.
167 return edge_servicing_costs_;
168 }
169 // Returns the servicing costs of the nodes in the current routing problem.
171 return node_servicing_costs_;
172 }
173
174 // Returns the traversing costs of the arcs in the current routing problem.
176 return arc_traversing_costs_;
177 }
178 // Returns the traversing costs of the edges in the current routing problem.
180 return edge_traversing_costs_;
181 }
182
183 // Returns the name of graph objects. The implementations should fit all
184 // instances of NEARP files,
185 std::string GetArcName(Arc arc) const;
186 std::string GetArcName(int64_t tail, int64_t head) const {
187 return GetArcName({tail, head});
188 }
189 std::string GetEdgeName(Edge edge) const;
190 std::string GetEdgeName(int64_t tail, int64_t head) const {
191 return GetEdgeName({tail, head});
192 }
193 std::string GetNodeName(int64_t node) const {
194 CHECK_GE(node, 0);
195 CHECK_LT(node, NumberOfNodes());
196 return absl::StrCat("N", node + 1);
197 }
198
199 private:
200 // Parsing.
201 enum Section {
202 METADATA,
203 ARCS_WITH_SERVICING,
204 ARCS_WITHOUT_SERVICING,
205 EDGES_WITH_SERVICING,
206 EDGES_WITHOUT_SERVICING,
207 NODES_WITH_SERVICING,
208 // No need for a state to parse nodes without servicing demands: they do
209 // not have any data associated with them (their number is known in the
210 // header of the data file).
211 UNDEFINED_SECTION
212 };
213
214 void Initialize();
215 bool ParseFile(absl::string_view file_name);
216 bool ParseMetadataLine(const std::vector<std::string>& words);
217 bool ParseArc(std::string_view line, bool with_servicing);
218 bool ParseEdge(std::string_view line, bool with_servicing);
219 bool ParseNode(std::string_view line);
220
221 // Parsing data.
222 Section section_;
223
224 // Instance data:
225 // - metadata
226 std::string name_;
227 std::string comment_;
228 int num_arcs_;
229 int num_edges_;
230 int num_nodes_;
231 int num_arcs_with_servicing_;
232 int num_edges_with_servicing_;
233 int num_nodes_with_servicing_;
234 int64_t depot_;
235
236 // - graph costs and servicing demands. Keep track of the order of the
237 // demands: the output format requires to use the servicing-demands IDs,
238 // which are indices when iterating through these maps.
239 // Specifically, for nodes, a vector is not suitable, as indices are not
240 // necessarily contiguous.
241 gtl::linked_hash_map<Arc, int64_t> arc_traversing_costs_;
242 gtl::linked_hash_map<Edge, int64_t> edge_traversing_costs_;
243
244 gtl::linked_hash_map<Arc, int64_t> arc_servicing_demands_;
245 gtl::linked_hash_map<Edge, int64_t> edge_servicing_demands_;
246 gtl::linked_hash_map<int64_t, int64_t> node_servicing_demands_;
247
248 gtl::linked_hash_map<Arc, int64_t> arc_servicing_costs_;
249 gtl::linked_hash_map<Edge, int64_t> edge_servicing_costs_;
250 gtl::linked_hash_map<int64_t, int64_t> node_servicing_costs_;
251
252 // - vehicles
253 int num_vehicles_;
254 int64_t capacity_;
255};
256} // namespace operations_research::routing
257
258#endif // OR_TOOLS_ROUTING_PARSERS_NEARP_PARSER_H_
const gtl::linked_hash_map< Arc, int64_t > & arc_traversing_costs() const
Returns the traversing costs of the arcs in the current routing problem.
int64_t depot() const
Returns the index of the depot.
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< Arc, int64_t > & arc_servicing_costs() const
Returns the servicing costs of the arcs in the current routing problem.
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 GetEdgeName(Edge edge) const
const std::string & name() const
Returns the name of the instance being solved.
const std::string & comment() const
Returns the comment of the instance being solved, typically an upper bound.
std::string GetArcName(int64_t tail, int64_t head) const
bool LoadFile(absl::string_view file_name)
Loads instance from a file into this parser object.
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 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 GetNodeName(int64_t node) const
const gtl::linked_hash_map< Edge, int64_t > & edge_servicing_demands() const
Returns the servicing demands of the edges in the current routing problem.
std::string GetEdgeName(int64_t tail, int64_t head) const
std::string GetArcName(Arc arc) 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.
int NumberOfVehicles() const
Returns the maximum number of vehicles to use.
int NumberOfNodes() const
Returns the number of nodes in the current routing problem.
int64_t capacity() const
Returns the capacity of the vehicles.
const NearpParser & operator=(const NearpParser &)=delete
NearpParser(const NearpParser &)=delete
Common utilities for parsing routing instances.