Cull to three good methods, now more efficient
dkl9

dkl9 commited on 2025-190 03:05:41
Showing 1 changed files, with 19 additions and 46 deletions.

... ...
@@ -61,60 +61,31 @@ def show_mat(distances: DistTable) -> str:
61 61
         rows.append(row)
62 62
     return "\n".join(rows)
63 63
 
64
-# promising
65
-def score_nearest(distances: DistTable, sample: IndSeq) -> float:
66
-    return sum(0 if i in sample else min(distances[i][j] for j in sample) for i in range(len(distances)))
67
-
68
-# too centred and slow
69
-def score_total(distances: DistTable, sample: IndSeq) -> float:
70
-    return sum(sum(
71
-        0 if i in sample else distances[i][j] for j in sample
72
-    ) for i in range(len(distances)))
73
-
74
-# promising, needs revision
75
-def score_spread(distances: DistTable, sample: IndSeq) -> float:
76
-    return -sum(sum(distances[sample[i]][j] for j in sample[:i]) for i in range(len(sample)))
77
-
78
-def score_sqrt_spread(distances: DistTable, sample: IndSeq) -> float:
79
-    return -sum(sum(
80
-        math.sqrt(distances[sample[i]][j]) for j in sample[:i]
81
-    ) for i in range(len(sample)))
82
-
83
-def greedy_min_seq(distances: DistTable, score_func: Func[[DistTable, IndSeq], float]) -> IndSeq:
84
-    seq = []
85
-    options = set(range(len(distances)))
86
-    while options:
87
-        best = min(options, key=lambda o: score_func(distances, seq + [o]))
88
-        seq.append(best)
89
-        options.remove(best)
90
-    return seq
91
-
92
-def score_maximin(distances: DistTable, sample: IndSeq) -> float:
93
-    return min(min(distances[sample[i]][j] for j in sample[:i]) for i in range(1, len(sample)))
94
-
95
-# promising
96
-def greedy_maximin(distances: DistTable) -> IndSeq:
64
+# good results, slow
65
+def cachey_nearest(distances: DistTable) -> IndSeq:
97 66
     seq = []
98 67
     options = set(range(len(distances)))
99
-    start = min(options, key=lambda o: score_nearest(distances, [o]))
100
-    seq.append(start)
101
-    options.remove(start)
68
+    nearests = [math.inf for _ in range(len(distances))]
102 69
     while options:
103
-        best = max(options, key=lambda o: score_maximin(distances, seq + [o]))
70
+        reduceds = {o: [min(distances[o][i], nearests[i]) for i in range(len(nearests))] for o in options}
71
+        best = min(options, key=lambda o: sum(reduceds[o]))
72
+        nearests = reduceds[best]
104 73
         seq.append(best)
105 74
         options.remove(best)
106 75
     return seq
107 76
 
108
-# too edge-clustery
109
-def furthest_nb(distances: DistTable) -> IndSeq:
77
+# good results, sketchy on a couple trials
78
+def cachey_maximin(distances: DistTable) -> IndSeq:
110 79
     seq = []
111 80
     options = set(range(len(distances)))
112
-    start = min(options, key=lambda o: score_nearest(distances, [o]))
81
+    start = min(options, key=lambda o: sum(distances[o]))
113 82
     seq.append(start)
114 83
     options.remove(start)
84
+    score = math.inf
115 85
     while options:
116
-        dl = distances[seq[-1]]
117
-        best = max(options, key=lambda o: dl[o])
86
+        updateds = {o: min(min(distances[o][i] for i in seq), score) for o in options}
87
+        best = max(options, key=lambda o: updateds[o])
88
+        score = updateds[best]
118 89
         seq.append(best)
119 90
         options.remove(best)
120 91
     return seq
... ...
@@ -130,7 +101,7 @@ def distance_hierarchy(distances: DistTable) -> BinaryTree:
130 101
         p = forest[i].merge(forest[j])
131 102
     return p
132 103
 
133
-# promising
104
+# good results, sketchy on somewhat more trials
134 105
 def scattered_hierarchy(hierarchy: BinaryTree) -> IndSeq:
135 106
     seq = []
136 107
     while hierarchy.usage < hierarchy.weight:
... ...
@@ -152,8 +123,10 @@ def total_len(distances: DistTable, seq: IndSeq) -> float:
152 123
     return sum(distances[i][j] for (i, j) in itertools.pairwise(seq))
153 124
 
154 125
 points: list[str] = [l.strip() for l in sys.stdin]
126
+to = time.time()
155 127
 dt: DistTable = distance_table(points, lambda a, b: Levenshtein.distance(a, b, weights=(1, 1, 3)))
156
-print(show_mat(dt))
128
+tf = time.time()
129
+print(f"took {tf - to} s to calculate distances")
157 130
 to = time.time()
158 131
 h: BinaryTree = distance_hierarchy(dt)
159 132
 tf = time.time()
... ...
@@ -161,8 +134,8 @@ print(f"took {tf - to} s to build hierarchy")
161 134
 print(h)
162 135
 METHODS = [
163 136
     ("graph", lambda: scattered_hierarchy(h)),
164
-    ("nearest-nb sum", lambda: greedy_min_seq(dt, score_nearest)),
165
-    ("maximin", lambda: greedy_maximin(dt)),
137
+    ("nearest-nb", lambda: cachey_nearest(dt)),
138
+    ("maximin", lambda: cachey_maximin(dt)),
166 139
 ]
167 140
 for (name, method) in METHODS:
168 141
     to = time.time()
169 142