For today
Prepare for a quiz on the workshop and Chapters 1-2
Read Think Complexity Chapter 3 and do the reading quiz
Start your annotated bibliography (see instructions below) and turn in the first installment here.
Today
Quiz
Chapter 2
Deques
DFS, BFS, and Dijkstra
For next time
Work on the notebook for Chapter 3, and turn it in
Read Think Complexity Chapter 4 and do the reading quiz
Turn in the second installment of your annotated bibliography
Optional video: Raymond Hettinger Modern Python Dictionaries A confluence of a dozen great ideas PyCon 2017
Chapter 2 review
1) Let's look over the solution notebook.
2) What about this other way of choosing m edges?
def m_pairs(nodes, numEdges): total = 0 pairs = set() while total<numEdges: edge = np.random.choice(nodes, 2) if edge[0] != edge[1] and tuple(edge)not in pairs: pairs.add(tuple(edge)) total+=1 return list(pairs)
3) Can we write m_pairs as a generator function that always yield m edges, and chooses every edge with equal probability?
To classify the asymptotic behavior of a Python program, you have to know the order of growth for operations on Python's data structures.
Which is easiest to remember if you have a mental model of their implementation.
Although that violates one of the goals of software engineering, information hiding.
Let's review Think Python Appendix B.2
Dijkstra's algorithm
reachable_nodes performs depth-first search (DFS)
def reachable_nodes(G, start):
seen = set()
stack = [start]
while stack:
node = stack.pop()
if node not in seen:
seen.add(node)
stack.extend(G.neighbors(node))
return seen
Here's the simplest way to make it breadth-first search (BFS)
def reachable_nodes(G, start):
seen = set()
stack = [start]
while stack:
node = stack.pop(0)
if node not in seen:
seen.add(node)
stack.extend(G.neighbors(node))
return seen
But that's not a good idea. Why?
One solution is to use a deque.
def reachable_nodes_bfs(G, start):
seen = set()
queue = deque([start])
while queue:
node = queue.popleft()
if node not in seen:
seen.add(node)
queue.extend(G.neighbors(node))
return seen
Read about the deque data structure and the Python implementation of a deque.
There is a short path (that's right, I said it) from BFS to Dijkstra's algorithm:
def shortest_path_dijkstra(G, start):
dist = {start: 0}
queue = deque([start])
while queue:
node = queue.popleft()
new_dist = dist[node] + 1
neighbors = set(G[node]) - set(dist)
for n in neighbors:
dist[n] = new_dist
queue.extend(neighbors)
return dist
This algorithm only works if we use BFS, not DFS. Why?
Note: This version of Dijkstra's algorithm only works in the case where all edges have the same length. There is a more general version that works even if the edges have different lengths (as long as they are non-negative). You can read about it here.
And you can read more about Dijkstra here. A few highlights
1) He and I have the same birthday (37 years apart)
2) He did early work in concurrent programming and defined Semaphores, which are the basis of my Little Book of Semaphores.
3) He was a prolific essayist, and many of his EWDs had a profound influence on the development of computer science (for better and for worse, IMO). Here is one famous example.