23#include "absl/strings/str_join.h"
24#include "absl/strings/str_split.h"
25#include "absl/strings/string_view.h"
33void NearpParser::Initialize() {
39 num_arcs_with_servicing_ = 0;
40 num_edges_with_servicing_ = 0;
41 num_nodes_with_servicing_ = 0;
43 arc_traversing_costs_.clear();
44 edge_traversing_costs_.clear();
45 arc_servicing_demands_.clear();
46 edge_servicing_demands_.clear();
47 node_servicing_demands_.
clear();
55 return ParseFile(file_name);
58bool NearpParser::ParseFile(absl::string_view file_name) {
62 static auto section_headers = std::array<const char*, 14>({
79 for (
const std::string& line :
81 const std::vector<std::string> words =
82 absl::StrSplit(line, absl::ByAnyChar(
" :\t"), absl::SkipEmpty());
84 if (words.empty())
continue;
86 if (absl::c_linear_search(section_headers, words[0])) {
88 if (words[0] ==
"ReN.") {
90 section_ = NODES_WITH_SERVICING;
91 }
else if (words[0] ==
"ReE.") {
94 section_ = EDGES_WITH_SERVICING;
95 }
else if (words[0] ==
"EDGE") {
97 section_ = EDGES_WITHOUT_SERVICING;
98 }
else if (words[0] ==
"ReA.") {
101 section_ = ARCS_WITH_SERVICING;
102 }
else if (words[0] ==
"ARC") {
104 section_ = ARCS_WITHOUT_SERVICING;
106 if (!ParseMetadataLine(words)) {
107 LOG(ERROR) <<
"Error when parsing a metadata line: " << line;
118 case NODES_WITH_SERVICING:
122 case EDGES_WITH_SERVICING:
126 case EDGES_WITHOUT_SERVICING:
132 if (edge_traversing_costs_.size() ==
NumberOfEdges())
continue;
134 case ARCS_WITH_SERVICING:
138 case ARCS_WITHOUT_SERVICING:
144 if (arc_traversing_costs_.size() ==
NumberOfArcs())
continue;
152 case NODES_WITH_SERVICING:
153 if (!ParseNode(line)) {
154 LOG(ERROR) <<
"Could not parse line in required nodes: " << line;
158 case EDGES_WITH_SERVICING:
159 if (!ParseEdge(line,
true)) {
160 LOG(ERROR) <<
"Could not parse line in required edges: " << line;
164 case EDGES_WITHOUT_SERVICING:
165 if (!ParseEdge(line,
false)) {
166 LOG(ERROR) <<
"Could not parse line in edges: " << line;
170 case ARCS_WITH_SERVICING:
171 if (!ParseArc(line,
true)) {
172 LOG(ERROR) <<
"Could not parse line in required arcs: " << line;
176 case ARCS_WITHOUT_SERVICING:
177 if (!ParseArc(line,
false)) {
178 LOG(ERROR) <<
"Could not parse line in arcs: " << line;
183 LOG(ERROR) <<
"Could not parse line outside node-edge-arc lists: "
190 return section_ != METADATA;
194std::optional<int64_t> ParseNodeIndex(std::string_view text);
199 const int64_t traversing_cost;
200 const int64_t servicing_demand;
201 const int64_t servicing_cost;
204std::optional<ArcOrEdge> ParseArcOrEdge(std::string_view line,
205 bool with_servicing);
208bool NearpParser::ParseMetadataLine(
const std::vector<std::string>& words) {
209 if (words[0] ==
"Name") {
210 name_ = absl::StrJoin(words.begin() + 1, words.end(),
" ");
211 }
else if (words[0] ==
"Optimal" && words[1] ==
"value") {
212 comment_ = absl::StrJoin(words.begin() + 2, words.end(),
" ");
213 }
else if (words[0] ==
"#Vehicles") {
216 if (num_vehicles_ < -1) {
217 LOG(ERROR) <<
"Error when parsing the number of vehicles: " << words[1];
220 }
else if (words[0] ==
"Capacity") {
222 if (capacity_ <= 0) {
223 LOG(ERROR) <<
"Error when parsing the capacity: " << words[1];
226 }
else if (words[0] ==
"Depot" && words[1] ==
"Node") {
227 const std::optional<int64_t>
depot = ParseNodeIndex(words[2]);
228 if (!
depot.has_value()) {
229 LOG(ERROR) <<
"Error when parsing the depot: " << words[1];
232 depot_ =
depot.value();
233 }
else if (words[0] ==
"#Nodes") {
235 if (num_nodes_ <= 0) {
236 LOG(ERROR) <<
"Error when parsing the number of nodes: " << words[1];
239 }
else if (words[0] ==
"#Edges") {
241 if (num_edges_ <= 0) {
242 LOG(ERROR) <<
"Error when parsing the number of edges: " << words[1];
245 }
else if (words[0] ==
"#Arcs") {
247 if (num_arcs_ <= 0) {
248 LOG(ERROR) <<
"Error when parsing the number of arcs: " << words[1];
251 }
else if (words[0] ==
"#Required" && words[1] ==
"N") {
253 if (num_nodes_with_servicing_ <= 0) {
254 LOG(ERROR) <<
"Error when parsing the number of nodes with servicing: "
258 }
else if (words[0] ==
"#Required" && words[1] ==
"E") {
260 if (num_edges_with_servicing_ <= 0) {
261 LOG(ERROR) <<
"Error when parsing the number of edges with servicing: "
265 }
else if (words[0] ==
"#Required" && words[1] ==
"A") {
267 if (num_arcs_with_servicing_ <= 0) {
268 LOG(ERROR) <<
"Error when parsing the number of arcs with servicing: "
273 LOG(ERROR) <<
"Unrecognized metadata line: " << absl::StrJoin(words,
" ");
279bool NearpParser::ParseArc(std::string_view line,
bool with_servicing) {
280 std::optional<ArcOrEdge> parsed_arc = ParseArcOrEdge(line, with_servicing);
281 if (!parsed_arc.has_value()) {
285 Arc arc{parsed_arc->tail, parsed_arc->head};
286 arc_traversing_costs_[arc] = parsed_arc->traversing_cost;
288 if (with_servicing) {
289 arc_servicing_demands_[arc] = parsed_arc->servicing_demand;
290 arc_servicing_costs_[arc] = parsed_arc->servicing_cost;
296bool NearpParser::ParseEdge(std::string_view line,
bool with_servicing) {
297 std::optional<ArcOrEdge> parsed_edge = ParseArcOrEdge(line, with_servicing);
298 if (!parsed_edge.has_value()) {
302 Edge edge{parsed_edge->tail, parsed_edge->head};
303 edge_traversing_costs_[edge] = parsed_edge->traversing_cost;
305 if (with_servicing) {
306 edge_servicing_demands_[edge] = parsed_edge->servicing_demand;
307 edge_servicing_costs_[edge] = parsed_edge->servicing_cost;
313bool NearpParser::ParseNode(std::string_view line) {
314 const std::vector<std::string> words =
315 absl::StrSplit(line, absl::ByAnyChar(
" :\t(),"), absl::SkipEmpty());
320 LOG(ERROR) <<
"Error when parsing the node name: " << words[0];
325 const int64_t servicing_demand =
327 if (servicing_demand < 0) {
328 LOG(ERROR) <<
"Error when parsing the node servicing demand: " << words[1];
333 if (servicing_cost < 0) {
334 LOG(ERROR) <<
"Error when parsing the node servicing cost: " << words[1];
339 node_servicing_demands_.insert({id, servicing_demand});
340 node_servicing_costs_.insert({id, servicing_cost});
346std::optional<int64_t> ParseNodeIndex(std::string_view text) {
349 LOG(ERROR) <<
"Could not parse node index: " << text;
355std::optional<ArcOrEdge> ParseArcOrEdge(std::string_view line,
356 bool with_servicing) {
357 const std::vector<std::string> words =
358 absl::StrSplit(line, absl::ByAnyChar(
" :\t(),"), absl::SkipEmpty());
363 std::optional<int64_t> opt_tail = ParseNodeIndex(words[1]);
364 if (!opt_tail.has_value()) {
365 LOG(ERROR) <<
"Error when parsing the tail node: " << words[1];
368 const int64_t tail = opt_tail.value();
370 std::optional<int64_t> opt_head = ParseNodeIndex(words[2]);
371 if (!opt_head.has_value()) {
372 LOG(ERROR) <<
"Error when parsing the head node: " << words[2];
375 const int64_t head = opt_head.value();
378 LOG(ERROR) <<
"The head and tail nodes are identical: " << line;
384 if (traversing_cost < 0) {
385 LOG(ERROR) <<
"Error when parsing the traversing cost: " << words[3];
390 const int64_t next_id = (with_servicing) ? 6 : 4;
391 if (words.size() > next_id) {
392 LOG(ERROR) <<
"Extraneous elements in line, starting with: "
398 if (!with_servicing) {
399 return ArcOrEdge{tail, head, traversing_cost,
403 const int64_t servicing_demand =
405 if (servicing_demand < 0) {
406 LOG(ERROR) <<
"Error when parsing the servicing demand: " << words[4];
410 const int64_t servicing_cost =
412 if (servicing_cost < 0) {
413 LOG(ERROR) <<
"Error when parsing the servicing cost: " << words[5];
417 return ArcOrEdge{tail, head, traversing_cost, servicing_demand,
424 if (arc_servicing_costs_.contains(arc)) {
425 int64_t arc_position = std::distance(arc_servicing_demands_.begin(),
426 arc_servicing_demands_.find(arc));
427 CHECK_LT(arc_position, arc_servicing_demands_.size());
428 return absl::StrCat(
"A", arc_position + 1);
430 int64_t arc_position = std::distance(arc_traversing_costs_.begin(),
431 arc_traversing_costs_.find(arc));
432 CHECK_LT(arc_position, arc_traversing_costs_.size());
433 return absl::StrCat(
"NrA", arc_position - num_arcs_with_servicing_ + 1);
438 if (edge_servicing_costs_.contains(edge)) {
439 int64_t edge_position = std::distance(edge_servicing_demands_.begin(),
440 edge_servicing_demands_.find(edge));
441 CHECK_LT(edge_position, edge_servicing_demands_.size());
442 return absl::StrCat(
"E", edge_position + 1);
444 int64_t edge_position = std::distance(edge_traversing_costs_.begin(),
445 edge_traversing_costs_.find(edge));
446 CHECK_LT(edge_position, edge_traversing_costs_.size());
447 return absl::StrCat(
"NrE", edge_position - num_edges_with_servicing_ + 1);
ABSL_ATTRIBUTE_REINITIALIZES void clear()
int NumberOfArcsWithServicing() const
int64_t depot() const
Returns the index of the depot.
std::string GetEdgeName(Edge edge) const
bool LoadFile(absl::string_view file_name)
Loads instance from a file into this parser object.
int NumberOfEdgesWithServicing() const
std::string GetArcName(Arc arc) const
int NumberOfNodesWithServicing() const
int NumberOfEdges() const
Common utilities for parsing routing instances.
int32_t ParseLeadingInt32Value(const char *str, int32_t deflt)
int64_t ParseLeadingInt64Value(const char *str, int64_t deflt)