OR-Tools  9.6
nearp_parser.h
Go to the documentation of this file.
1 // Copyright 2010-2022 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_NEARP_PARSER_H_
76 #define OR_TOOLS_ROUTING_NEARP_PARSER_H_
77 
78 #include <algorithm>
79 #include <string>
80 #include <string_view>
81 #include <vector>
82 
84 #include "ortools/base/logging.h"
86 
87 namespace operations_research {
88 class NearpParser {
89  public:
90  NearpParser();
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.
135  }
136  // Returns the number of edges in the current routing problem that do not
137  // require servicing.
140  }
141  // Returns the number of nodes in the current routing problem that do not
142  // require servicing.
145  }
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_NEARP_PARSER_H_
std::string GetArcName(int64_t tail, int64_t head) const
Definition: nearp_parser.h:185
const gtl::linked_hash_map< int64_t, int64_t > & node_servicing_costs() const
Definition: nearp_parser.h:169
const gtl::linked_hash_map< Edge, int64_t > & edge_servicing_demands() const
Definition: nearp_parser.h:152
const NearpParser & operator=(const NearpParser &)=delete
std::string GetArcName(Arc arc) const
std::string GetEdgeName(Edge edge) const
int64_t NumberOfNodesWithoutServicing() const
Definition: nearp_parser.h:143
bool LoadFile(const std::string &file_name)
Definition: nearp_parser.cc:52
const gtl::linked_hash_map< Arc, int64_t > & arc_servicing_costs() const
Definition: nearp_parser.h:161
const gtl::linked_hash_map< int64_t, int64_t > & node_servicing_demands() const
Definition: nearp_parser.h:156
NearpParser(const NearpParser &)=delete
std::string GetEdgeName(int64_t tail, int64_t head) const
Definition: nearp_parser.h:189
const gtl::linked_hash_map< Edge, int64_t > & edge_traversing_costs() const
Definition: nearp_parser.h:178
const gtl::linked_hash_map< Arc, int64_t > & arc_servicing_demands() const
Definition: nearp_parser.h:148
const gtl::linked_hash_map< Arc, int64_t > & arc_traversing_costs() const
Definition: nearp_parser.h:174
std::string GetNodeName(int64_t node) const
Definition: nearp_parser.h:192
const std::string & name() const
Definition: nearp_parser.h:101
const std::string & comment() const
Definition: nearp_parser.h:103
const gtl::linked_hash_map< Edge, int64_t > & edge_servicing_costs() const
Definition: nearp_parser.h:165
int arc
Collection of objects used to extend the Constraint Solver library.
int line
Definition: parse_proto.cc:31
int64_t tail
int64_t head