23#include "absl/strings/str_join.h"
24#include "absl/strings/str_split.h"
32void NearpParser::Initialize() {
38 num_arcs_with_servicing_ = 0;
39 num_edges_with_servicing_ = 0;
40 num_nodes_with_servicing_ = 0;
42 arc_traversing_costs_.clear();
43 edge_traversing_costs_.clear();
44 arc_servicing_demands_.clear();
45 edge_servicing_demands_.clear();
46 node_servicing_demands_.
clear();
54 return ParseFile(file_name);
57bool NearpParser::ParseFile(
const std::string& file_name) {
61 static auto section_headers = std::array<const char*, 14>({
78 for (
const std::string&
line :
80 const std::vector<std::string> words =
81 absl::StrSplit(
line, absl::ByAnyChar(
" :\t"), absl::SkipEmpty());
83 if (words.empty())
continue;
85 if (absl::c_linear_search(section_headers, words[0])) {
87 if (words[0] ==
"ReN.") {
89 section_ = NODES_WITH_SERVICING;
90 }
else if (words[0] ==
"ReE.") {
93 section_ = EDGES_WITH_SERVICING;
94 }
else if (words[0] ==
"EDGE") {
96 section_ = EDGES_WITHOUT_SERVICING;
97 }
else if (words[0] ==
"ReA.") {
100 section_ = ARCS_WITH_SERVICING;
101 }
else if (words[0] ==
"ARC") {
103 section_ = ARCS_WITHOUT_SERVICING;
105 if (!ParseMetadataLine(words)) {
106 LOG(ERROR) <<
"Error when parsing a metadata line: " <<
line;
117 case NODES_WITH_SERVICING:
121 case EDGES_WITH_SERVICING:
125 case EDGES_WITHOUT_SERVICING:
131 if (edge_traversing_costs_.size() ==
NumberOfEdges())
continue;
133 case ARCS_WITH_SERVICING:
137 case ARCS_WITHOUT_SERVICING:
143 if (arc_traversing_costs_.size() ==
NumberOfArcs())
continue;
151 case NODES_WITH_SERVICING:
152 if (!ParseNode(
line)) {
153 LOG(ERROR) <<
"Could not parse line in required nodes: " <<
line;
157 case EDGES_WITH_SERVICING:
158 if (!ParseEdge(
line,
true)) {
159 LOG(ERROR) <<
"Could not parse line in required edges: " <<
line;
163 case EDGES_WITHOUT_SERVICING:
164 if (!ParseEdge(
line,
false)) {
165 LOG(ERROR) <<
"Could not parse line in edges: " <<
line;
169 case ARCS_WITH_SERVICING:
170 if (!ParseArc(
line,
true)) {
171 LOG(ERROR) <<
"Could not parse line in required arcs: " <<
line;
175 case ARCS_WITHOUT_SERVICING:
176 if (!ParseArc(
line,
false)) {
177 LOG(ERROR) <<
"Could not parse line in arcs: " <<
line;
182 LOG(ERROR) <<
"Could not parse line outside node-edge-arc lists: "
189 return section_ != METADATA;
193std::optional<int64_t> ParseNodeIndex(std::string_view text);
203std::optional<ArcOrEdge> ParseArcOrEdge(std::string_view
line,
204 bool with_servicing);
207bool NearpParser::ParseMetadataLine(
const std::vector<std::string>& words) {
208 if (words[0] ==
"Name") {
209 name_ = absl::StrJoin(words.begin() + 1, words.end(),
" ");
210 }
else if (words[0] ==
"Optimal" && words[1] ==
"value") {
211 comment_ = absl::StrJoin(words.begin() + 2, words.end(),
" ");
212 }
else if (words[0] ==
"#Vehicles") {
215 if (num_vehicles_ < -1) {
216 LOG(ERROR) <<
"Error when parsing the number of vehicles: " << words[1];
219 }
else if (words[0] ==
"Capacity") {
221 if (capacity_ <= 0) {
222 LOG(ERROR) <<
"Error when parsing the capacity: " << words[1];
225 }
else if (words[0] ==
"Depot" && words[1] ==
"Node") {
226 const std::optional<int64_t>
depot = ParseNodeIndex(words[2]);
227 if (!
depot.has_value()) {
228 LOG(ERROR) <<
"Error when parsing the depot: " << words[1];
231 depot_ =
depot.value();
232 }
else if (words[0] ==
"#Nodes") {
234 if (num_nodes_ <= 0) {
235 LOG(ERROR) <<
"Error when parsing the number of nodes: " << words[1];
238 }
else if (words[0] ==
"#Edges") {
240 if (num_edges_ <= 0) {
241 LOG(ERROR) <<
"Error when parsing the number of edges: " << words[1];
244 }
else if (words[0] ==
"#Arcs") {
246 if (num_arcs_ <= 0) {
247 LOG(ERROR) <<
"Error when parsing the number of arcs: " << words[1];
250 }
else if (words[0] ==
"#Required" && words[1] ==
"N") {
252 if (num_nodes_with_servicing_ <= 0) {
253 LOG(ERROR) <<
"Error when parsing the number of nodes with servicing: "
257 }
else if (words[0] ==
"#Required" && words[1] ==
"E") {
259 if (num_edges_with_servicing_ <= 0) {
260 LOG(ERROR) <<
"Error when parsing the number of edges with servicing: "
264 }
else if (words[0] ==
"#Required" && words[1] ==
"A") {
266 if (num_arcs_with_servicing_ <= 0) {
267 LOG(ERROR) <<
"Error when parsing the number of arcs with servicing: "
272 LOG(ERROR) <<
"Unrecognized metadata line: " << absl::StrJoin(words,
" ");
278bool NearpParser::ParseArc(std::string_view
line,
bool with_servicing) {
279 std::optional<ArcOrEdge> parsed_arc = ParseArcOrEdge(
line, with_servicing);
280 if (!parsed_arc.has_value()) {
284 Arc
arc{parsed_arc->tail, parsed_arc->head};
285 arc_traversing_costs_[
arc] = parsed_arc->traversing_cost;
287 if (with_servicing) {
288 arc_servicing_demands_[
arc] = parsed_arc->servicing_demand;
289 arc_servicing_costs_[
arc] = parsed_arc->servicing_cost;
295bool NearpParser::ParseEdge(std::string_view
line,
bool with_servicing) {
296 std::optional<ArcOrEdge> parsed_edge = ParseArcOrEdge(
line, with_servicing);
297 if (!parsed_edge.has_value()) {
301 Edge
edge{parsed_edge->tail, parsed_edge->head};
302 edge_traversing_costs_[
edge] = parsed_edge->traversing_cost;
304 if (with_servicing) {
305 edge_servicing_demands_[
edge] = parsed_edge->servicing_demand;
306 edge_servicing_costs_[
edge] = parsed_edge->servicing_cost;
312bool NearpParser::ParseNode(std::string_view
line) {
313 const std::vector<std::string> words =
314 absl::StrSplit(
line, absl::ByAnyChar(
" :\t(),"), absl::SkipEmpty());
319 LOG(ERROR) <<
"Error when parsing the node name: " << words[0];
327 LOG(ERROR) <<
"Error when parsing the node servicing demand: " << words[1];
333 LOG(ERROR) <<
"Error when parsing the node servicing cost: " << words[1];
345std::optional<int64_t> ParseNodeIndex(std::string_view text) {
348 LOG(ERROR) <<
"Could not parse node index: " << text;
354std::optional<ArcOrEdge> ParseArcOrEdge(std::string_view
line,
355 bool with_servicing) {
356 const std::vector<std::string> words =
357 absl::StrSplit(
line, absl::ByAnyChar(
" :\t(),"), absl::SkipEmpty());
360 const std::string
name = words[0];
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;
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) {
406 LOG(ERROR) <<
"Error when parsing the servicing demand: " << words[4];
413 LOG(ERROR) <<
"Error when parsing the servicing cost: " << words[5];
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);
std::pair< iterator, bool > insert(const value_type &v)
ABSL_ATTRIBUTE_REINITIALIZES void clear()
size_type size() const
Derive size_ from set_, as list::size might be O(N).
bool LoadFile(const std::string &file_name)
Loads instance from a file into this parser object.
int NumberOfNodesWithServicing() const
std::string GetEdgeName(Edge edge) const
std::string GetArcName(Arc arc) const
int64_t depot() const
Returns the index of the depot.
int NumberOfEdgesWithServicing() const
int NumberOfArcsWithServicing() const
int NumberOfEdges() const
const std::string name
A name for logging purposes.
In SWIG mode, we don't want anything besides these top-level includes.
int32_t ParseLeadingInt32Value(const char *str, int32_t deflt)
int64_t ParseLeadingInt64Value(const char *str, int64_t deflt)
const int64_t traversing_cost
const int64_t servicing_demand
const int64_t servicing_cost