121 #ifndef OR_TOOLS_GRAPH_ONE_TREE_LOWER_BOUND_H_
122 #define OR_TOOLS_GRAPH_ONE_TREE_LOWER_BOUND_H_
133 #include "ortools/base/integral_types.h"
156 template <
typename CostType>
160 : step1_initialized_(false),
163 max_iterations_(max_iterations > 0 ? max_iterations
164 : MaxIterations(number_of_nodes)),
165 number_of_nodes_(number_of_nodes) {}
167 bool Next() {
return iteration_++ < max_iterations_; }
170 return (1.0 * (iteration_ - 1) * (2 * max_iterations_ - 5) /
171 (2 * (max_iterations_ - 1))) *
173 (iteration_ - 2) * step1_ +
174 (0.5 * (iteration_ - 1) * (iteration_ - 2) /
175 ((max_iterations_ - 1) * (max_iterations_ - 2))) *
180 const std::vector<int>& degrees) {
181 if (!step1_initialized_) {
182 step1_initialized_ =
true;
183 UpdateStep(one_tree_cost);
187 void OnNewWMax(CostType one_tree_cost) { UpdateStep(one_tree_cost); }
192 static int MaxIterations(
int number_of_nodes) {
193 return static_cast<int>(28 * std::pow(number_of_nodes, 0.62));
196 void UpdateStep(CostType one_tree_cost) {
197 step1_ = one_tree_cost / (2 * number_of_nodes_);
200 bool step1_initialized_;
203 const int max_iterations_;
204 const int number_of_nodes_;
209 template <
typename CostType,
typename CostFunction>
214 number_of_iterations_(2 * number_of_nodes),
221 number_of_nodes, cost);
226 const int min_iterations = 2;
227 if (iteration_ >= number_of_iterations_) {
228 number_of_iterations_ /= 2;
229 if (number_of_iterations_ < min_iterations)
return false;
241 const std::vector<int>& degrees) {
243 for (
int degree : degrees) {
244 const double delta = degree - 2;
245 norm += delta * delta;
247 step_ = lambda_ * (upper_bound_ - w) / norm;
254 int number_of_iterations_;
255 CostType upper_bound_;
265 template <
typename CostFunction>
267 int number_of_neighbors,
268 const CostFunction& cost) {
269 using CostType = decltype(cost(0, 0));
270 std::set<std::pair<int, int>> nearest;
271 for (
int i = 0; i < number_of_nodes; ++i) {
272 std::vector<std::pair<CostType, int>> neighbors;
273 neighbors.reserve(number_of_nodes - 1);
274 for (
int j = 0; j < number_of_nodes; ++j) {
276 neighbors.emplace_back(cost(i, j), j);
279 int size = neighbors.size();
280 if (number_of_neighbors < size) {
281 std::nth_element(neighbors.begin(),
282 neighbors.begin() + number_of_neighbors - 1,
284 size = number_of_neighbors;
286 for (
int j = 0; j < size; ++j) {
287 nearest.insert({i, neighbors[j].second});
288 nearest.insert({neighbors[j].second, i});
296 template <
typename CostFunction>
298 const CostFunction& cost,
299 std::set<std::pair<int, int>>* arcs) {
301 const std::vector<int> mst =
303 return cost(graph.
Tail(arc), graph.
Head(arc));
305 for (
int arc : mst) {
306 arcs->insert({graph.
Tail(arc), graph.
Head(arc)});
307 arcs->insert({graph.
Head(arc), graph.
Tail(arc)});
313 template <
typename CostFunction,
typename GraphType,
typename AcceptFunction>
315 const CostFunction& cost,
316 AcceptFunction accept) {
318 double best_edge_cost = 0;
319 for (
const auto node : graph.AllNodes()) {
321 const double edge_cost = cost(node, source);
322 if (best_node == -1 || edge_cost < best_edge_cost) {
324 best_edge_cost = edge_cost;
334 template <
typename CostFunction,
typename GraphType,
typename CostType>
336 const CostFunction& cost,
337 const std::vector<double>& weights,
338 const std::vector<int>& sorted_arcs,
339 CostType* one_tree_cost) {
340 const auto weighed_cost = [&cost, &weights](
int from,
int to) {
341 return cost(from, to) + weights[from] + weights[to];
344 std::vector<int> mst;
345 if (!sorted_arcs.empty()) {
346 mst = BuildKruskalMinimumSpanningTreeFromSortedArcs<GraphType>(graph,
349 mst = BuildPrimMinimumSpanningTree<GraphType>(
350 graph, [&weighed_cost, &graph](
int arc) {
351 return weighed_cost(graph.Tail(arc), graph.Head(arc));
354 std::vector<int> degrees(graph.num_nodes() + 1, 0);
356 for (
int arc : mst) {
357 degrees[graph.Head(arc)]++;
358 degrees[graph.Tail(arc)]++;
359 *one_tree_cost += cost(graph.Tail(arc), graph.Head(arc));
363 const int extra_node = graph.num_nodes();
364 const auto update_one_tree = [extra_node, one_tree_cost, °rees,
366 *one_tree_cost += cost(node, extra_node);
371 graph, extra_node, weighed_cost,
372 [extra_node](
int n) {
return n != extra_node; });
373 update_one_tree(node);
375 graph, extra_node, weighed_cost,
376 [extra_node, node](
int n) {
return n != extra_node && n != node; }));
381 template <
typename CostFunction,
typename Algorithm>
383 int nearest_neighbors,
384 const CostFunction& cost,
385 Algorithm* algorithm) {
386 if (number_of_nodes < 2)
return 0;
387 if (number_of_nodes == 2)
return cost(0, 1) + cost(1, 0);
388 using CostType = decltype(cost(0, 0));
389 auto nearest =
NearestNeighbors(number_of_nodes - 1, nearest_neighbors, cost);
395 for (
const auto& arc : nearest) {
396 graph.
AddArc(arc.first, arc.second);
398 std::vector<double> weights(number_of_nodes, 0);
399 std::vector<double> best_weights(number_of_nodes, 0);
400 double max_w = -std::numeric_limits<double>::infinity();
403 while (algorithm->Next()) {
404 CostType one_tree_cost = 0;
405 const std::vector<int> degrees =
407 algorithm->OnOneTree(one_tree_cost, w, degrees);
409 for (
int j = 0; j < number_of_nodes; ++j) {
410 w += weights[j] * (degrees[j] - 2);
414 best_weights = weights;
415 algorithm->OnNewWMax(one_tree_cost);
417 const double step = algorithm->GetStep();
418 for (
int j = 0; j < number_of_nodes; ++j) {
419 weights[j] += step * (degrees[j] - 2);
426 CostType one_tree_cost = 0;
430 const std::vector<int> degrees =
431 ComputeOneTree(complete_graph, cost, best_weights, {}, &one_tree_cost);
433 for (
int j = 0; j < number_of_nodes; ++j) {
434 w += best_weights[j] * (degrees[j] - 2);
455 template <
typename CostFunction>
457 int number_of_nodes,
const CostFunction& cost,
459 using CostType = decltype(cost(0, 0));
470 number_of_nodes, cost);
475 LOG(ERROR) <<
"Unsupported algorithm: " << parameters.
algorithm;
483 template <
typename CostFunction>
CostType TravelingSalesmanCost()
void OnNewWMax(CostType one_tree_cost)
void OnOneTree(CostType one_tree_cost, double w, const std::vector< int > °rees)
HeldWolfeCrowderEvaluator(int number_of_nodes, const CostFunction &cost)
VolgenantJonkerEvaluator(int number_of_nodes, int max_iterations)
void OnNewWMax(CostType one_tree_cost)
void OnOneTree(CostType one_tree_cost, double w, const std::vector< int > °rees)
NodeIndexType Tail(ArcIndexType arc) const
NodeIndexType Head(ArcIndexType arc) const
ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head)
std::set< std::pair< int, int > > NearestNeighbors(int number_of_nodes, int number_of_neighbors, const CostFunction &cost)
std::vector< typename Graph::ArcIndex > BuildPrimMinimumSpanningTree(const Graph &graph, const ArcValue &arc_value)
double ComputeOneTreeLowerBoundWithAlgorithm(int number_of_nodes, int nearest_neighbors, const CostFunction &cost, Algorithm *algorithm)
double ComputeOneTreeLowerBoundWithParameters(int number_of_nodes, const CostFunction &cost, const TravelingSalesmanLowerBoundParameters ¶meters)
std::vector< int > ComputeOneTree(const GraphType &graph, const CostFunction &cost, const std::vector< double > &weights, const std::vector< int > &sorted_arcs, CostType *one_tree_cost)
void AddArcsFromMinimumSpanningTree(int number_of_nodes, const CostFunction &cost, std::set< std::pair< int, int >> *arcs)
double ComputeOneTreeLowerBound(int number_of_nodes, const CostFunction &cost)
int GetNodeMinimizingEdgeCostToSource(const GraphType &graph, int source, const CostFunction &cost, AcceptFunction accept)
int volgenant_jonker_iterations