Skip to content

Commit e2c1ce4

Browse files
formularinstokhos
authored andcommitted
Karger's Algorithm (TheAlgorithms#2237)
* Add implementation of Karger's Algorithm * Remove print statement from karger's algorithm function * Fix style issues in graphs/karger.py * Change for loops to set comprehensions where appropriate in graphs/karger.py
1 parent 2c32f4a commit e2c1ce4

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

Diff for: graphs/karger.py

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""
2+
An implementation of Karger's Algorithm for partitioning a graph.
3+
"""
4+
5+
import random
6+
from typing import Dict, List, Set, Tuple
7+
8+
9+
# Adjacency list representation of this graph:
10+
# https://en.wikipedia.org/wiki/File:Single_run_of_Karger%E2%80%99s_Mincut_algorithm.svg
11+
TEST_GRAPH = {
12+
'1': ['2', '3', '4', '5'],
13+
'2': ['1', '3', '4', '5'],
14+
'3': ['1', '2', '4', '5', '10'],
15+
'4': ['1', '2', '3', '5', '6'],
16+
'5': ['1', '2', '3', '4', '7'],
17+
'6': ['7', '8', '9', '10', '4'],
18+
'7': ['6', '8', '9', '10', '5'],
19+
'8': ['6', '7', '9', '10'],
20+
'9': ['6', '7', '8', '10'],
21+
'10': ['6', '7', '8', '9', '3']
22+
}
23+
24+
25+
def partition_graph(graph: Dict[str, List[str]]) -> Set[Tuple[str, str]]:
26+
"""
27+
Partitions a graph using Karger's Algorithm. Implemented from
28+
pseudocode found here:
29+
https://en.wikipedia.org/wiki/Karger%27s_algorithm.
30+
This function involves random choices, meaning it will not give
31+
consistent outputs.
32+
33+
Args:
34+
graph: A dictionary containing adacency lists for the graph.
35+
Nodes must be strings.
36+
37+
Returns:
38+
The cutset of the cut found by Karger's Algorithm.
39+
40+
>>> graph = {'0':['1'], '1':['0']}
41+
>>> partition_graph(graph)
42+
{('0', '1')}
43+
"""
44+
# Dict that maps contracted nodes to a list of all the nodes it "contains."
45+
contracted_nodes = {node: {node} for node in graph}
46+
47+
graph_copy = {node: graph[node][:] for node in graph}
48+
49+
while len(graph_copy) > 2:
50+
51+
# Choose a random edge.
52+
u = random.choice(list(graph_copy.keys()))
53+
v = random.choice(graph_copy[u])
54+
55+
# Contract edge (u, v) to new node uv
56+
uv = u + v
57+
uv_neighbors = list(set(graph_copy[u] + graph_copy[v]))
58+
uv_neighbors.remove(u)
59+
uv_neighbors.remove(v)
60+
graph_copy[uv] = uv_neighbors
61+
for neighbor in uv_neighbors:
62+
graph_copy[neighbor].append(uv)
63+
64+
contracted_nodes[uv] = {contracted_node for contracted_node in
65+
contracted_nodes[u].union(contracted_nodes[v])}
66+
67+
# Remove nodes u and v.
68+
del graph_copy[u]
69+
del graph_copy[v]
70+
for neighbor in uv_neighbors:
71+
if u in graph_copy[neighbor]:
72+
graph_copy[neighbor].remove(u)
73+
if v in graph_copy[neighbor]:
74+
graph_copy[neighbor].remove(v)
75+
76+
# Find cutset.
77+
groups = [contracted_nodes[node] for node in graph_copy]
78+
return {(node, neighbor) for node in groups[0]
79+
for neighbor in graph[node] if neighbor in groups[1]}
80+
81+
82+
if __name__ == "__main__":
83+
print(partition_graph(TEST_GRAPH))

0 commit comments

Comments
 (0)