<>
"""czep's Graph library.

**********************************************************************
This file was generated using py2html which is contained in the source
code to the book Artificial Intelligence: A Modern Approach
by Russell and Norvig.
**********************************************************************

Everyone has their own favorite way to implement graphs, and this one
is mine.  The simplest way to represent a graph in Python is with a
dictionary of adjacency lists as GvR describes [1].  David Eppstein
represents the adjacency list itself as another dictionary, thereby
enabling storage of edge lengths as well as exploiting the built-in
advantage that dictionaries have in quickly determining whether a
key exists [2].

Although such powerful simplicity is attractive, some applications
require vertices and edges to be associated with arbitrary data.  In
addition, many algorithms benefit from a class-based approach wherein
the fundamental building blocks of graphs are formal objects.

References:
[1] http://www.python.org/doc/essays/graphs.html
[2] http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/119466
"""
__author__ = 'Scott Czepiel <http://czep.net/>'
__version__ = '1.0'

import heapq


class Vertex:
    """A Vertex object that can be added to a Graph.

    A Graph contains a dictionary of vertices, where each key must
    be unique within a given Graph.  The Vertex itself cannot be
    used as a key because it is a mutable object, and dictionary
    keys must be immutable.  Therefore, when supplying a key, be
    sure to choose a string, number (int or float), or a tuple, but
    not something like a list or arbitrary object.

    Since keys are merely unique identifiers, if there is no reason
    to supply a key explicity, the default behavior will obtain the
    next available unique value maintained in a class variable."""

    vcount = 0
    def get_key(self):
        self.__class__.vcount += 1
        return self.__class__.vcount

    def __init__(self, key=None, data={}):
        """Constructor for vertex objects.

        The key is just a way of uniquely identifying the vertex
        so that it can be easily added to a graph.  Assign any
        immutable type that you wish to use to identify the vertex,
        or let the class automatically assign the next available
        value that it thinks is unique, though no checking is done.

        Any additional information that needs to accompany a vertex
        can be passed to the 'data' argument.  Many functions
        assume this to be a dictionary.
        """
        # set key
        if key is None:
            self.key = self.get_key()
        else:
            self.key = key
        # set data
        if type(data) == type({}):
            self.data = data
        else:
            self.data = {'data': data}
        # init adjacency dict
        self.Adj = {}

    def __repr__(self):
        """Return a string to describe this vertex."""
        return "Vertex: '%s'" % str(self.key)


class _VertexReference:
    """Internal object used to store additional data about a vertex.

    Many algorithms require a number of temporary variables to be
    associated with each vertex.  One approach would be to simply add
    them to the actual Vertex objects as necessary.  However, I feel
    it is impolite to ask an object to handle a bunch of variables
    it knows nothing about.  These variables belong to the algorithm
    or the graph, but certainly not to the vertex.  This could cause
    problems if multiple algorithms are accessing the same variables
    simultaneously.  Furthermore, it's not just the addition of
    variables that justifies a separate object:  we need to override
    the comparison operators to use Vertices with the heapq library.
    We can only do this once for the Vertex class, but by subclassing
    a reference to the Vertex, we can accomodate an endless number
    of different representations."""

    def __init__(self, g, key, data={}):
        """Create a reference to a Vertex in the context of a Graph.

        The key is any immutable object that serves to identify a
        Vertex.  Note that we don't really hold a reference to a
        Vertex object itself, rather, we hold a reference to the
        unique identifier of a Vertex in a given Graph.
        """
        if not isinstance(g, Graph):
            raise ValueError, 'Required argument is not a Graph.'
        if key not in g.V:
            raise KeyError, '%s not found in Graph.' % str(key)
        self.g = g
        self.key = key
        # set data
        if type(data) == type({}):
            self.data = data
        else:
            self.data = {'data': data}


class _SingleSourceVertex(_VertexReference):
    """Vertex reference used in single-source probs, eg. Dijkstra."""

    def __init__(self, *args):
        _VertexReference.__init__(self, *args)

    def __repr__(self):
        return "*VertexRef: '%s'" % str(self.key)

    def __lt__(self, other): return self.data['d'] < other.data['d']
    def __le__(self, other): return self.data['d'] <= other.data['d']
    def __eq__(self, other): return self.key == other.key
    def __ne__(self, other): return self.key != other.key
    def __gt__(self, other): return self.data['d'] > other.data['d']
    def __ge__(self, other): return self.data['d'] >= other.data['d']


class Edge:
    """A directed edge from one vertex to another.

    This is a directed edge, i.e. a one-way street.  An edge has a
    start vertex, u, and an end vertex, v.  The pair (u, v) uniquely
    identifies an edge.  Duplicate edges cannot exist in the same
    graph.  Note that the opposite way in a two-way street would
    be represented as another edge, identified as (v, u)."""

    def __init__(self, u, v, w=1.0, data={}):
        """Constructor for edge objects.

        Both u and v must be vertices, else an error will be raised.
        The weight of the edge defaults to 1.0, and as with vertices
        any arbitrary data can be stored in the dict 'data'.
        """
        if not isinstance(u, Vertex) or not isinstance(v, Vertex):
            raise ValueError, 'Edge constructor requires 2 Vertices.'
        self.u = u
        self.v = v
        self.w = w
        # set data
        if type(data) == type({}):
            self.data = data
        else:
            self.data = {'data': data}

    def __repr__(self):
        return "Edge from %s to %s with weight %f." %(self.u,
            self.v, self.w)

