mirror of
https://github.com/RPCSX/mbuild.git
synced 2026-01-31 01:05:17 +01:00
162 lines
4.0 KiB
Python
Executable File
162 lines
4.0 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# FILE: dfs.py
|
|
# AUTHOR: Mark Charney <mark.charney@intel.com>
|
|
#BEGIN_LEGAL
|
|
#
|
|
#Copyright (c) 2016 Intel Corporation
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
#END_LEGAL
|
|
|
|
"""This file provides a node_t type and a dfs() routine that prints out
|
|
cycles found in a graph represented as a list of node_t objects.
|
|
"""
|
|
|
|
_dfs_verbose = False
|
|
|
|
class node_t(object):
|
|
def __init__(self,name='no-name-for-node'):
|
|
self.name = name
|
|
self.afters = []
|
|
self.befores = []
|
|
self.zero()
|
|
|
|
# The colors are:
|
|
# 0 = white (unvisited),
|
|
# 1=grey (discovered, visiting),
|
|
# 2=black (finalized)
|
|
self.color = 0
|
|
|
|
self.discover = 0
|
|
self.finalize = 0
|
|
self.predecessor = None
|
|
def zero(self):
|
|
self.color = 0
|
|
def add_successor(self, s):
|
|
self.afters.append(s)
|
|
s.befores.append(self)
|
|
def add_ancestor(self, s):
|
|
self.befores.append(s)
|
|
s.afters.append(self)
|
|
def __str__(self):
|
|
s = []
|
|
s.append("TARGET: %s\n\t" % self.name)
|
|
s.append("discovered %d finalized %d\n\t" % (self.discover, self.finalize))
|
|
s.extend(map(lambda(x): "\t\n%s" % x.name, self.afters))
|
|
return ''.join(s)
|
|
|
|
|
|
|
|
def _print_cycle(last_visit, grey_loop_closer):
|
|
pad = ''
|
|
p = last_visit
|
|
while 1:
|
|
print pad, p.name
|
|
if p == grey_loop_closer:
|
|
break
|
|
p = p.predecessor
|
|
pad += ' '
|
|
|
|
def _visit(n):
|
|
global _dfs_time
|
|
n.color = 1
|
|
n.discover = _dfs_time
|
|
if _dfs_verbose:
|
|
print "visiting %s" % str(n)
|
|
_dfs_time += 1
|
|
retval = False
|
|
for a in n.afters:
|
|
if a.color == 0:
|
|
a.predecessor = n
|
|
retval |= _visit(a)
|
|
elif a.color == 1:
|
|
# a back-edge
|
|
print "cycle"
|
|
_print_cycle(n,a)
|
|
retval = True
|
|
n.color = 2
|
|
n.finalize = _dfs_time
|
|
_dfs_time += 1
|
|
return retval
|
|
|
|
def dfs(nodes):
|
|
"""Depth first search a list of node_t objects. Print out cycles.
|
|
@rtype: bool
|
|
@return: True if cycles were detected.
|
|
"""
|
|
global _dfs_time
|
|
_dfs_time = 0
|
|
for t in nodes:
|
|
t.zero()
|
|
cycle = False
|
|
for n in nodes:
|
|
if n.color == 0:
|
|
cycle |= _visit(n)
|
|
return cycle
|
|
|
|
#######################################################
|
|
|
|
# stuff for a strongly connected components algorithm -- currently
|
|
# unused.
|
|
|
|
def _node_cmp(aa,bb):
|
|
return aa.finalize.__cmp__(bb.finalize)
|
|
|
|
def _visit_transpose(n):
|
|
global _dfs_time
|
|
n.color = 1
|
|
if _dfs_verbose:
|
|
print "visiting %s" % str(n)
|
|
for a in n.befores:
|
|
if a.color == 0:
|
|
_visit_transpose(a)
|
|
n.color = 2
|
|
|
|
|
|
def dfs_transpose(nodes):
|
|
global _dfs_time
|
|
_dfs_time = 0
|
|
for t in nodes:
|
|
t.zero()
|
|
nodes.sort(cmp=_node_cmp)
|
|
for n in nodes:
|
|
if n.color == 0:
|
|
_visit_transpose(n)
|
|
if _dfs_verbose:
|
|
print "===="
|
|
|
|
####################################################
|
|
|
|
def _test_dfs():
|
|
node1 = node_t('1')
|
|
node2 = node_t('2')
|
|
node3 = node_t('3')
|
|
node4 = node_t('4')
|
|
node1.add_successor(node2)
|
|
node1.add_successor(node3)
|
|
node3.add_successor(node4)
|
|
node4.add_successor(node1)
|
|
|
|
nodes = [ node1, node2, node3, node4 ]
|
|
cycle = dfs(nodes)
|
|
if cycle:
|
|
print "CYCLE DETECTED"
|
|
#print "VISIT TRANSPOSE"
|
|
#dfs_transpose(nodes)
|
|
|
|
# print "NODES\n", "\n".join(map(str,nodes))
|
|
|
|
if __name__ == '__main__':
|
|
_test_dfs()
|