diff --git a/data/tc_test.csv b/data/tc_test.csv new file mode 100644 index 0000000..97c10a6 --- /dev/null +++ b/data/tc_test.csv @@ -0,0 +1,16 @@ +FROM,TO,DIST +A,B,1 +A,C,1 +A,D,1 +A,E,1 +B,C,1 +B,D,1 +B,E,1 +C,D,1 +E,C,1 +D,E,1 +B,F,1 +E,F,1 +E,G,1 +F,H,1 +G,H,1 diff --git a/include/graph/algorithm/tc.hpp b/include/graph/algorithm/tc.hpp new file mode 100644 index 0000000..b2db6e2 --- /dev/null +++ b/include/graph/algorithm/tc.hpp @@ -0,0 +1,73 @@ +/** + * @file tc.hpp + * + * @brief Minimum spanning tree using Kruskal's and Prim's algorithms. + * + * @copyright Copyright (c) 2022 + * + * SPDX-License-Identifier: BSL-1.0 + * + * @authors + * Andrew Lumsdaine + * Phil Ratzloff + * Kevin Deweese + */ + +#include "graph/graph.hpp" + +#ifndef GRAPH_MST_HPP +# define GRAPH_MST_HPP + +namespace std::graph { + +/** + * @ingroup graph_algorithms + * @brief Find the number of triangles in a graph. + * + * Complexity: O(|V|^3) + * + * @tparam G The graph type. + * + * @param g The graph. + */ +template +requires ranges::random_access_range> && integral> +size_t triangle_count(G&& g) { + size_t N(size(vertices(g))); + size_t triangles(0); + + for (vertex_id_t uid = 0; uid < N; ++uid) { + std::graph::incidence_iterator i(g, uid); + auto ie = ranges::end(edges(g, uid)); + while (i != ie) { + auto&& [vid, uv] = *i; + if(vid < uid) { + ++i; + continue; + } + std::graph::incidence_iterator j(g, vid); + auto je = ranges::end(edges(g, vid)); + auto i2 = i; + + // Alternatively use std::set_intersection(i2, ie, j, je, counter) but this is slower + while (i2 != ie && j != je) { + auto&& [wid1, uw] = *i2; + auto&& [wid2, vw] = *j; + if (wid1 < wid2) { + ++i2; + } else if (wid2 < wid1) { + ++j; + } else { + ++triangles; + ++i2; + ++j; + } + } + ++i; + } + } + return triangles; +} +} // namespace std::graph + +#endif //GRAPH_MST_HPP \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f97ccca..525f8ce 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -47,6 +47,7 @@ set(UNITTEST_SOURCES "mis_tests.cpp" "pagerank_tests.cpp" "mst_tests.cpp" + "tc_tests.cpp" ) foreach(SOURCE IN LISTS UNITTEST_SOURCES) diff --git a/tests/tc_tests.cpp b/tests/tc_tests.cpp new file mode 100644 index 0000000..17e0c08 --- /dev/null +++ b/tests/tc_tests.cpp @@ -0,0 +1,25 @@ +#include +#include "csv_routes.hpp" +#include "graph/graph.hpp" +#include "graph/algorithm/tc.hpp" +#include "graph/container/dynamic_graph.hpp" +#include "graph/views/incidence.hpp" +#ifdef _MSC_VER +# include "Windows.h" +#endif + +using std::cout; +using std::endl; + +using routes_vol_graph_traits = std::graph::container::vol_graph_traits; +using routes_vol_graph_type = std::graph::container::dynamic_adjacency_graph; + +TEST_CASE("triangle counting test", "[tc]") { + init_console(); + + using G = routes_vol_graph_type; + auto&& g = load_ordered_graph(TEST_DATA_ROOT_DIR "tc_test.csv", name_order_policy::alphabetical, true); + + size_t triangles = std::graph::triangle_count(g); + REQUIRE(triangles == 11); +} \ No newline at end of file