graph: remove ebert_graph usage
This commit is contained in:
@@ -101,7 +101,6 @@ cc_library(
|
||||
srcs = ["minimum_vertex_cover.cc"],
|
||||
hdrs = ["minimum_vertex_cover.h"],
|
||||
deps = [
|
||||
":ebert_graph",
|
||||
":max_flow",
|
||||
"@com_google_absl//absl/log:check",
|
||||
],
|
||||
@@ -398,7 +397,6 @@ cc_test(
|
||||
srcs = ["shortest_paths_test.cc"],
|
||||
tags = ["noasan"], # Times out occasionally in ASAN mode.
|
||||
deps = [
|
||||
":ebert_graph",
|
||||
":graph",
|
||||
":shortest_paths",
|
||||
":strongly_connected_components",
|
||||
@@ -471,7 +469,6 @@ cc_test(
|
||||
srcs = ["max_flow_test.cc"],
|
||||
data = ["//ortools/graph/testdata:max_flow_test1.pb.txt"],
|
||||
deps = [
|
||||
":ebert_graph",
|
||||
":flow_problem_cc_proto",
|
||||
":max_flow",
|
||||
"//ortools/base:gmock_main",
|
||||
@@ -681,7 +678,6 @@ cc_library(
|
||||
srcs = ["dag_shortest_path.cc"],
|
||||
hdrs = ["dag_shortest_path.h"],
|
||||
deps = [
|
||||
":ebert_graph",
|
||||
":graph",
|
||||
":topologicalsorter",
|
||||
"@com_google_absl//absl/algorithm:container",
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
|
||||
%include "ortools/base/base.i"
|
||||
|
||||
%import "ortools/graph/ebert_graph.h"
|
||||
|
||||
%{
|
||||
#include "ortools/graph/assignment.h"
|
||||
#include "ortools/graph/max_flow.h"
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/types/span.h"
|
||||
#include "ortools/graph/ebert_graph.h"
|
||||
#include "ortools/graph/graph.h"
|
||||
#include "ortools/graph/topologicalsorter.h"
|
||||
|
||||
@@ -109,7 +108,7 @@ std::vector<PathWithLength> KShortestPathsOnDag(
|
||||
const ShortestPathOnDagProblem problem =
|
||||
ReadProblem(num_nodes, arcs_with_length);
|
||||
|
||||
KShortestPathsOnDagWrapper<util::StaticGraph<>> shortest_paths_on_dag(
|
||||
KShortestPathsOnDagWrapper<GraphType> shortest_paths_on_dag(
|
||||
&problem.graph, &problem.arc_lengths, problem.topological_order,
|
||||
path_count);
|
||||
shortest_paths_on_dag.RunKShortestPathOnDag({source});
|
||||
@@ -119,9 +118,9 @@ std::vector<PathWithLength> KShortestPathsOnDag(
|
||||
}
|
||||
|
||||
std::vector<double> lengths = shortest_paths_on_dag.LengthsTo(destination);
|
||||
std::vector<std::vector<ArcIndex>> arc_paths =
|
||||
std::vector<std::vector<GraphType::ArcIndex>> arc_paths =
|
||||
shortest_paths_on_dag.ArcPathsTo(destination);
|
||||
std::vector<std::vector<NodeIndex>> node_paths =
|
||||
std::vector<std::vector<GraphType::NodeIndex>> node_paths =
|
||||
shortest_paths_on_dag.NodePathsTo(destination);
|
||||
std::vector<PathWithLength> paths;
|
||||
paths.reserve(lengths.size());
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
|
||||
%include "ortools/base/base.i"
|
||||
|
||||
%import "ortools/graph/ebert_graph.h"
|
||||
|
||||
%{
|
||||
#include "ortools/graph/assignment.h"
|
||||
#include "ortools/graph/max_flow.h"
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
#include "absl/types/span.h"
|
||||
#include "ortools/base/logging.h"
|
||||
#include "ortools/graph/bounded_dijkstra.h"
|
||||
#include "ortools/graph/ebert_graph.h"
|
||||
#include "ortools/graph/shortest_paths.h"
|
||||
|
||||
namespace operations_research {
|
||||
@@ -82,6 +81,7 @@ namespace operations_research {
|
||||
// The paths in `paths` start with `origin` and end at `destination`.
|
||||
//
|
||||
// If the computations are unsuccessful for any reason, the vectors are empty.
|
||||
template <class GraphType>
|
||||
struct KShortestPaths {
|
||||
// The paths are stored as vectors of nodes, like the other graph algorithms.
|
||||
// TODO(user): what about vectors of arcs? That might be faster
|
||||
@@ -89,7 +89,7 @@ struct KShortestPaths {
|
||||
// user really needs it). It would also have the nice benefit of removing the
|
||||
// need for `distances` (compute it on the fly), with a reference to the graph
|
||||
// and the costs.
|
||||
std::vector<std::vector<NodeIndex>> paths;
|
||||
std::vector<std::vector<typename GraphType::NodeIndex>> paths;
|
||||
std::vector<PathDistance> distances;
|
||||
};
|
||||
|
||||
@@ -113,10 +113,10 @@ struct KShortestPaths {
|
||||
// Science. 17 (11): 712–716, 1971.
|
||||
// https://doi.org/10.1287%2Fmnsc.17.11.712
|
||||
template <class GraphType>
|
||||
KShortestPaths YenKShortestPaths(const GraphType& graph,
|
||||
const std::vector<PathDistance>& arc_lengths,
|
||||
NodeIndex source, NodeIndex destination,
|
||||
unsigned k);
|
||||
KShortestPaths<GraphType> YenKShortestPaths(
|
||||
const GraphType& graph, const std::vector<PathDistance>& arc_lengths,
|
||||
typename GraphType::NodeIndex source,
|
||||
typename GraphType::NodeIndex destination, unsigned k);
|
||||
|
||||
// End of the interface. Below is the implementation.
|
||||
|
||||
@@ -137,23 +137,26 @@ const PathDistance kDisconnectedDistance =
|
||||
// In a multigraph, this function returns an index for one of the edges between
|
||||
// the source and the destination.
|
||||
template <class GraphType>
|
||||
ArcIndex FindArcIndex(const GraphType& graph, const NodeIndex source,
|
||||
const NodeIndex destination) {
|
||||
typename GraphType::ArcIndex FindArcIndex(
|
||||
const GraphType& graph, const typename GraphType::NodeIndex source,
|
||||
const typename GraphType::NodeIndex destination) {
|
||||
const auto outgoing_arcs_iter = graph.OutgoingArcs(source);
|
||||
const auto arc =
|
||||
std::find_if(outgoing_arcs_iter.begin(), outgoing_arcs_iter.end(),
|
||||
[&graph, destination](const ArcIndex arc) {
|
||||
return graph.Head(arc) == destination;
|
||||
});
|
||||
const auto arc = std::find_if(
|
||||
outgoing_arcs_iter.begin(), outgoing_arcs_iter.end(),
|
||||
[&graph, destination](const typename GraphType::ArcIndex arc) {
|
||||
return graph.Head(arc) == destination;
|
||||
});
|
||||
return (arc != outgoing_arcs_iter.end()) ? *arc : GraphType::kNilArc;
|
||||
}
|
||||
|
||||
// Determines the shortest path from the given source and destination, returns a
|
||||
// tuple with the path (as a vector of node indices) and its cost.
|
||||
template <class GraphType>
|
||||
std::tuple<std::vector<NodeIndex>, PathDistance> ComputeShortestPath(
|
||||
const GraphType& graph, const std::vector<PathDistance>& arc_lengths,
|
||||
const NodeIndex source, const NodeIndex destination) {
|
||||
std::tuple<std::vector<typename GraphType::NodeIndex>, PathDistance>
|
||||
ComputeShortestPath(const GraphType& graph,
|
||||
const std::vector<PathDistance>& arc_lengths,
|
||||
const typename GraphType::NodeIndex source,
|
||||
const typename GraphType::NodeIndex destination) {
|
||||
BoundedDijkstraWrapper<GraphType, PathDistance> dijkstra(&graph,
|
||||
&arc_lengths);
|
||||
dijkstra.RunBoundedDijkstra(source, kMaxDistance);
|
||||
@@ -165,25 +168,29 @@ std::tuple<std::vector<NodeIndex>, PathDistance> ComputeShortestPath(
|
||||
// This case only happens when some arcs have an infinite length (i.e.
|
||||
// larger than `kMaxDistance`): `BoundedDijkstraWrapper::NodePathTo` fails
|
||||
// to return a path, even empty.
|
||||
return {std::vector<NodeIndex>{}, kDisconnectedDistance};
|
||||
return {std::vector<typename GraphType::NodeIndex>{},
|
||||
kDisconnectedDistance};
|
||||
}
|
||||
|
||||
if (std::vector<NodeIndex> path = std::move(dijkstra.NodePathTo(destination));
|
||||
if (std::vector<typename GraphType::NodeIndex> path =
|
||||
std::move(dijkstra.NodePathTo(destination));
|
||||
!path.empty()) {
|
||||
return {std::move(path), path_length};
|
||||
} else {
|
||||
return {std::vector<NodeIndex>{}, kDisconnectedDistance};
|
||||
return {std::vector<typename GraphType::NodeIndex>{},
|
||||
kDisconnectedDistance};
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the total length of a path.
|
||||
template <class GraphType>
|
||||
PathDistance ComputePathLength(const GraphType& graph,
|
||||
const absl::Span<const PathDistance> arc_lengths,
|
||||
const absl::Span<const NodeIndex> path) {
|
||||
PathDistance ComputePathLength(
|
||||
const GraphType& graph, const absl::Span<const PathDistance> arc_lengths,
|
||||
const absl::Span<const typename GraphType::NodeIndex> path) {
|
||||
PathDistance distance = 0;
|
||||
for (NodeIndex i = 0; i < path.size() - 1; ++i) {
|
||||
const ArcIndex arc = internal::FindArcIndex(graph, path[i], path[i + 1]);
|
||||
for (typename GraphType::NodeIndex i = 0; i < path.size() - 1; ++i) {
|
||||
const typename GraphType::ArcIndex arc =
|
||||
internal::FindArcIndex(graph, path[i], path[i + 1]);
|
||||
DCHECK_NE(arc, GraphType::kNilArc);
|
||||
distance += arc_lengths[arc];
|
||||
}
|
||||
@@ -192,8 +199,11 @@ PathDistance ComputePathLength(const GraphType& graph,
|
||||
|
||||
// Stores a path with a priority (typically, the distance), with a comparison
|
||||
// operator that operates on the priority.
|
||||
template <class GraphType>
|
||||
class PathWithPriority {
|
||||
public:
|
||||
using NodeIndex = typename GraphType::NodeIndex;
|
||||
|
||||
PathWithPriority(PathDistance priority, std::vector<NodeIndex> path)
|
||||
: path_(std::move(path)), priority_(priority) {}
|
||||
bool operator<(const PathWithPriority& other) const {
|
||||
@@ -265,10 +275,12 @@ class UnderlyingContainerAdapter : public Container {
|
||||
// spur paths, the cheapest being:
|
||||
// S_1^2 = B - E - F - G - H
|
||||
template <class GraphType>
|
||||
KShortestPaths YenKShortestPaths(const GraphType& graph,
|
||||
const std::vector<PathDistance>& arc_lengths,
|
||||
NodeIndex source, NodeIndex destination,
|
||||
unsigned k) {
|
||||
KShortestPaths<GraphType> YenKShortestPaths(
|
||||
const GraphType& graph, const std::vector<PathDistance>& arc_lengths,
|
||||
typename GraphType::NodeIndex source,
|
||||
typename GraphType::NodeIndex destination, unsigned k) {
|
||||
using NodeIndex = typename GraphType::NodeIndex;
|
||||
|
||||
CHECK_GT(internal::kDisconnectedDistance, internal::kMaxDistance);
|
||||
|
||||
CHECK_GE(k, 0) << "k must be nonnegative. Input value: " << k;
|
||||
@@ -289,7 +301,7 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
|
||||
<< destination
|
||||
<< ". Number of nodes in the input graph: " << graph.num_nodes();
|
||||
|
||||
KShortestPaths paths;
|
||||
KShortestPaths<GraphType> paths;
|
||||
|
||||
// First step: compute the shortest path.
|
||||
{
|
||||
@@ -306,7 +318,7 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
|
||||
|
||||
// Generate variant paths.
|
||||
internal::UnderlyingContainerAdapter<
|
||||
std::priority_queue<internal::PathWithPriority>>
|
||||
std::priority_queue<internal::PathWithPriority<GraphType>>>
|
||||
variant_path_queue;
|
||||
|
||||
// One path has already been generated (the shortest one). Only k-1 more
|
||||
@@ -364,7 +376,7 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
|
||||
previous_path.begin() + root_path.length());
|
||||
if (!has_same_prefix_as_root_path) continue;
|
||||
|
||||
const ArcIndex after_spur_node_arc =
|
||||
const typename GraphType::ArcIndex after_spur_node_arc =
|
||||
internal::FindArcIndex(graph, previous_path[spur_node_position],
|
||||
previous_path[spur_node_position + 1]);
|
||||
VLOG(4) << " after_spur_node_arc: " << graph.Tail(after_spur_node_arc)
|
||||
@@ -417,8 +429,8 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
|
||||
// coincide at the spur node).
|
||||
const bool root_path_leads_to_spur_path = absl::c_any_of(
|
||||
graph.OutgoingArcs(root_path.back()),
|
||||
[&graph, node_after_spur_in_spur_path =
|
||||
*(spur_path.begin() + 1)](const ArcIndex arc_index) {
|
||||
[&graph, node_after_spur_in_spur_path = *(spur_path.begin() + 1)](
|
||||
const typename GraphType::ArcIndex arc_index) {
|
||||
return graph.Head(arc_index) == node_after_spur_in_spur_path;
|
||||
});
|
||||
CHECK(root_path_leads_to_spur_path);
|
||||
@@ -471,12 +483,12 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
|
||||
// filter by fingerprints? Due to the probability of error with
|
||||
// fingerprints, still use this slow-but-exact code, but after
|
||||
// filtering.
|
||||
const bool is_new_path_already_known =
|
||||
std::any_of(variant_path_queue.container().cbegin(),
|
||||
variant_path_queue.container().cend(),
|
||||
[&new_path](const internal::PathWithPriority& element) {
|
||||
return element.path() == new_path;
|
||||
});
|
||||
const bool is_new_path_already_known = std::any_of(
|
||||
variant_path_queue.container().cbegin(),
|
||||
variant_path_queue.container().cend(),
|
||||
[&new_path](const internal::PathWithPriority<GraphType>& element) {
|
||||
return element.path() == new_path;
|
||||
});
|
||||
if (is_new_path_already_known) continue;
|
||||
|
||||
const PathDistance path_length =
|
||||
@@ -498,7 +510,7 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
|
||||
// this iteration found no shorter one.
|
||||
if (variant_path_queue.empty()) break;
|
||||
|
||||
const internal::PathWithPriority& next_shortest_path =
|
||||
const internal::PathWithPriority<GraphType>& next_shortest_path =
|
||||
variant_path_queue.top();
|
||||
VLOG(5) << "> New path generated: "
|
||||
<< absl::StrJoin(next_shortest_path.path(), " - ") << " ("
|
||||
|
||||
@@ -128,8 +128,9 @@ TEST(KShortestPathsYenTest, ReducesToShortestPath) {
|
||||
(void)graph.Build();
|
||||
std::vector<PathDistance> lengths{1, 1};
|
||||
|
||||
const KShortestPaths paths = YenKShortestPaths(graph, lengths, /*source=*/0,
|
||||
/*destination=*/2, /*k=*/1);
|
||||
const KShortestPaths<StaticGraph<>> paths =
|
||||
YenKShortestPaths(graph, lengths, /*source=*/0,
|
||||
/*destination=*/2, /*k=*/1);
|
||||
EXPECT_THAT(paths.paths, ElementsAre(std::vector<int>{0, 1, 2}));
|
||||
EXPECT_THAT(paths.distances, ElementsAre(2));
|
||||
}
|
||||
@@ -141,8 +142,9 @@ TEST(KShortestPathsYenTest, OnlyHasOnePath) {
|
||||
(void)graph.Build();
|
||||
std::vector<PathDistance> lengths{1, 1};
|
||||
|
||||
const KShortestPaths paths = YenKShortestPaths(graph, lengths, /*source=*/0,
|
||||
/*destination=*/2, /*k=*/10);
|
||||
const KShortestPaths<StaticGraph<>> paths =
|
||||
YenKShortestPaths(graph, lengths, /*source=*/0,
|
||||
/*destination=*/2, /*k=*/10);
|
||||
EXPECT_THAT(paths.paths, ElementsAre(std::vector<int>{0, 1, 2}));
|
||||
EXPECT_THAT(paths.distances, ElementsAre(2));
|
||||
}
|
||||
@@ -155,8 +157,9 @@ TEST(KShortestPathsYenTest, HasTwoPaths) {
|
||||
(void)graph.Build();
|
||||
std::vector<PathDistance> lengths{1, 30, 1};
|
||||
|
||||
const KShortestPaths paths = YenKShortestPaths(graph, lengths, /*source=*/0,
|
||||
/*destination=*/2, /*k=*/10);
|
||||
const KShortestPaths<StaticGraph<>> paths =
|
||||
YenKShortestPaths(graph, lengths, /*source=*/0,
|
||||
/*destination=*/2, /*k=*/10);
|
||||
EXPECT_THAT(paths.paths,
|
||||
ElementsAre(std::vector<int>{0, 1, 2}, std::vector<int>{0, 2}));
|
||||
EXPECT_THAT(paths.distances, ElementsAre(2, 30));
|
||||
@@ -172,8 +175,9 @@ TEST(KShortestPathsYenTest, HasTwoPathsWithLongerPath) {
|
||||
(void)graph.Build();
|
||||
std::vector<PathDistance> lengths{1, 30, 1, 1, 1};
|
||||
|
||||
const KShortestPaths paths = YenKShortestPaths(graph, lengths, /*source=*/0,
|
||||
/*destination=*/4, /*k=*/10);
|
||||
const KShortestPaths<StaticGraph<>> paths =
|
||||
YenKShortestPaths(graph, lengths, /*source=*/0,
|
||||
/*destination=*/4, /*k=*/10);
|
||||
EXPECT_THAT(paths.paths, ElementsAre(std::vector<int>{0, 1, 2, 3, 4},
|
||||
std::vector<int>{0, 4}));
|
||||
EXPECT_THAT(paths.distances, ElementsAre(4, 30));
|
||||
@@ -190,8 +194,9 @@ TEST(KShortestPathsYenTest, ReturnsTheRightNumberOfPaths) {
|
||||
(void)graph.Build();
|
||||
std::vector<PathDistance> lengths{1, 1, 1, 1, 1};
|
||||
|
||||
const KShortestPaths paths = YenKShortestPaths(graph, lengths, /*source=*/0,
|
||||
/*destination=*/2, /*k=*/2);
|
||||
const KShortestPaths<StaticGraph<>> paths =
|
||||
YenKShortestPaths(graph, lengths, /*source=*/0,
|
||||
/*destination=*/2, /*k=*/2);
|
||||
EXPECT_THAT(paths.paths,
|
||||
ElementsAre(std::vector<int>{0, 2}, std::vector<int>{0, 1, 2}));
|
||||
EXPECT_THAT(paths.distances, ElementsAre(1, 2));
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "ortools/base/gmock.h"
|
||||
#include "ortools/base/path.h"
|
||||
#include "ortools/graph/ebert_graph.h"
|
||||
#include "ortools/graph/flow_problem.pb.h"
|
||||
#include "ortools/util/file_util.h"
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/log/check.h"
|
||||
#include "ortools/graph/ebert_graph.h"
|
||||
#include "ortools/graph/max_flow.h"
|
||||
|
||||
namespace operations_research {
|
||||
@@ -31,7 +30,7 @@ std::vector<bool> BipartiteMinimumVertexCover(
|
||||
// alternating matched/unmatched edges to find a minimum vertex cover.
|
||||
SimpleMaxFlow max_flow;
|
||||
const int num_left = left_to_right_arcs.size();
|
||||
std::vector<ArcIndex> arcs;
|
||||
std::vector<SimpleMaxFlow::ArcIndex> arcs;
|
||||
for (int i = 0; i < num_left; ++i) {
|
||||
for (const int right_node : left_to_right_arcs[i]) {
|
||||
DCHECK_GE(right_node, num_left);
|
||||
@@ -56,7 +55,7 @@ std::vector<bool> BipartiteMinimumVertexCover(
|
||||
}
|
||||
CHECK(max_flow.Solve(source, sink) == SimpleMaxFlow::OPTIMAL);
|
||||
std::vector<int> maximum_matching(num_left + num_right, -1);
|
||||
for (const ArcIndex arc : arcs) {
|
||||
for (const SimpleMaxFlow::ArcIndex arc : arcs) {
|
||||
if (max_flow.Flow(arc) > 0) {
|
||||
maximum_matching[max_flow.Tail(arc)] = max_flow.Head(arc);
|
||||
maximum_matching[max_flow.Head(arc)] = max_flow.Tail(arc);
|
||||
|
||||
@@ -69,7 +69,7 @@ void AssignmentMinFlow() {
|
||||
// [END solve]
|
||||
|
||||
// [START print_solution]
|
||||
if (status == MinCostFlow::OPTIMAL) {
|
||||
if (status == SimpleMinCostFlow::OPTIMAL) {
|
||||
LOG(INFO) << "Total cost: " << min_cost_flow.OptimalCost();
|
||||
LOG(INFO) << "";
|
||||
for (std::size_t i = 0; i < min_cost_flow.NumArcs(); ++i) {
|
||||
|
||||
@@ -75,7 +75,7 @@ void BalanceMinFlow() {
|
||||
// [END solve]
|
||||
|
||||
// [START print_solution]
|
||||
if (status == MinCostFlow::OPTIMAL) {
|
||||
if (status == SimpleMinCostFlow::OPTIMAL) {
|
||||
LOG(INFO) << "Total cost: " << min_cost_flow.OptimalCost();
|
||||
LOG(INFO) << "";
|
||||
for (std::size_t i = 0; i < min_cost_flow.NumArcs(); ++i) {
|
||||
|
||||
@@ -62,7 +62,7 @@ void SimpleMinCostFlowProgram() {
|
||||
// [END solve]
|
||||
|
||||
// [START print_solution]
|
||||
if (status == MinCostFlow::OPTIMAL) {
|
||||
if (status == SimpleMinCostFlow::OPTIMAL) {
|
||||
LOG(INFO) << "Minimum cost flow: " << min_cost_flow.OptimalCost();
|
||||
LOG(INFO) << "";
|
||||
LOG(INFO) << " Arc Flow / Capacity Cost";
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "absl/log/check.h"
|
||||
#include "absl/random/random.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "ortools/graph/ebert_graph.h"
|
||||
#include "ortools/graph/graph.h"
|
||||
#include "ortools/graph/strongly_connected_components.h"
|
||||
|
||||
@@ -31,8 +30,9 @@ template <class GraphType>
|
||||
void CheckPathDataPair(
|
||||
const GenericPathContainer<GraphType>& container,
|
||||
const GenericPathContainer<GraphType>& distance_container,
|
||||
PathDistance expected_distance, NodeIndex expected_predecessor,
|
||||
NodeIndex tail, NodeIndex head) {
|
||||
PathDistance expected_distance,
|
||||
typename GraphType::NodeIndex expected_predecessor,
|
||||
typename GraphType::NodeIndex tail, typename GraphType::NodeIndex head) {
|
||||
EXPECT_EQ(expected_distance, container.GetDistance(tail, head));
|
||||
EXPECT_EQ(expected_distance, distance_container.GetDistance(tail, head));
|
||||
EXPECT_EQ(expected_predecessor,
|
||||
@@ -40,7 +40,7 @@ void CheckPathDataPair(
|
||||
EXPECT_DEATH(distance_container.GetPenultimateNodeInPath(tail, head),
|
||||
"Path not stored.");
|
||||
// Checking path between tail and head.
|
||||
std::vector<NodeIndex> paths;
|
||||
std::vector<typename GraphType::NodeIndex> paths;
|
||||
container.GetPath(tail, head, &paths);
|
||||
if (tail == head) {
|
||||
EXPECT_GE(1, paths.size());
|
||||
@@ -49,7 +49,7 @@ void CheckPathDataPair(
|
||||
}
|
||||
} else if (!paths.empty()) {
|
||||
EXPECT_EQ(tail, paths[0]);
|
||||
NodeIndex current = head;
|
||||
typename GraphType::NodeIndex current = head;
|
||||
for (int i = paths.size() - 1; i >= 0; --i) {
|
||||
EXPECT_EQ(current, paths[i]);
|
||||
current = container.GetPenultimateNodeInPath(tail, current);
|
||||
@@ -63,12 +63,13 @@ template <class GraphType>
|
||||
void CheckPathDataRow(const GraphType& graph,
|
||||
const GenericPathContainer<GraphType>& container,
|
||||
const GenericPathContainer<GraphType>& distance_container,
|
||||
const NodeIndex expected_paths[],
|
||||
const PathDistance expected_distances[], NodeIndex tail) {
|
||||
const typename GraphType::NodeIndex expected_paths[],
|
||||
const PathDistance expected_distances[],
|
||||
typename GraphType::NodeIndex tail) {
|
||||
int index = tail * graph.num_nodes();
|
||||
for (typename GraphType::NodeIterator iterator(graph); iterator.Ok();
|
||||
iterator.Next()) {
|
||||
const NodeIndex head(iterator.Index());
|
||||
const typename GraphType::NodeIndex head(iterator.Index());
|
||||
CheckPathDataPair(container, distance_container, expected_distances[index],
|
||||
expected_paths[index], tail, head);
|
||||
++index;
|
||||
@@ -79,8 +80,9 @@ template <class GraphType>
|
||||
void CheckPathDataRowFromGraph(
|
||||
const GraphType& graph, const GenericPathContainer<GraphType>& container,
|
||||
const GenericPathContainer<GraphType>& distance_container,
|
||||
const NodeIndex expected_paths[], const PathDistance expected_distances[],
|
||||
NodeIndex tail) {
|
||||
const typename GraphType::NodeIndex expected_paths[],
|
||||
const PathDistance expected_distances[],
|
||||
typename GraphType::NodeIndex tail) {
|
||||
int index = tail * graph.num_nodes();
|
||||
for (typename GraphType::NodeIndex head : graph.AllNodes()) {
|
||||
CheckPathDataPair(container, distance_container, expected_distances[index],
|
||||
@@ -93,11 +95,11 @@ template <class GraphType>
|
||||
void CheckPathData(const GraphType& graph,
|
||||
const GenericPathContainer<GraphType>& container,
|
||||
const GenericPathContainer<GraphType>& distance_container,
|
||||
const NodeIndex expected_paths[],
|
||||
const typename GraphType::NodeIndex expected_paths[],
|
||||
const PathDistance expected_distances[]) {
|
||||
for (typename GraphType::NodeIterator iterator(graph); iterator.Ok();
|
||||
iterator.Next()) {
|
||||
const NodeIndex tail(iterator.Index());
|
||||
const typename GraphType::NodeIndex tail(iterator.Index());
|
||||
CheckPathDataRow(graph, container, distance_container, expected_paths,
|
||||
expected_distances, tail);
|
||||
}
|
||||
@@ -107,7 +109,8 @@ template <class GraphType>
|
||||
void CheckPathDataFromGraph(
|
||||
const GraphType& graph, const GenericPathContainer<GraphType>& container,
|
||||
const GenericPathContainer<GraphType>& distance_container,
|
||||
const NodeIndex expected_paths[], const PathDistance expected_distances[]) {
|
||||
const typename GraphType::NodeIndex expected_paths[],
|
||||
const PathDistance expected_distances[]) {
|
||||
for (typename GraphType::NodeIndex tail : graph.AllNodes()) {
|
||||
CheckPathDataRowFromGraph(graph, container, distance_container,
|
||||
expected_paths, expected_distances, tail);
|
||||
@@ -121,10 +124,10 @@ void CheckPathDataFromGraph(
|
||||
GenericPathContainer<GraphType>::BuildPathDistanceContainer()
|
||||
|
||||
template <class GraphType>
|
||||
void TestShortestPathsFromGraph(const GraphType& graph,
|
||||
const std::vector<PathDistance>& lengths,
|
||||
const NodeIndex expected_paths[],
|
||||
const PathDistance expected_distances[]) {
|
||||
void TestShortestPathsFromGraph(
|
||||
const GraphType& graph, const std::vector<PathDistance>& lengths,
|
||||
const typename GraphType::NodeIndex expected_paths[],
|
||||
const PathDistance expected_distances[]) {
|
||||
const int kThreads = 32;
|
||||
const typename GraphType::NodeIndex source = 0;
|
||||
std::vector<typename GraphType::NodeIndex> some_nodes;
|
||||
@@ -170,7 +173,7 @@ void TestShortestPathsFromGraph(const GraphType& graph,
|
||||
// Many-to-all shortest paths with duplicates.
|
||||
{
|
||||
BUILD_CONTAINERS();
|
||||
std::vector<NodeIndex> sources(3, source);
|
||||
std::vector<typename GraphType::NodeIndex> sources(3, source);
|
||||
ComputeManyToAllShortestPathsWithMultipleThreads(graph, lengths, sources,
|
||||
kThreads, &container);
|
||||
ComputeManyToAllShortestPathsWithMultipleThreads(
|
||||
@@ -235,21 +238,6 @@ void TestShortestPathsFromGraph(
|
||||
|
||||
// Series of shortest paths tests on small graphs.
|
||||
|
||||
// Empty fixture templates to collect the types of graphs on which
|
||||
// we want to base the shortest paths template instances that we
|
||||
// test.
|
||||
template <typename GraphType>
|
||||
class ShortestPathsDeathTest : public testing::Test {};
|
||||
template <typename GraphType>
|
||||
class ShortestPathsTest : public testing::Test {};
|
||||
|
||||
typedef testing::Types<StarGraph, ForwardStarGraph>
|
||||
EbertGraphTypesForShortestPathsTesting;
|
||||
|
||||
TYPED_TEST_SUITE(ShortestPathsDeathTest,
|
||||
EbertGraphTypesForShortestPathsTesting);
|
||||
TYPED_TEST_SUITE(ShortestPathsTest, EbertGraphTypesForShortestPathsTesting);
|
||||
|
||||
template <typename GraphType>
|
||||
class GraphShortestPathsDeathTest : public testing::Test {};
|
||||
template <typename GraphType>
|
||||
|
||||
@@ -248,7 +248,6 @@ cc_library(
|
||||
"//ortools/graph",
|
||||
"//ortools/graph:christofides",
|
||||
"//ortools/graph:connected_components",
|
||||
"//ortools/graph:ebert_graph",
|
||||
"//ortools/graph:linear_assignment",
|
||||
"//ortools/graph:min_cost_flow",
|
||||
"//ortools/lp_data",
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include "ortools/base/types.h"
|
||||
#include "ortools/constraint_solver/constraint_solver.h"
|
||||
#include "ortools/glop/parameters.pb.h"
|
||||
#include "ortools/graph/ebert_graph.h"
|
||||
#include "ortools/graph/min_cost_flow.h"
|
||||
#include "ortools/port/proto_utils.h"
|
||||
#include "ortools/routing/parameters.pb.h"
|
||||
@@ -3073,6 +3072,7 @@ int64_t ComputeBestVehicleToResourceAssignment(
|
||||
/*reserve_num_nodes*/ 2 + num_vehicles + num_resource_classes,
|
||||
/*reserve_num_arcs*/ num_vehicles + num_vehicles * num_resource_classes +
|
||||
num_resource_classes);
|
||||
using ArcIndex = SimpleMinCostFlow::ArcIndex;
|
||||
const int source_index = num_vehicles + num_resource_classes;
|
||||
const int sink_index = source_index + 1;
|
||||
const auto flow_rc_index = [num_vehicles](int rc) {
|
||||
|
||||
Reference in New Issue
Block a user