Merged r[280]:[358] from source:/sandbox/follower/b-singlefile/ (Enable building of Single File Library version of OpenLayers library).
git-svn-id: http://svn.openlayers.org/trunk/openlayers@359 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
#
|
||||
# According to <http://www.vrplumber.com/programming/> this file
|
||||
# is licensed under a BSD-style license. We only use the section
|
||||
# originally by Tim Peters.
|
||||
#
|
||||
# TODO: The use of this code needs to be okayed by someone.
|
||||
#
|
||||
|
||||
class RecursionError( OverflowError, ValueError ):
|
||||
'''Unable to calculate result because of recursive structure'''
|
||||
|
||||
|
||||
def sort(nodes, routes, noRecursion=1):
|
||||
'''Passed a list of node IDs and a list of source,dest ID routes
|
||||
attempt to create a list of stages where each sub list
|
||||
is one stage in a process.
|
||||
'''
|
||||
children, parents = _buildChildrenLists(routes)
|
||||
# first stage is those nodes
|
||||
# having no incoming routes...
|
||||
stage = []
|
||||
stages = [stage]
|
||||
taken = []
|
||||
for node in nodes:
|
||||
if (not parents.get(node)):
|
||||
stage.append (node)
|
||||
if nodes and not stage:
|
||||
# there is no element which does not depend on
|
||||
# some other element!!!
|
||||
stage.append( nodes[0])
|
||||
taken.extend( stage )
|
||||
nodes = filter ( lambda x, l=stage: x not in l, nodes )
|
||||
while nodes:
|
||||
previousStageChildren = []
|
||||
nodelen = len(nodes)
|
||||
# second stage are those nodes
|
||||
# which are direct children of the first stage
|
||||
for node in stage:
|
||||
for child in children.get (node, []):
|
||||
if child not in previousStageChildren and child not in taken:
|
||||
previousStageChildren.append(child)
|
||||
elif child in taken and noRecursion:
|
||||
raise RecursionError( (child, node) )
|
||||
# unless they are children of other direct children...
|
||||
# TODO, actually do that...
|
||||
stage = previousStageChildren
|
||||
removes = []
|
||||
for current in stage:
|
||||
currentParents = parents.get( current, [] )
|
||||
for parent in currentParents:
|
||||
if parent in stage and parent != current:
|
||||
# might wind up removing current...
|
||||
if not current in parents.get(parent, []):
|
||||
# is not mutually dependent...
|
||||
removes.append( current )
|
||||
for remove in removes:
|
||||
while remove in stage:
|
||||
stage.remove( remove )
|
||||
stages.append( stage)
|
||||
taken.extend( stage )
|
||||
nodes = filter ( lambda x, l=stage: x not in l, nodes )
|
||||
if nodelen == len(nodes):
|
||||
if noRecursion:
|
||||
raise RecursionError( nodes )
|
||||
else:
|
||||
stages.append( nodes[:] )
|
||||
nodes = []
|
||||
return stages
|
||||
|
||||
def _buildChildrenLists (routes):
|
||||
childrenTable = {}
|
||||
parentTable = {}
|
||||
for sourceID,destinationID in routes:
|
||||
currentChildren = childrenTable.get( sourceID, [])
|
||||
currentParents = parentTable.get( destinationID, [])
|
||||
if not destinationID in currentChildren:
|
||||
currentChildren.append ( destinationID)
|
||||
if not sourceID in currentParents:
|
||||
currentParents.append ( sourceID)
|
||||
childrenTable[sourceID] = currentChildren
|
||||
parentTable[destinationID] = currentParents
|
||||
return childrenTable, parentTable
|
||||
|
||||
|
||||
def toposort (nodes, routes, noRecursion=1):
|
||||
'''Topological sort from Tim Peters, fairly efficient
|
||||
in comparison (it seems).'''
|
||||
#first calculate the recursion depth
|
||||
|
||||
dependencies = {}
|
||||
inversedependencies = {}
|
||||
if not nodes:
|
||||
return []
|
||||
if not routes:
|
||||
return [nodes]
|
||||
for node in nodes:
|
||||
dependencies[ node ] = (0, node)
|
||||
inversedependencies[ node ] = []
|
||||
|
||||
|
||||
for depended, depends in routes:
|
||||
# is it a null rule
|
||||
try:
|
||||
newdependencylevel, object = dependencies.get ( depends, (0, depends))
|
||||
except TypeError:
|
||||
print depends
|
||||
raise
|
||||
dependencies[ depends ] = (newdependencylevel + 1, depends)
|
||||
# "dependency (existence) of depended-on"
|
||||
newdependencylevel,object = dependencies.get ( depended, (0, depended) )
|
||||
dependencies[ depended ] = (newdependencylevel, depended)
|
||||
# Inverse dependency set up
|
||||
dependencieslist = inversedependencies.get ( depended, [])
|
||||
dependencieslist.append (depends)
|
||||
inversedependencies[depended] = dependencieslist
|
||||
### Now we do the actual sorting
|
||||
# The first task is to create the sortable
|
||||
# list of dependency-levels
|
||||
sortinglist = dependencies.values()
|
||||
sortinglist.sort ()
|
||||
output = []
|
||||
while sortinglist:
|
||||
deletelist = []
|
||||
generation = []
|
||||
output.append( generation)
|
||||
while sortinglist and sortinglist[0][0] == 0:
|
||||
number, object = sortinglist[0]
|
||||
generation.append ( object )
|
||||
deletelist.append( object )
|
||||
for inverse in inversedependencies.get(object, () ):
|
||||
try:
|
||||
oldcount, inverse = dependencies [ inverse]
|
||||
if oldcount > 0:
|
||||
# will be dealt with on later pass
|
||||
dependencies [ inverse] = (oldcount-1, inverse)
|
||||
else:
|
||||
# will be dealt with on this pass,
|
||||
# so needs not to be in the sorting list next time
|
||||
deletelist.append( inverse )
|
||||
# just in case a loop comes through
|
||||
inversedependencies[object] = []
|
||||
except KeyError:
|
||||
# dealing with a recursion-breaking run...
|
||||
pass
|
||||
del sortinglist [0]
|
||||
# if no elements could be deleted, then
|
||||
# there is something which depends upon itself
|
||||
if not deletelist:
|
||||
if noRecursion:
|
||||
raise RecursionError( sortinglist )
|
||||
else:
|
||||
# hack so that something gets deleted...
|
||||
## import pdb
|
||||
## pdb.set_trace()
|
||||
dependencies[sortinglist[0][1]] = (0,sortinglist[0][1])
|
||||
# delete the items that were dealt with
|
||||
for item in deletelist:
|
||||
try:
|
||||
del dependencies [ item ]
|
||||
except KeyError:
|
||||
pass
|
||||
# need to recreate the sortinglist
|
||||
sortinglist = dependencies.values()
|
||||
if not generation:
|
||||
output.remove( generation )
|
||||
sortinglist.sort ()
|
||||
return output
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
nodes = ['a', 'b', 'c', 'd', 'e', 'f']
|
||||
route = [('a', 'b'), ('b', 'c'), ('b', 'd'), ('e','f')]
|
||||
|
||||
for x in toposort( nodes, route):
|
||||
for a in x:
|
||||
print a
|
||||
|
||||
raise SystemExit
|
||||
|
||||
|
||||
|
||||
import pprint, traceback
|
||||
nodes= [ 0,1,2,3,4,5 ]
|
||||
testingValues = [
|
||||
[ (0,1),(1,2),(2,3),(3,4),(4,5)],
|
||||
[ (0,1),(0,2),(1,2),(3,4),(4,5)],
|
||||
[
|
||||
(0,1),
|
||||
(0,2),
|
||||
(0,2),
|
||||
(2,4),
|
||||
(2,5),
|
||||
(3,2),
|
||||
(0,3)],
|
||||
[
|
||||
(0,1), # 3-element cycle test, no orphan nodes
|
||||
(1,2),
|
||||
(2,0),
|
||||
(2,4),
|
||||
(2,5),
|
||||
(3,2),
|
||||
(0,3)],
|
||||
[
|
||||
(0,1),
|
||||
(1,1),
|
||||
(1,1),
|
||||
(1,4),
|
||||
(1,5),
|
||||
(1,2),
|
||||
(3,1),
|
||||
(2,1),
|
||||
(2,0)],
|
||||
[
|
||||
(0,1),
|
||||
(1,0),
|
||||
(0,2),
|
||||
(0,3),
|
||||
],
|
||||
[
|
||||
(0,1),
|
||||
(1,0),
|
||||
(0,2),
|
||||
(3,1),
|
||||
],
|
||||
]
|
||||
print 'sort, no recursion allowed'
|
||||
for index in range(len(testingValues)):
|
||||
## print ' %s -- %s'%( index, testingValues[index])
|
||||
try:
|
||||
print ' ', sort( nodes, testingValues[index] )
|
||||
except:
|
||||
print 'exception raised'
|
||||
print 'toposort, no recursion allowed'
|
||||
for index in range(len(testingValues)):
|
||||
## print ' %s -- %s'%( index, testingValues[index])
|
||||
try:
|
||||
print ' ', toposort( nodes, testingValues[index] )
|
||||
except:
|
||||
print 'exception raised'
|
||||
print 'sort, recursion allowed'
|
||||
for index in range(len(testingValues)):
|
||||
## print ' %s -- %s'%( index, testingValues[index])
|
||||
try:
|
||||
print ' ', sort( nodes, testingValues[index],0 )
|
||||
except:
|
||||
print 'exception raised'
|
||||
print 'toposort, recursion allowed'
|
||||
for index in range(len(testingValues)):
|
||||
## print ' %s -- %s'%( index, testingValues[index])
|
||||
try:
|
||||
print ' ', toposort( nodes, testingValues[index],0 )
|
||||
except:
|
||||
print 'exception raised'
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user