Znajomy wykładał dzisiaj o mean field approximating the disease spreading model, postanowiłem posłuchać. Niestety nie przewidziałem jak bardzo podstawowy będzie dzisiejszy wykład. Stąd zamiast słuchać zacząłem pisać. Tak powstała wizualizacja tegoż modelu, w wersji z dyskretnym czasem. Kompletny kod poniżej.
Przykładowa stopklatka z wizualizacji: Węzły czerwone są zarażone, ich etykiety oznaczają czas zarażenia. Dwie liczby komentarza to aktualny czas oraz liczba już zarażonych węzłów.
Kod działa pod OS X, wymaga graphviza. Pod
Linuksem chyba wystarczy zastąpić polecenie open jakimś odpowiednikiem
(xdg-open? przeglądarką pdf-ów?). Linia kontrolująca parametry modelu jest pod
koniec, jej znaczenie: g = graph(liczba wierzchołków, średnia liczba krawędzi, początkowa liczba chorych, szansa na wyleczenie)
#!/usr/bin/env python
from random import *
from time import sleep
from os import system
class node:
def __init__(self, num):
self.infected = False
self.infecting = False
self.links = []
self.num = num
self.changeTime = 0
def bond(self, other):
self.links.append(other)
other.links.append(self)
def color(self):
if self.infected:
return "red"
else:
return "blue"
class graph:
def fix(self):
for n in self.nodes:
if len(n.links) == 0:
o = sample(self.nodes, 1)[0]
while n == o:
o = sample(self.nodes, 1)[0]
n.bond(o)
def rand1(self, N, K, I, C):
self.Pcure = C
self.nodes = map(lambda x: node(x), xrange(N))
for i in xrange(N * K / 2):
a = randint(0, N - 1)
b = randint(0, N - 1)
while a == b:
b = randint(0, N - 1)
self.nodes[a].bond(self.nodes[b])
self.fix()
for n in sample(self.nodes, I):
n.infected = True
n.infecting = True
self.time = 0
def clique(self, N, K, I, C):
self.Pcure = C
self.nodes = map(lambda x: node(x), xrange(N))
for i in xrange(N):
for j in xrange(i):
self.nodes[i].bond(self.nodes[j])
for n in sample(self.nodes, I):
n.infected = True
n.infecting = True
self.time = 0
def erdos(self, N, K, I, C):
self.Pcure = C
self.nodes = map(lambda x: node(x), xrange(N))
q = float(K * N) / (N * (N-1) / 2)
for i in xrange(N):
for j in xrange(i):
if uniform(0, 1) < q:
self.nodes[i].bond(self.nodes[j])
for n in sample(self.nodes, I):
n.infected = True
n.infecting = True
self.time = 0
def slottedStep(self):
self.time += 1
for n in self.nodes:
if n.infected and uniform(0, 1) < self.Pcure:
n.infected = False
n.changeTime = self.time
for n in self.nodes:
if n.infecting:
x = sample(n.links, 1)[0]
if not x.infected:
x.infected = True
x.changeTime = self.time
for n in self.nodes:
n.infecting = n.infected
def show(self):
infected = 0
for n in self.nodes:
if n.infected:
infected += 1
print " ".join(map(lambda n: repr(n.infected), self.nodes))
dot = file("sis.dot", "w")
print >> dot, "graph g {"
print >> dot, "graph [dpi=300, overlap=scale, splines=true, aspect=1];"
print >> dot, "frame [label=\"%d, %d\", fontsize=30, shape=none];" % (self.time, infected)
for n in self.nodes:
print >> dot, "n%d [color = %s, style = filled, label=%d];" % (n.num, n.color(), n.changeTime)
for m in n.links:
if n.num < m.num:
print >> dot, "n%d -- n%d;" % (n.num, m.num)
print >> dot, "}"
dot.close()
system("neato -Tpdf -o sis.pdf sis.dot")
system("open sis.pdf")
def __init__(self, N, K, I, C):
self.erdos(N, K, I, C)
while True:
g = graph(32, 8, 1, 0.0)
g.show()
interesting = True
while interesting:
sleep(0.5)
g.slottedStep()
g.show()
interesting = False
for n in g.nodes:
interesting = interesting or not n.infected
sleep(2)