graph: Add few samples
This commit is contained in:
64
ortools/graph/samples/bfs_directed.cc
Normal file
64
ortools/graph/samples/bfs_directed.cc
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
#include "ortools/graph/bfs.h"
|
||||
|
||||
namespace {
|
||||
|
||||
absl::Status Main() {
|
||||
// The arcs of this directed graph are encoded as a list of pairs, where
|
||||
// .first is the source and .second is the destination of each arc.
|
||||
const std::vector<std::pair<int, int>> arcs = {
|
||||
{0, 1}, {0, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 0}, {3, 5}, {4, 5}};
|
||||
const int num_nodes = 6;
|
||||
|
||||
// Transform the graph to an adjacency_list
|
||||
std::vector<std::vector<int>> adjacency_list(num_nodes);
|
||||
for (const auto& [start, end] : arcs) {
|
||||
adjacency_list[start].push_back(end);
|
||||
}
|
||||
|
||||
// Solve the shortest path problem from 0 to 5.
|
||||
const int source = 0;
|
||||
const int terminal = 5;
|
||||
ASSIGN_OR_RETURN(
|
||||
const std::vector<int> bfs_tree,
|
||||
util::graph::GetBFSRootedTree(adjacency_list, num_nodes, source));
|
||||
ASSIGN_OR_RETURN(const std::vector<int> shortest_path,
|
||||
util::graph::GetBFSShortestPath(bfs_tree, terminal));
|
||||
|
||||
// Print to length of the path and then the nodes in the path.
|
||||
std::cout << "Shortest path length (in arcs): " << shortest_path.size() - 1
|
||||
<< std::endl;
|
||||
std::cout << "Shortest path nodes: " << absl::StrJoin(shortest_path, ", ")
|
||||
<< std::endl;
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
QCHECK_OK(Main());
|
||||
return 0;
|
||||
}
|
||||
72
ortools/graph/samples/bfs_one_to_all.cc
Normal file
72
ortools/graph/samples/bfs_one_to_all.cc
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
#include "ortools/graph/bfs.h"
|
||||
|
||||
namespace {
|
||||
|
||||
absl::Status Main() {
|
||||
// The arcs of this directed graph are encoded as a list of pairs, where
|
||||
// .first is the source and .second is the destination of each arc.
|
||||
const std::vector<std::pair<int, int>> arcs = {{0, 1}, {1, 2}, {1, 3},
|
||||
{2, 3}, {3, 0}, {4, 2}};
|
||||
const int num_nodes = 5;
|
||||
|
||||
// Transform the graph to an adjacency_list
|
||||
std::vector<std::vector<int>> adjacency_list(num_nodes);
|
||||
for (const auto& [start, end] : arcs) {
|
||||
adjacency_list[start].push_back(end);
|
||||
}
|
||||
|
||||
// Compute the shortest path from 0 to each reachable node.
|
||||
const int source = 0;
|
||||
ASSIGN_OR_RETURN(
|
||||
const std::vector<int> bfs_tree,
|
||||
util::graph::GetBFSRootedTree(adjacency_list, num_nodes, source));
|
||||
// Runs in O(num nodes). Nodes that are not reachable have distance -1.
|
||||
ASSIGN_OR_RETURN(const std::vector<int> node_distances,
|
||||
util::graph::GetBFSDistances(bfs_tree));
|
||||
for (int t = 0; t < num_nodes; ++t) {
|
||||
if (t == source) {
|
||||
continue;
|
||||
}
|
||||
if (node_distances[t] >= 0) {
|
||||
ASSIGN_OR_RETURN(const std::vector<int> shortest_path,
|
||||
util::graph::GetBFSShortestPath(bfs_tree, t));
|
||||
std::cout << "Shortest path from 0 to " << t
|
||||
<< " has length: " << node_distances[t] << std::endl;
|
||||
std::cout << "Path is: " << absl::StrJoin(shortest_path, ", ")
|
||||
<< std::endl;
|
||||
} else {
|
||||
std::cout << "No path from 0 to " << t << std::endl;
|
||||
}
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
QCHECK_OK(Main());
|
||||
return 0;
|
||||
}
|
||||
66
ortools/graph/samples/bfs_undirected.cc
Normal file
66
ortools/graph/samples/bfs_undirected.cc
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
#include "ortools/graph/bfs.h"
|
||||
|
||||
namespace {
|
||||
|
||||
absl::Status Main() {
|
||||
// The edges of this undirected graph encoded as a list of pairs, where .first
|
||||
// and .second are the endpoints of each edge (the order does not matter).
|
||||
const std::vector<std::pair<int, int>> edges = {
|
||||
{0, 1}, {0, 2}, {1, 2}, {2, 3}};
|
||||
const int num_nodes = 4;
|
||||
|
||||
// Transform the graph to an adjacency_list
|
||||
std::vector<std::vector<int>> adjacency_list(num_nodes);
|
||||
for (const auto& [node1, node2] : edges) {
|
||||
// Include both orientations of the edge
|
||||
adjacency_list[node1].push_back(node2);
|
||||
adjacency_list[node2].push_back(node1);
|
||||
}
|
||||
|
||||
// Solve the shortest path problem from 0 to 3.
|
||||
const int source = 0;
|
||||
const int terminal = 3;
|
||||
ASSIGN_OR_RETURN(
|
||||
const std::vector<int> bfs_tree,
|
||||
util::graph::GetBFSRootedTree(adjacency_list, num_nodes, source));
|
||||
ASSIGN_OR_RETURN(const std::vector<int> shortest_path,
|
||||
util::graph::GetBFSShortestPath(bfs_tree, terminal));
|
||||
|
||||
// Print to length of the path and then the nodes in the path.
|
||||
std::cout << "Shortest path length (in arcs): " << shortest_path.size() - 1
|
||||
<< std::endl;
|
||||
std::cout << "Shortest path nodes: " << absl::StrJoin(shortest_path, ", ")
|
||||
<< std::endl;
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
QCHECK_OK(Main());
|
||||
return 0;
|
||||
}
|
||||
81
ortools/graph/samples/dag_shortest_path_one_to_all.cc
Normal file
81
ortools/graph/samples/dag_shortest_path_one_to_all.cc
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/base/status_macros.h"
|
||||
#include "ortools/graph/dag_shortest_path.h"
|
||||
#include "ortools/graph/graph.h"
|
||||
#include "ortools/graph/topologicalsorter.h"
|
||||
|
||||
namespace {
|
||||
|
||||
absl::Status Main() {
|
||||
util::StaticGraph<> graph;
|
||||
std::vector<double> weights;
|
||||
graph.AddArc(0, 2);
|
||||
weights.push_back(5.0);
|
||||
graph.AddArc(0, 3);
|
||||
weights.push_back(4.0);
|
||||
graph.AddArc(1, 3);
|
||||
weights.push_back(1.0);
|
||||
graph.AddArc(2, 4);
|
||||
weights.push_back(-3.0);
|
||||
graph.AddArc(3, 4);
|
||||
weights.push_back(0.0);
|
||||
|
||||
// Static graph reorders the arcs at Build() time, use permutation to get
|
||||
// from the old ordering to the new one.
|
||||
std::vector<int32_t> permutation;
|
||||
graph.Build(&permutation);
|
||||
util::Permute(permutation, &weights);
|
||||
|
||||
// We need a topological order. We can find it by hand on this small graph,
|
||||
// e.g., {0, 1, 2, 3, 4}, but we demonstrate how to compute one instead.
|
||||
ASSIGN_OR_RETURN(const std::vector<int32_t> topological_order,
|
||||
util::graph::FastTopologicalSort(graph));
|
||||
|
||||
operations_research::ShortestPathsOnDagWrapper<util::StaticGraph<>>
|
||||
shortest_path_on_dag(&graph, &weights, topological_order);
|
||||
const int source = 0;
|
||||
shortest_path_on_dag.RunShortestPathOnDag({source});
|
||||
|
||||
// For each node other than 0, print its distance and the shortest path.
|
||||
for (int i = 1; i < 5; ++i) {
|
||||
if (shortest_path_on_dag.IsReachable(i)) {
|
||||
std::cout << "Length of shortest path to node " << i << ": "
|
||||
<< shortest_path_on_dag.LengthTo(i) << std::endl;
|
||||
std::cout << "Shortest path to node " << i << ": "
|
||||
<< absl::StrJoin(shortest_path_on_dag.NodePathTo(i), ", ")
|
||||
<< std::endl;
|
||||
|
||||
} else {
|
||||
std::cout << "No path to node: " << i << std::endl;
|
||||
}
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
QCHECK_OK(Main());
|
||||
return 0;
|
||||
}
|
||||
120
ortools/graph/samples/dag_shortest_path_sequential.cc
Normal file
120
ortools/graph/samples/dag_shortest_path_sequential.cc
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// [START imports]
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/graph/dag_shortest_path.h"
|
||||
#include "ortools/graph/graph.h"
|
||||
// [END imports]
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
|
||||
// [START graph]
|
||||
// Create a graph with n + 2 nodes, indexed from 0:
|
||||
// * Node n is `source`
|
||||
// * Node n+1 is `dest`
|
||||
// * Nodes M = [0, 1, ..., n-1] are in the middle.
|
||||
//
|
||||
// The graph has 3 * n - 1 arcs (with weights):
|
||||
// * (source -> i) with weight 100 for i in M
|
||||
// * (i -> dest) with weight 100 for i in M
|
||||
// * (i -> (i+1)) with weight 1 for i = 0, ..., n-2
|
||||
//
|
||||
// Every path [source, i, dest] for i in M is a shortest path from source to
|
||||
// dest with weight 200.
|
||||
const int n = 10;
|
||||
const int source = n;
|
||||
const int dest = n + 1;
|
||||
util::StaticGraph<> graph;
|
||||
// There are 3 types of arcs: (1) source to M, (2) M to dest, and (3) within
|
||||
// M. This vector stores all of them, first of type (1), then type (2),
|
||||
// then type (3). The arcs are ordered by i in M within each type.
|
||||
std::vector<double> weights(3 * n - 1);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
graph.AddArc(source, i);
|
||||
weights[i] = 100.0;
|
||||
}
|
||||
for (int i = 0; i < n; ++i) {
|
||||
graph.AddArc(i, dest);
|
||||
weights[n + i] = 100.0;
|
||||
}
|
||||
for (int i = 0; i + 1 < n; ++i) {
|
||||
graph.AddArc(i, i + 1);
|
||||
weights[2 * n + i] = 1.0;
|
||||
}
|
||||
|
||||
// Static graph reorders the arcs at Build() time, use permutation to get from
|
||||
// the old ordering to the new one.
|
||||
std::vector<int32_t> permutation;
|
||||
graph.Build(&permutation);
|
||||
util::Permute(permutation, &weights);
|
||||
// [END graph]
|
||||
|
||||
// [START first-path]
|
||||
// A reusable shortest path calculator.
|
||||
// We need a topological order. For this structured graph, we find it by hand
|
||||
// instead of using util::graph::FastTopologicalSort().
|
||||
std::vector<int32_t> topological_order = {source};
|
||||
for (int i = 0; i < n; ++i) {
|
||||
topological_order.push_back(i);
|
||||
}
|
||||
topological_order.push_back(dest);
|
||||
|
||||
operations_research::ShortestPathsOnDagWrapper<util::StaticGraph<>>
|
||||
shortest_path_on_dag(&graph, &weights, topological_order);
|
||||
shortest_path_on_dag.RunShortestPathOnDag({source});
|
||||
|
||||
std::cout << "Initial distance: " << shortest_path_on_dag.LengthTo(dest)
|
||||
<< std::endl;
|
||||
std::cout << "Initial path: "
|
||||
<< absl::StrJoin(shortest_path_on_dag.NodePathTo(dest), ", ")
|
||||
<< std::endl;
|
||||
// [END first-path]
|
||||
|
||||
// [START more-paths]
|
||||
// Now, we make a single arc from source to M free, and a single arc from M
|
||||
// to dest free, and resolve. If the free edge from the source hits before
|
||||
// the free edge to the dest in M, we use both, walking through M. Otherwise,
|
||||
// we use only one free arc.
|
||||
std::vector<std::pair<int, int>> fast_paths = {{2, 4}, {8, 1}, {3, 7}};
|
||||
for (const auto [free_from_source, free_to_dest] : fast_paths) {
|
||||
weights[permutation[free_from_source]] = 0;
|
||||
weights[permutation[n + free_to_dest]] = 0;
|
||||
|
||||
shortest_path_on_dag.RunShortestPathOnDag({source});
|
||||
std::cout << "source -> " << free_from_source << " and " << free_to_dest
|
||||
<< " -> dest are now free" << std::endl;
|
||||
std::string label = absl::StrCat("_", free_from_source, "_", free_to_dest);
|
||||
std::cout << "Distance" << label << ": "
|
||||
<< shortest_path_on_dag.LengthTo(dest) << std::endl;
|
||||
std::cout << "Path" << label << ": "
|
||||
<< absl::StrJoin(shortest_path_on_dag.NodePathTo(dest), ", ")
|
||||
<< std::endl;
|
||||
|
||||
// Restore the old weights
|
||||
weights[permutation[free_from_source]] = 100;
|
||||
weights[permutation[n + free_to_dest]] = 100;
|
||||
}
|
||||
// [END more-paths]
|
||||
return 0;
|
||||
}
|
||||
44
ortools/graph/samples/dag_simple_shortest_path.cc
Normal file
44
ortools/graph/samples/dag_simple_shortest_path.cc
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/graph/dag_shortest_path.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
|
||||
// The input graph, encoded as a list of arcs with distances.
|
||||
std::vector<operations_research::ArcWithLength> arcs = {
|
||||
{.tail = 0, .head = 2, .length = 5},
|
||||
{.tail = 0, .head = 3, .length = 4},
|
||||
{.tail = 1, .head = 3, .length = 1},
|
||||
{.tail = 2, .head = 4, .length = -3},
|
||||
{.tail = 3, .head = 4, .length = 0}};
|
||||
const int num_nodes = 5;
|
||||
|
||||
const int source = 0;
|
||||
const int destination = 4;
|
||||
const operations_research::PathWithLength path_with_length =
|
||||
operations_research::ShortestPathsOnDag(num_nodes, arcs, source,
|
||||
destination);
|
||||
|
||||
// Print to length of the path and then the nodes in the path.
|
||||
std::cout << "Shortest path length: " << path_with_length.length << std::endl;
|
||||
std::cout << "Shortest path nodes: "
|
||||
<< absl::StrJoin(path_with_length.node_path, ", ") << std::endl;
|
||||
return 0;
|
||||
}
|
||||
172
ortools/graph/samples/dijkstra_all_pairs_shortest_paths.cc
Normal file
172
ortools/graph/samples/dijkstra_all_pairs_shortest_paths.cc
Normal file
@@ -0,0 +1,172 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Solves all pairs shortest paths (APSP) by repeatedly using Dijkstra's
|
||||
// algorithm.
|
||||
//
|
||||
// This example runs on a randomly generated graph. The nodes are each points
|
||||
// in Euclidean 2D space, placed uniformly at random on [0, 1] * [0, 1]. Two
|
||||
// nodes are connected by an edge if they are within distance L, and the edge
|
||||
// length is the Euclidean distance. We find and return all pairs of points that
|
||||
// connected by a path with distance at most 3*L. As input flags, we take the
|
||||
// number of nodes, and the desired number of neighbors per node. We compute L
|
||||
// from these quantities.
|
||||
//
|
||||
// The problem is naturally modeled on an undirected graph, but our APSP is
|
||||
// implemented for directed graphs, so we include each edge as two arcs.
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/random/random.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/graph/bounded_dijkstra.h"
|
||||
#include "ortools/graph/graph.h"
|
||||
|
||||
ABSL_FLAG(int32_t, num_nodes, 50,
|
||||
"How many nodes to create in the random graph");
|
||||
|
||||
ABSL_FLAG(double, expected_neighbors, 5,
|
||||
"The average number of neighbors of a node, if < 2, then most nodes "
|
||||
"will not be connected.");
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr double kPi = M_PI; // Post C++ 20, prefer std::numbers::pi
|
||||
|
||||
std::vector<std::pair<double, double>> GenerateRandomPoints(int32_t n) {
|
||||
absl::BitGen bit_gen;
|
||||
std::vector<std::pair<double, double>> result(n);
|
||||
for (int32_t i = 0; i < n; ++i) {
|
||||
result[i].first = absl::Uniform(bit_gen, 0.0, 1.0);
|
||||
result[i].second = absl::Uniform(bit_gen, 0.0, 1.0);
|
||||
}
|
||||
absl::c_sort(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
double Distance(const std::pair<double, double>& node1,
|
||||
const std::pair<double, double>& node2) {
|
||||
const double dx = node1.first - node2.first;
|
||||
const double dy = node1.second - node2.second;
|
||||
return std::sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
std::pair<util::StaticGraph<int32_t, int32_t>, std::vector<double>> MakeGraph(
|
||||
const std::vector<std::pair<double, double>>& points,
|
||||
double max_edge_distance) {
|
||||
util::StaticGraph<int32_t, int32_t> graph;
|
||||
CHECK_LE(points.size(),
|
||||
static_cast<size_t>(std::numeric_limits<int32_t>::max()));
|
||||
const int32_t num_nodes = static_cast<int32_t>(points.size());
|
||||
if (num_nodes > 0) {
|
||||
graph.AddNode(num_nodes - 1);
|
||||
}
|
||||
std::vector<double> arcs;
|
||||
for (int32_t i = 0; i < num_nodes; ++i) {
|
||||
for (int32_t j = i + 1; j < num_nodes; ++j) {
|
||||
// We want to add an arc for all pairs of points within max_edge_distance,
|
||||
// but checking all O(n^2) pairs is too slow. The points are sorted by x,
|
||||
// so we can easily exclude points if there x distance exceeds
|
||||
// max_edge_distance.
|
||||
if (points[j].first - points[i].first > max_edge_distance) {
|
||||
break;
|
||||
}
|
||||
const double dist = Distance(points[i], points[j]);
|
||||
if (dist <= max_edge_distance) {
|
||||
graph.AddArc(i, j);
|
||||
arcs.push_back(dist);
|
||||
graph.AddArc(j, i);
|
||||
arcs.push_back(dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<int32_t> permutation;
|
||||
graph.Build(&permutation);
|
||||
util::Permute(permutation, &arcs);
|
||||
|
||||
return {std::move(graph), std::move(arcs)};
|
||||
}
|
||||
|
||||
std::vector<std::pair<int32_t, int32_t>> AllPairsWithinDistance(
|
||||
const util::StaticGraph<int32_t, int32_t>& graph,
|
||||
const std::vector<double>& arc_lengths, double limit) {
|
||||
operations_research::BoundedDijkstraWrapper<util::StaticGraph<>, double>
|
||||
dijkstra(&graph, &arc_lengths);
|
||||
std::vector<std::pair<int32_t, int32_t>> result;
|
||||
for (int32_t start = 0; start < graph.num_nodes(); ++start) {
|
||||
const std::vector<int32_t> reachable =
|
||||
dijkstra.RunBoundedDijkstra(start, limit);
|
||||
for (const int32_t dest : reachable) {
|
||||
result.push_back({start, dest});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
const int32_t n = absl::GetFlag(FLAGS_num_nodes);
|
||||
CHECK_GE(n, 2); // Don't divide by zero below.
|
||||
const double expected_neighbors = absl::GetFlag(FLAGS_expected_neighbors);
|
||||
CHECK_GE(expected_neighbors, 0);
|
||||
const std::vector<std::pair<double, double>> node_locations =
|
||||
GenerateRandomPoints(n);
|
||||
const double expected_edges = n * expected_neighbors / 2.0;
|
||||
// The expected number of neighbors is (n-1)*pi*(max_edge_distance)**2. So
|
||||
// (n-1)*pi*(max_edge_distance)**2 = expected_neighbors
|
||||
// sqrt(expected_neighbors/((n-1) * pi)) = max_edge_distance
|
||||
const double max_edge_distance =
|
||||
std::sqrt(expected_neighbors / ((n - 1) * kPi));
|
||||
std::cout << "Building graph..." << std::endl;
|
||||
const auto [graph, arc_lengths] =
|
||||
MakeGraph(node_locations, max_edge_distance);
|
||||
std::cout << "Done building graph" << std::endl;
|
||||
const double limit = 3 * max_edge_distance;
|
||||
// This is an upper bound on the expected number of connected pairs. You can
|
||||
// only reach points within euclidean distance of limit, but not all these
|
||||
// points will actually be reachable, you need a path of points separated by
|
||||
// at most max_edge_distance.
|
||||
const double estimated_connected_pairs = (kPi * limit * limit * n) * n / 2;
|
||||
std::cout << "Nodes: " << n << std::endl;
|
||||
std::cout << "Estimated neighbors per node: " << expected_neighbors
|
||||
<< std::endl;
|
||||
std::cout << "Max distance for edge: " << max_edge_distance << std::endl;
|
||||
std::cout << "Estimated edges: " << expected_edges << std::endl;
|
||||
std::cout << "Actual edges: " << graph.num_arcs() / 2 << std::endl;
|
||||
std::cout << "All pairs shortest path distance limit: " << limit << std::endl;
|
||||
std::cout << "Upper bound (estimated) on pairs of points within limit: "
|
||||
<< estimated_connected_pairs << std::endl;
|
||||
|
||||
const absl::Time start = absl::Now();
|
||||
const std::vector<std::pair<int, int>> all_pairs_within_distance =
|
||||
AllPairsWithinDistance(graph, arc_lengths, limit);
|
||||
const absl::Duration shortest_path_time = absl::Now() - start;
|
||||
// Our problem is undirected, so everything appears twice.
|
||||
std::cout << "Actual pairs of points within distance limit: "
|
||||
<< all_pairs_within_distance.size() / 2 << std::endl;
|
||||
std::cout << "Shortest path time: " << shortest_path_time << std::endl;
|
||||
return 0;
|
||||
}
|
||||
61
ortools/graph/samples/dijkstra_directed.cc
Normal file
61
ortools/graph/samples/dijkstra_directed.cc
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/graph/bounded_dijkstra.h"
|
||||
|
||||
namespace {
|
||||
struct Arc {
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
int length = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
|
||||
// The input graph, encoded as a list of arcs with distances.
|
||||
std::vector<Arc> arcs = {
|
||||
{.start = 0, .end = 1, .length = 3}, {.start = 0, .end = 2, .length = 5},
|
||||
{.start = 1, .end = 2, .length = 1}, {.start = 1, .end = 3, .length = 4},
|
||||
{.start = 1, .end = 4, .length = 0}, {.start = 2, .end = 4, .length = 2},
|
||||
{.start = 3, .end = 2, .length = 2}, {.start = 3, .end = 5, .length = 4},
|
||||
{.start = 4, .end = 3, .length = 2}, {.start = 4, .end = 5, .length = 5}};
|
||||
|
||||
// Transform the graph.
|
||||
std::vector<int> tails;
|
||||
std::vector<int> heads;
|
||||
std::vector<int> lengths;
|
||||
for (const Arc& arc : arcs) {
|
||||
tails.push_back(arc.start);
|
||||
heads.push_back(arc.end);
|
||||
lengths.push_back(arc.length);
|
||||
}
|
||||
|
||||
// Solve the shortest path problem from 0 to 5.
|
||||
std::pair<int, std::vector<int>> result =
|
||||
operations_research::SimpleOneToOneShortestPath<int>(0, 5, tails, heads,
|
||||
lengths);
|
||||
|
||||
// Print to length of the path and then the nodes in the path.
|
||||
std::cout << "Shortest path length: " << result.first << std::endl;
|
||||
std::cout << "Shortest path nodes: " << absl::StrJoin(result.second, ", ")
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
63
ortools/graph/samples/dijkstra_one_to_all.cc
Normal file
63
ortools/graph/samples/dijkstra_one_to_all.cc
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/graph/bounded_dijkstra.h"
|
||||
#include "ortools/graph/graph.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
|
||||
// Create the graph
|
||||
util::StaticGraph<> graph;
|
||||
std::vector<int> weights;
|
||||
graph.AddArc(0, 1);
|
||||
weights.push_back(2);
|
||||
graph.AddArc(1, 2);
|
||||
weights.push_back(4);
|
||||
graph.AddArc(1, 3);
|
||||
weights.push_back(0);
|
||||
graph.AddArc(2, 3);
|
||||
weights.push_back(6);
|
||||
graph.AddArc(3, 0);
|
||||
weights.push_back(8);
|
||||
graph.AddArc(4, 2);
|
||||
weights.push_back(1);
|
||||
|
||||
// Static graph reorders the arcs at Build() time, use permutation to get
|
||||
// from the old ordering to the new one.
|
||||
std::vector<int32_t> permutation;
|
||||
graph.Build(&permutation);
|
||||
util::Permute(permutation, &weights);
|
||||
|
||||
// Compute the shortest path to each reachable node.
|
||||
operations_research::BoundedDijkstraWrapper<util::StaticGraph<>, int>
|
||||
dijkstra(&graph, &weights);
|
||||
const std::vector<int> reachable_from_zero = dijkstra.RunBoundedDijkstra(
|
||||
/*source_node=*/0, /*distance_limit=*/std::numeric_limits<int>::max());
|
||||
|
||||
// Print paths from zero to the reachable nodes ordered by distance.
|
||||
for (const int dest : reachable_from_zero) {
|
||||
const int distance = dijkstra.distances()[dest];
|
||||
const std::vector<int32_t> path = dijkstra.NodePathTo(dest);
|
||||
std::cout << "Distance to " << dest << ": " << distance << std::endl;
|
||||
std::cout << "Path to " << dest << ": " << absl::StrJoin(path, ", ")
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
115
ortools/graph/samples/dijkstra_sequential.cc
Normal file
115
ortools/graph/samples/dijkstra_sequential.cc
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// [START imports]
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/graph/bounded_dijkstra.h"
|
||||
#include "ortools/graph/graph.h"
|
||||
// [END imports]
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
|
||||
// [START graph]
|
||||
// Create a graph with n + 2 nodes, indexed from 0:
|
||||
// * Node n is `source`
|
||||
// * Node n+1 is `dest`
|
||||
// * Nodes M = [0, 1, ..., n-1] are in the middle.
|
||||
//
|
||||
// The graph has 3 * n arcs (with weights):
|
||||
// * (source -> i) with weight 100 for i in M
|
||||
// * (i -> (i+1) % n) with weight 1 for i in M
|
||||
// * (i -> dest) with weight 100 for i in M
|
||||
//
|
||||
// Every path [source, i, dest] for i in M is a shortest path from source to
|
||||
// dest with weight 200.
|
||||
const int n = 10;
|
||||
const int source = n;
|
||||
const int dest = n + 1;
|
||||
util::StaticGraph<> graph;
|
||||
// There are 3 types of arcs: (1) source to M, (2) within M, and (3) M to
|
||||
// dest. This vector stores all of them, first of type (1), then type (2),
|
||||
// then type (3). The arcs are ordered by i in M within each type.
|
||||
std::vector<int> weights(3 * n);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
graph.AddArc(source, i);
|
||||
weights[i] = 100;
|
||||
}
|
||||
for (int i = 0; i < n; ++i) {
|
||||
graph.AddArc(i, (i + 1) % n);
|
||||
weights[n + i] = 1;
|
||||
}
|
||||
for (int i = 0; i < n; ++i) {
|
||||
graph.AddArc(i, dest);
|
||||
weights[2 * n + i] = 100;
|
||||
}
|
||||
|
||||
// Static graph reorders the arcs at Build() time, use permutation to get from
|
||||
// the old ordering to the new one.
|
||||
std::vector<int32_t> permutation;
|
||||
graph.Build(&permutation);
|
||||
util::Permute(permutation, &weights);
|
||||
// [END graph]
|
||||
|
||||
// [START first-path]
|
||||
// A reusable shortest path calculator.
|
||||
operations_research::BoundedDijkstraWrapper<util::StaticGraph<>, int>
|
||||
dijkstra(&graph, &weights);
|
||||
|
||||
// This function returns false if there is no path from `source` to `dest`
|
||||
// of length at most `distance_limit`. Avoid CHECK when you cannot prove a
|
||||
// path exists.
|
||||
CHECK(dijkstra.OneToOneShortestPath(
|
||||
source, dest, /*distance_limit=*/std::numeric_limits<int>::max()));
|
||||
std::cout << "Initial distance: " << dijkstra.distances()[dest] << std::endl;
|
||||
std::cout << "Initial path: "
|
||||
<< absl::StrJoin(dijkstra.NodePathTo(dest), ", ") << std::endl;
|
||||
// [END first-path]
|
||||
|
||||
// [START more-paths]
|
||||
// Now, we make a single arc from source to M free, and a single arc from M
|
||||
// to dest free, and resolve. The shortest path is now to use these free arcs,
|
||||
// walking through M to connect them.
|
||||
std::vector<std::pair<int, int>> fast_paths = {{2, 4}, {8, 1}, {3, 7}};
|
||||
for (const auto [free_from_source, free_to_dest] : fast_paths) {
|
||||
weights[permutation[free_from_source]] = 0;
|
||||
weights[permutation[2 * n + free_to_dest]] = 0;
|
||||
|
||||
CHECK(dijkstra.OneToOneShortestPath(
|
||||
source, dest, /*distance_limit=*/std::numeric_limits<int>::max()));
|
||||
std::cout << "source -> " << free_from_source << " and " << free_to_dest
|
||||
<< " -> dest are now free" << std::endl;
|
||||
std::string label = absl::StrCat("_", free_from_source, "_", free_to_dest);
|
||||
std::cout << "Distance" << label << ": " << dijkstra.distances()[dest]
|
||||
<< std::endl;
|
||||
std::cout << "Path" << label << ": "
|
||||
<< absl::StrJoin(dijkstra.NodePathTo(dest), ", ") << std::endl;
|
||||
|
||||
// Restore the old weights
|
||||
weights[permutation[free_from_source]] = 100;
|
||||
weights[permutation[2 * n + free_to_dest]] = 100;
|
||||
}
|
||||
// [END more-paths]
|
||||
return 0;
|
||||
}
|
||||
70
ortools/graph/samples/dijkstra_undirected.cc
Normal file
70
ortools/graph/samples/dijkstra_undirected.cc
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2010-2024 Google LLC
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "ortools/base/init_google.h"
|
||||
#include "ortools/graph/bounded_dijkstra.h"
|
||||
|
||||
namespace {
|
||||
// An edge in an undirected graph, the order of the endpoints does not matter.
|
||||
struct Edge {
|
||||
int endpoint1 = 0;
|
||||
int endpoint2 = 0;
|
||||
int length = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
InitGoogle(argv[0], &argc, &argv, true);
|
||||
|
||||
// The input graph, encoded as a list of edges with distances.
|
||||
std::vector<Edge> edges = {
|
||||
{.endpoint1 = 0, .endpoint2 = 1, .length = 8},
|
||||
{.endpoint1 = 0, .endpoint2 = 2, .length = 1},
|
||||
{.endpoint1 = 1, .endpoint2 = 2, .length = 0},
|
||||
{.endpoint1 = 1, .endpoint2 = 3, .length = 1},
|
||||
{.endpoint1 = 1, .endpoint2 = 4, .length = 4},
|
||||
{.endpoint1 = 2, .endpoint2 = 4, .length = 5},
|
||||
{.endpoint1 = 3, .endpoint2 = 4, .length = 2},
|
||||
};
|
||||
|
||||
// Transform the graph.
|
||||
std::vector<int> tails;
|
||||
std::vector<int> heads;
|
||||
std::vector<int> lengths;
|
||||
for (const Edge& edge : edges) {
|
||||
// The "forward" directed edge
|
||||
tails.push_back(edge.endpoint1);
|
||||
heads.push_back(edge.endpoint2);
|
||||
lengths.push_back(edge.length);
|
||||
// The "backward" directed edge
|
||||
tails.push_back(edge.endpoint2);
|
||||
heads.push_back(edge.endpoint1);
|
||||
lengths.push_back(edge.length);
|
||||
}
|
||||
|
||||
// Solve the shortest path problem from 0 to 4.
|
||||
std::pair<int, std::vector<int>> result =
|
||||
operations_research::SimpleOneToOneShortestPath<int>(0, 4, tails, heads,
|
||||
lengths);
|
||||
|
||||
// Print to length of the path and then the nodes in the path.
|
||||
std::cout << "Shortest path length: " << result.first << std::endl;
|
||||
std::cout << "Shortest path nodes: " << absl::StrJoin(result.second, ", ")
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user