graph: Add few samples

This commit is contained in:
Corentin Le Molgat
2024-01-19 17:58:32 +01:00
parent 653be26d29
commit 78a091097e
11 changed files with 928 additions and 0 deletions

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}
}

View 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;
}

View 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;
}