Bron–Kerbosch algorithm

Develop a program that identifies and lists all maximal cliques within an undirected graph. A maximal clique is a subset of vertices where every two distinct vertices are adjacent (i.e., there's an edge connecting them), and the clique cannot be extended by including any adjacent vertex not already in the clique.

Task
Bron–Kerbosch algorithm
You are encouraged to solve this task according to the task description, using any language you may know.
Objective
Background

In graph theory, a clique is a subset of vertices of an undirected graph such that every two distinct vertices in the clique are connected by an edge. A maximal clique is a clique that cannot be extended by adding one more adjacent vertex, meaning it's not a subset of a larger clique.

The Bron-Kerbosch algorithm is a recursive backtracking algorithm used to find all maximal cliques in an undirected graph efficiently. The algorithm is particularly effective due to its use of pivot selection, which reduces the number of recursive calls and improves performance.

Program Functionality
  1. Input Representation:
  • The graph is represented as a list of edges, where each edge is a tuple of two vertices (e.g., `('a', 'b')` indicates an undirected edge between vertices `'a'` and `'b'`).
  1. Graph Construction:
  • Convert the list of edges into an adjacency list using a `HashMap<String, HashSet<String>>`. Each key in the hashmap represents a vertex, and its corresponding hash set contains all adjacent vertices (neighbors).
  1. Bron-Kerbosch Algorithm Implementation:
  • Sets Used:
    • R (Current Clique): A set representing the current clique being constructed.
    • P (Potential Candidates): A set of vertices that can be added to R to form a larger clique.
    • X (Excluded Vertices): A set of vertices that have already been processed and should not be reconsidered for the current clique.
  • Algorithm Steps:
    • If both P and X are empty, and R contains more than two vertices, R is a maximal clique and is added to the list of cliques.
    • Otherwise, select a pivot vertex from the union of P and X that has the maximum number of neighbors. This pivot helps minimize the number of recursive calls.
    • Iterate over all vertices in P that are **not** neighbors of the pivot. For each such vertex:
      • Add the vertex to R.
      • Update P and X to include only those vertices that are neighbors of the added vertex.
      • Recursively call the Bron-Kerbosch function with the updated sets.
      • After recursion, move the vertex from P to X to mark it as processed.
  1. Output:
  • After executing the algorithm, the program prints all maximal cliques with more than two vertices. Each clique is displayed as a comma-separated list of its constituent vertices.
Example

Given the following edges:

('a', 'b'), ('b', 'a'), ('a', 'c'), ('c', 'a'), ('b', 'c'), ('c', 'b'), ('d', 'e'), ('e', 'd'), ('d', 'f'), ('f', 'd'), ('e', 'f'), ('f', 'e') 

Expected Output:

a, b, c d, e, f 

These outputs represent the two maximal cliques in the graph: one comprising vertices `a`, `b`, and `c`, and the other comprising vertices `d`, `e`, and `f`.

Pseudocode

Below is the pseudocode for the Bron-Kerbosch algorithm with pivoting, closely following the Rust implementation provided earlier.

FUNCTION BronKerbosch(R, P, X, G, Cliques) // R: Current clique (Set) // P: Potential candidates to expand the clique (Set) // X: Vertices already processed (Set) // G: Graph represented as an adjacency list (Dictionary) // Cliques: List to store all maximal cliques (List of Lists) IF P is empty AND X is empty THEN IF size of R > 2 THEN SORT R lexicographically ADD R to Cliques END IF RETURN END IF // Select a pivot vertex from P ∪ X with the maximum degree Pivot := vertex in (P ∪ X) with the highest number of neighbors in G // Candidates are vertices in P that are not neighbors of the pivot Candidates := P - Neighbors(Pivot) FOR EACH vertex v IN Candidates DO // New clique including vertex v NewR := R ∪ {v} // New potential candidates are neighbors of v in P Neighbors_v := G[v] NewP := P ∩ Neighbors_v // New excluded vertices are neighbors of v in X NewX := X ∩ Neighbors_v // Recursive call with updated sets BronKerbosch(NewR, NewP, NewX, G, Cliques) // Move vertex v from P to X P := P - {v} X := X ∪ {v} END FOR END FUNCTION FUNCTION Main() // Define input edges as a list of tuples Input := [ ('a', 'b'), ('b', 'a'), ('a', 'c'), ('c', 'a'), ('b', 'c'), ('c', 'b'), ('d', 'e'), ('e', 'd'), ('d', 'f'), ('f', 'd'), ('e', 'f'), ('f', 'e') ] // Build the graph as an adjacency list Graph := empty Dictionary FOR EACH (src, dest) IN Input DO IF src NOT IN Graph THEN Graph[src] := empty Set END IF ADD dest TO Graph[src] END FOR // Initialize R, P, X R := empty Set P := set of all vertices in Graph X := empty Set // Initialize list to store cliques Cliques := empty List // Execute the Bron-Kerbosch algorithm BronKerbosch(R, P, X, Graph, Cliques) // Sort the cliques for consistent output SORT Cliques lexicographically // Print each clique FOR EACH Clique IN Cliques DO PRINT elements of Clique separated by commas END FOR END FUNCTION 


Works with: C# version .NET 9
Translation of: Java
using System; using System.Collections.Generic; using System.Linq;  public class BronKerboschAlgorithm {  private static List<List<string>> cliques = new List<List<string>>();   public static void Main(string[] args)  {  var edges = new List<Edge>  {  new Edge("a", "b"), new Edge("b", "a"),  new Edge("a", "c"), new Edge("c", "a"),  new Edge("b", "c"), new Edge("c", "b"),  new Edge("d", "e"), new Edge("e", "d"),  new Edge("d", "f"), new Edge("f", "d"),  new Edge("e", "f"), new Edge("f", "e")  };   // Build the graph as an adjacency list  var graph = new Dictionary<string, HashSet<string>>();  foreach (var edge in edges)  {  if (!graph.ContainsKey(edge.Start))  graph[edge.Start] = new HashSet<string>();  graph[edge.Start].Add(edge.End);  }   // Initialize current clique, candidates and processed vertices  var currentClique = new SortedSet<string>();  var candidates = new HashSet<string>(graph.Keys);  var processedVertices = new HashSet<string>();   // Execute the Bron-Kerbosch algorithm to collect the cliques  BronKerbosch(currentClique, candidates, processedVertices, graph);   // Sort the cliques for consistent display  cliques = cliques.OrderBy(c => c, new ListComparer()).ToList();   // Display the cliques  Console.WriteLine("[{0}]", string.Join(", ", cliques.Select(c => "[" + string.Join(", ", c) + "]")));  }   private static void BronKerbosch(  SortedSet<string> currentClique,  HashSet<string> candidates,  HashSet<string> processedVertices,  Dictionary<string, HashSet<string>> graph)  {  if (candidates.Count == 0 && processedVertices.Count == 0)  {  if (currentClique.Count > 2)  {  cliques.Add(new List<string>(currentClique));  }  return;  }   // Select a pivot vertex from 'candidates' union 'processedVertices' with the maximum degree  var union = new HashSet<string>(candidates);  union.UnionWith(processedVertices);   string pivot = union.OrderByDescending(v => graph.ContainsKey(v) ? graph[v].Count : 0).First();   // 'possibles' are vertices in 'candidates' that are not neighbours of the 'pivot'  var possibles = new HashSet<string>(candidates);  if (graph.ContainsKey(pivot))  possibles.ExceptWith(graph[pivot]);   foreach (var vertex in possibles)  {  // Create a new clique including 'vertex'  var newClique = new SortedSet<string>(currentClique);  newClique.Add(vertex);   // 'newCandidates' are the members of 'candidates' that are neighbours of 'vertex'  var neighbours = graph.ContainsKey(vertex) ? graph[vertex] : new HashSet<string>();  var newCandidates = new HashSet<string>(candidates);  newCandidates.IntersectWith(neighbours);   // 'newProcessedVertices' are members of 'processedVertices' that are neighbours of 'vertex'  var newProcessedVertices = new HashSet<string>(processedVertices);  newProcessedVertices.IntersectWith(neighbours);   // Recursive call with the updated sets  BronKerbosch(newClique, newCandidates, newProcessedVertices, graph);   // Move 'vertex' from 'candidates' to 'processedVertices'  candidates.Remove(vertex);  processedVertices.Add(vertex);  }  }   private class ListComparer : IComparer<List<string>>  {  public int Compare(List<string> x, List<string> y)  {  for (int i = 0; i < Math.Min(x.Count, y.Count); i++)  {  int comparison = x[i].CompareTo(y[i]);  if (comparison != 0)  return comparison;  }  return x.Count.CompareTo(y.Count);  }  }   private class Edge  {  public string Start { get; }  public string End { get; }   public Edge(string start, string end)  {  Start = start;  End = end;  }  } } 
Output:
[[a, b, c], [d, e, f]] 
#include <algorithm> #include <cstdint> #include <iostream> #include <set> #include <string> #include <unordered_map> #include <vector> std::vector<std::vector<std::string>> cliques{}; struct Edge { std::string start; std::string end; }; template <typename T> void print_vector(const std::vector<T>& vec) { std::cout << "["; for ( uint32_t i = 0; i < vec.size() - 1; ++i ) { std::cout << vec[i] << ", "; } std::cout << vec.back() << "]"; } template <typename T> void print_2D_vector(const std::vector<std::vector<T>>& vecs) { std::cout << "["; for ( uint32_t i = 0; i < vecs.size() - 1; ++i ) { print_vector(vecs[i]); std::cout << ", "; } print_vector(vecs.back()); std::cout << "]" << std::endl; } void bron_kerbosch(const std::set<std::string>& current_clique,  std::set<std::string> candidates,  std::set<std::string> processed_vertices,  std::unordered_map<std::string, std::set<std::string>> graph) { if ( candidates.empty() && processed_vertices.empty() ) { if ( current_clique.size() > 2 ) { std::vector<std::string> clique(current_clique.begin(), current_clique.end()); cliques.emplace_back(clique); } return; } // Select a pivot vertex from 'candidates' union 'processedVertices' with the maximum degree std::set<std::string> union_set(candidates.begin(), candidates.end()); union_set.insert(processed_vertices.begin(), processed_vertices.end()); const std::string pivot = *std::max_element(union_set.begin(), union_set.end(),  [&graph](const std::string& s1, const std::string& s2) { return graph[s1].size() < graph[s2].size(); }); // 'possibles' are vertices in 'candidates' that are not neighbours of the 'pivot' std::set<std::string> possibles{}; std::set_difference(candidates.begin(), candidates.end(), graph[pivot].begin(), graph[pivot].end(), std::inserter(possibles, possibles.begin())); for ( const std::string& vertex : possibles) { // Create a new clique including 'vertex' std::set<std::string> new_cliques(current_clique.begin(), current_clique.end()); new_cliques.insert(vertex); // 'newCandidates' are the members of 'candidates' that are neighbours of 'vertex' std::set<std::string> new_candidates{}; std::set_intersection(candidates.begin(), candidates.end(), graph[vertex].begin(), graph[vertex].end(), std::inserter(new_candidates, new_candidates.begin())); // 'newProcessedVertices' are members of 'processedVertices' that are neighbours of 'vertex' std::set<std::string> new_processed_vertices{}; std::set_intersection(processed_vertices.begin(), processed_vertices.end(), graph[vertex].begin(), graph[vertex].end(), std::inserter(new_processed_vertices, new_processed_vertices.begin())); // Recursive call with the updated sets bron_kerbosch(new_cliques, new_candidates, new_processed_vertices, graph); // Move 'vertex' from 'candidates' to 'processedVertices' candidates.erase(vertex); processed_vertices.insert(vertex); } } int main() { const std::vector<Edge> edges = { Edge("a", "b"), Edge("b", "a"), Edge("a", "c"), Edge("c", "a"),  Edge("b", "c"), Edge("c", "b"), Edge("d", "e"), Edge("e", "d"),  Edge("d", "f"), Edge("f", "d"), Edge("e", "f"), Edge("f", "e") }; // Build the graph as an adjacency list std::unordered_map<std::string, std::set<std::string>> graph{}; std::for_each(edges.begin(), edges.end(), [&graph](const Edge& edge) { graph[edge.start].insert(edge.end); } ); // Initialize current clique, candidates and processed vertices std::set<std::string> current_clique{}; std::set<std::string> candidates{}; std::transform(graph.begin(), graph.end(), std::inserter(candidates, candidates.end()),  [](const auto& pair) { return pair.first; } ); std::set<std::string> processed_vertices{}; // Execute the Bron-Kerbosch algorithm to collect the cliques bron_kerbosch(current_clique, candidates, processed_vertices, graph); // Sort the cliques for consistent display std::sort(cliques.begin(), cliques.end(), [](const std::vector<std::string>& a, const std::vector<std::string>& b) { for ( uint32_t i = 0; i < std::min(a.size(), b.size()); ++i ) { if ( a[i] != b[i] ) { return a[i] < b[i]; } } return a.size() < b.size(); }); // Display the cliques print_2D_vector(cliques); } 
Output:
[[a, b, c], [d, e, f]] 
Works with: Dart version 3.6.1
Translation of: C++
List<List<String>> cliques = []; class Edge {  String start;  String end;  Edge(this.start, this.end); } void printVector<T>(List<T> vec) {  StringBuffer sb = StringBuffer();  sb.write('[');  for (int i = 0; i < vec.length - 1; i++) {  sb.write('${vec[i]}, ');  }  sb.write('${vec.last}]');  print(sb.toString()); } void print2DVector<T>(List<List<T>> vecs) {  StringBuffer sb = StringBuffer();  sb.write('[');  for (int i = 0; i < vecs.length - 1; i++) {  printVector(vecs[i]);  sb.write(', ');  }  printVector(vecs.last);  sb.write(']'); } void bronKerbosch(  Set<String> currentClique, Set<String> candidates, Set<String> processedVertices, Map<String, Set<String>> graph) {  if (candidates.isEmpty && processedVertices.isEmpty) {  if (currentClique.length > 2) {  cliques.add(List<String>.from(currentClique));  }  return;  }  // Select a pivot vertex from 'candidates' union 'processedVertices' with the maximum degree  Set<String> unionSet = Set<String>.from(candidates)..addAll(processedVertices);  String pivot = unionSet.reduce((s1, s2) => graph[s1]!.length > graph[s2]!.length ? s1 : s2);  // 'possibles' are vertices in 'candidates' that are not neighbors of the 'pivot'  Set<String> possibles = candidates.difference(graph[pivot]!);  for (String vertex in possibles) {  // Create a new clique including 'vertex'  Set<String> newCliques = Set<String>.from(currentClique)..add(vertex);  // 'newCandidates' are the members of 'candidates' that are neighbors of 'vertex'  Set<String> newCandidates = candidates.intersection(graph[vertex]!);  // 'newProcessedVertices' are members of 'processedVertices' that are neighbors of 'vertex'  Set<String> newProcessedVertices = processedVertices.intersection(graph[vertex]!);  // Recursive call with the updated sets  bronKerbosch(newCliques, newCandidates, newProcessedVertices, graph);  // Move 'vertex' from 'candidates' to 'processedVertices'  candidates.remove(vertex);  processedVertices.add(vertex);  } } void main() {  List<Edge> edges = [  Edge("a", "b"),  Edge("b", "a"),  Edge("a", "c"),  Edge("c", "a"),  Edge("b", "c"),  Edge("c", "b"),  Edge("d", "e"),  Edge("e", "d"),  Edge("d", "f"),  Edge("f", "d"),  Edge("e", "f"),  Edge("f", "e")  ];  // Build the graph as an adjacency list  Map<String, Set<String>> graph = {};  edges.forEach((edge) {  graph.putIfAbsent(edge.start, () => <String>{}).add(edge.end);  });  // Initialize current clique, candidates, and processed vertices  Set<String> currentClique = {};  Set<String> candidates = graph.keys.toSet();  Set<String> processedVertices = {};  // Execute the Bron-Kerbosch algorithm to collect the cliques  bronKerbosch(currentClique, candidates, processedVertices, graph);  // Sort the cliques for consistent display  cliques.sort((a, b) {  for (int i = 0; i < a.length && i < b.length; i++) {  if (a[i] != b[i]) {  return a[i].compareTo(b[i]);  }  }  return a.length.compareTo(b.length);  });  // Display the cliques  print2DVector(cliques); } 
Output:
[a, c, b] [f, e, d] 
Works with: Fortran version 7
Translation of: C++
program bron_kerbosch_cliques  implicit none    ! Maximum number of vertices and cliques  integer, parameter :: MAX_VERTICES = 100  integer, parameter :: MAX_CLIQUES = 1000  integer, parameter :: MAX_EDGES = 1000  integer, parameter :: MAX_NAME_LEN = 10    ! Graph representation using adjacency matrix and vertex names  logical :: adjacency_matrix(MAX_VERTICES, MAX_VERTICES)  character(len=MAX_NAME_LEN) :: vertex_names(MAX_VERTICES)  integer :: num_vertices    ! Cliques storage  integer :: cliques(MAX_CLIQUES, MAX_VERTICES)  integer :: clique_sizes(MAX_CLIQUES)  integer :: num_cliques    ! Edge structure  type :: edge_type  character(len=MAX_NAME_LEN) :: start  character(len=MAX_NAME_LEN) :: end  end type edge_type    ! Local variables  type(edge_type) :: edges(MAX_EDGES)  integer :: num_edges  logical :: current_clique(MAX_VERTICES)  logical :: candidates(MAX_VERTICES)  logical :: processed(MAX_VERTICES)  integer :: i, j    ! Initialize  num_vertices = 0  num_cliques = 0  num_edges = 12    ! Initialize adjacency matrix  adjacency_matrix = .false.    ! Define edges  edges(1) = edge_type("a", "b")  edges(2) = edge_type("b", "a")  edges(3) = edge_type("a", "c")  edges(4) = edge_type("c", "a")  edges(5) = edge_type("b", "c")  edges(6) = edge_type("c", "b")  edges(7) = edge_type("d", "e")  edges(8) = edge_type("e", "d")  edges(9) = edge_type("d", "f")  edges(10) = edge_type("f", "d")  edges(11) = edge_type("e", "f")  edges(12) = edge_type("f", "e")    ! Build graph  call build_graph(edges, num_edges)    ! Initialize sets for Bron-Kerbosch  current_clique = .false.  candidates = .false.  processed = .false.    ! Set all vertices as candidates  do i = 1, num_vertices  candidates(i) = .true.  end do    ! Run Bron-Kerbosch algorithm  call bron_kerbosch_recursive(current_clique, candidates, processed)    ! Sort and display cliques  call sort_cliques()  call print_cliques()   contains  ! Function to find vertex index by name  function find_vertex_index(name) result(index)  implicit none  character(len=*), intent(in) :: name  integer :: index  integer :: i    do i = 1, num_vertices  if (trim(vertex_names(i)) == trim(name)) then  index = i  return  end if  end do    ! Add new vertex if not found  num_vertices = num_vertices + 1  vertex_names(num_vertices) = trim(name)  index = num_vertices  end function find_vertex_index  ! Subroutine to build graph from edges  subroutine build_graph(edges_array, n_edges)  implicit none  type(edge_type), intent(in) :: edges_array(:)  integer, intent(in) :: n_edges  integer :: i, start_idx, end_idx    do i = 1, n_edges  start_idx = find_vertex_index(edges_array(i)%start)  end_idx = find_vertex_index(edges_array(i)%end)  adjacency_matrix(start_idx, end_idx) = .true.  end do  end subroutine build_graph  ! Count number of true values in logical array  function count_true(logical_array) result(count)  implicit none  logical, intent(in) :: logical_array(:)  integer :: count  integer :: i    count = 0  do i = 1, num_vertices  if (logical_array(i)) count = count + 1  end do  end function count_true  ! Find pivot vertex with maximum degree  function find_pivot(candidates_set, processed_set) result(pivot)  implicit none  logical, intent(in) :: candidates_set(:), processed_set(:)  integer :: pivot  integer :: i, max_degree, current_degree  logical :: union_set(MAX_VERTICES)    ! Create union of candidates and processed  do i = 1, num_vertices  union_set(i) = candidates_set(i) .or. processed_set(i)  end do    max_degree = -1  pivot = 1    do i = 1, num_vertices  if (union_set(i)) then  current_degree = count_neighbors(i)  if (current_degree > max_degree) then  max_degree = current_degree  pivot = i  end if  end if  end do  end function find_pivot  ! Count neighbors of a vertex  function count_neighbors(vertex) result(count)  implicit none  integer, intent(in) :: vertex  integer :: count  integer :: i    count = 0  do i = 1, num_vertices  if (adjacency_matrix(vertex, i)) count = count + 1  end do  end function count_neighbors  ! Set difference: result = set_a - set_b  subroutine set_difference(set_a, set_b, result_set)  implicit none  logical, intent(in) :: set_a(:), set_b(:)  logical, intent(out) :: result_set(:)  integer :: i    do i = 1, num_vertices  result_set(i) = set_a(i) .and. .not. set_b(i)  end do  end subroutine set_difference  ! Set intersection: result = set_a ∩ set_b  subroutine set_intersection(set_a, set_b, result_set)  implicit none  logical, intent(in) :: set_a(:), set_b(:)  logical, intent(out) :: result_set(:)  integer :: i    do i = 1, num_vertices  result_set(i) = set_a(i) .and. set_b(i)  end do  end subroutine set_intersection  ! Get neighbors of a vertex  subroutine get_neighbors(vertex, neighbors_set)  implicit none  integer, intent(in) :: vertex  logical, intent(out) :: neighbors_set(:)  integer :: i    do i = 1, num_vertices  neighbors_set(i) = adjacency_matrix(vertex, i)  end do  end subroutine get_neighbors  ! Recursive Bron-Kerbosch algorithm  recursive subroutine bron_kerbosch_recursive(current_clique_set, candidates_set, processed_set)  implicit none  logical, intent(in) :: current_clique_set(:)  logical, intent(inout) :: candidates_set(:), processed_set(:)    logical :: new_clique(MAX_VERTICES)  logical :: new_candidates(MAX_VERTICES)  logical :: new_processed(MAX_VERTICES)  logical :: possibles(MAX_VERTICES)  logical :: neighbors(MAX_VERTICES)  logical :: pivot_neighbors(MAX_VERTICES)  integer :: pivot, vertex  integer :: clique_size, i    ! If both candidates and processed are empty, we found a maximal clique  if (count_true(candidates_set) == 0 .and. count_true(processed_set) == 0) then  clique_size = count_true(current_clique_set)  if (clique_size > 2) then  call store_clique(current_clique_set)  end if  return  end if    ! Find pivot vertex  pivot = find_pivot(candidates_set, processed_set)  call get_neighbors(pivot, pivot_neighbors)    ! Get vertices in candidates that are not neighbors of pivot  call set_difference(candidates_set, pivot_neighbors, possibles)    ! For each vertex in possibles  do vertex = 1, num_vertices  if (.not. possibles(vertex)) cycle    ! Create new clique including vertex  new_clique = current_clique_set  new_clique(vertex) = .true.    ! Get neighbors of vertex  call get_neighbors(vertex, neighbors)    ! New candidates = candidates ∩ neighbors(vertex)  call set_intersection(candidates_set, neighbors, new_candidates)    ! New processed = processed ∩ neighbors(vertex)  call set_intersection(processed_set, neighbors, new_processed)    ! Recursive call  call bron_kerbosch_recursive(new_clique, new_candidates, new_processed)    ! Move vertex from candidates to processed  candidates_set(vertex) = .false.  processed_set(vertex) = .true.  end do  end subroutine bron_kerbosch_recursive  ! Store a clique  subroutine store_clique(clique_set)  implicit none  logical, intent(in) :: clique_set(:)  integer :: i, size    if (num_cliques >= MAX_CLIQUES) return    num_cliques = num_cliques + 1  size = 0    do i = 1, num_vertices  if (clique_set(i)) then  size = size + 1  cliques(num_cliques, size) = i  end if  end do    clique_sizes(num_cliques) = size  end subroutine store_clique  ! Sort cliques for consistent output  subroutine sort_cliques()  implicit none  integer :: i, j, k  integer :: temp_clique(MAX_VERTICES)  integer :: temp_size  logical :: swap_needed    ! Simple bubble sort  do i = 1, num_cliques - 1  do j = i + 1, num_cliques  swap_needed = .false.    ! Compare cliques lexicographically  do k = 1, min(clique_sizes(i), clique_sizes(j))  if (vertex_names(cliques(i, k)) < vertex_names(cliques(j, k))) then  exit  else if (vertex_names(cliques(i, k)) > vertex_names(cliques(j, k))) then  swap_needed = .true.  exit  end if  end do    if (.not. swap_needed .and. clique_sizes(i) > clique_sizes(j)) then  swap_needed = .true.  end if    if (swap_needed) then  ! Swap cliques  temp_clique(1:clique_sizes(i)) = cliques(i, 1:clique_sizes(i))  temp_size = clique_sizes(i)    cliques(i, 1:clique_sizes(j)) = cliques(j, 1:clique_sizes(j))  clique_sizes(i) = clique_sizes(j)    cliques(j, 1:temp_size) = temp_clique(1:temp_size)  clique_sizes(j) = temp_size  end if  end do  end do  end subroutine sort_cliques  ! Print all cliques  subroutine print_cliques()  implicit none  integer :: i, j    write(*, '(A)', advance='no') '['  do i = 1, num_cliques  write(*, '(A)', advance='no') '['  do j = 1, clique_sizes(i)  write(*, '(A)', advance='no') trim(vertex_names(cliques(i, j)))  if (j < clique_sizes(i)) write(*, '(A)', advance='no') ', '  end do  write(*, '(A)', advance='no') ']'  if (i < num_cliques) write(*, '(A)', advance='no') ', '  end do  write(*, '(A)') ']'  end subroutine print_cliques end program bron_kerbosch_cliques 
Output:
[[a, b, c], [d, e, f]] 
Type StringSet  values(99) As String  cnt As Integer    Declare Sub add_(value As String)  Declare Sub remove(value As String)  Declare Function isEmpty() As Boolean  Declare Function contains(value As String) As Boolean  Declare Function copy() As StringSet  Declare Function intersect(other As StringSet) As StringSet  Declare Function union_(other As StringSet) As StringSet  Declare Function except_(other As StringSet) As StringSet End Type Type Graph  adjacency(99, 99) As Byte  vertices(99) As String  vertexCount As Integer    Declare Sub aditionEdge(v1 As String, v2 As String)  Declare Function getNeighbors(vertex As String) As StringSet End Type Type CliqueList  cliques(99) As StringSet  cnt As Integer    Declare Sub add_(clique As StringSet) End Type ' StringSet methods implementation Sub StringSet.add_(value As String)  If Not this.contains(value) Then  this.values(this.cnt) = value  this.cnt += 1  End If End Sub Sub StringSet.remove(value As String)  Dim As Integer i, j  For i = 0 To this.cnt - 1  If this.values(i) = value Then  For j = i To this.cnt - 2  this.values(j) = this.values(j + 1)  Next  this.cnt -= 1  Exit For  End If  Next End Sub Function StringSet.isEmpty() As Boolean  Return this.cnt = 0 End Function Function StringSet.contains(value As String) As Boolean  For i As Integer = 0 To this.cnt - 1  If this.values(i) = value Then Return True  Next  Return False End Function Function StringSet.copy() As StringSet  Dim As StringSet result  result.cnt = this.cnt  For i As Integer = 0 To this.cnt - 1  result.values(i) = this.values(i)  Next  Return result End Function Function StringSet.intersect(other As StringSet) As StringSet  Dim As StringSet result  For i As Integer = 0 To this.cnt - 1  If other.contains(this.values(i)) Then  result.add_(this.values(i))  End If  Next  Return result End Function Function StringSet.union_(other As StringSet) As StringSet  Dim As StringSet result = this.copy()  For i As Integer = 0 To other.cnt - 1  result.add_(other.values(i))  Next  Return result End Function Function StringSet.except_(other As StringSet) As StringSet  Dim As StringSet result  For i As Integer = 0 To this.cnt - 1  If Not other.contains(this.values(i)) Then  result.add_(this.values(i))  End If  Next  Return result End Function ' Graph methods implementation Sub Graph.aditionEdge(v1 As String, v2 As String)  Dim As Integer v1idx = -1, v2idx = -1    For i As Integer = 0 To this.vertexCount - 1  If this.vertices(i) = v1 Then v1idx = i  If this.vertices(i) = v2 Then v2idx = i  Next    If v1idx = -1 Then  v1idx = this.vertexCount  this.vertices(this.vertexCount) = v1  this.vertexCount += 1  End If    If v2idx = -1 Then  v2idx = this.vertexCount  this.vertices(this.vertexCount) = v2  this.vertexCount += 1  End If    this.adjacency(v1idx, v2idx) = 1 End Sub Function Graph.getNeighbors(vertex As String) As StringSet  Dim As StringSet result  Dim As Integer vidx = -1, i    For i = 0 To this.vertexCount - 1  If this.vertices(i) = vertex Then  vidx = i  Exit For  End If  Next    If vidx <> -1 Then  For i = 0 To this.vertexCount - 1  If this.adjacency(vidx, i) = 1 Then  result.add_(this.vertices(i))  End If  Next  End If    Return result End Function ' CliqueList methods Sub CliqueList.add_(clique As StringSet)  this.cliques(this.cnt) = clique  this.cnt += 1 End Sub ' Bron-Kerbosch algorithm Sub BronKerbosch(r As StringSet, p As StringSet, x As StringSet, g As Graph, Byref cliques As CliqueList)  Dim As Integer i, j    If p.isEmpty() Andalso x.isEmpty() Then  If r.cnt > 2 Then  ' Sort the clique before aditioning (simple bubble sort)  For i = 0 To r.cnt - 2  For j = 0 To r.cnt - 2 - i  If r.values(j) > r.values(j + 1) Then  Swap r.values(j), r.values(j + 1)  End If  Next  Next  cliques.add_(r)  End If  Return  End If    ' Find pivot  Dim As String pivot, v  Dim As Integer maxC = -1  Dim As StringSet unionSet = p.union_(x)    For i = 0 To unionSet.cnt - 1  v = unionSet.values(i)  Dim As StringSet neighbors = g.getNeighbors(v)  If neighbors.cnt > maxC Then  maxC = neighbors.cnt  pivot = v  End If  Next    Dim As StringSet pivotNeighbors = g.getNeighbors(pivot)  Dim As StringSet candidates = p.except_(pivotNeighbors)    For i = 0 To candidates.cnt - 1  v = candidates.values(i)  Dim As StringSet newR = r.copy()  newR.add_(v)    Dim As StringSet neighbors = g.getNeighbors(v)  Dim As StringSet newP = p.intersect(neighbors)  Dim As StringSet newX = x.intersect(neighbors)    BronKerbosch(newR, newP, newX, g, cliques)    p.remove(v)  x.add_(v)  Next End Sub ' Main program Sub main()  Dim As Integer i, j  Dim As Graph g    ' add_ edges  g.aditionEdge("a", "b")  g.aditionEdge("b", "a")  g.aditionEdge("a", "c")  g.aditionEdge("c", "a")  g.aditionEdge("b", "c")  g.aditionEdge("c", "b")  g.aditionEdge("d", "e")  g.aditionEdge("e", "d")  g.aditionEdge("d", "f")  g.aditionEdge("f", "d")  g.aditionEdge("e", "f")  g.aditionEdge("f", "e")    Dim As StringSet r, p, x  Dim As CliqueList cliques    ' Initialize p with all vertices  For i = 0 To g.vertexCount - 1  p.add_(g.vertices(i))  Next    ' Execute algorithm  BronKerbosch(r, p, x, g, cliques)    ' Print results  For i = 0 To cliques.cnt - 1  Dim As StringSet clique = cliques.cliques(i)  For j = 0 To clique.cnt - 1  Print clique.values(j);  If j < clique.cnt - 1 Then Print ", ";  Next  Print  Next End Sub main() Sleep 
Output:
a, b, c d, e, f
Translation of: Python
package main import ( "fmt" "sort" "strings" ) // Using map[string]bool to simulate a set of strings type StringSet map[string]bool // Edge struct represents a graph edge type Edge struct { Start string End string } // Global variable to store cliques (slices of sorted strings) var cliques [][]string // --- Set Operations Helper Functions --- // setUnion returns the union of two sets (a U b) func setUnion(a, b StringSet) StringSet { union := make(StringSet) for k := range a { union[k] = true } for k := range b { union[k] = true } return union } // setIntersection returns the intersection of two sets (a ∩ b) func setIntersection(a, b StringSet) StringSet { intersection := make(StringSet) // Iterate over the smaller set for efficiency if len(a) < len(b) { for k := range a { if b[k] { intersection[k] = true } } } else { for k := range b { if a[k] { intersection[k] = true } } } return intersection } // setDifference returns the difference of two sets (a \ b) func setDifference(a, b StringSet) StringSet { difference := make(StringSet) for k := range a { if !b[k] { // If element from a is NOT in b difference[k] = true } } return difference } // setCopy creates a shallow copy of the set func setCopy(s StringSet) StringSet { newSet := make(StringSet) for k := range s { newSet[k] = true } return newSet } // setToSortedSlice converts a set to a sorted slice of strings func setToSortedSlice(s StringSet) []string { slice := make([]string, 0, len(s)) for k := range s { slice = append(slice, k) } sort.Strings(slice) return slice } // --- Printing Helper Functions --- // printSlice prints a sorted string slice like [a, b, c] func printSlice(slice []string) { fmt.Printf("[%s]", strings.Join(slice, ", ")) } // print2DSlice prints a slice of slices like [[a, b, c], [d, e, f]] func print2DSlice(slices [][]string) { fmt.Print("[") for i, slice := range slices { printSlice(slice) if i < len(slices)-1 { fmt.Print(", ") } } fmt.Println("]") } // --- Bron-Kerbosch Algorithm --- // bronKerbosch implements the algorithm with pivoting. // R: current clique being built // P: candidate vertices // X: processed vertices // graph: adjacency list representation (map[vertex] -> set of neighbors) func bronKerbosch(currentClique, candidates, processedVertices StringSet, graph map[string]StringSet) { if len(candidates) == 0 && len(processedVertices) == 0 { // Base case: Found a maximal clique if len(currentClique) > 2 { // Convert set to sorted slice before storing cliqueSlice := setToSortedSlice(currentClique) cliques = append(cliques, cliqueSlice) } return } // --- Pivot Selection --- // Choose a pivot u from P union X with the maximum number of neighbors in P. // Python version simplifies to max degree in the *whole graph* from P union X. We'll mimic that. unionSet := setUnion(candidates, processedVertices) pivot := "" maxDegree := -1 // Find pivot (vertex in P U X with highest degree in the whole graph)  if len(unionSet) > 0 {  // Find *any* element first to initialize pivot  for v := range unionSet {  pivot = v  if neighbors, ok := graph[pivot]; ok {  maxDegree = len(neighbors)  } else {  maxDegree = 0 // Handle nodes with no outgoing edges if they exist  }  break // Found the first element, stop  }  // Now find the actual max degree pivot  for v := range unionSet {  degree := 0  if neighbors, ok := graph[v]; ok {  degree = len(neighbors)  }  if degree > maxDegree {  maxDegree = degree  pivot = v  }  }  } else {  // If unionSet is empty, we should have hit the base case already,  // but handle defensively.  return  } // --- Iteration --- // Iterate through vertices v in P \ N(u) (candidates not neighbors of pivot) pivotNeighbors := graph[pivot] // Might be nil if pivot has no neighbors listed if pivotNeighbors == nil { pivotNeighbors = make(StringSet) // Treat as empty set if nil } // Create a copy of candidates to iterate over, as candidates set is modified inside the loop candidatesWithoutPivotNeighbors := setDifference(candidates, pivotNeighbors) // Need to iterate over a stable copy because 'candidates' is modified verticesToProcess := setToSortedSlice(candidatesWithoutPivotNeighbors) // Get keys to iterate safely for _, vertex := range verticesToProcess {  // Ensure vertex is still in the *current* candidates set before processing  // (It might have been removed if processing another vertex moved it to X implicitly,  // although the standard BK algorithm structure should prevent this here).  // This check is mostly for robustness if the sets were modified unexpectedly.  // In this specific BK implementation, removing happens *after* recursion, so it's safe.  // if !candidates[vertex] {  // continue  // } vertexNeighbors := graph[vertex] if vertexNeighbors == nil { vertexNeighbors = make(StringSet) } // Create new clique R U {v} newClique := setCopy(currentClique) newClique[vertex] = true // New candidates P ∩ N(v) newCandidates := setIntersection(candidates, vertexNeighbors) // New processed vertices X ∩ N(v) newProcessed := setIntersection(processedVertices, vertexNeighbors) // Recursive call bronKerbosch(newClique, newCandidates, newProcessed, graph) // Move vertex from P to X: P = P \ {v}, X = X U {v} delete(candidates, vertex) processedVertices[vertex] = true } } func main() { // Define edges edges := []Edge{ {"a", "b"}, {"b", "a"}, {"a", "c"}, {"c", "a"}, {"b", "c"}, {"c", "b"}, {"d", "e"}, {"e", "d"}, {"d", "f"}, {"f", "d"}, {"e", "f"}, {"f", "e"}, } // Build the graph as an adjacency list (map[string]StringSet) graph := make(map[string]StringSet) allVertices := make(StringSet) // Keep track of all unique vertices for _, edge := range edges { // Ensure the map for the start node exists if _, ok := graph[edge.Start]; !ok { graph[edge.Start] = make(StringSet) } graph[edge.Start][edge.End] = true // Add neighbor // Add vertices to our set of all vertices allVertices[edge.Start] = true allVertices[edge.End] = true } // Initialize sets for the algorithm currentClique := make(StringSet) // Candidates initially contain all vertices in the graph candidates := setCopy(allVertices) // Start with all unique vertices found processedVertices := make(StringSet) // Execute the Bron-Kerbosch algorithm bronKerbosch(currentClique, candidates, processedVertices, graph) // Sort the final list of cliques for consistent display // Sort first by length, then lexicographically by the elements sort.Slice(cliques, func(i, j int) bool { if len(cliques[i]) != len(cliques[j]) { return len(cliques[i]) < len(cliques[j]) } // If lengths are equal, compare element by element for k := 0; k < len(cliques[i]); k++ { if cliques[i][k] != cliques[j][k] { return cliques[i][k] < cliques[j][k] } } return false // Should not happen for distinct cliques }) // Display the cliques print2DSlice(cliques) } 
Output:
[[a, b, c], [d, e, f]] 
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; public final class BronKerboschAlgorithm { public static void main(String[] args) { List<Edge> edges = List.of( new Edge("a", "b"), new Edge("b", "a"), new Edge("a", "c"), new Edge("c", "a"), new Edge("b", "c"), new Edge("c", "b"), new Edge("d", "e"), new Edge("e", "d"), new Edge("d", "f"), new Edge("f", "d"), new Edge("e", "f"), new Edge("f", "e") );  // Build the graph as an adjacency list  Map<String, Set<String>> graph = new HashMap<String, Set<String>>();  edges.forEach( edge -> graph.computeIfAbsent(edge.start, v -> new HashSet<String>()).add(edge.end) );    // Initialize current clique, candidates and processed vertices  Set<String> currentClique = new TreeSet<String>();  Set<String> candidates = new HashSet<String>(graph.keySet());  Set<String> processedVertices = new HashSet<String>();  // Execute the Bron-Kerbosch algorithm to collect the cliques  bronKerbosch(currentClique, candidates, processedVertices, graph);    // Sort the cliques for consistent display  Collections.sort(cliques, listComparator);    // Display the cliques  System.out.println(cliques); }  private static void bronKerbosch(Set<String> currentClique, Set<String> candidates,  Set<String> processedVertices, Map<String, Set<String>> graph) {   if ( candidates.isEmpty() && processedVertices.isEmpty() ) {  if ( currentClique.size() > 2 ) {  List<String> clique = new ArrayList<String>(currentClique);  cliques.add(clique);  }  return;  }    // Select a pivot vertex from 'candidates' union 'processedVertices' with the maximum degree  Set<String> union = new HashSet<String>(candidates);  union.addAll(processedVertices);   String pivot =   union.stream().max( (s1, s2) -> Integer.compare(graph.get(s1).size(), graph.get(s2).size()) ).get();  // 'possibles' are vertices in 'candidates' that are not neighbours of the 'pivot'  Set<String> possibles = new HashSet<String>(candidates);  possibles.removeAll(graph.get(pivot));    for ( String vertex : possibles) {  // Create a new clique including 'vertex'  Set<String> newCliques = new TreeSet<String>(currentClique);  newCliques.add(vertex);  // 'newCandidates' are the members of 'candidates' that are neighbours of 'vertex'  Set<String> neighbours = graph.get(vertex);  Set<String> newCandidates = new HashSet<String>(candidates);  newCandidates.retainAll(neighbours);  // 'newProcessedVertices' are members of 'processedVertices' that are neighbours of 'vertex'  Set<String> newProcessedVertices = new HashSet<String>(processedVertices);  newProcessedVertices.retainAll(neighbours);  // Recursive call with the updated sets  bronKerbosch(newCliques, newCandidates, newProcessedVertices, graph);  // Move 'vertex' from 'candidates' to 'processedVertices'  candidates.remove(vertex);  processedVertices.add(vertex);  }  }  private static Comparator<List<String>> listComparator = (list1, list2) -> {  for ( int i = 0; i < Math.min(list1.size(), list2.size()); i++ ) {  final int comparison = list1.get(i).compareTo(list2.get(i));  if ( comparison != 0 ) {  return comparison;  }  }  return Integer.compare(list1.size(), list2.size()); };  private static List<List<String>> cliques = new ArrayList<List<String>>();  private static record Edge(String start, String end) {} } 
Output:
[[a, b, c], [d, e, f]] 
Translation of: C++
// Global variable to store the found cliques let cliques = []; // Equivalent to the Edge struct // (We'll just use plain objects inline) // Helper function to print the final result (similar to print_2D_vector) function printCliques(cliquesArray) {  // Sort cliques before printing for consistent output  // Sort primarily by first element, then second, etc., then by length  cliquesArray.sort((a, b) => {  const len = Math.min(a.length, b.length);  for (let i = 0; i < len; i++) {  if (a[i] < b[i]) return -1;  if (a[i] > b[i]) return 1;  }  // If one is a prefix of the other, shorter comes first  return a.length - b.length;  });  // Pretty print using JSON.stringify  console.log(JSON.stringify(cliquesArray, null, 2)); } // --- Set Operations Helpers --- // Set Intersection: Returns a new Set containing elements present in both setA and setB function setIntersection(setA, setB) {  const intersection = new Set();  for (const elem of setB) { // Iterate smaller set for potential efficiency  if (setA.has(elem)) {  intersection.add(elem);  }  }  return intersection; } // Set Difference: Returns a new Set containing elements present in setA but NOT in setB (A \ B) function setDifference(setA, setB) {  const difference = new Set(setA); // Start with a copy of setA  for (const elem of setB) {  difference.delete(elem); // Remove elements found in setB  }  return difference; } /**  * Bron-Kerbosch algorithm with pivoting to find maximal cliques.  * @param {Set<string>} currentClique - The clique being built (R in common notation).  * @param {Set<string>} candidates - Potential vertices to add (P).  * @param {Set<string>} processedVertices - Vertices already processed/excluded (X).  * @param {Map<string, Set<string>>} graph - Adjacency list representation of the graph.  */ function bronKerbosch(currentClique, candidates, processedVertices, graph) {  if (candidates.size === 0 && processedVertices.size === 0) {  // Base case: Found a maximal clique  if (currentClique.size > 2) {  // Convert Set to Array, sort it for consistent ordering, and add to results  const cliqueArray = Array.from(currentClique).sort();  cliques.push(cliqueArray);  }  return;  }  // --- Pivoting ---  // Combine candidates and processed vertices for pivot selection  const unionSet = new Set([...candidates, ...processedVertices]);  let pivot = '';  let maxDegree = -1;  // Select pivot: vertex in unionSet with the most neighbors *in candidates*  // (Optimization: C++ version used total degree, JS version uses neighbors in candidates for better pruning)  // Let's stick closer to the provided C++ heuristic (max degree in the *entire graph* among unionSet members) for direct translation.  for (const u of unionSet) {  const neighbors = graph.get(u) || new Set(); // Neighbors in the whole graph  if (neighbors.size > maxDegree) {  maxDegree = neighbors.size;  pivot = u;  }  }  // If unionSet was empty (should be caught by base case, but safety check)  if (!pivot && unionSet.size > 0) {  pivot = unionSet.values().next().value; // Fallback: pick any element if degree calc failed  } else if (!pivot) {  return; // Union set is truly empty  }  // 'possibles': Candidates that are NOT neighbors of the pivot (candidates \ N(pivot))  const pivotNeighbors = graph.get(pivot) || new Set();  const possibles = setDifference(candidates, pivotNeighbors); // P \ N(u)  // --- Recursion ---  // Iterate over a *copy* of possibles because we modify 'candidates' and 'processedVertices' below  const possiblesCopy = Array.from(possibles);  for (const vertex of possiblesCopy) {  // Ensure vertex hasn't been moved from candidates in another branch's backtracking  // (This check is usually implicitly handled by iterating the right set,  // but explicit check can prevent errors if logic is complex)  if (!candidates.has(vertex)) {  continue;  }  const neighborsOfVertex = graph.get(vertex) || new Set();  // Create NEW clique for recursive call: currentClique U {vertex}  const newClique = new Set(currentClique);  newClique.add(vertex);  // Create NEW candidates for recursive call: candidates ∩ N(vertex)  const newCandidates = setIntersection(candidates, neighborsOfVertex);  // Create NEW processed vertices for recursive call: processedVertices ∩ N(vertex)  const newProcessedVertices = setIntersection(processedVertices, neighborsOfVertex);  // Recursive call  bronKerbosch(newClique, newCandidates, newProcessedVertices, graph);  // Backtracking: Move 'vertex' from candidates to processedVertices  // Modify the sets belonging to *this* function call's scope  candidates.delete(vertex);  processedVertices.add(vertex);  } } // --- Main Execution --- function main() {  const edges = [  { start: "a", end: "b" }, { start: "b", end: "a" },  { start: "a", end: "c" }, { start: "c", end: "a" },  { start: "b", end: "c" }, { start: "c", end: "b" },  { start: "d", end: "e" }, { start: "e", end: "d" },  { start: "d", end: "f" }, { start: "f", end: "d" },  { start: "e", end: "f" }, { start: "f", end: "e" }  ];  // Build the graph as an adjacency list (Map<string, Set<string>>)  const graph = new Map();  const allVertices = new Set(); // Keep track of all unique vertices  for (const edge of edges) {  // Ensure nodes exist in the map  if (!graph.has(edge.start)) {  graph.set(edge.start, new Set());  }  // Add edge  graph.get(edge.start).add(edge.end);  // Keep track of all vertices encountered  allVertices.add(edge.start);  allVertices.add(edge.end); // Ensure end node is also tracked if it never starts an edge  }  // Ensure all nodes mentioned (even if only as end nodes) exist as keys in the graph map  for(const vertex of allVertices) {  if (!graph.has(vertex)) {  graph.set(vertex, new Set());  }  }  // Initialize sets for the algorithm  const initialCurrentClique = new Set();  // Candidates are initially all vertices in the graph  const initialCandidates = new Set(allVertices);  const initialProcessedVertices = new Set();  // Reset global cliques array before running  cliques = [];  // Execute the Bron-Kerbosch algorithm  bronKerbosch(  initialCurrentClique,  initialCandidates,  initialProcessedVertices,  graph  );  // Display the cliques (sorted)  printCliques(cliques); } // Run the main function main(); 
Output:
[ [ "a", "b", "c" ], [ "d", "e", "f" ] ] 
""" For rosettacode.org/wiki/Bron–Kerbosch_algorithm The implementation below is taken from the Graphs julia package at https://github.com/JuliaGraphs/Graphs.jl/blob/ec6ab1b0e267e2b1722837aa113e8da9a405785b/src/community/cliques.jl Because the Graphs.jl package uses integers for vertex labels, the letters in the Rust example are converted to and from integers for program testing. """ mutable struct SimpleGraph{T <: Integer}  ne::T  vertices::Vector{T}  edges::Set{Tuple{T, T}}  adjacencies::Vector{Set{T}} end function SimpleGraph(ne::T, edge_list) where T <: Integer  vertices = collect(1:ne)  edges = Set{Tuple{T, T}}()  sets = [Set{T}() for _ in vertices]  for e in edge_list  push!(edges, e, reverse(e))  push!(sets[e[1]], e[2])  push!(sets[e[2]], e[1])  end  return SimpleGraph{T}(ne, vertices, edges, sets) end vertices(g::SimpleGraph) = g.vertices edges(g::SimpleGraph) = g.edges neighbors(g, v) = g.adjacencies[v] function Bron_Kerbosch_maximal_cliques(g::SimpleGraph{T}) where T  max_connections = -1  n_numbers = [Set{T}() for n in vertices(g)]  pivot_numbers = Set{T}() # handle empty graph  pivot_done_numbers = Set{T}() # initialize  for n in vertices(g)  nbrs = Set{T}()  union!(nbrs, neighbors(g, n))  delete!(nbrs, n) # ignore edges between n and itself  conn = length(nbrs)  if conn > max_connections  pivot_numbers = nbrs  n_numbers[n] = pivot_numbers  max_connections = conn  else  n_numbers[n] = nbrs  end  end  # Initial setup  cand = Set{T}(vertices(g))  smallcand = setdiff(cand, pivot_numbers)  done = Set{T}()  stack = Vector{Tuple{Set{T}, Set{T}, Set{T}}}()  clique_so_far = Vector{T}()  cliques = Vector{Vector{T}}()  # Start main loop  while !isempty(smallcand) || !isempty(stack)  if !isempty(smallcand) # Any vertices left to check?  n = pop!(smallcand)  else  # back out clique_so_far  cand, done, smallcand = pop!(stack)  pop!(clique_so_far)  continue  end  # Add next node to clique  push!(clique_so_far, n)  delete!(cand, n)  push!(done, n)  nn = n_numbers[n]  new_cand = intersect(cand, nn)  new_done = intersect(done, nn)  # check if we have more to search  if isempty(new_cand)  if isempty(new_done)  # Found a clique!  push!(cliques, collect(clique_so_far))  end  pop!(clique_so_far)  continue  end  # Shortcut--only one node left!  if isempty(new_done) && length(new_cand) == 1  push!(cliques, vcat(clique_so_far, collect(new_cand)))  pop!(clique_so_far)  continue  end  # find pivot node (max connected in cand)  # look in done vertices first  numb_cand = length(new_cand)  max_connections_done = -1  for n in new_done  cn = intersect(new_cand, n_numbers[n])  conn = length(cn)  if conn > max_connections_done  pivot_done_numbers = cn  max_connections_done = conn  if max_connections_done == numb_cand  break  end  end  end  # Shortcut--this part of tree already searched  if max_connections_done == numb_cand  pop!(clique_so_far)  continue  end  # still finding pivot node  # look in cand vertices second  max_connections = -1  for n in new_cand  cn = intersect(new_cand, n_numbers[n])  conn = length(cn)  if conn > max_connections  pivot_numbers = cn  max_connections = conn  if max_connections == numb_cand - 1  break  end  end  end  # pivot node is max connected in cand from done or cand  if max_connections_done > max_connections  pivot_numbers = pivot_done_numbers  end  # save search status for later backout  push!(stack, (cand, done, smallcand))  cand = new_cand  done = new_done  smallcand = setdiff(cand, pivot_numbers)  end  return cliques end char(i) = Char(Int32('a') + i - 1) int(t) = Tuple(Int32(x) .- Int32('a') .+ 1 for x in t) TEST_EDGES = [('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b'),  ('d', 'e'), ('d', 'f'), ('e', 'd'), ('e', 'f'), ('f', 'd'), ('f', 'e')] g_test = SimpleGraph(6, map(int, TEST_EDGES)) println("\nBron-Kerbosch maximal cliques: ") println([sort!(map(char, clique)) for clique in Bron_Kerbosch_maximal_cliques(g_test)]) 
Output:
Bron-Kerbosch maximal cliques: [['d', 'e', 'f'], ['a', 'b', 'c']] 
Works with: Kotlin version 1.3.31
Translation of: Java
import java.util.* object MainKt {  private val cliques: MutableList<List<String>> = mutableListOf()  @JvmStatic  fun main(args: Array<String>) {  val edges = listOf(  Edge("a", "b"), Edge("b", "a"), Edge("a", "c"), Edge("c", "a"),  Edge("b", "c"), Edge("c", "b"), Edge("d", "e"), Edge("e", "d"),  Edge("d", "f"), Edge("f", "d"), Edge("e", "f"), Edge("f", "e")  )  // Build the graph as an adjacency list  val graph: MutableMap<String, MutableSet<String>> = mutableMapOf()  edges.forEach { edge ->  graph.computeIfAbsent(edge.start) { mutableSetOf() }.add(edge.end)  }  // Initialize current clique, candidates, and processed vertices  val currentClique: MutableSet<String> = mutableSetOf()  val candidates: MutableSet<String> = mutableSetOf<String>().apply { addAll(graph.keys) }  val processedVertices: MutableSet<String> = mutableSetOf()  // Execute the Bron-Kerbosch algorithm to collect the cliques  bronKerbosch(currentClique, candidates, processedVertices, graph)  // Sort the cliques for consistent display  cliques.sortWith(listComparator)  // Display the cliques  println(cliques)  }  private fun bronKerbosch(  currentClique: MutableSet<String>,  candidates: MutableSet<String>,  processedVertices: MutableSet<String>,  graph: Map<String, Set<String>>  ) {  if (candidates.isEmpty() && processedVertices.isEmpty()) {  if (currentClique.size > 2) {  val clique = ArrayList(currentClique)  cliques.add(clique)  }  return  }  // Select a pivot vertex from 'candidates' union 'processedVertices' with the maximum degree  val union = candidates.toMutableSet().apply { addAll(processedVertices) }  val pivot = union.maxBy { s -> graph[s]?.size ?: 0 }  if (pivot == null) {  return  }  // 'possibles' are vertices in 'candidates' that are not neighbors of the 'pivot'  val possibles = candidates.toMutableSet().apply { removeAll(graph[pivot] ?: emptySet()) }  for (vertex in possibles) {  // Create a new clique including 'vertex'  val newCliques = currentClique.toMutableSet().apply { add(vertex) }  // 'newCandidates' are the members of 'candidates' that are neighbors of 'vertex'  val neighbors = graph[vertex] ?: emptySet()  val newCandidates = candidates.toMutableSet().apply { retainAll(neighbors) }  // 'newProcessedVertices' are members of 'processedVertices' that are neighbors of 'vertex'  val newProcessedVertices = processedVertices.toMutableSet().apply { retainAll(neighbors) }  // Recursive call with the updated sets  bronKerbosch(newCliques, newCandidates, newProcessedVertices, graph)  // Move 'vertex' from 'candidates' to 'processedVertices'  candidates.remove(vertex)  processedVertices.add(vertex)  }  }  private val listComparator = Comparator<Any> { list1, list2 ->  val typedList1 = list1 as List<String>  val typedList2 = list2 as List<String>  for (i in 0 until minOf(typedList1.size, typedList2.size)) {  val comparison = typedList1[i].compareTo(typedList2[i])  if (comparison != 0) {  return@Comparator comparison  }  }  typedList1.size.compareTo(typedList2.size)  }  private data class Edge(val start: String, val end: String) } 
Output:
[[a, b, c], [d, e, f]] 
Works with: Lua version 5.4
Translation of: Perl
local edges = {  { start = "a", end_ = "b" },  { start = "b", end_ = "a" },  { start = "a", end_ = "c" },  { start = "c", end_ = "a" },  { start = "b", end_ = "c" },  { start = "c", end_ = "b" },  { start = "d", end_ = "e" },  { start = "e", end_ = "d" },  { start = "d", end_ = "f" },  { start = "f", end_ = "d" },  { start = "e", end_ = "f" },  { start = "f", end_ = "e" }, } -- Simple serialization function for table display function serialize(obj)  local lua = ""  local t = type(obj)  if t == "number" then  lua = lua .. obj  elseif t == "boolean" then  lua = lua .. tostring(obj)  elseif t == "string" then  lua = lua .. string.format("%q", obj)  elseif t == "table" then  lua = lua .. "{\n"  for k, v in pairs(obj) do  lua = lua .. "[" .. serialize(k) .. "]=" .. serialize(v) .. ",\n"  end  lua = lua .. "}"  elseif t == "nil" then  return nil  else  error("can not serialize a " .. t .. " type.")  end  return lua end function bron_kerbosch(current_clique, candidates, processed_vertices, graph, cliques)  if next(candidates) == nil and next(processed_vertices) == nil then  if #current_clique > 2 then  local new_clique = {}  for _, v in ipairs(current_clique) do  table.insert(new_clique, v)  end  table.insert(cliques, new_clique)  end  return  end  -- Select a pivot vertex from 'candidates' union 'processedVertices' with the maximum degree  local union = {}  for k, v in pairs(candidates) do union[k] = v end  for k, v in pairs(processed_vertices) do union[k] = v end  local pivot = max_degree_vertex(union, graph)  -- 'possibles' are vertices in 'candidates' that are not neighbors of the 'pivot'  local possibles = {}  for k, v in pairs(candidates) do possibles[k] = v end    if graph[pivot] then  for _, neighbor in ipairs(graph[pivot]) do  possibles[neighbor] = nil  end  end  for vertex, _ in pairs(possibles) do  -- Create a new clique including 'vertex'  local new_clique = {}  for _, v in ipairs(current_clique) do  table.insert(new_clique, v)  end  table.insert(new_clique, vertex)  -- 'newCandidates' are the members of 'candidates' that are neighbors of 'vertex'  local neighbors = {}  if graph[vertex] then  for _, neighbor in ipairs(graph[vertex]) do  neighbors[neighbor] = true  end  end    local new_candidates = {}  for candidate, _ in pairs(candidates) do  if neighbors[candidate] then  new_candidates[candidate] = true  end  end  -- 'newProcessedVertices' are members of 'processedVertices' that are neighbors of 'vertex'  local new_processed_vertices = {}  for processed, _ in pairs(processed_vertices) do  if neighbors[processed] then  new_processed_vertices[processed] = true  end  end  -- Recursive call with the updated sets  bron_kerbosch(new_clique, new_candidates, new_processed_vertices, graph, cliques)  -- Move 'vertex' from 'candidates' to 'processedVertices'  candidates[vertex] = nil  processed_vertices[vertex] = true  end end function max_degree_vertex(vertices, graph)  local max_vertex, max_degree = nil, -1  for vertex, _ in pairs(vertices) do  local degree = 0  if graph[vertex] then  degree = #graph[vertex]  end  if degree > max_degree then  max_degree = degree  max_vertex = vertex  end  end  return max_vertex end function list_comparator(list1, list2)  local min_length = math.min(#list1, #list2)  for i = 1, min_length do  if list1[i] < list2[i] then  return -1  elseif list1[i] > list2[i] then  return 1  end  end  if #list1 < #list2 then  return -1  elseif #list1 > #list2 then  return 1  else  return 0  end end -- Build the graph as an adjacency list local graph = {} for _, edge in ipairs(edges) do  if not graph[edge.start] then  graph[edge.start] = {}  end  table.insert(graph[edge.start], edge.end_) end -- Initialize current clique, candidates, and processed vertices local current_clique = {} local candidates = {} for vertex, _ in pairs(graph) do  candidates[vertex] = true end local processed_vertices = {} -- Execute the Bron-Kerbosch algorithm to collect the cliques local cliques = {} bron_kerbosch(current_clique, candidates, processed_vertices, graph, cliques) -- Sort the cliques for consistent display table.sort(cliques, function(a, b) return list_comparator(a, b) < 0 end) -- Display the cliques print(serialize(cliques)) 
Output:
{ [1]={ [1]="a", [2]="c", [3]="b", }, [2]={ [1]="f", [2]="e", [3]="d", }, } 
Translation of: R
(* Global variable to store cliques *) cliques = {};  (* Function to print a sorted list *) printVector[vec_] := Print["[", StringRiffle[Sort[ToString /@ vec], ", "], "]"]  (* Function to print a list of lists *) print2DVector[vecs_] := (  Print["[" <> StringRiffle[  (Function[v, "[" <> StringRiffle[Sort[ToString /@ v], ", "] <> "]"] /@ vecs),  ", "  ] <> "]"] )  (* Bron-Kerbosch recursive function *) bronKerbosch[currentClique_, candidates_, processed_, adj_] := Module[  {unionSet, pivot, possibles, neighbors, newCandidates, newProcessed},    (* Base case *)  If[Length[candidates] == 0 && Length[processed] == 0,  If[Length[currentClique] > 2,  AppendTo[cliques, Sort[currentClique]]  ];  Return[]  ];   (* Union of candidates and processed *)  unionSet = Union[candidates, processed];   (* Choose pivot with maximum degree *)  pivot = First[MaximalBy[unionSet, Length[adj[#]] &]];   (* Possibles: candidates not adjacent to pivot *)  possibles = Complement[candidates, adj[pivot]];   (* Iterate over each possible vertex *)  Do[  neighbors = adj[vertex];  newCandidates = Intersection[candidates, neighbors];  newProcessed = Intersection[processed, neighbors];  bronKerbosch[Append[currentClique, vertex], newCandidates, newProcessed, adj],  {vertex, possibles}  ] ]  (* Main function *) main[] := Module[  {edges, nodes, adj, currentClique, candidates, processed},   (* Clear global cliques *)  cliques = {};   (* Define edges *)  edges = {  {"a", "b"}, {"b", "a"}, {"a", "c"}, {"c", "a"},  {"b", "c"}, {"c", "b"}, {"d", "e"}, {"e", "d"},  {"d", "f"}, {"f", "d"}, {"e", "f"}, {"f", "e"}  };   (* Build adjacency list as an association *)  nodes = Union[Flatten[edges]];  adj = Association[# -> {} & /@ nodes];  Do[  {u, v} = edge;  If[! MemberQ[adj[u], v], AppendTo[adj[u], v]],  {edge, edges}  ];   (* Initialize Bron-Kerbosch parameters *)  currentClique = {};  candidates = nodes;  processed = {};   (* Run Bron-Kerbosch *)  bronKerbosch[currentClique, candidates, processed, adj];   (* Remove duplicates and sort cliques by size and content *)  cliques = DeleteDuplicates[cliques];  cliques = SortBy[cliques, {Length, Identity}];   (* Print result *)  print2DVector[cliques] ]  (* Run main *) main[] 
Output:
[[a, b, c], [d, e, f]] 
Translation of: Wren
import std/[algorithm, sequtils, sets, strutils, tables] type StringSet = HashSet[string] const Empty = initHashSet[string]() proc bronKerbosch(r: var StringSet; # Current clique.  p: var StringSet; # Potential candidates to expand the clique.  x: var StringSet; # Vertices already processed.  g: Table[string, StringSet]; # Graph represented as an adjacency list.  cliques: var seq[seq[string]] # List to store all maximal cliques.  ) =  if card(p) == 0 and card(x) == 0:  if card(r) > 2:  let clique = sorted(toSeq(r.items))  cliques.add clique  return  # Select a pivot vertex from P ∪ X with the maximum degree.  var pivot = ""  for v in p + x:  let n = g.getOrDefault(v, Empty).len  if n > pivot.len: pivot = v  # Candidates are vertices in "p" that are not neighbors of the pivot.  let candidates = p - g[pivot]  for v in candidates:  # New clique including vertex "v".  var newR = r  newR.incl v  # New potential candidates are neighbors of "v" in "p".  let neighbors = g[v]  var newP = p * neighbors  # New excluded vertices are neighbors of "v" in "x".  var newX = x * neighbors  # Recursive call with updated sets.  bronKerbosch(newR, newP, newX, g, cliques)  # Move vertex "v" from "p" to "x".  p.excl v  x.incl v when isMainModule:  proc cmp(a, b: seq[string]): int =  ## Comparison procedure to use for sorting.  result = cmp(a.len, b.len)  if result == 0:  for i in 0..a.len:  result = cmp(a[i], b[i])  if result != 0: return  # Define the input edges as a list of tuples.  let input = [("a", "b"), ("b", "a"), ("a", "c"), ("c", "a"),  ("b", "c"), ("c", "b"), ("d", "e"), ("e", "d"),  ("d", "f"), ("f", "d"), ("e", "f"), ("f", "e")]  # Build the graph as an adjacency list.  var graph: Table[string, StringSet]  for (t1, t2) in input:  graph.mgetOrPut(t1, initHashSet[string]()).incl t2  # Initialize "r", "p", "x".  var r, x: StringSet  var p = toSeq(graph.keys).toHashSet()  # Initialize list to store cliques.  var cliques: seq[seq[string]]  # Execute the Bron-Kerbosch algorithm.  bronKerbosch(r, p, x, graph, cliques)  # Sort the cliques for consistent output.  cliques.sort(cmp)  # Print each clique.  for clique in cliques:  echo clique.join(", ") 
Output:
a, b, c d, e, f 
Works with: Perl version 5.22.1
Translation of: Java
use strict; use warnings; use Data::Dumper; my @edges = (  { start => "a", end => "b" },  { start => "b", end => "a" },  { start => "a", end => "c" },  { start => "c", end => "a" },  { start => "b", end => "c" },  { start => "c", end => "b" },  { start => "d", end => "e" },  { start => "e", end => "d" },  { start => "d", end => "f" },  { start => "f", end => "d" },  { start => "e", end => "f" },  { start => "f", end => "e" }, ); # Build the graph as an adjacency list my %graph; foreach my $edge (@edges) {  push @{ $graph{ $edge->{start} } }, $edge->{end}; } # Initialize current clique, candidates, and processed vertices my @current_clique; my %candidates = map { $_ => 1 } keys %graph; my %processed_vertices; # Execute the Bron-Kerbosch algorithm to collect the cliques my @cliques; bron_kerbosch(\@current_clique, \%candidates, \%processed_vertices, \%graph, \@cliques); # Sort the cliques for consistent display @cliques = sort { list_comparator($a, $b) } @cliques; # Display the cliques print Dumper(\@cliques); sub bron_kerbosch {  my ($current_clique, $candidates, $processed_vertices, $graph, $cliques) = @_;  if (!%$candidates && !%$processed_vertices) {  if (@$current_clique > 2) {  push @$cliques, [@$current_clique];  }  return;  }  # Select a pivot vertex from 'candidates' union 'processedVertices' with the maximum degree  my %union = (%$candidates, %$processed_vertices);  my $pivot = max_degree_vertex(\%union, $graph);  # 'possibles' are vertices in 'candidates' that are not neighbors of the 'pivot'  my %possibles = %$candidates;  delete $possibles{$_} for @{ $graph->{$pivot} };  foreach my $vertex (keys %possibles) {  # Create a new clique including 'vertex'  my @new_cliques = @$current_clique;  push @new_cliques, $vertex;  # 'newCandidates' are the members of 'candidates' that are neighbors of 'vertex'  my %neighbors = map { $_ => 1 } @{ $graph->{$vertex} };  my %new_candidates = map { $_ => 1 } grep { $neighbors{$_} } keys %$candidates;  # 'newProcessedVertices' are members of 'processedVertices' that are neighbors of 'vertex'  my %new_processed_vertices = map { $_ => 1 } grep { $neighbors{$_} } keys %$processed_vertices;  # Recursive call with the updated sets  bron_kerbosch(\@new_cliques, \%new_candidates, \%new_processed_vertices, $graph, $cliques);  # Move 'vertex' from 'candidates' to 'processedVertices'  delete $candidates->{$vertex};  $processed_vertices->{$vertex} = 1;  } } sub max_degree_vertex {  my ($vertices, $graph) = @_;  my ($max_vertex, $max_degree) = (undef, -1);  foreach my $vertex (keys %$vertices) {  my $degree = scalar @{ $graph->{$vertex} };  if ($degree > $max_degree) {  $max_degree = $degree;  $max_vertex = $vertex;  }  }  return $max_vertex; } sub list_comparator {  my ($list1, $list2) = @_;  my $min_length = $#$list1 < $#$list2 ? $#$list1 : $#$list2;  for my $i (0..$min_length) {  my $comparison = $list1->[$i] cmp $list2->[$i];  if ($comparison != 0) {  return $comparison;  }  }  return $#$list1 <=> $#$list2; } 
Output:
$VAR1 = [ [ 'a', 'c', 'b' ], [ 'f', 'e', 'd' ] ]; 
Translation of: Wren

Note this uses an updated sets2.e, the experimental version of sets.e - download from the github repo and remove the requires statement to run (if/since 1.0.6 not yet shipped). Code to clean up no longer needed sets omitted for clarity and out of sheer laziness.

with javascript_semantics requires("1.0.6") include sets2.e // Cliques: List to store all maximal cliques (List of Lists of strings) sequence cliques = {} procedure BronKerbosch(integer r, p, x, g)  // r: Current clique (Set of strings)  // p: Potential candidates to expand the clique (Set of strings)  // x: Vertices already processed (Set of strings)  // g: Graph represented as an adjacency list (Dict of strings to List of Strings)  if is_empty(p) and is_empty(x) then  if set_size(r)>2 then  cliques = append(cliques,get_members(r))  end if  return  end if    // Select a pivot vertex from union(p,x) with the maximum degree.  object pivot  integer maxC = -1  for v in union(p,x) do  integer l = length(getd(v,g))  if l>maxC then  {maxC,pivot} = {l,v}  end if  end for  // Candidates are vertices in P that are not neighbours of the pivot.  sequence candidates = difference(p, getd(pivot,g), symmetric:=false)  for v in candidates do  // New clique including vertex v.  integer newR = new_set(r)  add_member(newR,v)  // New potential candidates are neighbours of v in p.  // New excluded vertices are neighbours of v in x.  sequence neighbours = getd(v,g)  integer newP = intersection(p,neighbours,-1),  newX = intersection(x,neighbours,-1)  // Recursive call with updated sets.  BronKerbosch(newR, newP, newX, g)  // Move vertex v from p to x.  remove_member(p,v)  add_member(x,v)  end for end procedure // Define the input edges as a list of tuples. constant input = {  {"a", "b"}, {"b", "a"}, {"a", "c"}, {"c", "a"},  {"b", "c"}, {"c", "b"}, {"d", "e"}, {"e", "d"},  {"d", "f"}, {"f", "d"}, {"e", "f"}, {"f", "e"} } // Build the graph as an adjacency list. integer graph = new_dict() for t in input do  setd(t[1],unique(deep_copy(getdd(t[1],{},graph))&{t[2]}),graph) end for // Initialize r, p, x. integer r = new_set(),  p = new_set(getd_all_keys(graph)),  x = new_set() // Execute the Bron-Kerbosch algorithm. BronKerbosch(r, p, x, graph) // Sort cliques for consistent output. cliques = sort(deep_copy(cliques)) ?cliques 
Output:
{{"a","b","c"},{"d","e","f"}} 
Works with: PowerShell version 6.2.3
Translation of: Python
# Global variable to store cliques $global:cliques = @()  # Edge class equivalent class Edge {  [string]$Start  [string]$End   Edge([string]$start, [string]$end) {  $this.Start = $start  $this.End = $end  } }  function Print-Vector {  param([array]$vec)   $sortedVec = $vec | Sort-Object  Write-Host -NoNewline "[$($sortedVec -join ', ')]" }  function Print-2DVector {  param([array]$vecs)   Write-Host -NoNewline "["  for ($i = 0; $i -lt ($vecs.Count - 1); $i++) {  Print-Vector $vecs[$i]  Write-Host -NoNewline ", "  }  if ($vecs.Count -gt 0) {  Print-Vector $vecs[-1]  }  Write-Host "]" }  function Invoke-BronKerbosch {  param(  [System.Collections.Generic.HashSet[string]]$CurrentClique,  [System.Collections.Generic.HashSet[string]]$Candidates,  [System.Collections.Generic.HashSet[string]]$ProcessedVertices,  [hashtable]$Graph  )   if ($Candidates.Count -eq 0 -and $ProcessedVertices.Count -eq 0) {  if ($CurrentClique.Count -gt 2) {  $cliqueArray = @()  foreach ($item in $CurrentClique) {  $cliqueArray += $item  }  $global:cliques += ,$cliqueArray  }  return  }   # Select a pivot vertex from 'Candidates' union 'ProcessedVertices' with the maximum degree  $unionSet = [System.Collections.Generic.HashSet[string]]::new()  $unionSet.UnionWith($Candidates)  $unionSet.UnionWith($ProcessedVertices)   $pivot = $null  $maxDegree = -1  foreach ($vertex in $unionSet) {  $degree = $Graph[$vertex].Count  if ($degree -gt $maxDegree) {  $maxDegree = $degree  $pivot = $vertex  }  }   # 'Possibles' are vertices in 'Candidates' that are not neighbors of the 'pivot'  $possibles = [System.Collections.Generic.HashSet[string]]::new()  $possibles.UnionWith($Candidates)  $possibles.ExceptWith($Graph[$pivot])   # Create a copy of candidates to iterate over (to avoid modification during iteration)  $candidatesCopy = [System.Collections.Generic.HashSet[string]]::new()  $candidatesCopy.UnionWith($Candidates)   foreach ($vertex in $possibles) {  # Create a new clique including 'vertex'  $newClique = [System.Collections.Generic.HashSet[string]]::new()  $newClique.UnionWith($CurrentClique)  $newClique.Add($vertex) | Out-Null   # 'NewCandidates' are the members of 'Candidates' that are neighbors of 'vertex'  $newCandidates = [System.Collections.Generic.HashSet[string]]::new()  $newCandidates.UnionWith($Candidates)  $newCandidates.IntersectWith($Graph[$vertex])   # 'NewProcessedVertices' are members of 'ProcessedVertices' that are neighbors of 'vertex'  $newProcessedVertices = [System.Collections.Generic.HashSet[string]]::new()  $newProcessedVertices.UnionWith($ProcessedVertices)  $newProcessedVertices.IntersectWith($Graph[$vertex])   # Recursive call with the updated sets  Invoke-BronKerbosch $newClique $newCandidates $newProcessedVertices $Graph   # Move 'vertex' from 'Candidates' to 'ProcessedVertices'  $Candidates.Remove($vertex) | Out-Null  $ProcessedVertices.Add($vertex) | Out-Null  } }  function Main {  $global:cliques = @()   # Define edges  $edges = @(  [Edge]::new("a", "b"), [Edge]::new("b", "a"), [Edge]::new("a", "c"), [Edge]::new("c", "a"),  [Edge]::new("b", "c"), [Edge]::new("c", "b"), [Edge]::new("d", "e"), [Edge]::new("e", "d"),  [Edge]::new("d", "f"), [Edge]::new("f", "d"), [Edge]::new("e", "f"), [Edge]::new("f", "e")  )   # Build the graph as an adjacency list using hashtable  $graph = @{}  foreach ($edge in $edges) {  if (-not $graph.ContainsKey($edge.Start)) {  $graph[$edge.Start] = [System.Collections.Generic.HashSet[string]]::new()  }  $graph[$edge.Start].Add($edge.End) | Out-Null  }   # Initialize current clique, candidates, and processed vertices  $currentClique = [System.Collections.Generic.HashSet[string]]::new()  $candidates = [System.Collections.Generic.HashSet[string]]::new()  foreach ($key in $graph.Keys) {  $candidates.Add($key) | Out-Null  }  $processedVertices = [System.Collections.Generic.HashSet[string]]::new()   # Execute the Bron-Kerbosch algorithm to collect the cliques  Invoke-BronKerbosch $currentClique $candidates $processedVertices $graph   # Sort the cliques for consistent display  $global:cliques = $global:cliques | Sort-Object { $_.Count }, { $_ -join ',' }   # Display the cliques  Print-2DVector $global:cliques }  # Run the main function Main 
Output:
[[a, b, c], [d, e, f]] 
from collections import defaultdict # Global variable to store cliques cliques = [] class Edge: def __init__(self, start, end): self.start = start self.end = end def print_vector(vec): print("[" + ", ".join(sorted(map(str, vec))) + "]", end="") def print_2D_vector(vecs): print("[", end="") for i in range(len(vecs) - 1): print_vector(vecs[i]) print(", ", end="") print_vector(vecs[-1]) print("]") def bron_kerbosch(current_clique, candidates, processed_vertices, graph): global cliques if not candidates and not processed_vertices: if len(current_clique) > 2: cliques.append(list(current_clique)) return # Select a pivot vertex from 'candidates' union 'processed_vertices' with the maximum degree union_set = candidates.union(processed_vertices) pivot = max(union_set, key=lambda v: len(graph[v])) # 'possibles' are vertices in 'candidates' that are not neighbors of the 'pivot' possibles = candidates.difference(graph[pivot]) for vertex in possibles: # Create a new clique including 'vertex' new_clique = current_clique.union({vertex}) # 'new_candidates' are the members of 'candidates' that are neighbors of 'vertex' new_candidates = candidates.intersection(graph[vertex]) # 'new_processed_vertices' are members of 'processed_vertices' that are neighbors of 'vertex' new_processed_vertices = processed_vertices.intersection(graph[vertex]) # Recursive call with the updated sets bron_kerbosch(new_clique, new_candidates, new_processed_vertices, graph) # Move 'vertex' from 'candidates' to 'processed_vertices' candidates.remove(vertex) processed_vertices.add(vertex) def main(): global cliques # Define edges edges = [ Edge("a", "b"), Edge("b", "a"), Edge("a", "c"), Edge("c", "a"), Edge("b", "c"), Edge("c", "b"), Edge("d", "e"), Edge("e", "d"), Edge("d", "f"), Edge("f", "d"), Edge("e", "f"), Edge("f", "e") ] # Build the graph as an adjacency list graph = defaultdict(set) for edge in edges: graph[edge.start].add(edge.end) # Initialize current clique, candidates, and processed vertices current_clique = set() candidates = set(graph.keys()) processed_vertices = set() # Execute the Bron-Kerbosch algorithm to collect the cliques bron_kerbosch(current_clique, candidates, processed_vertices, graph) # Sort the cliques for consistent display cliques.sort(key=lambda x: (len(x), x)) # Display the cliques print_2D_vector(cliques) if __name__ == "__main__": main() 
[[a, b, c], [d, e, f]] 

R

Works with: R
Translation of: Python
# Global variable to store cliques cliques <- list()  # Function to print a vector (sorted) print_vector <- function(vec) {  cat("[", paste(sort(as.character(vec)), collapse = ", "), "]", sep = "") }  # Function to print a list of vectors print_2D_vector <- function(vecs) {  cat("[")  n <- length(vecs)  for (i in seq_len(n)) {  print_vector(vecs[[i]])  if (i < n) cat(", ")  }  cat("]\n") }  # Bron-Kerbosch algorithm implementation bron_kerbosch <- function(current_clique, candidates, processed_vertices, graph) {  # Access the global 'cliques' variable  cliques <<- cliques   # Base case: if both candidates and processed are empty, we have a maximal clique  if (length(candidates) == 0 && length(processed_vertices) == 0) {  if (length(current_clique) > 2) {  cliques <<- append(cliques, list(sort(current_clique)))  }  return()  }   # Union of candidates and processed vertices  union_set <- unique(c(candidates, processed_vertices))   # Choose pivot with maximum degree  pivot <- union_set[which.max(sapply(union_set, function(v) length(graph[[v]])))]   # Possibles: candidates not adjacent to pivot  possibles <- setdiff(candidates, graph[[pivot]])   # Iterate over each possible vertex  for (vertex in possibles) {  # Neighbors of vertex  neighbors <- graph[[vertex]]   # Intersect candidates and processed with neighbors  new_candidates <- intersect(candidates, neighbors)  new_processed_vertices <- intersect(processed_vertices, neighbors)   # Recursive call with updated sets (don't modify original sets)  bron_kerbosch(c(current_clique, vertex), new_candidates, new_processed_vertices, graph)  } }  # Main function main <- function() {  # Clear global cliques  cliques <<- list()   # Define edges (as character pairs)  edges <- list(  c("a", "b"), c("b", "a"), c("a", "c"), c("c", "a"),  c("b", "c"), c("c", "b"), c("d", "e"), c("e", "d"),  c("d", "f"), c("f", "d"), c("e", "f"), c("f", "e")  )   # Build graph as adjacency list  graph <- list()  nodes <- unique(unlist(edges))  for (node in nodes) {  graph[[node]] <- c()  }   for (edge in edges) {  start <- edge[1]  end <- edge[2]  if (!(end %in% graph[[start]])) {  graph[[start]] <- c(graph[[start]], end)  }  }   # Initialize Bron-Kerbosch parameters  current_clique <- c()  candidates <- names(graph)  processed_vertices <- c()   # Run Bron-Kerbosch  bron_kerbosch(current_clique, candidates, processed_vertices, graph)   # Remove duplicates and sort cliques by size and content  unique_cliques <- unique(lapply(cliques, sort))  cliques <<- unique_cliques[order(sapply(unique_cliques, length), sapply(unique_cliques, function(x) paste(sort(x), collapse = ",")))]   # Print result  print_2D_vector(cliques) }  # Run main main() 
Output:
[[a, b, c], [d, e, f]] 
# Returns all maximal Cliques as sorted List of Lists. sub BronKerbosch ( @undirected_edges ) { #| Adjacency list of the whole Graph, as immutable hash (Map) of immutable Sets. my Map $G = @undirected_edges .map({ |( .[0,1], .[1,0] ) }) .classify( {.[0]}, :as{.[1]} ) .duckmap( *.Set ) .Map; #| Number of neighbors in G my Map $degree = $G.map({ .key => .value.elems }).Map; return gather BK(); sub BK ( Set  :$R = Set.new, #= Current clique SetHash :$P is copy = SetHash.new($G.keys), #= Potential candidates to expand the clique SetHash :$X is copy = SetHash.new, #= Vertices already processed ) { if !$P and !$X { take $R.keys.sort.cache if $R.elems > 2; return; } my $Pivot = ($P$X).max({ $degree{$_} }).key; my @Candidates = ( $P (-) $G{$Pivot} ).keys; for $G{@Candidates}:kv -> $v, $Neighbors_of_v { &?ROUTINE.( # Recursive call with updated sets R => ($R$v), P => ($P$Neighbors_of_v), X => ($X$Neighbors_of_v), ); # Move vertex v from P to X $P{$v} = False; $X{$v} = True; } } } say .join(",") for sort BronKerbosch <a-b a-c b-c d-e d-f e-f>».split("-"); 
Output:
a,b,c d,e,f
require 'set' def bron_kerbosch_v2(r, p, x, g, cliques)  if p.empty? && x.empty?  if r.size > 2  cliques << r.to_a.sort  end  return  end  pivot = (p | x).max_by { |v| g[v]&.size.to_i }  if pivot  neighbors = g[pivot] || Set.new  candidates = p - neighbors  candidates.each do |v|  new_r = r.dup.add(v)  neighbors_v = g[v] || Set.new  new_p = p & neighbors_v  new_x = x & neighbors_v  bron_kerbosch_v2(new_r, new_p, new_x, g, cliques)  p.delete(v)  x.add(v)  end  end end def main  input = [  ['a', 'b'], ['b', 'a'], ['a', 'c'], ['c', 'a'],  ['b', 'c'], ['c', 'b'], ['d', 'e'], ['e', 'd'],  ['d', 'f'], ['f', 'd'], ['e', 'f'], ['f', 'e']  ]  graph = Hash.new { |hash, key| hash[key] = Set.new }  input.each do |src, dest|  graph[src].add(dest)  end  r = Set.new  p = graph.keys.to_set  x = Set.new  cliques = []  bron_kerbosch_v2(r, p, x, graph, cliques)  sorted_cliques = cliques.sort  sorted_cliques.each do |clique|  puts clique.join(', ')  end end main 
use std::collections::{HashMap, HashSet}; fn bron_kerbosch_v2(  r: &HashSet<String>,  p: &mut HashSet<String>,  x: &mut HashSet<String>,  g: &HashMap<String, HashSet<String>>,  cliques: &mut Vec<Vec<String>>, ) {  if p.is_empty() && x.is_empty() {  if r.len() > 2 {  let mut clique: Vec<String> = r.iter().cloned().collect();  clique.sort();  cliques.push(clique);  }  return;  }  // Choose a pivot with the maximum degree in P ∪ X  let pivot = p  .union(x)  .max_by_key(|v| g.get(*v).map_or(0, |neighbors| neighbors.len()))  .cloned();  if let Some(pivot_vertex) = pivot {  let neighbors = g.get(&pivot_vertex).cloned().unwrap_or_default();  let candidates: Vec<String> = p.difference(&neighbors).cloned().collect();  for v in candidates {  // New R is R ∪ {v}  let mut new_r = r.clone();  new_r.insert(v.clone());  // New P is P ∩ N(v)  let neighbors_v = g.get(&v).cloned().unwrap_or_default();  let mut new_p = p.intersection(&neighbors_v).cloned().collect::<HashSet<String>>();  // New X is X ∩ N(v)  let mut new_x = x.intersection(&neighbors_v).cloned().collect::<HashSet<String>>();  // Recursive call  bron_kerbosch_v2(&new_r, &mut new_p, &mut new_x, g, cliques);  // Move v from P to X  p.remove(&v);  x.insert(v);  }  } } fn main() {  // Define the input edges  let input = vec![  ("a", "b"),  ("b", "a"),  ("a", "c"),  ("c", "a"),  ("b", "c"),  ("c", "b"),  ("d", "e"),  ("e", "d"),  ("d", "f"),  ("f", "d"),  ("e", "f"),  ("f", "e"),  ];  // Build the graph as an adjacency list  let mut graph: HashMap<String, HashSet<String>> = HashMap::new();  for (src, dest) in input.iter() {  graph  .entry(src.to_string())  .or_insert_with(HashSet::new)  .insert(dest.to_string());  }  // Initialize R, P, X  let r: HashSet<String> = HashSet::new();  let mut p: HashSet<String> = graph.keys().cloned().collect();  let mut x: HashSet<String> = HashSet::new();  // Collect cliques  let mut cliques: Vec<Vec<String>> = Vec::new();  bron_kerbosch_v2(&r, &mut p, &mut x, &graph, &mut cliques);  // Sort the cliques for consistent output  let mut sorted_cliques = cliques.clone();  sorted_cliques.sort();  // Print each clique  for clique in sorted_cliques {  println!("{}", clique.join(", "));  } } 
Works with: Scala version 2.13.8
Translation of: Java
import scala.collection.mutable import scala.collection.immutable.TreeSet  object BronKerboschAlgorithm {    case class Edge(start: String, end: String)    private var cliques: mutable.ListBuffer[List[String]] = mutable.ListBuffer.empty[List[String]]    def main(args: Array[String]): Unit = {  val edges = List(  Edge("a", "b"), Edge("b", "a"), Edge("a", "c"), Edge("c", "a"),  Edge("b", "c"), Edge("c", "b"), Edge("d", "e"), Edge("e", "d"),  Edge("d", "f"), Edge("f", "d"), Edge("e", "f"), Edge("f", "e")  )    // Build the graph as an adjacency list  val graph: mutable.Map[String, mutable.Set[String]] = mutable.Map.empty  edges.foreach { edge =>  graph.getOrElseUpdate(edge.start, mutable.Set.empty[String]).add(edge.end)  }    // Initialize current clique, candidates and processed vertices  val currentClique: TreeSet[String] = TreeSet.empty[String]  val candidates: mutable.Set[String] = mutable.Set(graph.keySet.toSeq: _*)  val processedVertices: mutable.Set[String] = mutable.Set.empty[String]    // Execute the Bron-Kerbosch algorithm to collect the cliques  val immutableGraph = graph.map { case (k, v) => k -> v.toSet }.toMap  bronKerbosch(currentClique, candidates, processedVertices, immutableGraph)    // Sort the cliques for consistent display  cliques = cliques.sortWith(listComparator)    // Display the cliques  println(cliques.toList)  }    private def bronKerbosch(  currentClique: TreeSet[String],  candidates: mutable.Set[String],  processedVertices: mutable.Set[String],  graph: Map[String, Set[String]]  ): Unit = {    if (candidates.isEmpty && processedVertices.isEmpty) {  if (currentClique.size > 2) {  val clique = currentClique.toList  cliques += clique  }  return  }    // Select a pivot vertex from 'candidates' union 'processedVertices' with the maximum degree  val union = candidates ++ processedVertices  val pivot = union.maxBy(vertex => graph(vertex).size)    // 'possibles' are vertices in 'candidates' that are not neighbours of the 'pivot'  val possibles = candidates -- graph(pivot)    for (vertex <- possibles.toList) { // Convert to List to avoid concurrent modification  // Create a new clique including 'vertex'  val newCliques = currentClique + vertex    // 'newCandidates' are the members of 'candidates' that are neighbours of 'vertex'  val neighbours = graph(vertex)  val newCandidates = candidates.intersect(neighbours)    // 'newProcessedVertices' are members of 'processedVertices' that are neighbours of 'vertex'  val newProcessedVertices = processedVertices.intersect(neighbours)    // Recursive call with the updated sets  bronKerbosch(newCliques, newCandidates, newProcessedVertices, graph)    // Move 'vertex' from 'candidates' to 'processedVertices'  candidates.remove(vertex)  processedVertices.add(vertex)  }  }    private def listComparator(list1: List[String], list2: List[String]): Boolean = {  val minSize = math.min(list1.size, list2.size)  for (i <- 0 until minSize) {  val comparison = list1(i).compare(list2(i))  if (comparison != 0) {  return comparison < 0  }  }  list1.size < list2.size  } } 
Output:
List(List(a, b, c), List(d, e, f)) 
Works with: Swift
Translation of: Java
var cliques: [[String]] = [] struct Edge {  let start: String  let end: String } func bronKerbosch(currentClique: Set<String>, candidates: Set<String>, processedVertices: Set<String>, graph: [String: Set<String>]) {  if candidates.isEmpty && processedVertices.isEmpty {  if currentClique.count > 2 {  let clique = Array(currentClique).sorted()  cliques.append(clique)  }  return  }  let union = candidates.union(processedVertices)  let pivot = union.max(by: { graph[$0]!.count < graph[$1]!.count })!  let possibles = candidates.subtracting(graph[pivot]!)  for vertex in possibles {  var newClique = currentClique  newClique.insert(vertex)  let neighbors = graph[vertex]!  let newCandidates = candidates.intersection(neighbors)  let newProcessedVertices = processedVertices.intersection(neighbors)  bronKerbosch(currentClique: newClique, candidates: newCandidates, processedVertices: newProcessedVertices, graph: graph)  var newCandidatesSet = candidates  newCandidatesSet.remove(vertex)  var newProcessedVerticesSet = processedVertices  newProcessedVerticesSet.insert(vertex)  bronKerbosch(currentClique: currentClique, candidates: newCandidatesSet, processedVertices: newProcessedVerticesSet, graph: graph)  } } func main() {  let edges = [  Edge(start: "a", end: "b"), Edge(start: "b", end: "a"),  Edge(start: "a", end: "c"), Edge(start: "c", end: "a"),  Edge(start: "b", end: "c"), Edge(start: "c", end: "b"),  Edge(start: "d", end: "e"), Edge(start: "e", end: "d"),  Edge(start: "d", end: "f"), Edge(start: "f", end: "d"),  Edge(start: "e", end: "f"), Edge(start: "f", end: "e")  ]  var graph: [String: Set<String>] = [:]  for edge in edges {  if graph[edge.start] == nil {  graph[edge.start] = Set<String>()  }  graph[edge.start]?.insert(edge.end)  }  let currentClique = Set<String>()  let candidates = Set<String>(graph.keys)  let processedVertices = Set<String>()  bronKerbosch(currentClique: currentClique, candidates: candidates, processedVertices: processedVertices, graph: graph)  cliques.sort { (list1, list2) -> Bool in  for i in 0..<min(list1.count, list2.count) {  if list1[i] != list2[i] {  return list1[i] < list2[i]  }  }  return list1.count < list2.count  }  // Remove duplicates  var uniqueCliques = [[String]]()  var seen = Set<Set<String>>()    for clique in cliques {  let cliqueSet = Set(clique)  if !seen.contains(cliqueSet) {  seen.insert(cliqueSet)  uniqueCliques.append(clique)  }  }    print(uniqueCliques) } main() 
Output:
[["a", "b", "c"], ["d", "e", "f"]] 
Works with: Tcl version 8.6
Translation of: C++
# Global variable to store cliques set cliques {} # Procedure to print a list (equivalent to print_vector) proc print_list {lst} {  puts -nonewline "\["  set len [llength $lst]  for {set i 0} {$i < $len} {incr i} {  if {$i > 0} {  puts -nonewline ", "  }  puts -nonewline [lindex $lst $i]  }  puts -nonewline "\]" } # Procedure to print 2D list (equivalent to print_2D_vector) proc print_2D_list {lists} {  puts -nonewline "\["  set len [llength $lists]  for {set i 0} {$i < $len} {incr i} {  if {$i > 0} {  puts -nonewline ", "  }  print_list [lindex $lists $i]  }  puts "\]" } # Helper procedure to find set difference proc set_difference {set1 set2} {  set result {}  foreach item $set1 {  if {$item ni $set2} {  lappend result $item  }  }  return $result } # Helper procedure to find set intersection proc set_intersection {set1 set2} {  set result {}  foreach item $set1 {  if {$item in $set2} {  lappend result $item  }  }  return $result } # Helper procedure to find union of two sets proc set_union {set1 set2} {  set result {}  foreach item $set1 {  lappend result $item  }  foreach item $set2 {  if {$item ni $result} {  lappend result $item  }  }  return $result } # Bron-Kerbosch algorithm implementation proc bron_kerbosch {current_clique candidates processed_vertices graph} {  global cliques    # Check if both candidates and processed_vertices are empty  if {[llength $candidates] == 0 && [llength $processed_vertices] == 0} {  if {[llength $current_clique] > 2} {  lappend cliques $current_clique  set cliques $cliques  }  return  }    # Select pivot vertex with maximum degree  set union_set [set_union $candidates $processed_vertices]  set pivot ""  set max_degree -1    foreach vertex $union_set {  set degree [llength [dict get $graph $vertex]]  if {$degree > $max_degree} {  set max_degree $degree  set pivot $vertex  }  }    # Find possibles: vertices in candidates that are not neighbors of pivot  set pivot_neighbors [dict get $graph $pivot]  set possibles [set_difference $candidates $pivot_neighbors]    foreach vertex $possibles {  # Create new clique including vertex  set new_clique $current_clique  lappend new_clique $vertex    # Find new candidates: members of candidates that are neighbors of vertex  set vertex_neighbors [dict get $graph $vertex]  set new_candidates [set_intersection $candidates $vertex_neighbors]    # Find new processed vertices: members of processed_vertices that are neighbors of vertex  set new_processed_vertices [set_intersection $processed_vertices $vertex_neighbors]    # Recursive call  bron_kerbosch $new_clique $new_candidates $new_processed_vertices $graph    # Move vertex from candidates to processed_vertices  set candidates [set_difference $candidates [list $vertex]]  lappend processed_vertices $vertex  } } # Main procedure proc main {} {  global cliques    # Define edges  set edges {  {a b} {b a} {a c} {c a}  {b c} {c b} {d e} {e d}  {d f} {f d} {e f} {f e}  }    # Build graph as adjacency list (using dictionary)  set graph [dict create]  foreach edge $edges {  set start [lindex $edge 0]  set end [lindex $edge 1]  if {[dict exists $graph $start]} {  set neighbors [dict get $graph $start]  if {$end ni $neighbors} {  lappend neighbors $end  dict set graph $start $neighbors  }  } else {  dict set graph $start [list $end]  }  }    # Initialize current clique, candidates and processed vertices  set current_clique {}  set candidates {}  dict for {vertex neighbors} $graph {  lappend candidates $vertex  }  set processed_vertices {}    # Execute Bron-Kerbosch algorithm  bron_kerbosch $current_clique $candidates $processed_vertices $graph    # Sort cliques for consistent display  # First sort each clique internally  set sorted_cliques {}  foreach clique $cliques {  set sorted_clique [lsort $clique]  lappend sorted_cliques $sorted_clique  }    # Then sort cliques by lexicographic order  proc compare_cliques {a b} {  set len_a [llength $a]  set len_b [llength $b]  set min_len [expr {$len_a < $len_b ? $len_a : $len_b}]    for {set i 0} {$i < $min_len} {incr i} {  set elem_a [lindex $a $i]  set elem_b [lindex $b $i]  if {$elem_a ne $elem_b} {  return [string compare $elem_a $elem_b]  }  }  return [expr {$len_a - $len_b}]  }    set cliques [lsort -command compare_cliques $sorted_cliques]    # Display the cliques  print_2D_list $cliques } # Run the main procedure main 
Output:
[[a, b, c], [d, e, f]] 
Library: Wren-set
Library: Wren-sort
import "./set" for Set import "./sort" for Sort // r: Current clique (Set of strings) // p: Potential candidates to expand the clique (Set of strings) // x: Vertices already processed (Set of strings) // g: Graph represented as an adjacency list (Map of strings to Sets) // Cliques: List to store all maximal cliques (List of Lists of strings) var BronKerbosch = Fn.new { |r, p, x, g, cliques|  if (p.isEmpty && x.isEmpty) {  if (r.count > 2) {  var clique = r.toList  Sort.quick(clique)  cliques.add(clique)  }  return  }  // Select a pivot vertex from P ∪ X with the maximum degree.  var pivot = p.union(x).max { |v| g[v] ? g[v].count : 0 }  // Candidates are vertices in P that are not neighbors of the pivot.  var candidates = p.except(g[pivot])  for (v in candidates) {  // New clique including vertex v.  var newR = r.copy()  newR.add(v)  // New potential candidates are neighbors of v in p.  var neighbors = g[v]  var newP = p.intersect(neighbors)  // New excluded vertices are neighbors of v in x.  var newX = x.intersect(neighbors)  // Recursive call with updated sets.  BronKerbosch.call(newR, newP, newX, g, cliques)  // Move vertex v from p to x.  p.remove(v)  x.add(v)  } } // Define the input edges as a list of tuples. var input = [  ["a", "b"], ["b", "a"], ["a", "c"], ["c", "a"],  ["b", "c"], ["c", "b"], ["d", "e"], ["e", "d"],  ["d", "f"], ["f", "d"], ["e", "f"], ["f", "e"] ] // Build the graph as an adjacency list. var graph = {} for (t in input) {  if (!graph.containsKey(t[0])) graph[t[0]] = Set.new()  graph[t[0]].add(t[1]) } // Initialize r, p, x. var r = Set.new() var p = Set.new(graph.keys) var x = Set.new() // Initialize list to store cliques. var cliques = [] // Execute the Bron-Kerbosch algorithm. BronKerbosch.call(r, p, x, graph, cliques) // Sort the cliqes for consistent output. Sort.quick(cliques) // Print each clique. for (clique in cliques) {  System.print(clique.join(", ")) } 
Output:
a, b, c d, e, f 
Works with: Zig version 0.14.0
Translation of: C++
const std = @import("std"); const Edge = struct {  start: []const u8,  end: []const u8, }; fn printVector(vec: []const []const u8) !void {  const stdout = std.io.getStdOut().writer();  try stdout.print("[", .{});  for (vec, 0..) |element, i| {  if (i < vec.len - 1) {  try stdout.print("{s}, ", .{element});  } else {  try stdout.print("{s}", .{element});  }  }  try stdout.print("]", .{}); } fn print2DVector(vecs: []const []const []const u8) !void {  const stdout = std.io.getStdOut().writer();  try stdout.print("[", .{});  for (vecs, 0..) |vec, i| {  try printVector(vec);  if (i < vecs.len - 1) {  try stdout.print(", ", .{});  }  }  try stdout.print("]\n", .{}); } fn bronKerbosch(  allocator: std.mem.Allocator,  currentClique: *std.StringArrayHashMap([]const u8),  candidates: *std.StringArrayHashMap([]const u8),  processedVertices: *std.StringArrayHashMap([]const u8),  graph: *std.StringArrayHashMap(std.StringHashMap(void)),  cliques: *std.ArrayList([]const []const u8), ) !void {  if (candidates.count() == 0 and processedVertices.count() == 0) {  if (currentClique.count() > 2) {  var cliqueList = std.ArrayList([]const u8).init(allocator);  var it = currentClique.iterator();  while (it.next()) |entry| {  try cliqueList.append(entry.key_ptr.*);  }  const cliqueSlice = try cliqueList.toOwnedSlice();  try cliques.append(cliqueSlice);  }  return;  }  // Find pivot with maximum degree  var pivot: []const u8 = "";  var maxDegree: usize = 0;  var it = graph.iterator();  while (it.next()) |entry| {  const vertex = entry.key_ptr.*;  const degree = entry.value_ptr.count();  if (degree > maxDegree or (maxDegree == 0 and pivot.len == 0)) {  maxDegree = degree;  pivot = vertex;  }  }  // Candidates not connected to pivot  var possibles = std.StringArrayHashMap([]const u8).init(allocator);  defer possibles.deinit();  var cand_it = candidates.iterator();  while (cand_it.next()) |entry| {  const vertex = entry.key_ptr.*;  const is_connected = if (graph.get(vertex)) |neighbors|  neighbors.contains(pivot)  else  false;  if (!is_connected) {  try possibles.put(vertex, vertex);  }  }  // Iterate over possible vertices  var poss_it = possibles.iterator();  while (poss_it.next()) |entry| {  const vertex = entry.key_ptr.*;  // New clique  var newClique = std.StringArrayHashMap([]const u8).init(allocator);  defer newClique.deinit();  var clique_it = currentClique.iterator();  while (clique_it.next()) |clique_entry| {  try newClique.put(clique_entry.key_ptr.*, clique_entry.key_ptr.*);  }  try newClique.put(vertex, vertex);  // New candidates (neighbors of vertex)  var newCandidates = std.StringArrayHashMap([]const u8).init(allocator);  defer newCandidates.deinit();  if (graph.get(vertex)) |vertexNeighbors| {  var cand_iter = candidates.iterator();  while (cand_iter.next()) |cand| {  if (vertexNeighbors.contains(cand.key_ptr.*)) {  try newCandidates.put(cand.key_ptr.*, cand.key_ptr.*);  }  }  }  // New processed vertices (neighbors of vertex)  var newProcessed = std.StringArrayHashMap([]const u8).init(allocator);  defer newProcessed.deinit();  if (graph.get(vertex)) |vertexNeighbors| {  var proc_it = processedVertices.iterator();  while (proc_it.next()) |proc| {  if (vertexNeighbors.contains(proc.key_ptr.*)) {  try newProcessed.put(proc.key_ptr.*, proc.key_ptr.*);  }  }  }  // Recursive call  try bronKerbosch(allocator, &newClique, &newCandidates, &newProcessed, graph, cliques);  // Move vertex from candidates to processed  _ = candidates.*.swapRemove(vertex); // swapRemove - O(1)   // _ = candidates.*.orderedRemove(vertex); // orderedRemove - O(N)  try processedVertices.put(vertex, vertex);  } } pub fn main() !void {  var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);  defer arena.deinit();  const allocator = arena.allocator();  const edges: []const Edge = &.{  .{ .start = "a", .end = "b" },  .{ .start = "b", .end = "a" },  .{ .start = "a", .end = "c" },  .{ .start = "c", .end = "a" },  .{ .start = "b", .end = "c" },  .{ .start = "c", .end = "b" },  .{ .start = "d", .end = "e" },  .{ .start = "e", .end = "d" },  .{ .start = "d", .end = "f" },  .{ .start = "f", .end = "d" },  .{ .start = "e", .end = "f" },  .{ .start = "f", .end = "e" },  };  // Initialize graph  var graph = std.StringArrayHashMap(std.StringHashMap(void)).init(allocator);  defer graph.deinit();  for (edges) |edge| {  if (!graph.contains(edge.start)) {  try graph.put(edge.start, std.StringHashMap(void).init(allocator));  }  if (!graph.contains(edge.end)) {  try graph.put(edge.end, std.StringHashMap(void).init(allocator));  }  if (graph.getPtr(edge.start)) |neighbors| {  try neighbors.put(edge.end, {});  }  if (graph.getPtr(edge.end)) |neighbors| {  try neighbors.put(edge.start, {});  }  }  var currentClique = std.StringArrayHashMap([]const u8).init(allocator);  defer currentClique.deinit();  var candidates = std.StringArrayHashMap([]const u8).init(allocator);  defer candidates.deinit();  var graph_it = graph.iterator();  while (graph_it.next()) |entry| {  try candidates.put(entry.key_ptr.*, entry.key_ptr.*);  }  var processedVertices = std.StringArrayHashMap([]const u8).init(allocator);  defer processedVertices.deinit();  var cliques = std.ArrayList([]const []const u8).init(allocator);  defer cliques.deinit();  try bronKerbosch(allocator, &currentClique, &candidates, &processedVertices, &graph, &cliques);  // Sort cliques  std.sort.heap([]const []const u8, cliques.items, {}, struct {  fn lessThan(_: void, a: []const []const u8, b: []const []const u8) bool {  const minLen = @min(a.len, b.len);  for (0..minLen) |i| {  if (!std.mem.eql(u8, a[i], b[i])) {  return std.mem.lessThan(u8, a[i], b[i]);  }  }  return a.len < b.len;  }  }.lessThan);  try print2DVector(cliques.items); } 
Output:
[[d, f, e]]