00001
00002 """
00003 Directed graph class
00004 """
00005
00006 __copyright__ = """
00007 Copyright 2008 Sean Ross-Ross
00008 """
00009 __license__ = """
00010 This file is part of SLIMpy .
00011
00012 SLIMpy is free software: you can redistribute it and/or modify
00013 it under the terms of the GNU Lesser General Public License as published by
00014 the Free Software Foundation, either version 3 of the License, or
00015 (at your option) any later version.
00016
00017 SLIMpy is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00020 GNU Lesser General Public License for more details.
00021
00022 You should have received a copy of the GNU Lesser General Public License
00023 along with SLIMpy . If not, see <http://www.gnu.org/licenses/>.
00024 """
00025
00026 from slimpy_base.Core.Graph.Graph.Graph import graph as __Graph
00027 from slimpy_base.Environment.InstanceManager import InstanceManager
00028
00029 from itertools import ifilter
00030
00031
00032 class DiGraph( __Graph ):
00033 """
00034 general purpose graph
00035 """
00036 env = InstanceManager()
00037
00038
00039
00040 def __init__( self ):
00041
00042 """
00043 method calls set the graph to empty and
00044 """
00045
00046 self.__adjacencyList = {}
00047 self.__invAdjacencyList = {}
00048 self._node_info = {}
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 def setAdjacencyList( self, adjList ):
00068 """
00069 set the adjacency list to adjList
00070 """
00071
00072 self.__adjacencyList = adjList
00073
00074 def setInvAdjacencyList( self, adjList ):
00075 """
00076 set the adjacency list to adjList
00077 """
00078
00079 self.__invAdjacencyList = adjList
00080
00081
00082
00083 def appendEdge( self, source, target, Etype=False , colour='black' ):
00084 """
00085 Append an edge to the graph
00086 @param source: doesn't have to be in the graph already
00087 @param target: doesn't have to be in the graph already
00088 @param colour: 'red' if data -> container
00089 'green' if container -> data
00090 'black' [default] if other
00091 """
00092
00093
00094 self.setAdj( source, target, Etype, colour )
00095
00096 self.setInvAdj( source, target, Etype, colour )
00097
00098 return "|%06s | \tAdding edge: %s --> %s " %( Etype, source, target )
00099
00100 def set_node_info( self, node, **kw ):
00101 info = self._node_info.setdefault(node, {})
00102 info.update( kw )
00103
00104 def node_info(self, node):
00105 return self._node_info.setdefault(node, {})
00106
00107 def setInvAdj( self, source, target, Etype, colour ):
00108 """
00109 called by appendEdge
00110 """
00111
00112
00113 l1 = self.__invAdjacencyList.setdefault( target, {} )
00114
00115 l1[source] = dict( Etype=Etype, colour=colour )
00116
00117 self.__invAdjacencyList.setdefault( source, {} )
00118
00119
00120 def setAdj( self, source, target, Etype, colour ):
00121 """
00122 called by appendEdge
00123 """
00124
00125
00126 l1 = self.__adjacencyList.setdefault( source, {} )
00127
00128 l1[target] = dict( Etype=Etype, colour=colour )
00129
00130 self.__adjacencyList.setdefault( target, {} )
00131
00132
00133
00134 def appendNode( self, node ):
00135 self.adjacencyList.setdefault( node, {} )
00136 self.invAdjacencyList.setdefault( node, {} )
00137
00138
00139 def __iter__( self ):
00140 return self.getAdjacencyList().keys().__iter__()
00141
00142
00143 def iter_edges(self):
00144 for v in self.__adjacencyList.iterkeys():
00145 for u in self.__adjacencyList[v].iterkeys():
00146 yield v,u
00147 return
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 def getAdjacencyList( self ):
00159 """
00160 get the adjacency matrix for the graph
00161 """
00162 return self.__adjacencyList
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 def getInvAdjacencyList( self ):
00173 return self.__invAdjacencyList
00174
00175
00176 def getEdgeColour( self, u, v ):
00177 edge = self.getEdge( u, v )
00178
00179 colour = edge.get( 'colour', 'black' )
00180
00181 return colour
00182
00183 def getEdgeType( self, u, v ):
00184 edge = self.getEdge( u, v )
00185
00186
00187 flag = edge.get( 'Etype', False )
00188 return flag
00189
00190 def getEdge( self, u, v ):
00191 try:
00192 adjDict = self.getAdjacencyList()
00193 edge = adjDict[u][v]
00194
00195 except KeyError, msg:
00196
00197 adjDict = self.getAdjacencyList()
00198 edge = adjDict[v][u]
00199 return edge
00200
00201
00202 def adj( self, item ):
00203 """
00204 return a list of all indices pointed to by element item
00205 """
00206 adjacencyList = self.getAdjacencyList()
00207 return adjacencyList[item].keys()
00208
00209 def invAdj( self, item ):
00210 invAdjlist = self.getInvAdjacencyList()
00211 try:
00212 return invAdjlist[item].keys()
00213 except KeyError, msg:
00214 raise
00215
00216
00217
00218 def getAllNodes( self, s=None ):
00219 "get all nodes except s"
00220 nodes = self.getAdjacencyList().keys()
00221 if s:
00222 nodes.remove( s )
00223
00224 return nodes
00225
00226 def getSourceNodes( self ):
00227 """
00228 return all nodes which do not depend on any other node
00229 """
00230
00231 return ifilter( lambda u : not len( self.invAdj( u ) ) , self )
00232
00233 def transp( self ):
00234 from copy import copy
00235 g = copy( self )
00236 tmp = g.getAdjacencyList()
00237 g.setAdjacencyList( g.getInvAdjacencyList() )
00238 g.setInvAdjacencyList ( tmp )
00239 return g
00240
00241
00242
00243
00244 def __len__( self ):
00245 return len( self.getAdjacencyList() )
00246
00247 def clean( self ):
00248 self.__init__()
00249
00250 def numedges(self):
00251 'returns the number of edges in this graph'
00252 sum = 0
00253 adj = self.getAdjacencyList()
00254 for val in adj.values():
00255 sum += len(val)
00256 return sum
00257
00258 def __repr__( self ):
00259 return "<SLIMpy.Digraph: %s nodes, %s edges>" % (len(self), self.numedges() )
00260
00261