graph: remove ebert_graph usage

This commit is contained in:
Corentin Le Molgat
2025-01-08 09:44:58 +01:00
parent 847e205aae
commit a5adf42213
14 changed files with 97 additions and 104 deletions

View File

@@ -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",

View File

@@ -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"

View File

@@ -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());

View File

@@ -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"

View File

@@ -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): 712716, 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(), " - ") << " ("

View File

@@ -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));

View File

@@ -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"

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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";

View File

@@ -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>

View File

@@ -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",

View File

@@ -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) {