changeset 26:f6073c187926

Added a version of Dijkstra that uses a heap.
author Brian Neal <bgneal@gmail.com>
date Sat, 05 Jan 2013 13:30:58 -0600
parents a46783561538
children 78116556b491
files SmallWorldGraph.py ch4ex4.py
diffstat 2 files changed, 50 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/SmallWorldGraph.py	Sat Jan 05 13:00:07 2013 -0600
+++ b/SmallWorldGraph.py	Sat Jan 05 13:30:58 2013 -0600
@@ -1,6 +1,7 @@
 """This module contains the SmallWorldGraph class for 4.4, exercise 4.
 
 """
+import heapq
 import itertools
 import random
 
@@ -127,6 +128,30 @@
                     queue.append(w)
                     sort_flag = True
 
+    def shortest_path_tree2(self, source):
+        """Finds the length of the shortest path from the source vertex to all
+        other vertices in the graph. This length is stored on the vertices as an
+        attribute named 'dist'. The algorithm used is Dijkstra's with a Heap
+        used to sort/store pending nodes to be examined.
+
+        """
+        for v in self.vertices():
+            v.dist = INFINITY
+        source.dist = 0
+
+        queue = []
+        heapq.heappush(queue, (0, source))
+        while len(queue):
+
+            _, v = heapq.heappop(queue)
+
+            # for each neighbor of v, see if we found a new shortest path
+            for w, e in self[v].iteritems():
+                d = v.dist + e.length
+                if d < w.dist:
+                    w.dist = d
+                    heapq.heappush(queue, (d, w))
+
     def all_pairs_floyd_warshall(self):
         """Finds the shortest paths between all pairs of vertices using the
         Floyd-Warshall algorithm.
@@ -158,7 +183,7 @@
     def big_l(self):
         """Computes the "big-L" value for the graph as per Watts & Strogatz.
 
-        big_l() is defined as the number of edges in the shortest path between
+        L is defined as the number of edges in the shortest path between
         two vertices, averaged over all vertices.
 
         Uses the shortest_path_tree() method, called once for every node.
@@ -177,7 +202,7 @@
     def big_l2(self):
         """Computes the "big-L" value for the graph as per Watts & Strogatz.
 
-        big_l() is defined as the number of edges in the shortest path between
+        L is defined as the number of edges in the shortest path between
         two vertices, averaged over all vertices.
 
         Uses the all_pairs_floyd_warshall() method.
@@ -190,3 +215,23 @@
         if len(result):
             return sum(result) / float(len(result))
         return 0.0
+
+    def big_l3(self):
+        """Computes the "big-L" value for the graph as per Watts & Strogatz.
+
+        L is defined as the number of edges in the shortest path between
+        two vertices, averaged over all vertices.
+
+        Uses the shortest_path_tree2() method, called once for every node.
+
+        """
+        d = {}
+        for v in self.vertices():
+            self.shortest_path_tree2(v)
+            t = [((v, w), w.dist) for w in self.vertices() if v is not w]
+            d.update(t)
+
+        if len(d):
+            return sum(d.values()) / float(len(d))
+        return 0.0
+
--- a/ch4ex4.py	Sat Jan 05 13:00:07 2013 -0600
+++ b/ch4ex4.py	Sat Jan 05 13:30:58 2013 -0600
@@ -11,7 +11,7 @@
 from SmallWorldGraph import SmallWorldGraph
 
 # Use Dijkstra or Floyd-Warshall to compute L
-DIJKSTRA = False
+DIJKSTRA = True
 
 # compute C(0)
 n = 1000
@@ -19,7 +19,7 @@
 vs = [Vertex(str(i)) for i in range(n)]
 g = SmallWorldGraph(vs, k, 0.0)
 c0 = g.clustering_coefficient()
-l0 = g.big_l() if DIJKSTRA else g.big_l2()
+l0 = g.big_l3() if DIJKSTRA else g.big_l2()
 print 'c0 =', c0, 'l0 =', l0
 
 # compute data
@@ -34,7 +34,7 @@
 for p in p_vals:
     g = SmallWorldGraph(vs, k, p)
     c_vals.append(g.clustering_coefficient() / c0)
-    l = g.big_l() if DIJKSTRA else g.big_l2()
+    l = g.big_l3() if DIJKSTRA else g.big_l2()
     l_vals.append(l / l0)
 
 p_vals.insert(0, 0.0)