Skip to content
This repository was archived by the owner on Apr 25, 2020. It is now read-only.

Commit b539367

Browse files
committed
add v0.1.3 to github.
1 parent b51bde0 commit b539367

31 files changed

Lines changed: 1460 additions & 0 deletions

CHANGES.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
v0.1.3, 26th February 2014 -- added project on github. No changes to the code.
3+
4+
v0.1.3, 26th September 2011 -- added advanced documentation, which is now completed - source code remained the same.
5+
v0.1.2, 29th August 2011 -- added more documentation, and a starting example, fixed some console output.
6+
v0.1.1b, 29th August 2011 -- removed matplotlib from the install_requires package - please install matplotlib separately.
7+
v0.1.1, 28th August 2011 -- setup.py dependency bug fix.
8+
v0.1.0, 28th August 2011 -- Initial release after part-time development since October 2010.

ComplexNetworkSim/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from agents import NetworkAgent
2+
from simulation import NetworkSimulation, Sim
3+
from plotting import PlotCreator
4+
from animation import AnimationCreator

ComplexNetworkSim/agents.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
'''
2+
Module for the NetworkAgent class that can be subclassed by agents.
3+
4+
@author: Joe Schaul <joe.schaul@gmail.com>
5+
'''
6+
7+
from SimPy import Simulation as Sim
8+
import networkx as nx
9+
import random
10+
11+
SEED = 123456789
12+
13+
ADD_EDGE = "add edge"
14+
REMOVE_EDGE = "remove edge"
15+
ADD_NODE = "add node"
16+
REMOVE_NODE = "remove node"
17+
18+
19+
class NetworkAgent(Sim.Process):
20+
'''NetworkAgent class that can be subclassed by agents. '''
21+
22+
#class variables, shared between all instances of this class
23+
r = random.Random(SEED)
24+
TIMESTEP_DEFAULT = 1.0
25+
26+
def __init__(self, state, initialiser, stateVector=[], name='network_process', **stateParameters):
27+
Sim.Process.__init__(self, name)
28+
self.state = state
29+
self.stateVector = stateVector
30+
self.stateParameters = stateParameters
31+
self.initialize(*initialiser)
32+
33+
34+
def initialize(self, id, sim, globalTopo, globalParams):
35+
''' this gets called automatically '''
36+
self.id = id
37+
self.sim = sim
38+
self.globalTopology = globalTopo
39+
self.globalSharedParameters = globalParams
40+
41+
def getAllNodes(self):
42+
return self.globalTopology.nodes()
43+
44+
def getAllAgents(self, state=None):
45+
neighs = self.getAllNodes()
46+
if state is not None:
47+
return [self.globalTopology.node[n]['agent'] for n in neighs
48+
if self.globalTopology.node[n]['agent'].state == state]
49+
else:
50+
return [self.globalTopology.node[n]['agent'] for n in neighs]
51+
52+
53+
54+
def getNeighbouringAgents(self, state=None):
55+
''' returns list of neighbours, but as agents, not nodes.
56+
so e.g. one can set result[0].state = INFECTED '''
57+
neighs = self.globalTopology.neighbors(self.id)
58+
if state is not None:
59+
return [self.globalTopology.node[n]['agent'] for n in neighs
60+
if self.globalTopology.node[n]['agent'].state == state]
61+
else:
62+
return [self.globalTopology.node[n]['agent'] for n in neighs]
63+
64+
def getNeighbouringAgentsIter(self, state=None):
65+
'''same as getNeighbouringAgents, but returns generator expression,
66+
not list.
67+
'''
68+
neighs = self.globalTopology.neighbors(self.id)
69+
if state is not None:
70+
return (self.globalTopology.node[n]['agent'] for n in neighs
71+
if self.globalTopology.node[n]['agent'].state == state)
72+
else:
73+
return (self.globalTopology.node[n]['agent'] for n in neighs)
74+
75+
def getNeighbouringNodes(self):
76+
''' returns list of neighbours as nodes.
77+
Call self.getAgent() on one of them to get the agent.'''
78+
return self.globalTopology.neighbors(self.id)
79+
80+
def getAgent(self, id):
81+
'''returns agent of specified ID.'''
82+
return self.globalTopology.node[id]['agent']
83+
84+
def addNewNode(self, state):
85+
#add & activate new agent
86+
return self.sim.addNewNode(state)
87+
88+
#add a random edge
89+
#u = NetworkAgent.r.choice(self.globalTopology.nodes())
90+
#self.globalTopology.add_edge(u, id)
91+
92+
def die(self):
93+
self.removeNode(self.id)
94+
95+
def removeNode(self, id):
96+
# cancel ? self.getAgent(id)
97+
self.globalTopology.remove_node(id)
98+
99+
def removeEdge(self, node1, node2):
100+
101+
self.globalTopology.remove_edge(self.id, self.currentSupernodeID)
102+
self.logTopoChange(REMOVE_EDGE, node1, node2)
103+
104+
105+
def addEdge(self, node1, node2):
106+
self.globalTopology.add_edge(self.id, self.currentSupernodeID)
107+
self.logTopoChange(ADD_EDGE, node1, node2)
108+
109+
110+
def logTopoChange(self, action, node, node2=None):
111+
#TODO: test, add this to netlogger...
112+
print action, node, node2
113+
114+
115+
116+
117+
118+
119+
120+
121+
122+
123+

