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 |