Use a weird traversal of binary trees
dkl9

dkl9 commited on 2025-185 22:47:45
Showing 1 changed files, with 67 additions and 0 deletions.

... ...
@@ -6,6 +6,42 @@ Func: typing.TypeAlias = collections.abc.Callable
6 6
 DistTable: typing.TypeAlias = list[list[float]]
7 7
 IndSeq: typing.TypeAlias = list[int]
8 8
 
9
+def tree_weight(x) -> int:
10
+    if x is None:
11
+        return 0
12
+    elif isinstance(x, BinaryTree):
13
+        return x.weight
14
+    return 1
15
+
16
+class BinaryTree:
17
+    def __init__(self, a, b=None):
18
+        self.x = self.y = self.parent = None
19
+        self.a = a
20
+        self.b = b
21
+        self.weight = tree_weight(a) + tree_weight(b)
22
+        self.usage = 0
23
+
24
+    def __str__(self) -> str:
25
+        return str(self.a) if self.b is None else f"({self.a} {self.b})"
26
+
27
+    def merge(self, other):
28
+        a, b = self, other
29
+        while a.parent:
30
+            a = a.parent
31
+        while b.parent:
32
+            b = b.parent
33
+        if a is b:
34
+            return a
35
+        parent = BinaryTree(a, b)
36
+        a.parent = b.parent = parent
37
+        return parent
38
+
39
+    def use(self):
40
+        assert self.usage < self.weight
41
+        self.usage += 1
42
+        if self.parent:
43
+            self.parent.use()
44
+
9 45
 def distance_table[T](points: list[T], metric: Func[[T, T], float]) -> DistTable:
10 46
     return [[metric(x, y) for y in points] for x in points]
11 47
 
... ...
@@ -26,5 +62,36 @@ def greedy_min_seq(distances: DistTable, score_func: Func[[DistTable, IndSeq], f
26 62
         options.remove(best)
27 63
     return seq
28 64
 
65
+def distance_hierarchy(distances: DistTable) -> BinaryTree:
66
+    n = len(distances)
67
+    forest = [BinaryTree(i) for i in range(n)]
68
+    p = None
69
+    for (i, j) in sorted(
70
+        ((i, j) for i in range(n) for j in range(n)),
71
+        key=lambda ij: distances[ij[0]][ij[1]]
72
+    ):
73
+        p = forest[i].merge(forest[j])
74
+    return p
75
+
76
+def scattered_hierarchy(hierarchy: BinaryTree) -> IndSeq:
77
+    seq = []
78
+    while hierarchy.usage < hierarchy.weight:
79
+        fb = hierarchy
80
+        while fb.b is not None:
81
+            ua = fb.a.usage / fb.a.weight
82
+            ub = fb.b.usage / fb.b.weight
83
+            if ua < ub:
84
+                fb = fb.a
85
+            elif ua == ub and fb.a.weight > fb.b.weight:
86
+                fb = fb.a
87
+            else:
88
+                fb = fb.b
89
+        fb.use()
90
+        seq.append(fb.a)
91
+    return seq
92
+
29 93
 dt: DistTable = distance_table([(0, 2), (3, 2), (4, 2), (5, 0), (0, 0)], math.dist)
30 94
 print(greedy_min_seq(dt, score_total))
95
+h: BinaryTree = distance_hierarchy(dt)
96
+print(h)
97
+print(scattered_hierarchy(h))
31 98