19 #include <string_view>
22 #include "absl/strings/str_join.h"
23 #include "absl/strings/str_split.h"
31 void CarpParser::Initialize() {
35 number_of_edges_with_servicing_ = 0;
36 number_of_edges_without_servicing_ = 0;
37 total_servicing_cost_ = 0;
39 traversing_costs_.clear();
40 servicing_demands_.clear();
48 return ParseFile(file_name);
51 bool CarpParser::ParseFile(
const std::string& file_name) {
52 static auto section_headers = std::array<const char*, 12>({
60 "TIPO_COSTES_ARISTAS",
63 "LISTA_ARISTAS_NOREQ",
67 for (
const std::string&
line :
69 const std::vector<std::string> words =
70 absl::StrSplit(
line, absl::ByAnyChar(
" :\t"), absl::SkipEmpty());
72 if (absl::c_linear_search(section_headers, words[0])) {
74 if (words[0] ==
"LISTA_ARISTAS_REQ") {
77 section_ = ARCS_WITH_SERVICING;
78 }
else if (words[0] ==
"LISTA_ARISTAS_NOREQ") {
80 section_ = ARCS_WITHOUT_SERVICING;
82 if (!ParseMetadataLine(words)) {
83 LOG(ERROR) <<
"Error when parsing the following metadata line: "
91 case ARCS_WITH_SERVICING:
92 if (!ParseEdge(
line,
true)) {
93 LOG(ERROR) <<
"Could not parse line in LISTA_ARISTAS_REQ: " <<
line;
97 case ARCS_WITHOUT_SERVICING:
98 if (!ParseEdge(
line,
false)) {
99 LOG(ERROR) <<
"Could not parse line in LISTA_ARISTAS_NOREQ: "
105 LOG(ERROR) <<
"Could not parse line outside edge lists: " <<
line;
111 return !servicing_demands_.empty();
115 std::optional<int64_t> ParseNodeIndex(std::string_view text);
118 bool CarpParser::ParseMetadataLine(
const std::vector<std::string>& words) {
119 if (words[0] ==
"NOMBRE") {
120 name_ = absl::StrJoin(words.begin() + 1, words.end(),
" ");
121 }
else if (words[0] ==
"COMENTARIO") {
122 comment_ = absl::StrJoin(words.begin() + 1, words.end(),
" ");
123 }
else if (words[0] ==
"VERTICES") {
125 if (number_of_nodes_ <= 0) {
126 LOG(ERROR) <<
"Error when parsing the number of nodes: " << words[1];
129 }
else if (words[0] ==
"ARISTAS_REQ") {
130 number_of_edges_with_servicing_ =
132 if (number_of_edges_with_servicing_ <= 0) {
133 LOG(ERROR) <<
"Error when parsing the number of edges with servicing: "
137 }
else if (words[0] ==
"ARISTAS_NOREQ") {
138 number_of_edges_without_servicing_ =
140 if (number_of_edges_without_servicing_ < 0) {
143 LOG(ERROR) <<
"Error when parsing the number of edges without servicing: "
147 }
else if (words[0] ==
"VEHICULOS") {
149 if (n_vehicles_ <= 0) {
150 LOG(ERROR) <<
"Error when parsing the number of vehicles: " << words[1];
153 }
else if (words[0] ==
"CAPACIDAD") {
155 if (capacity_ <= 0) {
156 LOG(ERROR) <<
"Error when parsing the capacity: " << words[1];
159 }
else if (words[0] ==
"TIPO_COSTES_ARISTAS") {
160 if (words[1] !=
"EXPLICITOS") {
162 LOG(ERROR) <<
"Value of TIPO_COSTES_ARISTAS is unexpected, only "
163 "EXPLICITOS is supported, but "
164 << words[1] <<
" was found";
167 }
else if (words[0] ==
"COSTE_TOTAL_REQ") {
169 if (total_servicing_cost_ == -1) {
170 LOG(ERROR) <<
"Error when parsing the total servicing cost: " << words[1];
173 }
else if (words[0] ==
"DEPOSITO") {
175 const std::optional<int64_t>
depot = ParseNodeIndex(words[1]);
176 if (!
depot.has_value()) {
177 LOG(ERROR) <<
"Error when parsing the depot: " << words[1];
180 depot_ =
depot.value();
185 bool CarpParser::ParseEdge(std::string_view
line,
bool with_servicing) {
186 const std::vector<std::string> words =
187 absl::StrSplit(
line, absl::ByAnyChar(
" :\t(),"), absl::SkipEmpty());
190 std::optional<int64_t> opt_head = ParseNodeIndex(words[0]);
191 if (!opt_head.has_value()) {
192 LOG(ERROR) <<
"Error when parsing the head node: " << words[0];
195 const int64_t
head = opt_head.value();
197 std::optional<int64_t> opt_tail = ParseNodeIndex(words[1]);
198 if (!opt_tail.has_value()) {
199 LOG(ERROR) <<
"Error when parsing the tail node: " << words[1];
202 const int64_t
tail = opt_tail.value();
205 LOG(ERROR) <<
"The head and tail nodes are identical: " <<
line;
210 if (words[2] !=
"coste") {
211 LOG(ERROR) <<
"Unexpected keyword: " << words[2];
218 if (with_servicing) {
219 if (words[4] !=
"demanda") {
220 LOG(ERROR) <<
"Unexpected keyword: " << words[2];
224 servicing_demands_[{
tail,
head}] = servicing;
228 const int64_t next_id = (with_servicing) ? 6 : 4;
229 if (words.size() > next_id) {
230 LOG(ERROR) <<
"Extraneous elements in line, starting with: "
239 std::optional<int64_t> ParseNodeIndex(std::string_view text) {
242 LOG(ERROR) <<
"Could not parse node index: " << text;
bool LoadFile(const std::string &file_name)
int64_t NumberOfEdgesWithServicing() const
int64_t NumberOfEdges() const
Collection of objects used to extend the Constraint Solver library.
int64_t ParseLeadingInt64Value(const char *str, int64_t deflt)