Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
solomon_parser.cc
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
15
16#include <cstdint>
17#include <memory>
18#include <string>
19#include <vector>
20
21#include "absl/strings/ascii.h"
22#include "absl/strings/match.h"
23#include "absl/strings/str_join.h"
24#include "absl/strings/str_split.h"
25#include "absl/strings/string_view.h"
29#include "ortools/base/path.h"
32#include "re2/re2.h"
33
35
37 : sections_({{"VEHICLE", VEHICLE}, {"CUSTOMER", CUSTOMER}}) {
38 Initialize();
39}
40
41bool SolomonParser::LoadFile(absl::string_view file_name) {
42 Initialize();
43 return ParseFile(file_name);
44}
45
46bool SolomonParser::LoadFile(absl::string_view file_name,
47 const std::string& archive_name) {
48 Initialize();
49 if (!absl::StartsWith(archive_name, "/")) {
50 return false;
51 }
52 const std::string fake_zip_path = "/zip" + archive_name;
53 std::shared_ptr<zipfile::ZipArchive> fake_zip_closer(
54 zipfile::OpenZipArchive(archive_name));
55 if (nullptr == fake_zip_closer) return false;
56 const std::string zip_filename = file::JoinPath(fake_zip_path, file_name);
57 return ParseFile(zip_filename);
58}
59
60void SolomonParser::Initialize() {
61 name_.clear();
62 vehicles_ = 0;
63 coordinates_.clear();
64 capacity_ = 0;
65 demands_.clear();
66 time_windows_.clear();
67 service_times_.clear();
68 section_ = NAME;
69 to_read_ = 1;
70}
71
72bool SolomonParser::ParseFile(absl::string_view file_name) {
73 for (const std::string& line :
75 const std::vector<std::string> words =
76 absl::StrSplit(line, absl::ByAnyChar(" :\t"), absl::SkipEmpty());
77 // Skip blank lines
78 if (words.empty()) continue;
79 if (to_read_ > 0) {
80 switch (section_) {
81 case NAME: {
82 name_ = words[0];
83 break;
84 }
85 case VEHICLE: {
86 if (to_read_ == 1) {
87 if (words.size() != 2) return false;
88 vehicles_ = strings::ParseLeadingInt32Value(words[0], -1);
89 if (vehicles_ < 0) return false;
90 capacity_ = strings::ParseLeadingInt32Value(words[1], -1);
91 if (capacity_ < 0) return false;
92 }
93 break;
94 }
95 case CUSTOMER: {
96 if (to_read_ < 2) {
97 std::vector<int64_t> values;
98 for (int i = 1; i < words.size(); ++i) {
99 const int64_t value =
101 if (value < 0) return false;
102 values.push_back(value);
103 }
104 coordinates_.push_back({values[0], values[1]});
105 demands_.push_back(values[2]);
106 time_windows_.push_back({values[3], values[4]});
107 service_times_.push_back(values[5]);
108 ++to_read_;
109 }
110 break;
111 }
112 default: {
113 LOG(ERROR) << "Reading data outside section";
114 return false;
115 }
116 }
117 --to_read_;
118 } else { // New section
119 section_ = gtl::FindWithDefault(sections_, words[0], UNKNOWN);
120 switch (section_) {
121 case VEHICLE: {
122 // Two rows: header and data.
123 to_read_ = 2;
124 break;
125 }
126 case CUSTOMER: {
127 to_read_ = 2;
128 break;
129 }
130 default: {
131 LOG(ERROR) << "Unknown section: " << section_;
132 return false;
133 }
134 }
135 }
136 }
137 return section_ == CUSTOMER;
138}
139
141
142bool SolomonSolutionParser::LoadFile(absl::string_view file_name) {
143 Initialize();
144 return ParseFile(file_name);
145}
146
147void SolomonSolutionParser::Initialize() {
148 routes_.clear();
149 key_values_.clear();
150}
151
152bool SolomonSolutionParser::ParseFile(absl::string_view file_name) {
153 bool success = false;
154 for (const std::string& line :
156 success = true;
157 const std::vector<std::string> words =
158 absl::StrSplit(line, ':', absl::SkipEmpty());
159 // Skip blank lines
160 if (words.empty()) continue;
161 std::string key = words[0];
162 std::string value = words.size() > 1
163 ? absl::StrJoin(words.begin() + 1, words.end(), ":")
164 : "";
165 if (!RE2::FullMatch(key, "Route\\s*(\\d+)\\s*")) {
166 absl::StripAsciiWhitespace(&key);
167 absl::StripAsciiWhitespace(&value);
168 key_values_[key] = value;
169 // Note: the "Solution" key will be captured here. That key has no actual
170 // usefulness and serves as a separator before reading routes.
171 continue;
172 }
173 routes_.push_back(std::vector<int>());
174 for (const auto item :
175 absl::StrSplit(value, absl::ByAnyChar(" \t"), absl::SkipEmpty())) {
176 routes_.back().push_back(strings::ParseLeadingInt32Value(item, -1));
177 }
178 }
179 return success;
180}
181
182} // namespace operations_research::routing
bool LoadFile(absl::string_view file_name)
Loads instance from a file.
std::string JoinPath()
Definition path.h:82
const MapUtilMappedT< Collection > & FindWithDefault(const Collection &collection, const KeyType &key, const MapUtilMappedT< Collection > &value)
Definition map_util.h:36
Common utilities for parsing routing instances.
int32_t ParseLeadingInt32Value(const char *str, int32_t deflt)
Definition numbers.cc:60
int64_t ParseLeadingInt64Value(const char *str, int64_t deflt)
Definition numbers.cc:167
std::shared_ptr< ZipArchive > OpenZipArchive(absl::string_view path, const ZipFileOptions &options)
Definition zipfile.cc:32