Google OR-Tools v9.15
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 ORTOOLS_ROUTING_PARSERS_NEARP_PARSER_H_
76#define ORTOOLS_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 // ORTOOLS_ROUTING_PARSERS_NEARP_PARSER_H_
const gtl::linked_hash_map< Arc, int64_t > & arc_traversing_costs() const
const gtl::linked_hash_map< int64_t, int64_t > & node_servicing_costs() const
const gtl::linked_hash_map< Arc, int64_t > & arc_servicing_costs() const
const gtl::linked_hash_map< Edge, int64_t > & edge_servicing_costs() const
std::string GetEdgeName(Edge edge) const
const std::string & comment() const
std::string GetArcName(int64_t tail, int64_t head) const
bool LoadFile(absl::string_view file_name)
const gtl::linked_hash_map< Edge, int64_t > & edge_traversing_costs() const
const gtl::linked_hash_map< int64_t, int64_t > & node_servicing_demands() const
std::string GetNodeName(int64_t node) const
const gtl::linked_hash_map< Edge, int64_t > & edge_servicing_demands() const
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
const NearpParser & operator=(const NearpParser &)=delete
NearpParser(const NearpParser &)=delete