Skip to content

Commit

Permalink
[BENCH] Bron-Kerbosch clique detection (bobluppes#157)
Browse files Browse the repository at this point in the history
* - added DFS cycle detection for directed and undirected graph
- added tests

* - corrected code according to comments

* Apply suggestions from code review

* - First example of potential use of the library

* - small fixes

* Update transport-example.md

Corrected trailling slashes

* clang format fix

* reflect breaking changes on main

* clang format fix

* - corrected according to git comments
- relative railway example
- corrected png files

* small fixes

* small fixes

* fix issues after merge

* fix syntax highlighting code blocks

* clang format

* - Added MST algorithm
- Added test cases and docs

* clang style correction

* Apply suggestions from code review

* Added topological sort algorithm DFS-based

* small fixes

* clang format fix

* added test

* more tests

* Minor fixes
Added one test

* Clang format

* Update topological-sort.md

Corrected doc file

* DOCS for DFS based cycle detection

* small fixes

* Update dfs-based.md

* Added Floyd-WArshall algorithm
- algorithm
- test
- documentation

* clang tidy

* removed redundant negative cicle check and according tests, added two new tests

* Bron-Kerbosch algorithm

* Added to readme

* corrected according to comments

* Update README.md

* folder name correction, added json to docs

* small correction in name and headers

* benchmark test Bron-Kerbosch

* Changed according to comments

---------

Co-authored-by: Bob Luppes <[email protected]>
  • Loading branch information
Hromz and bobluppes authored Oct 19, 2023
1 parent 04c8528 commit 58423fc
Showing 1 changed file with 173 additions and 0 deletions.
173 changes: 173 additions & 0 deletions perf/graaflib/bron_kerbosch_benchmark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#include <benchmark/benchmark.h>
#include <graaflib/algorithm/clique_detection/bron_kerbosch.h>
#include <graaflib/graph.h>

#include <random>
#include <vector>

namespace {
// Generating random number of vertices (1- 30) for a clique
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> random_clique_size(1,
30);
template <typename EDGE_T>
[[nodiscard]] std::vector<graaf::vertex_id_t> create_vertices(
graaf::undirected_graph<int, EDGE_T>& graph, size_t n) {
std::vector<graaf::vertex_id_t> vertices{};
vertices.reserve(n);

for (size_t i{0}; i < n; ++i) {
vertices.push_back(graph.add_vertex(i));
}

return vertices;
}

template <typename EDGE_T>
void add_clique(graaf::undirected_graph<int, EDGE_T>& graph,
const std::vector<graaf::vertex_id_t>& vertices,
size_t start_vertex, size_t clique_size) {
// We are in range of vector of vertices
size_t end_vertex = std::min(start_vertex + clique_size, vertices.size());

// Constructing a clique
for (size_t i{start_vertex}; i < end_vertex; ++i) {
for (size_t j{i + 1}; j < end_vertex; ++j) {
graph.add_edge(vertices[i], vertices[j], 1);
}
}
}
} // namespace

static void bron_kerbosh_cliques(benchmark::State& state) {
const auto number_of_edges{static_cast<size_t>(state.range(0))};

graaf::undirected_graph<int, int> graph{};

// We create enough vertices to construct the requested number of edges
const auto number_of_vertices{number_of_edges + 1};
const auto vertices{create_vertices(graph, number_of_vertices)};
const auto clique_size = static_cast<size_t>(state.range(1));

for (size_t i{0}; i < number_of_edges; i += clique_size) {
add_clique(graph, vertices, i, clique_size);
}

for (auto _ : state) {
auto result = graaf::algorithm::bron_kerbosch(graph);
benchmark::DoNotOptimize(result);
}

state.SetComplexityN(state.range(1));
}

static void bron_kerbosh_connected_cliques(benchmark::State& state) {
const auto number_of_edges{static_cast<size_t>(state.range(0))};

graaf::undirected_graph<int, int> graph{};

// We create enough vertices to construct the requested number of edges
const auto number_of_vertices{number_of_edges + 1};
const auto vertices{create_vertices(graph, number_of_vertices)};
const auto clique_size = static_cast<size_t>(state.range(1));

// Connecting all cliques
for (size_t i{0}; i + clique_size < number_of_edges; i += clique_size) {
graph.add_edge(vertices[i], vertices[i + clique_size], 1);
}

for (size_t i{0}; i < number_of_edges; i += clique_size) {
add_clique(graph, vertices, i, clique_size);
}

for (auto _ : state) {
auto result = graaf::algorithm::bron_kerbosch(graph);
benchmark::DoNotOptimize(result);
}

state.SetComplexityN(state.range(1));
}

static void bron_kerbosh_random_cliques(benchmark::State& state) {
const auto number_of_edges{static_cast<size_t>(state.range(0))};

graaf::undirected_graph<int, int> graph{};

// We create enough vertices to construct the requested number of edges
const auto number_of_vertices{number_of_edges + 1};
const auto vertices{create_vertices(graph, number_of_vertices)};
size_t clique_size = random_clique_size(rng);

for (size_t i{0}; i + clique_size < number_of_edges; i += clique_size) {
add_clique(graph, vertices, i, clique_size++);
clique_size = random_clique_size(rng);
}

for (auto _ : state) {
auto result = graaf::algorithm::bron_kerbosch(graph);
benchmark::DoNotOptimize(result);
}

state.SetComplexityN(state.range(0));
}

static void bron_kerbosh_connected_random_cliques(benchmark::State& state) {
const auto number_of_edges{static_cast<size_t>(state.range(0))};

graaf::undirected_graph<int, int> graph{};

// We create enough vertices to construct the requested number of edges
const auto number_of_vertices{number_of_edges + 1};
const auto vertices{create_vertices(graph, number_of_vertices)};
size_t clique_size = random_clique_size(rng);

// Connecting all cliques
for (size_t i{0}; i < number_of_edges; ++i) {
graph.add_edge(vertices[i], vertices[i + 1], 1);
}

for (size_t i{0}; i + clique_size < number_of_edges; i += clique_size) {
add_clique(graph, vertices, i, clique_size++);
clique_size = random_clique_size(rng);
}

for (auto _ : state) {
auto result = graaf::algorithm::bron_kerbosch(graph);
benchmark::DoNotOptimize(result);
}

state.SetComplexityN(state.range(0));
}

BENCHMARK(bron_kerbosh_cliques)
->Ranges({{100, 10000}, {2, 32}}) /* clique size 2 ^ n */
->Unit(benchmark::kMillisecond)
->Complexity();
BENCHMARK(bron_kerbosh_connected_cliques)
->Ranges({{100, 10000}, {2, 32}}) /* clique size 2 ^ n */
->Unit(benchmark::kMillisecond)
->Complexity();
BENCHMARK(bron_kerbosh_cliques)
->Ranges({{100, 1000},
{1000, 1000}}) /* Dense graph, number of vertices are
min(state.range(1), vertex.size()) */
->Unit(benchmark::kMillisecond)
->Complexity();
BENCHMARK(bron_kerbosh_cliques)
->Ranges({{100, 10000}, {10, 60}}) /* large cliques */
->Unit(benchmark::kMillisecond)
->Complexity();
BENCHMARK(bron_kerbosh_connected_cliques)
->Ranges({{100, 10000}, {10, 60}}) /* large cliques */
->Unit(benchmark::kMillisecond)
->Complexity();
BENCHMARK(bron_kerbosh_random_cliques) /* random clique size between 1-30 */
->Range(100, 10000)
->Unit(benchmark::kMillisecond)
->Complexity();
BENCHMARK(
bron_kerbosh_connected_random_cliques) /* random clique size between 1-30 */
->Range(100, 10000)
->Unit(benchmark::kMillisecond)
->Complexity();

0 comments on commit 58423fc

Please sign in to comment.