view SmallWorldGraph.py @ 23:74c9d126bd05

Working on the SmallWorldGraph exercises.
author Brian Neal <bgneal@gmail.com>
date Wed, 02 Jan 2013 16:50:55 -0600
parents
children 5c2c4ce095ef
line wrap: on
line source
"""This module contains the SmallWorldGraph class for 4.4, exercise 4.

"""
import itertools
import random

from Graph import Edge
from RandomGraph import RandomGraph


class SmallWorldGraph(RandomGraph):
    """A small world graph for 4.4, exercise 4 in Think Complexity."""

    def __init__(self, vs, k, p):
        """Create a small world graph. Parameters:
            vs - a list of vertices
            k - regular graph parameter k: the number of edges between vertices
            p - probability for rewiring.

        First a regular graph is created from the list of vertices and parameter
        k, which specifies how many edges each vertex should have. Then the
        rewire() method is called with parameter p to rewire the graph according
        to the algorithm by Watts and Strogatz.

        """
        super(SmallWorldGraph, self).__init__(vs=vs)
        self.add_regular_edges(k)
        self.rewire(p)

    def rewire(self, p):
        """Assuming the graph is initially a regular graph, rewires the graph
        using the Watts and Strogatz algorithm.

        """
        # We iterate over the edges in a random order:
        edges = self.edges()
        random.shuffle(edges)
        vertices = self.vertices()

        for e in edges:
            if random.random() < p:
                v, w = e    # remember the 2 vertices this edge connected
                self.remove_edge(e)     # remove from graph

                # pick another vertex to connect to v; duplicate edges are
                # forbidden
                while True:
                    x = random.choice(vertices)
                    if v is not x and not self.get_edge(v, x):
                        self.add_edge(Edge(v, x))
                        break

    def clustering_coefficient(self):
        """Compute the clustering coefficient for this graph as defined by Watts
        and Strogatz.

        """
        cv = {}
        for v in self:
            # consider a node and its neighbors
            nodes = self.out_vertices(v)
            nodes.append(v)

            # compute the maximum number of possible edges between these nodes
            # if they were all connected to each other:
            n = len(nodes)
            if n == 1:
                # edge case of only 1 node; handle this case to avoid division
                # by zero in the general case
                cv[v] = 1.0
                continue

            possible = n * (n - 1) / 2.0

            # now compute how many edges actually exist between the nodes
            actual = 0
            for x, y in itertools.combinations(nodes, 2):
                if self.get_edge(x, y):
                    actual += 1

            # the fraction of actual / possible is this nodes C sub v value
            cv[v] = actual / possible

        # The clustering coefficient is the average of all C sub v values
        if len(cv):
            return sum(cv.values()) / float(len(cv))
        return 0.0