~bzr-pqm/bzr/bzr.dev

974.1.65 by Aaron Bentley
Cleanup and test-fixing
1
	
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
2
def max_distance(node, ancestors, distances):
974.1.66 by Aaron Bentley
more cleanups, docs, sorting stuff
3
    """Calculate the max distance to an ancestor.  
4
    Return None if not all possible ancestors have known distances"""
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
5
    best = None
6
    if node in distances:
7
        best = distances[node]
8
    for ancestor in ancestors[node]:
974.1.66 by Aaron Bentley
more cleanups, docs, sorting stuff
9
        # An ancestor which is not listed in ancestors will never be in
10
        # distances, so we pretend it never existed.
974.1.64 by Aaron Bentley
Handled ancestors that are missing when finding a base
11
        if ancestor not in ancestors:
12
            continue
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
13
        if ancestor not in distances:
14
            return None
15
        if best is None or distances[ancestor] > best:
16
            best = distances[ancestor] + 1
17
    return best
18
19
    
974.1.66 by Aaron Bentley
more cleanups, docs, sorting stuff
20
def farthest_nodes(graph, ancestors, start):
21
    """Produce a list of nodes, sorted by distance from a start node.
22
    This is an algorithm devised by Aaron Bentley, because applying Dijkstra
23
    backwards seemed too complicated.
24
25
    For each node, we walk its descendants.  If all the descendant's ancestors
26
    have a max-distance-to-start, (excluding ones that can never reach start),
27
    we calculate their max-distance-to-start, and schedule their descendants.
28
29
    So when a node's last parent acquires a distance, it will acquire a
30
    distance on the next iteration.
31
32
    Once we know the max distances for all nodes, we can return a list sorted
33
    by distance, farthest first.
34
    """
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
35
    distances = {start: 0}
974.1.60 by aaron.bentley at utoronto
Initial import of common-ancestor detection
36
    lines = set([start])
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
37
    while len(lines) > 0:
38
        new_lines = set()
39
        for line in lines:
974.1.62 by Aaron Bentley
Added farthest_node sanity checks
40
            assert line not in graph[line], "%s refers to itself" % line
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
41
            for descendant in graph[line]:
42
                distance = max_distance(descendant, ancestors, distances)
43
                if distance is None:
44
                    continue
45
                distances[descendant] = distance
46
                new_lines.add(descendant)
47
        lines = new_lines
48
49
    def by_distance(n):
974.1.66 by Aaron Bentley
more cleanups, docs, sorting stuff
50
        return distances[n],n
974.1.59 by aaron.bentley at utoronto
Created yet another longest-patch-picker
51
    node_list = distances.keys()
52
    node_list.sort(key=by_distance, reverse=True)
53
    return node_list