ComplexNetworkSim/animation.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
'''
2+
Module for the generation of visualisations of processes over complex networks
3+
Generates PNG images for each timestep and (if ImageMagick is available) a gif animation file.
4+
5+
@author: Joe Schaul <joe.schaul@gmail.com>
6+
'''
7+
8+
import utils
9+
from matplotlib import pyplot
10+
import networkx as nx
11+
import os
12+
#dependency: ImageMagick for gif creation. Works without too then only creates PNGs
13+
14+
class AnimationCreator(object):
15+
16+
def __init__(self, dir, name, title, mapping, trial=0, delay=100):
17+
self.name = name
18+
self.dir = os.path.abspath(dir)
19+
self.delay = delay
20+
self.mapping = mapping
21+
self.trial = trial
22+
self.title = title
23+
self.G = nx.Graph()
24+
25+
def create_gif(self, verbose=True):
26+
if verbose: print "Creating PNGs ...",
27+
self.createPNGs()
28+
29+
input = os.path.join(self.dir, self.name + "*.png")
30+
output = os.path.join(self.dir, self.name + ".gif")
31+
32+
if verbose: print "attempting gif creation ...",
33+
34+
failure = os.system("convert -delay %i -loop 0 \"%s\" \"%s\"" % (self.delay, input, output))
35+
if failure:
36+
print "Problem: Could not create gif. \nMaybe ImageMagick not installed correctly, or its 'convert' executable is not on your system path? \nPNG Image files are generated in any case."
37+
else:
38+
print "success! \nAnimation at %s " % str(output)
39+
40+
41+
def createPNGs(self):
42+
43+
states, topos, vector = utils.retrieveTrial(self.dir, self.trial)
44+
45+
init_topo = topos[0][1]
46+
if topos[0][0] != 0:
47+
print "problem - first topology not starting at 0!"
48+
self.G = init_topo
49+
self.layout = nx.layout.fruchterman_reingold_layout(self.G)
50+
self.nodesToDraw = self.G.nodes()
51+
self.edgesToDraw = self.G.edges()
52+
self.nodesToDraw.sort()
53+
self.edgesToDraw.sort()
54+
i = 1
55+
j = 0
56+
57+
58+
pyplot.figure()
59+
for t, s in states:
60+
61+
# start with initial topology, and check the topology tuples
62+
# each time to make sure to have an up-to-date graph topology
63+
if len(topos) > i and t == topos[i][0]:
64+
self.G = topos[i][1]
65+
fixednodes = [node for node in self.nodesToDraw if node in self.G.nodes()]
66+
self.layout = nx.layout.fruchterman_reingold_layout(self.G, pos=self.layout, fixed=fixednodes)
67+
i += 1
68+
69+
#convert states to colours and draw a figure
70+
colours = utils.states_to_colourString(s, self.mapping)
71+
pyplot.clf()
72+
self.nodesToDraw = self.G.nodes()
73+
self.nodesToDraw.sort()
74+
self.edgesToDraw = self.G.edges()
75+
self.edgesToDraw.sort()
76+
77+
nx.draw_networkx_nodes(self.G, nodelist=self.nodesToDraw, pos=self.layout, node_color=colours, with_labels=False)
78+
nx.draw_networkx_edges(self.G, edgelist=self.edgesToDraw, pos=self.layout, with_labels=False)
79+
80+
pyplot.suptitle("%s\ntime = %i" % (self.title, t))
81+
pyplot.axis('off')
82+
83+
pyplot.savefig(os.path.join(self.dir, self.name + "%02d.png" % j))
84+
j += 1
85+
86+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'''
2+
Custom exceptions when handling files to be more precise about the error
3+
that occurred.
4+
5+
@author: Joe Schaul <joe.schaul@gmail.com>
6+
'''
7+
8+
class LogOpeningError(Exception):
9+
"""Error happening when trying to open multiple simulation logs"""
10+
11+
12+
def __init__(self, value, logs):
13+
self.value = value
14+
self.logs = logs
15+
16+
def __str__(self):
17+
return repr(self.value)
18+
19+
20+

