def __init__(self, graph=None, idgenerator="set"): """constructor if graph is not none make a copy of the topological structure of graph (i.e. don't use the same id) args: - graph (Graph): the graph to copy, default=None - idgenerator (str): type of idgenerator to use, default 'set' """ self._vertices = IdDict(idgenerator=idgenerator) self._edges = IdDict(idgenerator=idgenerator) if graph is not None: self.extend(graph)
class Graph(object): """Directed graph with multiple links in this implementation : - vertices are tuple of edge_in,edge_out - edges are tuple of source,target """ def __init__(self, graph=None, idgenerator="set"): """constructor if graph is not none make a copy of the topological structure of graph (i.e. don't use the same id) args: - graph (Graph): the graph to copy, default=None - idgenerator (str): type of idgenerator to use, default 'set' """ self._vertices = IdDict(idgenerator=idgenerator) self._edges = IdDict(idgenerator=idgenerator) if graph is not None: self.extend(graph) # ########################################################## # # Graph concept # # ########################################################## def source(self, eid): """Retrieve the source vertex of an edge args: - eid (int): edge id return: - (int): vertex id """ try: return self._edges[eid][0] except KeyError: raise InvalidEdge(eid) def target(self, eid): """Retrieve the target vertex of an edge args: - eid (int): edge id return: - (int): vertex id """ try: return self._edges[eid][1] except KeyError: raise InvalidEdge(eid) def edge_vertices(self, eid): """Retrieve both source and target vertex of an edge args: - eid (int): edge id return: - (int, int): source id, target id """ try: return self._edges[eid] except KeyError: raise InvalidEdge(eid) def edge(self, source, target): """Find the matching edge with same source and same target return None if it don't succeed args: - source (int): source vertex - target (int): target vertex return: - (int): edge id with same source and target - (None): if search is unsuccessful """ if target not in self: raise InvalidVertex(target) for eid in self.out_edges(source): if self.target(eid) == target: return eid return None def __contains__(self, vid): """magic alias for `has_vertex` """ return self.has_vertex(vid) def has_vertex(self, vid): """test whether a vertex belong to the graph args: - vid (int): id of vertex return: - (bool) """ return vid in self._vertices def has_edge(self, eid): """test whether an edge belong to the graph args: - eid (int): id of edge return: - (bool) """ return eid in self._edges def is_valid(self): """Test the validity of the graph return: - (bool) """ return True # ########################################################## # # Vertex List Graph Concept # # ########################################################## def vertices(self): """Iterator on all vertices return: - (iter of int) """ return iter(self._vertices) def __iter__(self): """Magic alias for `vertices` """ return iter(self._vertices) def nb_vertices(self): """Total number of vertices in the graph return: - (int) """ return len(self._vertices) def __len__(self): """Magic alias for `nb_vertices` """ return self.nb_vertices() def in_neighbors(self, vid): """Iterator on the neighbors of vid where edges are directed from neighbor to vid args: - vid (int): vertex id return: - (iter of int): iter of vertex id """ if vid not in self: raise InvalidVertex(vid) neighbors_list = [self.source(eid) for eid in self._vertices[vid][0]] return iter(set(neighbors_list)) def out_neighbors(self, vid): """Iterator on the neighbors of vid where edges are directed from vid to neighbor args: - vid (int): vertex id return: - (iter of int): iter of vertex id """ if vid not in self: raise InvalidVertex(vid) neighbors_list = [self.target(eid) for eid in self._vertices[vid][1]] return iter(set(neighbors_list)) def neighbors(self, vid): """Iterator on all neighbors of vid both in and out args: - vid (int): vertex id return: - (iter of int): iter of vertex id """ neighbors_list = list(self.in_neighbors(vid)) neighbors_list.extend(self.out_neighbors(vid)) return iter(set(neighbors_list)) def nb_in_neighbors(self, vid): """Number of in neighbors of vid where edges are directed from neighbor to vid args: - vid (int): vertex id return: - (int) """ neighbors_set = list(self.in_neighbors(vid)) return len(neighbors_set) def nb_out_neighbors(self, vid): """Number of out neighbors of vid where edges are directed from vid to neighbor args: - vid (int): vertex id return: - (int) """ neighbors_set = list(self.out_neighbors(vid)) return len(neighbors_set) def nb_neighbors(self, vid): """Total number of both in and out neighbors of vid args: - vid (int): vertex id return: - (int) """ neighbors_set = list(self.neighbors(vid)) return len(neighbors_set) # ########################################################## # # Edge List Graph Concept # # ########################################################## def _iter_edges(self, vid): """ internal function that perform 'edges' with vid not None """ link_in, link_out = self._vertices[vid] for eid in link_in: yield eid for eid in link_out: yield eid def edges(self, vid=None): """Iterate on all edges connected to a given vertex. If vid is None (default), iterate on all edges in the graph args: - vid (int): vertex holdings edges, default (None) return: - (iter of int): iterator on edge ids """ if vid is None: return iter(self._edges) if vid not in self: raise InvalidVertex(vid) return self._iter_edges(vid) def nb_edges(self, vid=None): """Number of edges connected to a given vertex. If vid is None (default), total number of edges in the graph args: - vid (int): vertex holdings edges, default (None) return: - (int) """ if vid is None: return len(self._edges) if vid not in self: raise InvalidVertex(vid) return len(self._vertices[vid][0]) + len(self._vertices[vid][1]) def in_edges(self, vid): """Iterate on all edges pointing to a given vertex. args: - vid (int): vertex target of edges return: - (iter of int): iterator on edge ids """ if vid not in self: raise InvalidVertex(vid) for eid in self._vertices[vid][0]: yield eid def out_edges(self, vid): """Iterate on all edges away from a given vertex. args: - vid (int): vertex source of edges return: - (iter of int): iterator on edge ids """ if vid not in self: raise InvalidVertex(vid) for eid in self._vertices[vid][1]: yield eid def nb_in_edges(self, vid): """Number of edges pointing to a given vertex. args: - vid (int): vertex target of edges return: - (int) """ if vid not in self: raise InvalidVertex(vid) return len(self._vertices[vid][0]) def nb_out_edges(self, vid): """Number of edges away from a given vertex. args: - vid (int): vertex source of edges return: - (int) """ if vid not in self: raise InvalidVertex(vid) return len(self._vertices[vid][1]) # ########################################################## # # Mutable Vertex Graph concept # # ########################################################## def add_vertex(self, vid=None): """Add a vertex to the graph. If vid is not provided create a new vid args: - vid (int): id to use. If None (default) will generate a new one return: - vid (int): id used for the new vertex """ try: return self._vertices.add((set(), set()), vid) except KeyError: raise InvalidVertex(vid) def remove_vertex(self, vid): """Remove a specified vertex of the graph. Also remove all edge attached to it. args: - vid (int): id of vertex to remove """ if vid not in self: raise InvalidVertex(vid) link_in, link_out = self._vertices[vid] for edge in list(link_in): self.remove_edge(edge) for edge in list(link_out): self.remove_edge(edge) del self._vertices[vid] def clear(self): """Remove all vertices and edges don't change references to objects """ self._edges.clear() self._vertices.clear() # ########################################################## # # Mutable Edge Graph concept # # ########################################################## def add_edge(self, sid, tid, eid=None): """Add an edge to the graph. If eid is not provided generate a new one. args: - sid (int): id of source vertex - tid (int): id of target vertex - eid (int): id to use. If None (default) will generate a new one return: - eid (int): id used for new edge """ if sid not in self: raise InvalidVertex(sid) if tid not in self: raise InvalidVertex(tid) try: eid = self._edges.add((sid, tid), eid) except KeyError: raise InvalidEdge(eid) self._vertices[sid][1].add(eid) self._vertices[tid][0].add(eid) return eid def remove_edge(self, eid): """Remove a specified edge from the graph. args: - eid (int): id of edge to remove """ if not self.has_edge(eid): raise InvalidEdge(eid) sid, tid = self._edges[eid] self._vertices[sid][1].remove(eid) self._vertices[tid][0].remove(eid) del self._edges[eid] def clear_edges(self): """Remove all the edges of the graph don't change references to objects """ self._edges.clear() for vid, (in_set, out_set) in self._vertices.iteritems(): in_set.clear() out_set.clear() # ########################################################## # # Extend Graph concept # # ########################################################## def extend(self, graph): """Add the specified graph to self, create new vid and eid args: - graph (Graph): the graph to add return: - (dict of (int, int)): mapping between vertex id in graph and vertex id in extended self - (dict of (int, int)): mapping between edge id in graph and edge id in extended self """ # vertex adding trans_vid = {} for vid in list(graph.vertices()): trans_vid[vid] = self.add_vertex() # edge adding trans_eid = {} for eid in list(graph.edges()): sid = trans_vid[graph.source(eid)] tid = trans_vid[graph.target(eid)] trans_eid[eid] = self.add_edge(sid, tid) return trans_vid, trans_eid def sub_graph(self, vids): """ """ raise NotImplemented