2424 'topological_sort' ,
2525 'topological_sort_parallel' ,
2626 'max_flow' ,
27- 'find_bridges'
27+ 'find_bridges' ,
28+ 'find_maximal_cliques'
2829]
2930
3031Stack = Queue = deque
@@ -1169,7 +1170,6 @@ def _job(graph: Graph, u: str):
11691170 raise ValueError ("Graph is not acyclic." )
11701171 return L
11711172
1172-
11731173def _breadth_first_search_max_flow (graph : Graph , source_node , sink_node , flow_passed , for_dinic = False ):
11741174 bfs_queue = Queue ()
11751175 parent , currentPathC = {}, {}
@@ -1191,7 +1191,6 @@ def _breadth_first_search_max_flow(graph: Graph, source_node, sink_node, flow_pa
11911191 bfs_queue .append (next_node .name )
11921192 return (0 , parent )
11931193
1194-
11951194def _max_flow_edmonds_karp_ (graph : Graph , source , sink ):
11961195 m_flow = 0
11971196 flow_passed = {}
@@ -1209,7 +1208,6 @@ def _max_flow_edmonds_karp_(graph: Graph, source, sink):
12091208 new_flow , parent = _breadth_first_search_max_flow (graph , source , sink , flow_passed )
12101209 return m_flow
12111210
1212-
12131211def _depth_first_search_max_flow_dinic (graph : Graph , u , parent , sink_node , flow , flow_passed ):
12141212 if u == sink_node :
12151213 return flow
@@ -1233,7 +1231,6 @@ def _depth_first_search_max_flow_dinic(graph: Graph, u, parent, sink_node, flow,
12331231 return path_flow
12341232 return 0
12351233
1236-
12371234def _max_flow_dinic_ (graph : Graph , source , sink ):
12381235 max_flow = 0
12391236 flow_passed = {}
@@ -1253,7 +1250,6 @@ def _max_flow_dinic_(graph: Graph, source, sink):
12531250
12541251 return max_flow
12551252
1256-
12571253def max_flow (graph , source , sink , algorithm = 'edmonds_karp' , ** kwargs ):
12581254 raise_if_backend_is_not_python (
12591255 max_flow , kwargs .get ('backend' , Backend .PYTHON ))
@@ -1266,7 +1262,6 @@ def max_flow(graph, source, sink, algorithm='edmonds_karp', **kwargs):
12661262 "performing max flow on graphs." )
12671263 return getattr (algorithms , func )(graph , source , sink )
12681264
1269-
12701265def find_bridges (graph ):
12711266 """
12721267 Finds all bridges in an undirected graph using Tarjan's Algorithm.
@@ -1368,3 +1363,87 @@ def dfs(u):
13681363 bridges .append ((b , a ))
13691364 bridges .sort ()
13701365 return bridges
1366+
1367+ def _bron_kerbosc (graph : Graph , set_r : set , set_p : set , set_x : set , cliques : list ):
1368+ if not set_p and not set_x :
1369+ cliques .append (sorted (list (set_r )))
1370+ return
1371+
1372+ for v in list (set_p ):
1373+ neighbor_nodes = graph .neighbors (v )
1374+ neighbors = set (n .name for n in neighbor_nodes )
1375+ _bron_kerbosc (graph , set_r .union ({v }), set_p .intersection (neighbors ),
1376+ set_x .intersection (neighbors ), cliques )
1377+ set_p .remove (v )
1378+ set_x .add (v )
1379+
1380+ def _find_maximal_cliques_bron_kerbosc_adjacency_list (graph : Graph ) -> list :
1381+ cliques = []
1382+ vertices = set (graph .vertices )
1383+ _bron_kerbosc (graph , set (), vertices , set (), cliques )
1384+ return sorted (cliques )
1385+
1386+ _find_maximal_cliques_bron_kerbosc_adjacency_matrix = \
1387+ _find_maximal_cliques_bron_kerbosc_adjacency_list
1388+
1389+ def find_maximal_cliques (graph : Graph , algorithm : str , ** kwargs ) -> list :
1390+ """
1391+ Finds maximal cliques for an undirected graph.
1392+
1393+ Parameters
1394+ ==========
1395+
1396+ graph: Graph
1397+ The graph under consideration.
1398+ algorithm: str
1399+ The algorithm to be used. Currently, the following algorithms
1400+ are implemented,
1401+
1402+ 'bron_kerbosc' -> Bron Kerbosc algorithm as given in [1].
1403+ backend: pydatastructs.Backend
1404+ The backend to be used.
1405+ Optional, by default, the best available
1406+ backend is used.
1407+
1408+ Returns
1409+ =======
1410+
1411+ cliques: list
1412+ Python list with each element as list of vertices.
1413+
1414+ Examples
1415+ ========
1416+
1417+ >>> from pydatastructs import Graph, AdjacencyListGraphNode
1418+ >>> from pydatastructs import find_maximal_cliques
1419+ >>> V1 = AdjacencyListGraphNode('V1')
1420+ >>> V2 = AdjacencyListGraphNode('V2')
1421+ >>> V3 = AdjacencyListGraphNode('V3')
1422+ >>> V4 = AdjacencyListGraphNode('V4')
1423+ >>> G = Graph(V1, V2, V3, V4)
1424+ >>> G.add_edge('V1', 'V2')
1425+ >>> G.add_edge('V2', 'V1')
1426+ >>> G.add_edge('V2', 'V3')
1427+ >>> G.add_edge('V3', 'V2')
1428+ >>> G.add_edge('V1', 'V3')
1429+ >>> G.add_edge('V3', 'V1')
1430+ >>> G.add_edge('V1', 'V4')
1431+ >>> G.add_edge('V4', 'V1')
1432+ >>> find_maximal_cliques(G, 'bron_kerbosc')
1433+ [['V1', 'V2', 'V3'], ['V1', 'V4']]
1434+
1435+ References
1436+ ==========
1437+
1438+ .. [1] https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm
1439+ """
1440+ raise_if_backend_is_not_python (
1441+ find_maximal_cliques , kwargs .get ('backend' , Backend .PYTHON ))
1442+
1443+ import pydatastructs .graphs .algorithms as algorithms
1444+ func = "_find_maximal_cliques_" + algorithm + "_" + graph ._impl
1445+ if not hasattr (algorithms , func ):
1446+ raise NotImplementedError (
1447+ f"Currently { algorithm } algorithm isn't implemented for "
1448+ "finding maximal cliques on graphs." )
1449+ return getattr (algorithms , func )(graph )
0 commit comments