Diff of /pathaia/graphs/kruskal.py [000000] .. [7823dd]

Switch to unified view

a b/pathaia/graphs/kruskal.py
1
from .types import Parenthood, NumericalNodeProperty, Node, Edge
2
3
4
class UFDS:
5
    """
6
    Union-find data structure for felzenszwalb algorithm.
7
    Each unionFind instance X maintains a family of disjoint sets of
8
    hashable objects, supporting the following two methods:
9
    - X[item] returns a name for the set containing the given item.
10
      Each set is named by an arbitrarily-chosen one of its members; as
11
      long as the set remains unchanged it will keep the same name. If
12
      the item is not yet part of a set in X, a new singleton set is
13
      created for it.
14
    - X.union(item1, item2, ...) merges the sets containing each item
15
      into a single larger set.  If any item is not yet part of a set
16
      in X, it is added to X as one of the members of the merged set.
17
      Union-find data structure. Based on Josiah Carlson's code,
18
      http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/215912
19
      with significant additional changes by D. Eppstein.
20
      http://www.ics.uci.edu/~eppstein/PADS/UnionFind.py
21
    """
22
23
    def __init__(self):
24
        """
25
        Create a new empty union-find structure.
26
        ****************************************
27
        """
28
        # UFDS permit to compute the hierarchy
29
        # it is responsible to keep track of:
30
        # the parent is crucial, but it only guarantee the tree structure
31
        # should not be used outside of the object
32
        self._parent: Parenthood = {}
33
        # size is subjective, it is only used to fuse objects, no real quantitative interest
34
        # should not be used outside of the object
35
        self._size: NumericalNodeProperty = {}
36
37
    def get_root(self, node: Node) -> Node:
38
        """
39
        Find and return the name of the set containing the node.
40
        ********************************************************
41
        """
42
        # check for previously unknown object
43
        # if unknown, create an entry in the parent dico
44
        # then, size is set to 1
45
        # intra is set to 0
46
        if node not in self._parent:
47
            self._parent[node] = node
48
            self._size[node] = 1
49
            return node
50
        # find path of objects leading to the root
51
        path = [node]
52
        root = self._parent[node]
53
        while root != path[-1]:
54
            path.append(root)
55
            root = self._parent[root]
56
        # compress the path and return
57
        for ancestor in path:
58
            self._parent[ancestor] = root
59
        return root
60
61
    def __iter__(self):
62
        """
63
        Iterate through all items ever found or unioned by this structure.
64
        ******************************************************************
65
        """
66
        return iter(self.parents)
67
68
    def union(self, edge: Edge):
69
        """
70
        Find the sets containing the objects and merge them all.
71
        ********************************************************
72
        """
73
        n1, n2 = edge
74
        roots = [self.get_root(n1), self.get_root(n2)]
75
        # Find the heaviest root according to its weight.
76
        heaviest = max(roots, key=lambda r: self._size[r])
77
        for r in roots:
78
            if r != heaviest:
79
                self._size[heaviest] += self._size[r]
80
                self._parent[r] = heaviest