This code simulates a distributed averaging protocol. There is a network of nodes, and at the clicks of a Poisson process:
A random node wakes up
Transmits it's current average to all the nodes it is connected to
These nodes have a coroutine which waits to accept new values and compute the average.
from numpy.random import exponential, randint, uniform
import time
from itertools import product
class Node(object):
def __init__(self, number):
self.friends = []
self.count = 0
self.val = number
self.average = number
self.avg = self.averager()
self.avg.next()
def averager(self):
while True:
term = yield self.average
self.val += term
self.count += 1
self.average = self.val/self.count
class Network(object):
def __init__(self, num_nodes):
self.nodes = [0]*num_nodes
for i in range(num_nodes):
self.nodes[i] = Node(randint(1, 10))
self.set_connections()
def set_connections(self):
for f, g in product(self.nodes, self.nodes):
p = uniform()
if p < 0.8:
f.friends.append(g)
g.friends.append(f)
def mainloop(self):
num_nodes = len(self.nodes)
while True:
next_time = exponential(0.1)
node = self.nodes[randint(num_nodes)]
for friend in node.friends:
friend.avg.send(node.average)
print friend.average
time.sleep(next_time)
So far I've only tested it as follows:
>>> n = Network(10)
>>> n.mainloop()
and then observed that the friend.average printed out all converge to the same value.
My main concern about this code is that a lot of the logic for waking up nodes is in the Network class, whilst I'd rather it was in the node class. Also, there's no exception/error handling, or proper testing.
The main purpose of this was to try and understand coroutines, which was a bit of a mind bender.