Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
tsptw_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 <cmath>
17#include <limits>
18#include <memory>
19#include <string>
20#include <vector>
21
22#include "absl/strings/match.h"
23#include "absl/strings/str_split.h"
24#include "absl/strings/string_view.h"
27#include "ortools/base/path.h"
30
32namespace {
33
34double DoubleEuc2DDistance(const Coordinates2<double>& from,
35 const Coordinates2<double>& to) {
36 const double xd = from.x - to.x;
37 const double yd = from.y - to.y;
38 return sqrt(xd * xd + yd * yd);
39}
40
41double Euc2DDistance(const Coordinates2<double>& from,
42 const Coordinates2<double>& to) {
43 return std::floor(DoubleEuc2DDistance(from, to));
44}
45
46constexpr double kInfinity = std::numeric_limits<double>::infinity();
47
48std::shared_ptr<zipfile::ZipArchive> OpenZipArchiveIfItExists(
49 absl::string_view file_name) {
50 const absl::string_view archive_name = file::Dirname(file_name);
51 if (file::Extension(archive_name) == "zip") {
52 return zipfile::OpenZipArchive(archive_name);
53 } else {
54 return nullptr;
55 }
56}
57
58} // namespace
59
61 : size_(0),
62 depot_(0),
63 total_service_time_(0),
64 distance_function_(nullptr),
65 time_function_(nullptr) {}
66
67bool TspTWParser::LoadFile(absl::string_view file_name) {
68 std::shared_ptr<zipfile::ZipArchive> zip_archive(
69 OpenZipArchiveIfItExists(file_name));
70 coords_.clear();
71 time_windows_.clear();
72 service_times_.clear();
73 distance_matrix_.clear();
74 size_ = 0;
75 depot_ = 0;
76 total_service_time_ = 0;
77 distance_function_ = nullptr;
78 time_function_ = nullptr;
79 return ParseLopezIbanezBlum(file_name) || ParseDaSilvaUrrutia(file_name);
80}
81
82bool TspTWParser::ParseLopezIbanezBlum(absl::string_view file_name) {
83 int section = 0;
84 int entry_count = 0;
85 for (const std::string& line :
87 const std::vector<std::string> words =
88 absl::StrSplit(line, absl::ByAnyChar(" :\t"), absl::SkipEmpty());
89 if (words.empty()) continue;
90 // Parsing comments.
91 if (words[0] == "#") {
92 if (absl::StrContains(line, "service times")) {
93 const double total_service_time =
96 total_service_time_ = MathUtil::FastInt64Round(total_service_time);
97 }
98 }
99 continue;
100 }
101 switch (section) {
102 case 0: { // Parsing size.
103 if (words.size() != 1) return false;
104 size_ = strings::ParseLeadingInt32Value(words[0], -1);
105 if (size_ < 0) return false;
106 distance_matrix_.reserve(size_ * size_);
107 ++section;
108 entry_count = 0;
109 break;
110 }
111 case 1: { // Parsing distances.
112 if (words.size() != size_) return false;
113 for (const std::string& word : words) {
114 const double distance =
116 if (distance == kInfinity) return false;
117 distance_matrix_.push_back(distance);
118 }
119 ++entry_count;
120 if (entry_count == size_) {
121 ++section;
122 entry_count = 0;
123 }
124 break;
125 }
126 case 2: { // Parsing time windows.
127 if (words.size() != 2) return false;
128 std::vector<double> values;
129 for (const std::string& word : words) {
130 const double value =
132 if (value == kInfinity) return false;
133 values.push_back(value);
134 }
135 time_windows_.push_back({values[0], values[1]});
136 service_times_.push_back(0);
137 ++entry_count;
138 if (entry_count == size_) {
139 ++section;
140 }
141 break;
142 }
143 default: {
144 return false;
145 }
146 }
147 }
148 distance_function_ = [this](int from, int to) {
149 return distance_matrix_[from * size_ + to];
150 };
151 time_function_ = distance_function_;
152 return entry_count == size_;
153}
154
155bool TspTWParser::ParseDaSilvaUrrutia(absl::string_view file_name) {
156 for (const std::string& line :
157 FileLines(file_name, FileLineIterator::REMOVE_INLINE_CR)) {
158 // Skip header.
159 if (absl::StartsWith(line, "CUST NO.")) continue;
160 const std::vector<std::string> words =
161 absl::StrSplit(line, absl::ByAnyChar(" :\t"), absl::SkipEmpty());
162 // Skip comments and empty lines.
163 if (words.empty() || words[0] == "!!" || words[0][0] == '#') continue;
164 if (words.size() != 7) return false;
165 // Check that all field values are doubles, except first which must be a
166 // positive integer.
167 const int value = strings::ParseLeadingInt32Value(words[0], -1);
168 if (value < 0) return false;
169 // 999 represents the eof.
170 if (value == 999) continue;
171 std::vector<double> values;
172 for (int i = 1; i < words.size(); ++i) {
173 const double value = strings::ParseLeadingDoubleValue(
174 words[i], std::numeric_limits<double>::infinity());
175 if (value == std::numeric_limits<double>::infinity()) return false;
176 values.push_back(value);
177 }
178 coords_.push_back({values[0], values[1]});
179 time_windows_.push_back({values[3], values[4]});
180 service_times_.push_back(values[5]);
181 }
182 size_ = coords_.size();
183
184 // Enforce the triangular inequality (needed due to rounding).
185 distance_matrix_.reserve(size_ * size_);
186 for (int i = 0; i < size_; ++i) {
187 for (int j = 0; j < size_; ++j) {
188 distance_matrix_.push_back(Euc2DDistance(coords_[i], coords_[j]));
189 }
190 }
191 for (int i = 0; i < size_; i++) {
192 for (int j = 0; j < size_; j++) {
193 for (int k = 0; k < size_; k++) {
194 if (distance_matrix_[i * size_ + j] >
195 distance_matrix_[i * size_ + k] + distance_matrix_[k * size_ + j]) {
196 distance_matrix_[i * size_ + j] =
197 distance_matrix_[i * size_ + k] + distance_matrix_[k * size_ + j];
198 }
199 }
200 }
201 }
202
203 distance_function_ = [this](int from, int to) {
204 return distance_matrix_[from * size_ + to];
205 };
206 time_function_ = [this](int from, int to) {
207 return distance_matrix_[from * size_ + to] + service_times_[from];
208 };
209 return true;
210}
211
212} // namespace operations_research::routing
static int64_t FastInt64Round(double x)
Definition mathutil.h:260
bool LoadFile(absl::string_view file_name)
absl::string_view Extension(absl::string_view path)
Definition path.cc:133
absl::string_view Dirname(absl::string_view path)
Definition path.cc:105
static constexpr double kInfinity
double ParseLeadingDoubleValue(const char *str, double deflt)
Definition numbers.cc:205
int32_t ParseLeadingInt32Value(const char *str, int32_t deflt)
Definition numbers.cc:55
std::shared_ptr< ZipArchive > OpenZipArchive(absl::string_view path, const ZipFileOptions &options)
Definition zipfile.cc:32
trees with all degrees equal to