Files
archived-mbuild/mbuild/dfs.py
Mark Charney 52ceb3152e initial commit
Change-Id: I6fc3fd7babab231f4389689f9166e04ffba70136
2016-12-15 14:25:06 -05:00

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()