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