24
24
'topological_sort' ,
25
25
'topological_sort_parallel' ,
26
26
'max_flow' ,
27
- 'find_bridges'
27
+ 'find_bridges' ,
28
+ 'find_maximal_cliques'
28
29
]
29
30
30
31
Stack = Queue = deque
@@ -1169,7 +1170,6 @@ def _job(graph: Graph, u: str):
1169
1170
raise ValueError ("Graph is not acyclic." )
1170
1171
return L
1171
1172
1172
-
1173
1173
def _breadth_first_search_max_flow (graph : Graph , source_node , sink_node , flow_passed , for_dinic = False ):
1174
1174
bfs_queue = Queue ()
1175
1175
parent , currentPathC = {}, {}
@@ -1191,7 +1191,6 @@ def _breadth_first_search_max_flow(graph: Graph, source_node, sink_node, flow_pa
1191
1191
bfs_queue .append (next_node .name )
1192
1192
return (0 , parent )
1193
1193
1194
-
1195
1194
def _max_flow_edmonds_karp_ (graph : Graph , source , sink ):
1196
1195
m_flow = 0
1197
1196
flow_passed = {}
@@ -1209,7 +1208,6 @@ def _max_flow_edmonds_karp_(graph: Graph, source, sink):
1209
1208
new_flow , parent = _breadth_first_search_max_flow (graph , source , sink , flow_passed )
1210
1209
return m_flow
1211
1210
1212
-
1213
1211
def _depth_first_search_max_flow_dinic (graph : Graph , u , parent , sink_node , flow , flow_passed ):
1214
1212
if u == sink_node :
1215
1213
return flow
@@ -1233,7 +1231,6 @@ def _depth_first_search_max_flow_dinic(graph: Graph, u, parent, sink_node, flow,
1233
1231
return path_flow
1234
1232
return 0
1235
1233
1236
-
1237
1234
def _max_flow_dinic_ (graph : Graph , source , sink ):
1238
1235
max_flow = 0
1239
1236
flow_passed = {}
@@ -1253,7 +1250,6 @@ def _max_flow_dinic_(graph: Graph, source, sink):
1253
1250
1254
1251
return max_flow
1255
1252
1256
-
1257
1253
def max_flow (graph , source , sink , algorithm = 'edmonds_karp' , ** kwargs ):
1258
1254
raise_if_backend_is_not_python (
1259
1255
max_flow , kwargs .get ('backend' , Backend .PYTHON ))
@@ -1266,7 +1262,6 @@ def max_flow(graph, source, sink, algorithm='edmonds_karp', **kwargs):
1266
1262
"performing max flow on graphs." )
1267
1263
return getattr (algorithms , func )(graph , source , sink )
1268
1264
1269
-
1270
1265
def find_bridges (graph ):
1271
1266
"""
1272
1267
Finds all bridges in an undirected graph using Tarjan's Algorithm.
@@ -1368,3 +1363,87 @@ def dfs(u):
1368
1363
bridges .append ((b , a ))
1369
1364
bridges .sort ()
1370
1365
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