ComplexNetworkSim/logging.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
'''
2+
Special agent automatically initialised by the simulation that logs network
3+
states and topologies at every defined timestep.
4+
5+
@author: Joe Schaul <joe.schaul@gmail.com>
6+
'''
7+
8+
import networkx as nx
9+
from SimPy import Simulation as Sim
10+
11+
import utils
12+
13+
class NetworkLogger(Sim.Process):
14+
15+
def __init__(self, sim, directory, logging_interval):
16+
Sim.Process.__init__(self, sim=sim)
17+
self.sim = sim
18+
self.directory = directory
19+
self.interval = logging_interval
20+
self.stateTuples = []
21+
self.stateVectorTuples = []
22+
self.topology = nx.Graph()
23+
self.topoTuples = []
24+
25+
def Run(self):
26+
while True:
27+
self.logCurrentState()
28+
yield Sim.hold, self, self.interval
29+
30+
def logCurrentState(self):
31+
32+
nodes = self.sim.G.nodes(data=True)
33+
states = [node[1]['agent'].state for node in nodes]
34+
stateVectors = [node[1]['agent'].stateVector for node in nodes]
35+
36+
#log states
37+
self.stateTuples.append((self.sim.now(), states))
38+
self.stateVectorTuples.append((self.sim.now(), stateVectors))
39+
40+
#log new topology if it changed.
41+
if not nx.fast_could_be_isomorphic(self.topology, nx.Graph(self.sim.G)):
42+
self.topology = utils.create_copy_without_data(self.sim.G)
43+
self.topoTuples.append((self.sim.now(), self.topology))
44+
45+
46+
def logTrialToFiles(self, id):
47+
if not self.topoTuples:
48+
self.topoTuples.append((0, self.topology))
49+
#write states, topologies, and state vectors to file
50+
utils.logAllToFile(self.stateTuples, self.topoTuples,
51+
self.stateVectorTuples, self.directory, id)
52+
53+
54+
55+

ComplexNetworkSim/plotting.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'''
2+
Module for the generation of plots of system states.
3+
4+
@author: Joe Schaul <joe.schaul@gmail.com>
5+
'''
6+
7+
import utils
8+
import statistics
9+
import os
10+
11+
12+
from matplotlib import pyplot
13+
14+
class PlotCreator(object):
15+
'''Constructor - set examples=1 to get plot lines of first trial as well as the average'''
16+
def __init__(self, directory, name, title, statesToMonitor, colours, labels, examples=0):
17+
self.directory = os.path.abspath(directory)
18+
self.name = name
19+
self.statesToMonitor = statesToMonitor
20+
self.colours = colours
21+
self.labels = labels
22+
self.examples = examples
23+
self.title = title
24+
25+
def plotSimulation(self, ret=False, show=False, verbose=True):
26+
'''plots a simulation, time on x axis, nodes on y.
27+
Set ret=True for return of lines and no image creation. '''
28+
29+
states, topologies, vectors = utils.retrieveAllTrialsInDirectory(self.directory)
30+
stats = statistics.TrialStats(states, topologies)
31+
av = stats.trialAverage
32+
33+
pyplot.figure()
34+
lines = []
35+
for i in range(len(self.statesToMonitor)):
36+
if self.examples > 0:
37+
t0 = stats.trialstates[0]
38+
pyplot.plot(t0.times, t0.stateCounterForStateX[self.statesToMonitor[i]], "k", alpha=0.5)
39+
40+
try:
41+
pyplot.plot(av.times, av.stateCounterForStateX[self.statesToMonitor[i]], self.colours[i], label=self.labels[i])
42+
lines.append((av.times, av.stateCounterForStateX[self.statesToMonitor[i]], self.colours[i]))
43+
except KeyError:
44+
try:
45+
print "Plotting warning: skipping state = %s, colour = %s, label = %s, %s" \
46+
% (str(self.statesToMonitor[i]), str(self.colours[i]), str(self.labels[i]),
47+
"because no node is ever in this state in this trial")
48+
except KeyError:
49+
print "Plotting error: one of 'colours' or 'labels' has fewer elements",
50+
" than 'statesToMonitor'. Skipping this state."
51+
52+
pyplot.legend(loc=0)
53+
pyplot.title(self.title)
54+
pyplot.xlabel("Time")
55+
pyplot.ylabel("Nodes")
56+
if ret:
57+
return lines
58+
else:
59+
output_path = os.path.join(self.directory, "plot_" + self.name + ".png")
60+
pyplot.savefig(output_path)
61+
if verbose:
62+
print "Plot at", output_path
63+
64+
if show:
65+
pyplot.show()
66+

0 commit comments

Comments
 (0)