diff --git a/ortools/graph/BUILD.bazel b/ortools/graph/BUILD.bazel index 824d6cb89b..0d1be0e5a5 100644 --- a/ortools/graph/BUILD.bazel +++ b/ortools/graph/BUILD.bazel @@ -76,6 +76,25 @@ cc_library( ], ) +cc_test( + name = "bounded_dijkstra_test", + size = "small", + srcs = ["bounded_dijkstra_test.cc"], + deps = [ + ":bounded_dijkstra", + ":graph", + ":io", + ":test_util", + "//ortools/base:dump_vars", + "//ortools/base:gmock_main", + "//ortools/util:flat_matrix", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/random", + "@com_google_absl//absl/random:distributions", + "@com_google_benchmark//:benchmark", + ], +) + cc_library( name = "multi_dijkstra", hdrs = ["multi_dijkstra.h"], @@ -152,6 +171,25 @@ cc_library( ], ) +cc_test( + name = "cliques_test", + size = "medium", + srcs = ["cliques_test.cc"], + deps = [ + ":cliques", + "//ortools/base:gmock_main", + "//ortools/base:mathutil", + "//ortools/util:time_limit", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/functional:bind_front", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/random:distributions", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:span", + "@com_google_benchmark//:benchmark", + ], +) + cc_library( name = "hamiltonian_path", hdrs = ["hamiltonian_path.h"], @@ -271,6 +309,20 @@ cc_library( ], ) +cc_test( + name = "one_tree_lower_bound_test", + size = "medium", + srcs = ["one_tree_lower_bound_test.cc"], + deps = [ + ":one_tree_lower_bound", + "//ortools/base:gmock_main", + "//ortools/base:path", + "//ortools/base:types", + "//ortools/routing/parsers:tsplib_parser", + "@com_google_absl//absl/types:span", + ], +) + cc_library( name = "ebert_graph", hdrs = ["ebert_graph.h"], @@ -355,6 +407,23 @@ cc_library( ], ) +cc_test( + name = "k_shortest_paths_test", + srcs = ["k_shortest_paths_test.cc"], + deps = [ + ":graph", + ":io", + ":k_shortest_paths", + ":shortest_paths", + "//ortools/base:gmock_main", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/random:distributions", + "@com_google_absl//absl/strings", + "@com_google_benchmark//:benchmark", + ], +) + # Flow problem protobuf representation proto_library( name = "flow_problem_proto", @@ -438,6 +507,25 @@ cc_library( ], ) +cc_test( + name = "min_cost_flow_test", + size = "medium", + srcs = ["min_cost_flow_test.cc"], + deps = [ + ":graphs", + ":min_cost_flow", + "//ortools/base:gmock_main", + "@com_google_absl//absl/random:distributions", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/types:span", + "@com_google_benchmark//:benchmark", + ":graph", + # Using CLP because GLOP is too slow in non-opt mode. + "//ortools/algorithms:binary_search", + "//ortools/linear_solver", + ], +) + # Flow-problem solver cc_binary( name = "solve_flow_model", @@ -748,3 +836,13 @@ cc_library( "@com_google_absl//absl/container:inlined_vector", ], ) + +cc_library( + name = "test_util", + hdrs = ["test_util.h"], + deps = [ + ":graph", + "//ortools/base:types", + "@com_google_absl//absl/memory", + ], +) diff --git a/ortools/graph/bounded_dijkstra_test.cc b/ortools/graph/bounded_dijkstra_test.cc index d35805705b..a2622d2248 100644 --- a/ortools/graph/bounded_dijkstra_test.cc +++ b/ortools/graph/bounded_dijkstra_test.cc @@ -28,13 +28,12 @@ #include "absl/random/random.h" #include "benchmark/benchmark.h" #include "gtest/gtest.h" +#include "ortools/base/dump_vars.h" #include "ortools/base/gmock.h" #include "ortools/graph/graph.h" #include "ortools/graph/io.h" #include "ortools/graph/test_util.h" #include "ortools/util/flat_matrix.h" -#include "ortools/util/saturated_arithmetic.h" -#include "util/tuple/dump_vars.h" namespace operations_research { namespace { @@ -683,8 +682,7 @@ TEST(BoundedDisjktraTest, RandomizedStressTest) { EXPECT_EQ(dijkstra.distances()[node], node_min_dist[node]) << node; } ASSERT_FALSE(HasFailure()) - << DUMP_VARS(num_nodes, num_arcs, num_sources, limit, sources, - lengths) + << DUMP_VARS(num_nodes, num_arcs, num_sources, limit, lengths) << "\n With graph:\n" << util::GraphToString(graph, util::PRINT_GRAPH_ARCS); } diff --git a/ortools/graph/cliques_test.cc b/ortools/graph/cliques_test.cc index 623d104ba3..b28bbda188 100644 --- a/ortools/graph/cliques_test.cc +++ b/ortools/graph/cliques_test.cc @@ -33,7 +33,6 @@ #include "gtest/gtest.h" #include "ortools/base/mathutil.h" #include "ortools/util/time_limit.h" -#include "util/functional/to_callback.h" namespace operations_research { namespace { @@ -163,9 +162,7 @@ TEST(BronKerbosch, CompleteGraph) { CliqueReporter reporter; auto callback = absl::bind_front(&CliqueReporter::AppendClique, &reporter); - operations_research::FindCliques( - ::util::functional::ToPermanentCallback(graph), num_nodes, - ::util::functional::ToPermanentCallback(callback)); + operations_research::FindCliques(graph, num_nodes, callback); const std::vector>& all_cliques = reporter.all_cliques(); EXPECT_EQ(1, all_cliques.size()); EXPECT_EQ(num_nodes, all_cliques[0].size()); @@ -243,9 +240,7 @@ TEST(BronKerbosch, EmptyGraph) { CliqueReporter reporter; auto callback = absl::bind_front(&CliqueReporter::AppendClique, &reporter); - operations_research::FindCliques( - ::util::functional::ToPermanentCallback(graph), 10, - ::util::functional::ToPermanentCallback(callback)); + operations_research::FindCliques(graph, 10, callback); const std::vector>& all_cliques = reporter.all_cliques(); EXPECT_EQ(10, all_cliques.size()); for (int i = 0; i < 10; ++i) { @@ -336,9 +331,7 @@ TEST(BronKerbosch, MatchingGraph) { CliqueReporter reporter; auto callback = absl::bind_front(&CliqueReporter::AppendClique, &reporter); - operations_research::FindCliques( - ::util::functional::ToPermanentCallback(graph), 10, - ::util::functional::ToPermanentCallback(callback)); + operations_research::FindCliques(graph, 10, callback); const std::vector>& all_cliques = reporter.all_cliques(); EXPECT_EQ(5, all_cliques.size()); for (int i = 0; i < 5; ++i) { @@ -370,9 +363,7 @@ TEST(BronKerbosch, ModuloGraph5) { CliqueReporter reporter; auto callback = absl::bind_front(&CliqueReporter::AppendClique, &reporter); - operations_research::FindCliques( - ::util::functional::ToPermanentCallback(graph), 40, - ::util::functional::ToPermanentCallback(callback)); + operations_research::FindCliques(graph, 40, callback); const std::vector>& all_cliques = reporter.all_cliques(); EXPECT_EQ(5, all_cliques.size()); for (int i = 0; i < 5; ++i) { @@ -406,9 +397,7 @@ TEST(BronKerbosch, CompleteGraphCover) { CliqueReporter reporter; auto callback = absl::bind_front(&CliqueReporter::AppendClique, &reporter); - operations_research::CoverArcsByCliques( - ::util::functional::ToPermanentCallback(graph), 10, - ::util::functional::ToPermanentCallback(callback)); + operations_research::CoverArcsByCliques(graph, 10, callback); const std::vector>& all_cliques = reporter.all_cliques(); EXPECT_EQ(1, all_cliques.size()); EXPECT_EQ(10, all_cliques[0].size()); @@ -457,9 +446,7 @@ TEST(BronKerbosch, EmptyGraphCover) { CliqueReporter reporter; auto callback = absl::bind_front(&CliqueReporter::AppendClique, &reporter); - operations_research::CoverArcsByCliques( - ::util::functional::ToPermanentCallback(graph), 10, - ::util::functional::ToPermanentCallback(callback)); + operations_research::CoverArcsByCliques(graph, 10, callback); const std::vector>& all_cliques = reporter.all_cliques(); EXPECT_EQ(0, all_cliques.size()); } @@ -469,9 +456,7 @@ TEST(BronKerbosch, MatchingGraphCover) { CliqueReporter reporter; auto callback = absl::bind_front(&CliqueReporter::AppendClique, &reporter); - operations_research::CoverArcsByCliques( - ::util::functional::ToPermanentCallback(graph), 10, - ::util::functional::ToPermanentCallback(callback)); + operations_research::CoverArcsByCliques(graph, 10, callback); const std::vector>& all_cliques = reporter.all_cliques(); EXPECT_EQ(5, all_cliques.size()); for (int i = 0; i < 5; ++i) { @@ -486,9 +471,7 @@ TEST(BronKerbosch, ModuloGraph5Cover) { CliqueReporter reporter; auto callback = absl::bind_front(&CliqueReporter::AppendClique, &reporter); - operations_research::CoverArcsByCliques( - ::util::functional::ToPermanentCallback(graph), 40, - ::util::functional::ToPermanentCallback(callback)); + operations_research::CoverArcsByCliques(graph, 40, callback); const std::vector>& all_cliques = reporter.all_cliques(); EXPECT_EQ(5, all_cliques.size()); for (int i = 0; i < 5; ++i) { @@ -628,9 +611,7 @@ void BM_FindCliquesInModuloGraph(benchmark::State& state) { auto callback = absl::bind_front(&CliqueSizeVerifier::AppendClique, &verifier); - operations_research::FindCliques( - ::util::functional::ToPermanentCallback(graph), kGraphSize, - ::util::functional::ToPermanentCallback(callback)); + operations_research::FindCliques(graph, kGraphSize, callback); } EXPECT_EQ(state.max_iterations * kExpectedNumCliques, verifier.num_cliques()); } @@ -720,10 +701,8 @@ void BM_FindCliquesInFull7PartiteGraph(benchmark::State& state) { auto callback = absl::bind_front(&CliqueSizeVerifier::AppendClique, &verifier); - operations_research::FindCliques( - ::util::functional::ToPermanentCallback(graph), - kNumPartitions * kNumPartitions, - ::util::functional::ToPermanentCallback(callback)); + operations_research::FindCliques(graph, kNumPartitions * kNumPartitions, + callback); } EXPECT_EQ(state.max_iterations * kExpectedNumCliques, verifier.num_cliques()); } @@ -733,8 +712,7 @@ BENCHMARK(BM_FindCliquesInFull7PartiteGraph); void BM_FindCliquesInFullKPartiteGraphWithBronKerboschAlgorithm( benchmark::State& state) { int num_partitions = state.range(0); - const int kExpectedNumCliques = - ::MathUtil::IPow(num_partitions, num_partitions); + const int kExpectedNumCliques = std::pow(num_partitions, num_partitions); const int kExpectedCliqueSize = num_partitions; const auto graph = [num_partitions](int index1, int index2) { @@ -764,7 +742,7 @@ void BM_FindCliquesInRandomGraphWithBronKerboschAlgorithm( const double arc_probability = arc_probability_permille / 1000.0; const absl::flat_hash_set> adjacency_matrix = MakeRandomGraphAdjacencyMatrix(num_nodes, arc_probability, - absl::GetFlag(FLAGS_test_random_seed)); + GTEST_FLAG_GET(random_seed)); const auto graph = [adjacency_matrix](int index1, int index2) { return BitmapGraph(adjacency_matrix, index1, index2); }; diff --git a/ortools/graph/k_shortest_paths_test.cc b/ortools/graph/k_shortest_paths_test.cc index f36e743ff4..6daa856975 100644 --- a/ortools/graph/k_shortest_paths_test.cc +++ b/ortools/graph/k_shortest_paths_test.cc @@ -237,8 +237,8 @@ Graph GenerateUniformGraph(URBG&& urbg, const NodeIndexType num_nodes, for (ArcIndexType i = 0; i < std::min(num_edges, max_num_arcs); ++i) { NodeIndexType src, dst; std::tie(src, dst) = pick_two_distinct_nodes(); - if (arcs.contains({src, dst})) continue; - if (IsDirected && arcs.contains({dst, src})) continue; + if (arcs.find({src, dst}) != arcs.end()) continue; + if (IsDirected && (arcs.find({dst, src}) != arcs.end())) continue; arcs.insert({src, dst}); graph.AddArc(src, dst); diff --git a/ortools/graph/min_cost_flow_test.cc b/ortools/graph/min_cost_flow_test.cc index 6556bb1b2b..8ad26727b2 100644 --- a/ortools/graph/min_cost_flow_test.cc +++ b/ortools/graph/min_cost_flow_test.cc @@ -588,7 +588,7 @@ CostValue SolveMinCostFlow(GenericMinCostFlow* min_cost_flow) { template CostValue SolveMinCostFlowWithLP(GenericMinCostFlow* min_cost_flow) { - MPSolver solver("LPSolver", MPSolver::CLP_LINEAR_PROGRAMMING); + MPSolver solver("LPSolver", MPSolver::GLOP_LINEAR_PROGRAMMING); const Graph* graph = min_cost_flow->graph(); const NodeIndex num_nodes = graph->num_nodes(); const ArcIndex num_arcs = graph->num_arcs(); diff --git a/ortools/graph/test_util.h b/ortools/graph/test_util.h new file mode 100644 index 0000000000..0841acfc0f --- /dev/null +++ b/ortools/graph/test_util.h @@ -0,0 +1,65 @@ +// 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. + +// Unit test utilities related to graph.h. + +#ifndef UTIL_GRAPH_TEST_UTIL_H_ +#define UTIL_GRAPH_TEST_UTIL_H_ + +#include +#include + +#include "absl/memory/memory.h" +#include "ortools/base/types.h" +#include "ortools/graph/graph.h" + +namespace util { + +// Generate a 2-dimensional undirected grid graph. +// +// Eg. for width=3, height=2, it generates this: +// 0 <---> 1 <---> 2 +// ^ ^ ^ +// | | | +// v v v +// 3 <---> 4 <---> 5 +template +std::unique_ptr Create2DGridGraph(int64_t width, int64_t height) { + const int64_t num_arcs = 2L * ((width - 1) * height + width * (height - 1)); + auto graph = std::make_unique(/*num_nodes=*/width * height, + /*arc_capacity=*/num_arcs); + // Add horizontal edges. + for (int i = 0; i < height; ++i) { + for (int j = 1; j < width; ++j) { + const int left = i * width + (j - 1); + const int right = i * width + j; + graph->AddArc(left, right); + graph->AddArc(right, left); + } + } + // Add vertical edges. + for (int i = 1; i < height; ++i) { + for (int j = 0; j < width; ++j) { + const int up = (i - 1) * width + j; + const int down = i * width + j; + graph->AddArc(up, down); + graph->AddArc(down, up); + } + } + graph->Build(); + return graph; +} + +} // namespace util + +#endif // UTIL_GRAPH_TEST_UTIL_H_