diff --git a/ligra/BUILD b/ligra/BUILD index 13c975302..0a66e3ebe 100644 --- a/ligra/BUILD +++ b/ligra/BUILD @@ -128,6 +128,8 @@ cc_library( ":macros", ":undirected_edge", ":vertex", + "//pbbslib:assert", + "//pbbslib:sample_sort", "//pbbslib:utilities", ] ) diff --git a/ligra/graph_test_utils.cc b/ligra/graph_test_utils.cc index baf4c60a6..c4f1a7fae 100644 --- a/ligra/graph_test_utils.cc +++ b/ligra/graph_test_utils.cc @@ -2,14 +2,19 @@ #include +#include "pbbslib/assert.h" +#include "pbbslib/sample_sort.h" + namespace graph_test { symmetric_graph MakeUnweightedSymmetricGraph( const uintE num_vertices, - const std::unordered_set& edges) { + const std::unordered_set& edges, + const ShouldSortNeighbors should_sort_neighbors) { + using Edge = std::tuple; constexpr pbbs::empty weight{}; - pbbs::sequence> edge_sequence( - edges.size() * 2); + + pbbs::sequence edge_sequence(edges.size() * 2); auto edges_it{edges.cbegin()}; for (size_t i = 0; i < edges.size(); i++) { edge_sequence[2 * i] = @@ -24,7 +29,23 @@ symmetric_graph MakeUnweightedSymmetricGraph( weight); ++edges_it; } - return sym_graph_from_edges(edge_sequence, num_vertices); + + switch (should_sort_neighbors) { + case ShouldSortNeighbors::kYes: { + pbbs::sample_sort_inplace( + edge_sequence.slice(), + [](const Edge& left, const Edge& right) { + return std::tie(std::get<0>(left), std::get<1>(left)) + < std::tie(std::get<0>(right), std::get<1>(right)); + }); + constexpr bool kEdgesAreSorted{true}; + return sym_graph_from_edges(edge_sequence, num_vertices, kEdgesAreSorted); + } + case ShouldSortNeighbors::kNo: { + return sym_graph_from_edges(edge_sequence, num_vertices); + } + } + ABORT_INVALID_ENUM(ShouldSortNeighbors, should_sort_neighbors); } } // namespace graph_test diff --git a/ligra/graph_test_utils.h b/ligra/graph_test_utils.h index 351a1dc80..1eb2ac5b6 100644 --- a/ligra/graph_test_utils.h +++ b/ligra/graph_test_utils.h @@ -12,9 +12,15 @@ namespace graph_test { +enum class ShouldSortNeighbors { kYes, kNo }; + // Make an undirected, unweighted graph from a list of edges. +// +// If `should_sort_neighbors` is set to `ShouldSortNeighbors::kYes`, then each +// vertex's list of neighbors will be sorted in the graph representation. symmetric_graph MakeUnweightedSymmetricGraph( const uintE num_vertices, - const std::unordered_set& edges); + const std::unordered_set& edges, + ShouldSortNeighbors should_sort_neighbors = ShouldSortNeighbors::kNo); } // namespace graph_test diff --git a/ligra/unit_tests/BUILD b/ligra/unit_tests/BUILD index aa01d970e..2445bb500 100644 --- a/ligra/unit_tests/BUILD +++ b/ligra/unit_tests/BUILD @@ -3,6 +3,7 @@ cc_test( srcs = ["graph_test.cc"], deps = [ "//ligra:graph", + "//ligra:graph_test_utils", "//pbbslib:seq", "@googletest//:gtest_main", ], diff --git a/ligra/unit_tests/graph_test.cc b/ligra/unit_tests/graph_test.cc index 7a9151fc6..bfe1a1049 100644 --- a/ligra/unit_tests/graph_test.cc +++ b/ligra/unit_tests/graph_test.cc @@ -1,7 +1,10 @@ #include #include "ligra/graph.h" +#include "ligra/graph_test_utils.h" #include "pbbslib/seq.h" +namespace gt = graph_test; + TEST(TestSymGraphFromEdges, TestBrokenPath) { using edge = std::tuple; uintE n = 11; @@ -49,3 +52,50 @@ TEST(TestSymGraphFromEdges, TestGraphWithSingletons) { ASSERT_EQ(graph.get_vertex(2).getOutDegree(), 0); ASSERT_EQ(graph.get_vertex(3).getOutDegree(), 0); } + +TEST(symmetric_vertex, Intersect) { + using Vertex = symmetric_vertex; + + // Graph diagram: + // 0 - 1 - 2 + // \ / \ / + // 3 - 4 -- 5 + constexpr uintE kNumVertices{6}; + const std::unordered_set kEdges{ + {0, 1}, + {0, 3}, + {1, 2}, + {1, 3}, + {1, 4}, + {2, 4}, + {3, 4}, + {4, 5}, + }; + auto graph{gt::MakeUnweightedSymmetricGraph( + kNumVertices, kEdges, gt::ShouldSortNeighbors::kYes)}; + + { + const uintE u_id{0}; + const uintE v_id{5}; + Vertex u{graph.get_vertex(u_id)}; + Vertex v{graph.get_vertex(v_id)}; + EXPECT_EQ((u.intersect(&v, u_id, v_id)), 0); + EXPECT_EQ((v.intersect(&u, v_id, u_id)), 0); + } + { + const uintE u_id{0}; + const uintE v_id{1}; + Vertex u{graph.get_vertex(u_id)}; + Vertex v{graph.get_vertex(v_id)}; + EXPECT_EQ((u.intersect(&v, u_id, v_id)), 1); + EXPECT_EQ((v.intersect(&u, v_id, u_id)), 1); + } + { + const uintE u_id{1}; + const uintE v_id{3}; + Vertex u{graph.get_vertex(u_id)}; + Vertex v{graph.get_vertex(v_id)}; + EXPECT_EQ((u.intersect(&v, u_id, v_id)), 2); + EXPECT_EQ((v.intersect(&u, v_id, u_id)), 2); + } +} diff --git a/ligra/vertex.h b/ligra/vertex.h index b3b127bd2..a41568602 100644 --- a/ligra/vertex.h +++ b/ligra/vertex.h @@ -26,6 +26,7 @@ #include "pbbslib/sequence_ops.h" #include "macros.h" +// This `intersection` namespace is intended for internal use only. namespace intersection { template