Commit 9eb04ea4 authored by Morten Brun's avatar Morten Brun
Browse files

added example notebook

parent 1009466c
This diff is collapsed.
# This Python file uses the following encoding: utf-8
from __future__ import print_function, division
import matplotlib.pyplot as plt
import networkx as nx
import numpy as np
import random
# colors from our friends at http://colorbrewer2.org
COLORS = ['#8dd3c7','#ffffb3','#bebada','#fb8072','#80b1d3','#fdb462',
'#b3de69','#fccde5','#d9d9d9','#bc80bd','#ccebc5','#ffed6f']
def all_pairs(nodes):
"""Generates all pairs of nodes."""
for i, u in enumerate(nodes):
for j, v in enumerate(nodes):
if i < j:
yield u, v
def make_complete_graph(n):
"""Makes a complete graph with `n` nodes."""
G = nx.Graph()
nodes = range(n)
G.add_nodes_from(nodes)
G.add_edges_from(all_pairs(nodes))
return G
def flip(p):
"""Returns True with probability `p`."""
return random.random() < p
def random_pairs(nodes, p):
"""Generates random pairs of nodes.
Each possible edge is yielded with probability `p`.
"""
for i, u in enumerate(nodes):
for j, v in enumerate(nodes):
if i<j and flip(p):
yield u, v
def make_random_graph(n, p):
"""Makes a random graph where each edge exists with probability 'p'."""
G = nx.Graph()
nodes = range(n)
G.add_nodes_from(nodes)
G.add_edges_from(random_pairs(nodes, p))
return G
def reachable_nodes(G, start):
"""Finds all nodes reachable from `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
def is_connected(G):
"""Returns True if the graph is connected."""
start = next(G.nodes_iter())
reachable = reachable_nodes(G, start)
return len(reachable) == len(G)
def prob_connected(n, p, iters=100):
count = 0
for i in range(iters):
random_graph = make_random_graph(n, p)
if is_connected(random_graph):
count += 1
return count/iters
def reachable_nodes_precheck(G, start):
seen = set()
stack = [start]
while stack:
node = stack.pop()
if node not in seen:
seen.add(node)
neighbors = set(G[node])
neighbors -= seen
stack.extend(neighbors)
return seen
def adjacent_edges(nodes, halfk):
n = len(nodes)
for i, u in enumerate(nodes):
for j in range(i+1, i+halfk+1):
v = nodes[j % n]
yield u, v
def make_ring_lattice(n, k):
G = nx.Graph()
nodes = range(n)
G.add_nodes_from(nodes)
G.add_edges_from(adjacent_edges(nodes, k//2))
return G
def make_ws_graph(n, k, p):
ws = make_ring_lattice(n, k)
rewire(ws, p)
return ws
def rewire(G, p):
nodes = set(G.nodes())
for edge in G.edges():
if flip(p):
u, v = edge
choices = nodes - {u} - set(G[u])
new_v = choice(tuple(choices))
G.remove_edge(u, v)
G.add_edge(u, new_v)
def node_clustering(G, u):
neighbors = G[u]
k = len(neighbors)
if k < 2:
return 0
total = k * (k-1) / 2
exist = 0
for v, w in all_pairs(neighbors):
if G.has_edge(v, w):
exist +=1
return exist / total
def clustering_coefficient(G):
cc = np.mean([node_clustering(G, node) for node in G])
return cc
def node_clustering(G, u):
neighbors = G[u]
k = len(neighbors)
if k < 2:
return 0
edges = [G.has_edge(v, w) for v, w in all_pairs(neighbors)]
return sum(edges) / len(edges)
def path_lengths(G):
length_map = nx.shortest_path_length(G)
lengths = [length_map[u][v] for u, v in all_pairs(G)]
return lengths
def characteristic_path_length(G):
return np.mean(path_lengths(G))
def run_one_graph(n, k, p):
ws = make_ws_graph(n, k, p)
mpl = characteristic_path_length(ws)
cc = clustering_coefficient(ws)
print(mpl, cc)
return mpl, cc
def run_experiment(ps, n=1000, k=10, iters=20):
res = {}
for p in ps:
print(p)
res[p] = []
for _ in range(iters):
res[p].append(run_one_graph(n, k, p))
return res
from collections import 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
def reachable_nodes_bfs(G, start):
seen = set()
queue = deque([start])
while queue:
node = queue.popleft()
if node not in seen:
seen.add(node)
neighbors = set(G[node])
neighbors -= seen
queue.extend(neighbors)
return seen
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
def opposite_edges(nodes):
"""Enumerates edges that connect opposite nodes."""
n = len(nodes)
for i, u in enumerate(nodes):
j = i + n//2
v = nodes[j % n]
yield u, v
def make_regular_graph(n, k):
"""Makes graph with `n` nodes where all nodes have `k` neighbors.
Not possible if both `n` and `k` are odd.
"""
# a is the number of adjacent edges
# b is the number of opposite edges (0 or 1)
a, b = divmod(k, 2)
G = nx.Graph()
nodes = range(n)
G.add_nodes_from(nodes)
G.add_edges_from(adjacent_edges(nodes, a))
# if k is odd, add opposite edges
if b:
if n%2:
msg = "Can't make a regular graph if n and k are odd."
raise ValueError(msg)
G.add_edges_from(opposite_edges(nodes))
return G
def plain_bfs(G, source):
"""A fast BFS node generator"""
seen = set()
nextlevel = {source}
while nextlevel:
thislevel = nextlevel
nextlevel = set()
for v in thislevel:
if v not in seen:
seen.add(v)
nextlevel.update(G[v])
return seen
def plain_shortest_path(G, source):
"""A fast implementation of Dijkstra's algorithm with equal edge lengths."""
new_dist = 0
dist = {}
nextlevel = {source}
while nextlevel:
thislevel = nextlevel
nextlevel = set()
for v in thislevel:
if v not in dist:
dist[v] = new_dist
nextlevel.update(G[v])
new_dist += 1
return dist
def bfs(top_node, visit):
"""Breadth-first search on a graph, starting at top_node."""
visited = set()
queue = [top_node]
while len(queue):
curr_node = queue.pop(0) # Dequeue
visit(curr_node) # Visit the node
visited.add(curr_node)
# Enqueue non-visited and non-enqueued children
queue.extend(c for c in curr_node.children
if c not in visited and c not in queue)
def shortest_path_dfs(G, start):
dist = {start: 0}
queue = deque([start])
while queue:
node = queue.pop()
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 diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment