00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 #ifndef OR_TOOLS_GRAPH_HAMILTONIAN_PATH_H_
00076 #define OR_TOOLS_GRAPH_HAMILTONIAN_PATH_H_
00077
00078 #include <math.h>
00079 #include <stddef.h>
00080 #include <algorithm>
00081 #include <limits>
00082 #include <utility>
00083 #include <vector>
00084
00085 #include "base/integral_types.h"
00086 #include "base/logging.h"
00087 #include "util/bitset.h"
00088
00089 namespace operations_research {
00090
00091 typedef int PathNodeIndex;
00092
00093 template <typename T> class HamiltonianPathSolver {
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 public:
00106
00107
00108
00109
00110
00111
00112 typedef uint32 NodeSet;
00113
00114 explicit HamiltonianPathSolver(const std::vector<std::vector<T> >& cost);
00115 ~HamiltonianPathSolver();
00116
00117
00118 void ChangeCostMatrix(const std::vector<std::vector<T> >& cost);
00119
00120
00121 T HamiltonianCost();
00122
00123
00124 void HamiltonianPath(std::vector<PathNodeIndex>* path);
00125
00126
00127 T TravelingSalesmanCost();
00128
00129
00130 void TravelingSalesmanPath(std::vector<PathNodeIndex>* path);
00131
00132
00133
00134 bool IsRobust();
00135
00136
00137 bool VerifiesTriangleInequality();
00138
00139 private:
00140
00141 void CheckRobustness();
00142
00143
00144 void CheckTriangleInequality();
00145
00146
00147 void ComputeShortestPath(NodeSet s, PathNodeIndex dest);
00148
00149
00150 void CopyCostMatrix(const std::vector<std::vector<T> >& cost);
00151
00152
00153 void Init(const std::vector<std::vector<T> >& cost);
00154
00155
00156 void Free();
00157
00158
00159 void Path(PathNodeIndex end,
00160 std::vector<PathNodeIndex>* path);
00161
00162
00163 void Solve();
00164
00165 bool robust_;
00166 bool triangle_inequality_ok_;
00167 bool robustness_checked_;
00168 bool triangle_inequality_checked_;
00169 bool solved_;
00170 PathNodeIndex num_nodes_;
00171 T** cost_;
00172 NodeSet two_power_num_nodes_;
00173 T** memory_;
00174 };
00175
00176 static const int kHamiltonianPathSolverPadValue = 1557;
00177
00178 template <typename T>
00179 HamiltonianPathSolver<T>::HamiltonianPathSolver(const std::vector<std::vector<T> >& cost)
00180 : robust_(true),
00181 triangle_inequality_ok_(true),
00182 robustness_checked_(false),
00183 triangle_inequality_checked_(false),
00184 solved_(false),
00185 num_nodes_(0),
00186 cost_(NULL),
00187 two_power_num_nodes_(0),
00188 memory_(NULL) {
00189 Init(cost);
00190 }
00191
00192 template <typename T> HamiltonianPathSolver<T>::~HamiltonianPathSolver() {
00193 Free();
00194 }
00195
00196 template <typename T>
00197 void HamiltonianPathSolver<T>::Free() {
00198 if (num_nodes_ > 0) {
00199 delete [] memory_[0];
00200 delete [] memory_;
00201 for (int i = 0; i < num_nodes_; ++i) {
00202 delete [] cost_[i];
00203 }
00204 delete [] cost_;
00205 }
00206 }
00207
00208
00209
00210 template <typename T> void HamiltonianPathSolver<T>::
00211 ChangeCostMatrix(const std::vector<std::vector<T> >& cost) {
00212 robustness_checked_ = false;
00213 triangle_inequality_checked_ = false;
00214 solved_ = false;
00215 if (cost.size() == num_nodes_ && num_nodes_ > 0) {
00216 CopyCostMatrix(cost);
00217 } else {
00218 Free();
00219 Init(cost);
00220 }
00221 }
00222
00223 template <typename T>
00224 void HamiltonianPathSolver<T>::CopyCostMatrix(const std::vector<std::vector<T> >& cost) {
00225 for (int i = 0; i < num_nodes_; ++i) {
00226 CHECK_EQ(num_nodes_, cost[i].size()) << "Cost matrix must be square";
00227 for (int j = 0; j < num_nodes_; ++j) {
00228 cost_[i][j] = cost[i][j];
00229 }
00230 }
00231 }
00232
00233 template <typename T>
00234 bool HamiltonianPathSolver<T>::IsRobust() {
00235 if (!robustness_checked_) {
00236 CheckRobustness();
00237 }
00238 return robust_;
00239 }
00240
00241 template <typename T>
00242 bool HamiltonianPathSolver<T>::VerifiesTriangleInequality() {
00243 if (!triangle_inequality_checked_) {
00244 CheckTriangleInequality();
00245 }
00246 return triangle_inequality_ok_;
00247 }
00248
00249 template <typename T>
00250 void HamiltonianPathSolver<T>::CheckRobustness() {
00251 T min_cost = std::numeric_limits<T>::max();
00252 T max_cost = std::numeric_limits<T>::min();
00253
00254
00255 for (int i = 0; i < num_nodes_; ++i) {
00256 for (int j = 0; j < num_nodes_; ++j) {
00257 if (i == j) break;
00258 min_cost = std::min(min_cost, cost_[i][j]);
00259 max_cost = std::max(max_cost, cost_[i][j]);
00260 }
00261 }
00262
00263
00264 if (min_cost < 0) {
00265 robust_ = false;
00266 } else {
00267 robust_ = (min_cost >
00268 num_nodes_ * max_cost * std::numeric_limits<T>::epsilon());
00269 }
00270 robustness_checked_ = true;
00271 }
00272
00273 template <typename T>
00274 void HamiltonianPathSolver<T>::CheckTriangleInequality() {
00275 triangle_inequality_ok_ = true;
00276 triangle_inequality_checked_ = true;
00277 for (int k = 0; k < num_nodes_; ++k) {
00278 for (int i = 0; i < num_nodes_; ++i) {
00279 for (int j = 0; j < num_nodes_; ++j) {
00280 T detour_cost = cost_[i][k] + cost_[k][j];
00281 if (detour_cost < cost_[i][j]) {
00282 triangle_inequality_ok_ = false;
00283 return;
00284 }
00285 }
00286 }
00287 }
00288 }
00289
00290 template <typename T>
00291 void HamiltonianPathSolver<T>::Init(const std::vector<std::vector<T> >& cost) {
00292 num_nodes_ = cost.size();
00293 if (num_nodes_ > 0) {
00294 cost_ = new T*[num_nodes_];
00295 for (int i = 0; i < num_nodes_; ++i) {
00296 cost_[i] = new T[num_nodes_];
00297 }
00298
00299 CopyCostMatrix(cost);
00300
00301 two_power_num_nodes_ = 1 << num_nodes_;
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 const int padded_size = two_power_num_nodes_
00312 + kHamiltonianPathSolverPadValue;
00313 memory_ = new T * [num_nodes_];
00314 memory_[0] = new T[num_nodes_ * padded_size];
00315 for (int i = 1; i < num_nodes_; ++i) {
00316 memory_[i] = memory_[i-1] + padded_size;
00317 }
00318 }
00319 }
00320
00321 template <typename T>
00322 void HamiltonianPathSolver<T>::ComputeShortestPath(NodeSet subset,
00323 PathNodeIndex dest) {
00324
00325
00326
00327
00328
00329
00330
00331 const NodeSet first_singleton = LeastSignificantBitWord32(subset);
00332 const PathNodeIndex first_src =
00333 LeastSignificantBitPosition32(first_singleton);
00334 NodeSet start_subset = subset - first_singleton;
00335 T min_cost = memory_[first_src][start_subset] + cost_[first_src][dest];
00336 NodeSet copy = start_subset;
00337 while (copy != 0) {
00338 const NodeSet singleton = LeastSignificantBitWord32(copy);
00339 const PathNodeIndex src = LeastSignificantBitPosition32(singleton);
00340 const NodeSet new_subset = subset - singleton;
00341 const T cost = memory_[src][new_subset] + cost_[src][dest];
00342 if (cost < min_cost) {
00343 min_cost = cost;
00344 }
00345 copy -= singleton;
00346 }
00347 memory_[dest][subset] = min_cost;
00348 }
00349
00350 template <typename T> void HamiltonianPathSolver<T>::Solve() {
00351 if (solved_) return;
00352 for (PathNodeIndex dest = 0; dest < num_nodes_; ++dest) {
00353 memory_[dest][0] = cost_[0][dest];
00354 }
00355 for (NodeSet subset = 1; subset < two_power_num_nodes_; ++subset) {
00356 for (PathNodeIndex dest = 0; dest < num_nodes_; ++dest) {
00357 ComputeShortestPath(subset, dest);
00358 }
00359 }
00360 solved_ = true;
00361 }
00362
00363
00364 template <typename T> T HamiltonianPathSolver<T>::HamiltonianCost() {
00365 if (num_nodes_ <= 1) {
00366 return 0;
00367 }
00368 Solve();
00369 return memory_[num_nodes_ - 1][two_power_num_nodes_ - 1];
00370 }
00371
00372 template <typename T> void HamiltonianPathSolver<T>::
00373 HamiltonianPath(std::vector<PathNodeIndex>* path) {
00374 if (num_nodes_ <= 1) {
00375 path->resize(1);
00376 (*path)[0] = 0;
00377 return;
00378 }
00379 Solve();
00380 path->resize(num_nodes_);
00381 return Path(num_nodes_ - 1, path);
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412 template <typename T>
00413 void HamiltonianPathSolver<T>::Path(PathNodeIndex end,
00414 std::vector<PathNodeIndex>* path) {
00415 PathNodeIndex dest = end;
00416 NodeSet current_set = two_power_num_nodes_ - 1;
00417
00418
00419
00420 current_set -= 1;
00421 int i = num_nodes_ - 1;
00422 while (current_set != 0) {
00423 NodeSet copy = current_set;
00424 while (copy != 0) {
00425 const NodeSet singleton = LeastSignificantBitWord32(copy);
00426 const PathNodeIndex src = LeastSignificantBitPosition32(singleton);
00427 const NodeSet incumbent_set = current_set - singleton;
00428 const double current_cost = memory_[dest][current_set];
00429 const double incumbent_cost = memory_[src][incumbent_set]
00430 + cost_[src][dest];
00431
00432
00433 if (fabs(current_cost - incumbent_cost)
00434 <= std::numeric_limits<T>::epsilon() * current_cost) {
00435 current_set = incumbent_set;
00436 dest = src;
00437 (*path)[i] = dest;
00438 break;
00439 }
00440 copy -= singleton;
00441 }
00442 --i;
00443 }
00444 }
00445
00446 template <typename T> T HamiltonianPathSolver<T>::TravelingSalesmanCost() {
00447 if (num_nodes_ <= 1) {
00448 return 0;
00449 }
00450 Solve();
00451 return memory_[0][two_power_num_nodes_ - 1];
00452 }
00453
00454 template <typename T> void HamiltonianPathSolver<T>::
00455 TravelingSalesmanPath(std::vector<PathNodeIndex>* path) {
00456 if (num_nodes_ <= 1) {
00457 path->resize(1);
00458 (*path)[0] = 0;
00459 return;
00460 }
00461 Solve();
00462 path->resize(num_nodes_ + 1);
00463 Path(0, path);
00464
00465
00466
00467
00468
00469 (*path)[num_nodes_] = 0;
00470 }
00471
00472 }
00473
00474 #endif // OR_TOOLS_GRAPH_HAMILTONIAN_PATH_H_