Mercurial > public > think_complexity
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SmallWorldGraph.py Wed Jan 02 16:50:55 2013 -0600 @@ -0,0 +1,87 @@ +"""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