-
Notifications
You must be signed in to change notification settings - Fork 0
/
kruskals.py
113 lines (83 loc) · 2.2 KB
/
kruskals.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import collections
import math
class GraphCluster:
def __init__(self, *edges):
self.edges = set(edges)
self.vertices = set()
for e in edges:
for v in e:
self.vertices.add(v)
class KruskalsClusterer:
def __init__(self, n = 1):
self.n = n
def __call__(self, *points):
# compute distances
distances_dict = {}
for p1 in points:
for p2 in points:
if p1 is p2:
continue
distances_dict[tuple(sorted((p1, p2)))] = abs(p1 - p2)
# sort distances
distances = sorted(distances_dict.items(), key = lambda e: e[1])
del distances_dict
# compute clusters
clusters = set()
for p in points:
gc = GraphCluster()
gc.vertices.add(p)
clusters.add(gc)
for d in distances:
edge, distance = d
print('P1: ', edge[0][0],edge[0][1] , 'P2 ', edge[1][0],edge[1][1], 'D ', distance)
# check # of clusters
if len(clusters) <= self.n:
break
# check each cluster to see if points from edge are in any of them
c0 = None
c1 = None
for c in clusters:
# break out early if possible
if c0 != None and c1 != None:
break
if edge[0] in c.vertices:
c0 = c
if edge[1] in c.vertices:
c1 = c
# Case 1: points in the same cluster
if c0 == c1:
continue
# Case 2: points in unique clusters
else:
# add new edge & vertexes to 0
c0.edges.add(edge)
c0.vertices.add(edge[1])
# merge c1 into c0
for e in c1.edges:
c0.edges.add(e)
for v in c1.vertices:
c0.vertices.add(v)
clusters.remove(c1)
del c1
del distances
return clusters
class Point:
def __init__(self, *vector):
self._vector = vector
def __eq__(self, other):
return self._vector == other._vector
def __ge__(self, other):
return self._vector >= other._vector
def __getitem__(self, i):
return self._vector[i]
def __hash__(self):
return hash(self._vector)
def __le__(self, other):
return self._vector <= other._vector
def __len__(self):
return len(self._vector)
def __lt__(self, other):
return self._vector < other._vector
def __sub__(self, other):
assert len(other) == len(self), "points must have equal numbers of dimensions"
return math.sqrt(sum(((other[i] - self[i]) ** 2 for i in range(len(self)))))