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 |