class Graph:
    """A Graph is a collection of vertices connected by edges.

    The Graph maintains two dictionaries internally, V for Vertices
    and E for edges.  V is keyed by a Vertex object's 'key' attribute.
    E is keyed by the tuple (u, v) that serves as a unique identifier
    of an edge from vertex u to vertex v."""

    def __init__(self, g=None):
        """Graph constructor.

        If no arguments are passed, the graph will be created empty.
        Otherwise, g will be parsed as a dictionary of adjacency lists
        (represented as a dict of dicts).  All appropriate vertices
        and edges will be created implicitly.
        """
        self.V = {}
        self.E = {}
        if g is not None:
            if type(g) != type({}):
                raise ValueError, 'Optional arg must be a dictionary'
            # parse g as a dict of adjacency dicts
            for u in g:
                self.add_vertex(Vertex(key=u))
                for v in g[u]:
                    self.add_vertex(Vertex(key=v))
                    self.add_edge(Edge(self.V[u], self.V[v], w=g[u][v]))

    def add_vertex(self, u):
        """Add Vertex u to the Graph."""
        if not isinstance(u, Vertex):
            raise ValueError, 'Required argument must be a Vertex.'
        # ignore if already exists
        if u.key in self.V: return
        # add to the dictionary of vertices using the key
        self.V[u.key] = u

    def add_edge(self, e):
        """Add Edge e to the Graph."""
        if not isinstance(e, Edge):
            raise ValueError, 'Required argument must be an Edge.'
        # ignore if already exists
        if (e.u.key, e.v.key) in self.E: return
        # add to the dictionary of edges using the tuple (u, v) as key
        self.E[(e.u.key, e.v.key)] = e
        # add v's key to u's adjacency dict, with w as the value
        # NOTE:  this is not the same as:  e.u.Adj[e.v.key] = e.w
        # Q: Why? (+3 Bonus Points)
        self.V[e.u.key].Adj[e.v.key] = e.w

    def remove_vertex(self, u):
        """Remove a vertex identified by key from the Graph."""
        if u in self.V:
            del self.V[u]
            ebad = []
            for e in self.E:
                if self.E[e].u.key == u or self.E[e].v.key == u:
                    ebad.append(e)
            while ebad:
                self.remove_edge(ebad.pop(0))

    def remove_edge(self, e):
        """Remove an edge identified by key from the Graph."""
        if e in self.E:
            del self.E[e]

    def Vcount(self):
        return len(self.V)

    def Ecount(self):
        return len(self.E)

    def dijkstra(self, s):
        """Dijkstra's algorithm.

        Return the shortest-paths tree containing all vertices
        reachable from the start vertex, s.  This tree is represented
        as a dict of dicts where the key is the id of the vertex.
        The shortest-paths distance, d, and the parent of the vertex
        in the tree are also stored, eg.:
        S = { 'v': {'d': 9, 'par': 'u'},
              'u': {'d': 8, 'par': 'x'},
              'x': {'d': 5, 'par': 's'} }
        """
        # initialize the shortest paths tree to be returned
        S = {}
        # return if start vertex is not in the graph
        if s not in self.V: return S
        # initialize a priority queue with start vertex
        Q = [(0.0, s, None)]
        # loop for each vertex reference in Q
        while Q:
            # extract the minimum element from Q
            d, u, par = heapq.heappop(Q)
            # ignore if u is already in S
            if u not in S:
                # add u to S
                S[u] = {'d': d, 'par': par}
                # relax each v adjacent to u
                for v in self.V[u].Adj:
                    heapq.heappush(Q, (d + self.V[u].Adj[v], v, u))
        return S

    def bfs(self, s):
        """Breadth-first search.

        Return a breadth-first search tree containing all vertices
        reachable from s.  The tree is represented as a dict of dicts
        where the key is the id of the vertex.  The id of the parent
        vertex and the degree of separation from the start vertex
        are also stored, eg:
        """
        S = {}
        if s not in self.V: return S
        # initialize a FIFO queue of vertices to explore
        Q = [(0, s, None)]
        while Q:
            d, u, par = Q.pop(0)
            if u not in S:
                S[u] = {'d': d, 'par': par}
                # add all neighbors of u to the Q
                for v in self.V[u].Adj:
                    Q.append((d+1, v, u))
        return S


if __name__ == '__main__':

    # Canonical example from CLR 1e, p. 528
    # The shortest path from s to v is [s, x, u, v]
    # and has length 9.
    G = Graph({'s':{'u':10, 'x':5},
         'u':{'v':1, 'x':2},
         'v':{'y':4},
         'x':{'u':3, 'v':9, 'y':2},
         'y':{'s':7, 'v':6}})

    print "This graph has %d vertices and %d edges." % (G.Vcount(), G.Ecount())

    sptree = G.dijkstra('s')
    path = []
    vert = 'v'
    dist = sptree[vert]['d']
    while vert:
        path.append(vert)
        vert = sptree[vert]['par']
    path.reverse()
    print "\nThe shortest path from s to v is %s" % str(path)
    print "and has length %d." % dist

    bfstree = G.bfs('s')
    print "\nHere is a breadth-first search tree rooted at s:"
    print "Degree\tVertex\tParent"
    print "======\t======\t======"
    for pair in sorted([(v['d'], k, v['par']) for k, v in bfstree.iteritems()]):
        print "%3d%8s%9s" % (pair[0], pair[1], pair[2])
<