974.1.68
by Aaron Bentley
Added GPL notice |
1 |
# (C) 2005 Canonical
|
2 |
||
3 |
# This program is free software; you can redistribute it and/or modify
|
|
4 |
# it under the terms of the GNU General Public License as published by
|
|
5 |
# the Free Software Foundation; either version 2 of the License, or
|
|
6 |
# (at your option) any later version.
|
|
7 |
||
8 |
# This program is distributed in the hope that it will be useful,
|
|
9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11 |
# GNU General Public License for more details.
|
|
12 |
||
13 |
# You should have received a copy of the GNU General Public License
|
|
14 |
# along with this program; if not, write to the Free Software
|
|
15 |
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
16 |
||
974.1.59
by aaron.bentley at utoronto
Created yet another longest-patch-picker |
17 |
def max_distance(node, ancestors, distances): |
974.1.66
by Aaron Bentley
more cleanups, docs, sorting stuff |
18 |
"""Calculate the max distance to an ancestor.
|
19 |
Return None if not all possible ancestors have known distances"""
|
|
974.1.59
by aaron.bentley at utoronto
Created yet another longest-patch-picker |
20 |
best = None |
21 |
if node in distances: |
|
22 |
best = distances[node] |
|
23 |
for ancestor in ancestors[node]: |
|
974.1.66
by Aaron Bentley
more cleanups, docs, sorting stuff |
24 |
# An ancestor which is not listed in ancestors will never be in
|
25 |
# distances, so we pretend it never existed.
|
|
974.1.64
by Aaron Bentley
Handled ancestors that are missing when finding a base |
26 |
if ancestor not in ancestors: |
27 |
continue
|
|
974.1.59
by aaron.bentley at utoronto
Created yet another longest-patch-picker |
28 |
if ancestor not in distances: |
29 |
return None |
|
30 |
if best is None or distances[ancestor] > best: |
|
31 |
best = distances[ancestor] + 1 |
|
32 |
return best |
|
33 |
||
34 |
||
974.1.66
by Aaron Bentley
more cleanups, docs, sorting stuff |
35 |
def farthest_nodes(graph, ancestors, start): |
36 |
"""Produce a list of nodes, sorted by distance from a start node.
|
|
37 |
This is an algorithm devised by Aaron Bentley, because applying Dijkstra
|
|
38 |
backwards seemed too complicated.
|
|
39 |
||
40 |
For each node, we walk its descendants. If all the descendant's ancestors
|
|
41 |
have a max-distance-to-start, (excluding ones that can never reach start),
|
|
42 |
we calculate their max-distance-to-start, and schedule their descendants.
|
|
43 |
||
44 |
So when a node's last parent acquires a distance, it will acquire a
|
|
45 |
distance on the next iteration.
|
|
46 |
||
47 |
Once we know the max distances for all nodes, we can return a list sorted
|
|
48 |
by distance, farthest first.
|
|
49 |
"""
|
|
974.1.59
by aaron.bentley at utoronto
Created yet another longest-patch-picker |
50 |
distances = {start: 0} |
974.1.60
by aaron.bentley at utoronto
Initial import of common-ancestor detection |
51 |
lines = set([start]) |
974.1.59
by aaron.bentley at utoronto
Created yet another longest-patch-picker |
52 |
while len(lines) > 0: |
53 |
new_lines = set() |
|
54 |
for line in lines: |
|
974.1.62
by Aaron Bentley
Added farthest_node sanity checks |
55 |
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 |
56 |
for descendant in graph[line]: |
57 |
distance = max_distance(descendant, ancestors, distances) |
|
58 |
if distance is None: |
|
59 |
continue
|
|
60 |
distances[descendant] = distance |
|
61 |
new_lines.add(descendant) |
|
62 |
lines = new_lines |
|
63 |
||
64 |
def by_distance(n): |
|
974.1.66
by Aaron Bentley
more cleanups, docs, sorting stuff |
65 |
return distances[n],n |
974.1.59
by aaron.bentley at utoronto
Created yet another longest-patch-picker |
66 |
node_list = distances.keys() |
67 |
node_list.sort(key=by_distance, reverse=True) |
|
68 |
return node_list |