14#ifndef OR_TOOLS_GRAPH_HAMILTONIAN_PATH_H_
15#define OR_TOOLS_GRAPH_HAMILTONIAN_PATH_H_
104template <
typename Set>
109 return current_set_ != other.current_set_;
127template <
typename Integer>
134 static constexpr Integer
One =
static_cast<Integer
>(1);
135 static constexpr Integer
Zero =
static_cast<Integer
>(0);
139 explicit Set(Integer n) : value_(n) {
145 Integer
value()
const {
return value_; }
167 return (value_ & other.value_) == other.value_;
195 return Set(value_ & (singleton.value_ - 1)).Cardinality();
223template <
typename SetRange>
235 return current_set_ != other.current_set_;
242 const IntegerType c = current_set_.SmallestSingleton().value();
247 const IntegerType shift = current_set_.SmallestElement();
248 current_set_ = r == 0 ?
SetType(0) :
SetType(((r ^
a) >> (shift + 2)) | r);
257template <
typename Set>
265 : begin_(
Set::FullSet(card)),
266 end_(
Set::FullSet(card - 1).AddElement(max_card)) {
291template <
typename Set,
typename CostType>
314 (binomial_coefficients_[added_node][rank] -
315 binomial_coefficients_[removed_node][rank]);
325 memory_[offset] =
value;
339 bool CheckConsistency()
const;
346 std::vector<std::vector<uint64_t>> binomial_coefficients_;
350 std::vector<int64_t> base_offset_;
354 std::vector<CostType> memory_;
357template <
typename Set,
typename CostType>
361 if (max_card <= max_card_)
return;
362 max_card_ = max_card;
363 binomial_coefficients_.resize(max_card_ + 1);
366 for (
int n = 0; n <= max_card_; ++n) {
367 binomial_coefficients_[n].resize(n + 2);
368 binomial_coefficients_[n][0] = 1;
369 for (
int k = 1; k <= n; ++k) {
370 binomial_coefficients_[n][k] = binomial_coefficients_[n - 1][k - 1] +
371 binomial_coefficients_[n - 1][k];
375 binomial_coefficients_[n][n + 1] = 0;
377 base_offset_.resize(max_card_ + 1);
382 for (
int k = 0; k < max_card_; ++k) {
383 base_offset_[k + 1] =
384 base_offset_[k] + k * binomial_coefficients_[max_card_][k];
387 memory_.shrink_to_fit();
388 memory_.resize(max_card_ * (1 << (max_card_ - 1)));
389 DCHECK(CheckConsistency());
392template <
typename Set,
typename CostType>
394 for (
int n = 0; n <= max_card_; ++n) {
396 for (
int k = 0; k <= n; ++k) {
397 sum += binomial_coefficients_[n][k];
402 DCHECK_EQ(max_card_ * (1 << (max_card_ - 1)),
403 base_offset_[max_card_] + max_card_);
407template <
typename Set,
typename CostType>
412 uint64_t local_offset = 0;
414 for (
int node : set) {
417 local_offset += binomial_coefficients_[node][node_rank + 1];
428 return base_offset_[card] + card * local_offset;
431template <
typename Set,
typename CostType>
437template <
typename Set,
typename CostType>
440 return ValueAtOffset(Offset(set, node));
443template <
typename Set,
typename CostType>
447 SetValueAtOffset(Offset(set, node),
value);
453template <
typename CostType,
typename CostFunction>
518 template <
typename T,
522 struct SaturatedArithmetic {
523 static T Add(T
a, T
b) {
return a +
b; }
524 static T Sub(T
a, T
b) {
return a -
b; }
526 template <
bool Dummy>
527 struct SaturatedArithmetic<int64_t, Dummy> {
528 static int64_t Add(int64_t
a, int64_t
b) {
return CapAdd(
a,
b); }
529 static int64_t Sub(int64_t
a, int64_t
b) {
return CapSub(
a,
b); }
532 template <
bool Dummy>
533 struct SaturatedArithmetic<int32_t, Dummy> {
534 static int32_t Add(int32_t
a, int32_t
b) {
535 const int64_t a64 =
a;
536 const int64_t b64 =
b;
539 return static_cast<int32_t
>(
542 static int32_t Sub(int32_t
a, int32_t
b) {
543 const int64_t a64 =
a;
544 const int64_t b64 =
b;
547 return static_cast<int32_t
>(
552 template <
typename T>
553 using Saturated = SaturatedArithmetic<T>;
556 CostType Cost(
int i,
int j) {
return cost_(i, j); }
562 std::vector<int> ComputePath(CostType
cost,
NodeSet set,
int end);
565 bool PathIsValid(
const std::vector<int>& path, CostType
cost);
568 MatrixOrFunction<CostType, CostFunction, true> cost_;
577 std::vector<CostType> hamiltonian_costs_;
580 bool triangle_inequality_ok_;
581 bool robustness_checked_;
582 bool triangle_inequality_checked_;
584 std::vector<int> tsp_path_;
588 std::vector<std::vector<int>> hamiltonian_paths_;
593 int best_hamiltonian_path_end_node_;
595 LatticeMemoryManager<NodeSet, CostType> mem_;
599template <
typename CostType,
typename CostFunction>
601 int num_nodes, CostFunction
cost) {
606template <
typename CostType,
typename CostFunction>
611template <
typename CostType,
typename CostFunction>
613 int num_nodes, CostFunction
cost)
615 num_nodes_(num_nodes),
617 hamiltonian_costs_(0),
619 triangle_inequality_ok_(true),
620 robustness_checked_(false),
621 triangle_inequality_checked_(false),
627template <
typename CostType,
typename CostFunction>
630 ChangeCostMatrix(
cost.size(),
cost);
633template <
typename CostType,
typename CostFunction>
635 int num_nodes, CostFunction
cost) {
636 robustness_checked_ =
false;
637 triangle_inequality_checked_ =
false;
640 num_nodes_ = num_nodes;
641 CHECK_GE(NodeSet::MaxCardinality, num_nodes_);
642 CHECK(cost_.Check());
645template <
typename CostType,
typename CostFunction>
648 if (num_nodes_ == 0) {
651 hamiltonian_paths_.resize(1);
652 hamiltonian_costs_.resize(1);
653 best_hamiltonian_path_end_node_ = 0;
654 hamiltonian_costs_[0] = 0;
655 hamiltonian_paths_[0] = {0};
658 mem_.Init(num_nodes_);
661 for (
int dest = 0; dest < num_nodes_; ++dest) {
662 DCHECK_EQ(dest, mem_.BaseOffset(1, NodeSet::Singleton(dest)));
663 mem_.SetValueAtOffset(dest, Cost(0, dest));
668 for (
int card = 2; card <= num_nodes_; ++card) {
671 SetRangeWithCardinality<Set<uint32_t>>(card, num_nodes_)) {
674 const uint64_t set_offset = mem_.BaseOffset(card, set);
678 uint64_t subset_offset =
679 mem_.BaseOffset(card - 1, set.RemoveSmallestElement());
680 int prev_dest = set.SmallestElement();
682 for (
int dest : set) {
684 const NodeSet subset = set.RemoveElement(dest);
688 subset_offset += mem_.OffsetDelta(card - 1, prev_dest, dest, dest_rank);
690 for (
int src : subset) {
692 min_cost, Saturated<CostType>::Add(
694 mem_.ValueAtOffset(subset_offset + src_rank)));
698 mem_.SetValueAtOffset(set_offset + dest_rank, min_cost);
704 const NodeSet full_set = NodeSet::FullSet(num_nodes_);
708 tsp_cost_ = mem_.Value(full_set, 0);
709 tsp_path_ = ComputePath(tsp_cost_, full_set, 0);
711 hamiltonian_paths_.resize(num_nodes_);
712 hamiltonian_costs_.resize(num_nodes_);
717 const NodeSet hamiltonian_set = full_set.RemoveElement(0);
718 for (
int end_node : hamiltonian_set) {
719 const CostType
cost = mem_.Value(hamiltonian_set, end_node);
720 hamiltonian_costs_[end_node] =
cost;
721 if (
cost <= min_hamiltonian_cost) {
722 min_hamiltonian_cost =
cost;
723 best_hamiltonian_path_end_node_ = end_node;
725 DCHECK_LE(tsp_cost_, Saturated<CostType>::Add(
cost, Cost(end_node, 0)));
727 hamiltonian_paths_[end_node] =
728 ComputePath(hamiltonian_costs_[end_node], hamiltonian_set, end_node);
734template <
typename CostType,
typename CostFunction>
735std::vector<int> HamiltonianPathSolver<CostType, CostFunction>::ComputePath(
736 CostType
cost, NodeSet set,
int end_node) {
737 DCHECK(set.Contains(end_node));
738 const int path_size = set.Cardinality() + 1;
739 std::vector<int> path(path_size, 0);
740 NodeSet subset = set.RemoveElement(end_node);
741 path[path_size - 1] = end_node;
743 CostType current_cost =
cost;
744 for (
int rank = path_size - 2; rank >= 0; --rank) {
745 for (
int src : subset) {
746 const CostType partial_cost = mem_.Value(subset, src);
747 const CostType incumbent_cost =
748 Saturated<CostType>::Add(partial_cost, Cost(src, dest));
751 if (std::abs(Saturated<CostType>::Sub(current_cost, incumbent_cost)) <=
752 std::numeric_limits<CostType>::epsilon() * current_cost) {
753 subset = subset.RemoveElement(src);
754 current_cost = partial_cost;
766template <
typename CostType,
typename CostFunction>
767bool HamiltonianPathSolver<CostType, CostFunction>::PathIsValid(
768 const std::vector<int>& path, CostType
cost) {
770 for (
int node : path) {
771 coverage = coverage.AddElement(node);
773 DCHECK_EQ(NodeSet::FullSet(num_nodes_).
value(), coverage.value());
774 CostType check_cost = 0;
775 for (
int i = 0; i < path.size() - 1; ++i) {
777 Saturated<CostType>::Add(check_cost, Cost(path[i], path[i + 1]));
779 DCHECK_LE(std::abs(Saturated<CostType>::Sub(
cost, check_cost)),
780 std::numeric_limits<CostType>::epsilon() *
cost)
781 <<
"cost = " <<
cost <<
" check_cost = " << check_cost;
785template <
typename CostType,
typename CostFunction>
787 if (std::numeric_limits<CostType>::is_integer)
return true;
788 if (robustness_checked_)
return robust_;
793 for (
int i = 0; i < num_nodes_; ++i) {
794 for (
int j = 0; j < num_nodes_; ++j) {
795 if (i == j)
continue;
796 min_cost =
std::min(min_cost, Cost(i, j));
797 max_cost =
std::max(max_cost, Cost(i, j));
803 min_cost >= 0 && min_cost > num_nodes_ * max_cost *
804 std::numeric_limits<CostType>::epsilon();
805 robustness_checked_ =
true;
809template <
typename CostType,
typename CostFunction>
811 CostFunction>::VerifiesTriangleInequality() {
812 if (triangle_inequality_checked_)
return triangle_inequality_ok_;
813 triangle_inequality_ok_ =
true;
814 triangle_inequality_checked_ =
true;
815 for (
int k = 0; k < num_nodes_; ++k) {
816 for (
int i = 0; i < num_nodes_; ++i) {
817 for (
int j = 0; j < num_nodes_; ++j) {
818 const CostType detour_cost =
819 Saturated<CostType>::Add(Cost(i, k), Cost(k, j));
820 if (detour_cost < Cost(i, j)) {
821 triangle_inequality_ok_ =
false;
822 return triangle_inequality_ok_;
827 return triangle_inequality_ok_;
830template <
typename CostType,
typename CostFunction>
832 CostFunction>::BestHamiltonianPathEndNode() {
834 return best_hamiltonian_path_end_node_;
837template <
typename CostType,
typename CostFunction>
841 return hamiltonian_costs_[end_node];
844template <
typename CostType,
typename CostFunction>
848 return hamiltonian_paths_[end_node];
851template <
typename CostType,
typename CostFunction>
853 std::vector<PathNodeIndex>* path) {
854 *path = HamiltonianPath(best_hamiltonian_path_end_node_);
857template <
typename CostType,
typename CostFunction>
864template <
typename CostType,
typename CostFunction>
871template <
typename CostType,
typename CostFunction>
873 std::vector<PathNodeIndex>* path) {
874 *path = TravelingSalesmanPath();
877template <
typename CostType,
typename CostFunction>
908 CostType Cost(
int i,
int j) {
return cost_(i, j); }
911 void Solve(
int end_node);
914 CostType ComputeFutureLowerBound(
NodeSet current_set,
int last_visited);
932template <
typename CostType,
typename CostFunction>
937template <
typename CostType,
typename CostFunction>
939 int num_nodes, CostFunction
cost)
941 num_nodes_(num_nodes),
945template <
typename CostType,
typename CostFunction>
947 if (solved_ || num_nodes_ == 0)
return;
953 mem_.Init(num_nodes_);
954 NodeSet start_set = NodeSet::Singleton(0);
955 std::stack<std::pair<NodeSet, int>> state_stack;
956 state_stack.push(std::make_pair(start_set, 0));
958 while (!state_stack.empty()) {
959 const std::pair<NodeSet, int> current = state_stack.top();
962 const NodeSet current_set = current.first;
963 const int last_visited = current.second;
964 const CostType current_cost = mem_.Value(current_set, last_visited);
967 for (
int next_to_visit = 0; next_to_visit < num_nodes_; next_to_visit++) {
971 if (current_set.Contains(next_to_visit))
continue;
974 const int next_cardinality = current_set.Cardinality() + 1;
975 if (next_to_visit == end_node && next_cardinality != num_nodes_)
continue;
977 const NodeSet next_set = current_set.AddElement(next_to_visit);
978 const CostType next_cost =
979 current_cost + Cost(last_visited, next_to_visit);
982 const CostType previous_best = mem_.Value(next_set, next_to_visit);
983 if (previous_best != 0 && next_cost >= previous_best)
continue;
988 ComputeFutureLowerBound(next_set, next_to_visit);
989 if (tsp_cost_ != 0 && next_cost +
lower_bound >= tsp_cost_)
continue;
992 if (next_cardinality == num_nodes_) {
993 tsp_cost_ = next_cost;
998 mem_.SetValue(next_set, next_to_visit, next_cost);
999 state_stack.push(std::make_pair(next_set, next_to_visit));
1006template <
typename CostType,
typename CostFunction>
1013template <
typename CostType,
typename CostFunction>
1016 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
ElementIterator< Set > end() const
Set RemoveElement(int n) 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 > begin() 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
SetRangeIterator(const SetType set)
const SetRangeIterator & operator++()
SetType operator*() const
SetRangeIterator< SetRangeWithCardinality > begin() const
SetRangeWithCardinality(int card, int max_card)
SetRangeIterator< SetRangeWithCardinality > end() const
absl::StatusOr< SolveResult > Solve(const Model &model, const SolverType solver_type, const SolveArguments &solve_args, const SolverInitArguments &init_args)
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)
uint64_t BitCount64(uint64_t n)
int LeastSignificantBitPosition64(uint64_t n)
HamiltonianPathSolver< CostType, CostFunction > MakeHamiltonianPathSolver(int num_nodes, CostFunction cost)
int LeastSignificantBitPosition32(uint32_t n)
std::optional< int64_t > end