14 #ifndef OR_TOOLS_GRAPH_HAMILTONIAN_PATH_H_
15 #define OR_TOOLS_GRAPH_HAMILTONIAN_PATH_H_
88 #include <type_traits>
103 template <
typename Set>
108 return current_set_ != other.current_set_;
126 template <
typename Integer>
133 static constexpr Integer
One =
static_cast<Integer
>(1);
134 static constexpr Integer
Zero =
static_cast<Integer
>(0);
138 explicit Set(Integer n) : value_(n) {
144 Integer
value()
const {
return value_; }
166 return (value_ & other.value_) == other.value_;
194 return Set(value_ & (singleton.value_ - 1)).Cardinality();
222 template <
typename SetRange>
234 return current_set_ != other.current_set_;
241 const IntegerType c = current_set_.SmallestSingleton().value();
246 const IntegerType shift = current_set_.SmallestElement();
247 current_set_ = r == 0 ?
SetType(0) :
SetType(((r ^
a) >> (shift + 2)) | r);
256 template <
typename Set>
264 : begin_(
Set::FullSet(card)),
265 end_(
Set::FullSet(card - 1).AddElement(max_card)) {
290 template <
typename Set,
typename CostType>
313 (binomial_coefficients_[added_node][rank] -
314 binomial_coefficients_[removed_node][rank]);
324 memory_[offset] =
value;
338 bool CheckConsistency()
const;
345 std::vector<std::vector<uint64_t>> binomial_coefficients_;
349 std::vector<int64_t> base_offset_;
353 std::vector<CostType> memory_;
356 template <
typename Set,
typename CostType>
360 if (max_card <= max_card_)
return;
361 max_card_ = max_card;
362 binomial_coefficients_.resize(max_card_ + 1);
365 for (
int n = 0; n <= max_card_; ++n) {
366 binomial_coefficients_[n].resize(n + 2);
367 binomial_coefficients_[n][0] = 1;
368 for (
int k = 1; k <= n; ++k) {
369 binomial_coefficients_[n][k] = binomial_coefficients_[n - 1][k - 1] +
370 binomial_coefficients_[n - 1][k];
374 binomial_coefficients_[n][n + 1] = 0;
376 base_offset_.resize(max_card_ + 1);
381 for (
int k = 0; k < max_card_; ++k) {
382 base_offset_[k + 1] =
383 base_offset_[k] + k * binomial_coefficients_[max_card_][k];
386 memory_.shrink_to_fit();
387 memory_.resize(max_card_ * (1 << (max_card_ - 1)));
388 DCHECK(CheckConsistency());
391 template <
typename Set,
typename CostType>
393 for (
int n = 0; n <= max_card_; ++n) {
395 for (
int k = 0; k <= n; ++k) {
396 sum += binomial_coefficients_[n][k];
401 DCHECK_EQ(max_card_ * (1 << (max_card_ - 1)),
402 base_offset_[max_card_] + max_card_);
406 template <
typename Set,
typename CostType>
411 uint64_t local_offset = 0;
413 for (
int node : set) {
416 local_offset += binomial_coefficients_[node][node_rank + 1];
427 return base_offset_[card] + card * local_offset;
430 template <
typename Set,
typename CostType>
436 template <
typename Set,
typename CostType>
439 return ValueAtOffset(Offset(set, node));
442 template <
typename Set,
typename CostType>
446 SetValueAtOffset(Offset(set, node),
value);
452 template <
typename CostType,
typename CostFunction>
517 template <
typename T,
521 struct SaturatedArithmetic {
522 static T Add(T
a, T
b) {
return a +
b; }
523 static T Sub(T
a, T
b) {
return a -
b; }
525 template <
bool Dummy>
526 struct SaturatedArithmetic<int64_t, Dummy> {
527 static int64_t Add(int64_t
a, int64_t
b) {
return CapAdd(
a,
b); }
528 static int64_t Sub(int64_t
a, int64_t
b) {
return CapSub(
a,
b); }
531 template <
bool Dummy>
532 struct SaturatedArithmetic<int32_t, Dummy> {
533 static int32_t Add(int32_t
a, int32_t
b) {
534 const int64_t a64 =
a;
535 const int64_t b64 =
b;
538 return static_cast<int32_t
>(
541 static int32_t Sub(int32_t
a, int32_t
b) {
542 const int64_t a64 =
a;
543 const int64_t b64 =
b;
546 return static_cast<int32_t
>(
551 template <
typename T>
552 using Saturated = SaturatedArithmetic<T>;
555 CostType Cost(
int i,
int j) {
return cost_(i, j); }
561 std::vector<int> ComputePath(CostType
cost,
NodeSet set,
int end);
564 bool PathIsValid(
const std::vector<int>& path, CostType
cost);
567 MatrixOrFunction<CostType, CostFunction, true> cost_;
576 std::vector<CostType> hamiltonian_costs_;
579 bool triangle_inequality_ok_;
580 bool robustness_checked_;
581 bool triangle_inequality_checked_;
583 std::vector<int> tsp_path_;
587 std::vector<std::vector<int>> hamiltonian_paths_;
592 int best_hamiltonian_path_end_node_;
594 LatticeMemoryManager<NodeSet, CostType> mem_;
598 template <
typename CostType,
typename CostFunction>
600 int num_nodes, CostFunction
cost) {
605 template <
typename CostType,
typename CostFunction>
610 template <
typename CostType,
typename CostFunction>
612 int num_nodes, CostFunction
cost)
613 : cost_(std::move(
cost)),
614 num_nodes_(num_nodes),
616 hamiltonian_costs_(0),
618 triangle_inequality_ok_(true),
619 robustness_checked_(false),
620 triangle_inequality_checked_(false),
626 template <
typename CostType,
typename CostFunction>
629 ChangeCostMatrix(
cost.size(),
cost);
632 template <
typename CostType,
typename CostFunction>
634 int num_nodes, CostFunction
cost) {
635 robustness_checked_ =
false;
636 triangle_inequality_checked_ =
false;
639 num_nodes_ = num_nodes;
640 CHECK_GE(NodeSet::MaxCardinality, num_nodes_);
641 CHECK(cost_.Check());
644 template <
typename CostType,
typename CostFunction>
647 if (num_nodes_ == 0) {
650 hamiltonian_paths_.resize(1);
651 hamiltonian_costs_.resize(1);
652 best_hamiltonian_path_end_node_ = 0;
653 hamiltonian_costs_[0] = 0;
654 hamiltonian_paths_[0] = {0};
657 mem_.Init(num_nodes_);
660 for (
int dest = 0; dest < num_nodes_; ++dest) {
661 DCHECK_EQ(dest, mem_.BaseOffset(1, NodeSet::Singleton(dest)));
662 mem_.SetValueAtOffset(dest, Cost(0, dest));
667 for (
int card = 2; card <= num_nodes_; ++card) {
670 SetRangeWithCardinality<Set<uint32_t>>(card, num_nodes_)) {
673 const uint64_t set_offset = mem_.BaseOffset(card, set);
677 uint64_t subset_offset =
678 mem_.BaseOffset(card - 1, set.RemoveSmallestElement());
679 int prev_dest = set.SmallestElement();
681 for (
int dest : set) {
683 const NodeSet subset = set.RemoveElement(dest);
687 subset_offset += mem_.OffsetDelta(card - 1, prev_dest, dest, dest_rank);
689 for (
int src : subset) {
691 min_cost, Saturated<CostType>::Add(
693 mem_.ValueAtOffset(subset_offset + src_rank)));
697 mem_.SetValueAtOffset(set_offset + dest_rank, min_cost);
703 const NodeSet full_set = NodeSet::FullSet(num_nodes_);
707 tsp_cost_ = mem_.Value(full_set, 0);
708 tsp_path_ = ComputePath(tsp_cost_, full_set, 0);
710 hamiltonian_paths_.resize(num_nodes_);
711 hamiltonian_costs_.resize(num_nodes_);
716 const NodeSet hamiltonian_set = full_set.RemoveElement(0);
717 for (
int end_node : hamiltonian_set) {
718 const CostType
cost = mem_.Value(hamiltonian_set, end_node);
719 hamiltonian_costs_[end_node] =
cost;
720 if (
cost <= min_hamiltonian_cost) {
721 min_hamiltonian_cost =
cost;
722 best_hamiltonian_path_end_node_ = end_node;
724 DCHECK_LE(tsp_cost_, Saturated<CostType>::Add(
cost, Cost(end_node, 0)));
726 hamiltonian_paths_[end_node] =
727 ComputePath(hamiltonian_costs_[end_node], hamiltonian_set, end_node);
733 template <
typename CostType,
typename CostFunction>
734 std::vector<int> HamiltonianPathSolver<CostType, CostFunction>::ComputePath(
735 CostType
cost, NodeSet set,
int end_node) {
736 DCHECK(set.Contains(end_node));
737 const int path_size = set.Cardinality() + 1;
738 std::vector<int> path(path_size, 0);
739 NodeSet subset = set.RemoveElement(end_node);
740 path[path_size - 1] = end_node;
742 CostType current_cost =
cost;
743 for (
int rank = path_size - 2; rank >= 0; --rank) {
744 for (
int src : subset) {
745 const CostType partial_cost = mem_.Value(subset, src);
746 const CostType incumbent_cost =
747 Saturated<CostType>::Add(partial_cost, Cost(src, dest));
750 if (std::abs(Saturated<CostType>::Sub(current_cost, incumbent_cost)) <=
751 std::numeric_limits<CostType>::epsilon() * current_cost) {
752 subset = subset.RemoveElement(src);
753 current_cost = partial_cost;
765 template <
typename CostType,
typename CostFunction>
766 bool HamiltonianPathSolver<CostType, CostFunction>::PathIsValid(
767 const std::vector<int>& path, CostType
cost) {
769 for (
int node : path) {
770 coverage = coverage.AddElement(node);
772 DCHECK_EQ(NodeSet::FullSet(num_nodes_).
value(), coverage.value());
773 CostType check_cost = 0;
774 for (
int i = 0; i < path.size() - 1; ++i) {
776 Saturated<CostType>::Add(check_cost, Cost(path[i], path[i + 1]));
778 DCHECK_LE(std::abs(Saturated<CostType>::Sub(
cost, check_cost)),
779 std::numeric_limits<CostType>::epsilon() *
cost)
780 <<
"cost = " <<
cost <<
" check_cost = " << check_cost;
784 template <
typename CostType,
typename CostFunction>
786 if (std::numeric_limits<CostType>::is_integer)
return true;
787 if (robustness_checked_)
return robust_;
792 for (
int i = 0; i < num_nodes_; ++i) {
793 for (
int j = 0; j < num_nodes_; ++j) {
794 if (i == j)
continue;
795 min_cost =
std::min(min_cost, Cost(i, j));
796 max_cost =
std::max(max_cost, Cost(i, j));
802 min_cost >= 0 && min_cost > num_nodes_ * max_cost *
803 std::numeric_limits<CostType>::epsilon();
804 robustness_checked_ =
true;
808 template <
typename CostType,
typename CostFunction>
810 CostFunction>::VerifiesTriangleInequality() {
811 if (triangle_inequality_checked_)
return triangle_inequality_ok_;
812 triangle_inequality_ok_ =
true;
813 triangle_inequality_checked_ =
true;
814 for (
int k = 0; k < num_nodes_; ++k) {
815 for (
int i = 0; i < num_nodes_; ++i) {
816 for (
int j = 0; j < num_nodes_; ++j) {
817 const CostType detour_cost =
818 Saturated<CostType>::Add(Cost(i, k), Cost(k, j));
819 if (detour_cost < Cost(i, j)) {
820 triangle_inequality_ok_ =
false;
821 return triangle_inequality_ok_;
826 return triangle_inequality_ok_;
829 template <
typename CostType,
typename CostFunction>
831 CostFunction>::BestHamiltonianPathEndNode() {
833 return best_hamiltonian_path_end_node_;
836 template <
typename CostType,
typename CostFunction>
840 return hamiltonian_costs_[end_node];
843 template <
typename CostType,
typename CostFunction>
847 return hamiltonian_paths_[end_node];
850 template <
typename CostType,
typename CostFunction>
852 std::vector<PathNodeIndex>* path) {
853 *path = HamiltonianPath(best_hamiltonian_path_end_node_);
856 template <
typename CostType,
typename CostFunction>
863 template <
typename CostType,
typename CostFunction>
870 template <
typename CostType,
typename CostFunction>
872 std::vector<PathNodeIndex>* path) {
873 *path = TravelingSalesmanPath();
876 template <
typename CostType,
typename CostFunction>
907 CostType Cost(
int i,
int j) {
return cost_(i, j); }
910 void Solve(
int end_node);
913 CostType ComputeFutureLowerBound(
NodeSet current_set,
int last_visited);
931 template <
typename CostType,
typename CostFunction>
936 template <
typename CostType,
typename CostFunction>
938 int num_nodes, CostFunction
cost)
939 : cost_(std::move(
cost)),
940 num_nodes_(num_nodes),
944 template <
typename CostType,
typename CostFunction>
946 if (solved_ || num_nodes_ == 0)
return;
952 mem_.Init(num_nodes_);
953 NodeSet start_set = NodeSet::Singleton(0);
954 std::stack<std::pair<NodeSet, int>> state_stack;
955 state_stack.push(std::make_pair(start_set, 0));
957 while (!state_stack.empty()) {
958 const std::pair<NodeSet, int> current = state_stack.top();
961 const NodeSet current_set = current.first;
962 const int last_visited = current.second;
963 const CostType current_cost = mem_.Value(current_set, last_visited);
966 for (
int next_to_visit = 0; next_to_visit < num_nodes_; next_to_visit++) {
970 if (current_set.Contains(next_to_visit))
continue;
973 const int next_cardinality = current_set.Cardinality() + 1;
974 if (next_to_visit == end_node && next_cardinality != num_nodes_)
continue;
976 const NodeSet next_set = current_set.AddElement(next_to_visit);
977 const CostType next_cost =
978 current_cost + Cost(last_visited, next_to_visit);
981 const CostType previous_best = mem_.Value(next_set, next_to_visit);
982 if (previous_best != 0 && next_cost >= previous_best)
continue;
987 ComputeFutureLowerBound(next_set, next_to_visit);
988 if (tsp_cost_ != 0 && next_cost +
lower_bound >= tsp_cost_)
continue;
991 if (next_cardinality == num_nodes_) {
992 tsp_cost_ = next_cost;
997 mem_.SetValue(next_set, next_to_visit, next_cost);
998 state_stack.push(std::make_pair(next_set, next_to_visit));
1005 template <
typename CostType,
typename CostFunction>
1012 template <
typename CostType,
typename CostFunction>
1015 NodeSet current_set,
int last_visited) {
#define DCHECK_LE(val1, val2)
#define CHECK_GE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
const ElementIterator & operator++()
bool operator!=(const ElementIterator &other) const
CostType HamiltonianCost(int end_node)
void ChangeCostMatrix(CostFunction cost)
void ChangeCostMatrix(int num_nodes, CostFunction cost)
void TravelingSalesmanPath(std::vector< PathNodeIndex > *path)
std::vector< int > TravelingSalesmanPath()
bool VerifiesTriangleInequality()
std::vector< int > HamiltonianPath(int end_node)
void HamiltonianPath(std::vector< PathNodeIndex > *path)
HamiltonianPathSolver(CostFunction cost)
CostType TravelingSalesmanCost()
HamiltonianPathSolver(int num_nodes, CostFunction cost)
int BestHamiltonianPathEndNode()
uint64_t Offset(Set s, int node) const
void SetValue(Set s, int node, CostType value)
uint64_t OffsetDelta(int card, int added_node, int removed_node, int rank) const
void SetValueAtOffset(uint64_t offset, CostType value)
CostType Value(Set s, int node) const
uint64_t BaseOffset(int card, Set s) const
CostType ValueAtOffset(uint64_t offset) const
CostType HamiltonianCost(int end_node)
PruningHamiltonianSolver(CostFunction cost)
static const int MaxCardinality
bool Contains(int n) const
Set RemoveElement(int n) const
ElementIterator< Set > begin() const
int SingletonRank(Set singleton) const
int ElementRank(int n) const
bool operator!=(const Set &other) const
Set RemoveSmallestElement() const
Set SmallestSingleton() const
ElementIterator< Set > end() const
static constexpr Integer One
bool Includes(Set other) const
int SmallestElement() const
static Set Singleton(Integer n)
static constexpr Integer Zero
static Set FullSet(Integer card)
Set AddElement(int n) const
SetRange::SetType SetType
SetType::IntegerType IntegerType
bool operator!=(const SetRangeIterator &other) const
const SetRangeIterator & operator++()
SetRangeIterator(const SetType set)
SetType operator*() const
SetRangeIterator< SetRangeWithCardinality > begin() const
SetRangeWithCardinality(int card, int max_card)
SetRangeIterator< SetRangeWithCardinality > end() const
static const int32_t kint32min
static const int32_t kint32max
CpSolverResponse Solve(const CpModelProto &model_proto)
Solves the given CpModelProto and returns an instance of CpSolverResponse.
Collection of objects used to extend the Constraint Solver library.
int64_t CapAdd(int64_t x, int64_t y)
uint32_t BitCount32(uint32_t n)
int64_t CapSub(int64_t x, int64_t y)
HamiltonianPathSolver< CostType, CostFunction > MakeHamiltonianPathSolver(int num_nodes, CostFunction cost)
uint64_t BitCount64(uint64_t n)
int LeastSignificantBitPosition64(uint64_t n)
int LeastSignificantBitPosition32(uint32_t n)