Compare commits

...

33 Commits
stars ... main

Author SHA1 Message Date
b012436844 Remove gifs from jupyter 2022-06-21 17:46:20 +02:00
93ee5987f5 Final fixes 2022-06-21 17:41:23 +02:00
b35d988f38 Update gitignore 2022-06-21 17:40:12 +02:00
db68fbd789 Final changes 2022-06-21 17:39:36 +02:00
be3adf775e Added weighted star jupyter 2022-06-21 17:25:42 +02:00
c08a177c43 Fix filenames 2022-06-21 17:19:04 +02:00
Mateusz
f3a7a4a64d add experiments to jupyter 2022-06-21 17:07:27 +02:00
de0560d538 Add weighted star experiment 2022-06-21 17:00:18 +02:00
Mateusz
8ee201b319 jupyter correction remove prosty 2022-06-21 16:40:42 +02:00
Mateusz
c703d7e44d jupyter correction 2022-06-21 16:40:02 +02:00
edeb9d3b8f fixed propagation speed calculation 2022-06-21 16:37:09 +02:00
182287c23c Merge remote-tracking branch 'origin/main' 2022-06-21 16:28:15 +02:00
6f8563f7d8 Fix refactored experiments 2022-06-21 16:28:11 +02:00
Mateusz
921b8aaed0 add gifs to jupyter 2022-06-21 16:26:33 +02:00
8fe3c2bf8e Refactor experiments 2022-06-21 16:24:48 +02:00
46ae4299c4 Fix typos in prints 2022-06-21 16:15:55 +02:00
Mateusz
e93cc98193 simple conclusion 2022-06-21 16:02:32 +02:00
Mateusz
6e42853e38 corrections 2022-06-21 15:55:33 +02:00
Mateusz
5b67b5b953 implement bus and ring experiment 2022-06-21 15:45:29 +02:00
Mateusz
10ba0fbd9d rounds survived correction and add to star experiment 2022-06-21 15:25:05 +02:00
f6e749269a summary graph and experiment 2022-06-20 21:18:05 +02:00
f2d85a3e7d avg rank calculation for all topologies 2022-06-20 19:18:56 +02:00
6269168fb8 Added outline for nodes under attack in a given step. 2022-06-20 19:15:24 +02:00
53e8b1f414 Added Markdowns for Spacer Losowy and Model 2022-06-20 01:34:48 +02:00
02800bcb7e Added Step counter to the gif.
Fixed multiple infected nodes at step 0.
2022-06-20 01:10:32 +02:00
eb5e546e73 Added survivability counts 2022-06-16 22:38:52 +02:00
1bca995878 Show infections in star topology 2022-06-16 22:12:44 +02:00
816d1e53bf Use kamada_kawai layout in star topology 2022-06-16 22:08:24 +02:00
78e3b287fb Merge remote-tracking branch 'origin/stars'
# Conflicts:
#	network_attack_propagation.py
2022-06-16 22:06:23 +02:00
255420e622 Add path traversal with infection 2022-06-16 22:05:00 +02:00
b6706489da More flexible layouts 2022-06-16 21:17:45 +02:00
e9d501c132 Styling 2022-06-16 21:05:08 +02:00
Wirusik
14495cebda ring init 2022-06-16 20:58:13 +02:00
3 changed files with 737 additions and 68 deletions

6
.gitignore vendored
View File

@ -9,6 +9,12 @@
profile_default/ profile_default/
ipython_config.py ipython_config.py
*.gif
*.png
__pycache__/
.idea/
# Remove previous ipynb_checkpoints # Remove previous ipynb_checkpoints
# git rm -r .ipynb_checkpoints/ # git rm -r .ipynb_checkpoints/

File diff suppressed because one or more lines are too long

View File

@ -10,6 +10,7 @@ class Node:
def __init__(self, is_infected=False): def __init__(self, is_infected=False):
self.id = random.randint(1, 2000000) self.id = random.randint(1, 2000000)
self.is_infected = is_infected self.is_infected = is_infected
self.under_attack = False
def as_tuple(self): def as_tuple(self):
return self.id, self.is_infected return self.id, self.is_infected
@ -27,10 +28,15 @@ class Edge:
def as_tuple(self): def as_tuple(self):
return self.node_a, self.node_b, {'weight': self.weight} return self.node_a, self.node_b, {'weight': self.weight}
def has_node(self, node: Node) -> bool:
return self.node_a is node or self.node_b is node
class Graph: class Graph:
def __init__(self): def __init__(self, use_weights=False):
self.edges = [] self.edges = []
self.use_weights = use_weights
self.rounds_survived = 0
def add_edge(self, edge: Edge): def add_edge(self, edge: Edge):
self.edges.append(edge) self.edges.append(edge)
@ -45,87 +51,230 @@ class Graph:
nodes.add(edge.node_b) nodes.add(edge.node_b)
return nodes return nodes
def get_edges_with_node(self, node: Node):
return filter(lambda ed: ed.has_node(node), self.edges)
def clear_attacked(self) -> None:
for edge in self.edges:
edge.node_a.under_attack = False
edge.node_b.under_attack = False
def get_adjacent_nodes(self, node: Node) -> [(Node, int)]:
"""
:param node: Node to search for
:return: An array of tuples (node, weight)
"""
edges_with_node = self.get_edges_with_node(node)
nodes = set()
for e in edges_with_node:
if e.node_a is node:
nodes.add((e.node_b, e.weight))
else:
nodes.add((e.node_a, e.weight))
return nodes
def is_alive(self):
nodes_alive = list(filter(lambda x: not x.is_infected, self.get_nodes()))
return len(nodes_alive) > 0
def update_survived(self):
if not self.is_alive():
return
self.rounds_survived += 1
def infect_step(self):
infected_nodes = list(filter(lambda n: n.is_infected, self.get_nodes()))
for node in infected_nodes:
adjacent_nodes = self.get_adjacent_nodes(node)
if self.use_weights:
to_be_infected = random.choices([n[0] for n in adjacent_nodes], weights=[n[1] for n in adjacent_nodes])[0]
else:
to_be_infected = random.choice([n[0] for n in adjacent_nodes])
to_be_infected.is_infected = True
to_be_infected.under_attack = True
self.update_survived()
def update(num, layout, g_repr, ax, our_graph: Graph): def update(num, layout, g_repr, ax, our_graph: Graph):
""" """
This function is called every 'step', so if you wish to update the graph, do it here This function is called every 'step', so if you wish to update the graph, do it here
""" """
if not our_graph.is_alive():
return
if num != 0:
our_graph.infect_step()
ax.clear() ax.clear()
for n in our_graph.get_nodes(): ax.set_title(f'Step: {num}', loc='right', fontsize=30)
n.is_infected = bool(random.getrandbits(1))
colors = ['red' if n.is_infected else 'blue' for n in g_repr] colors = ['red' if n.is_infected else 'blue' for n in g_repr]
nx.draw_networkx(g_repr, ax=ax, pos=layout, node_color=colors, with_labels=False) edgecolors = ['black' if n.under_attack else 'none' for n in g_repr]
linewidths = [3 if c == 'black' else 0 for c in edgecolors]
sizes = [300 if n.is_infected else 150 for n in g_repr]
nx.draw(
g_repr,
ax=ax,
pos=layout,
node_color=colors,
linewidths=linewidths,
edgecolors=edgecolors,
with_labels=False,
node_size=sizes,
alpha=0.7,
)
our_graph.clear_attacked()
def do_graph_animation(output_file_name: str, in_graph: Graph, frame_count: int): def do_graph_animation(output_file_name: str, in_graph: Graph, frame_count: int, layout):
g_repr = nx.Graph() g_repr = nx.Graph()
# Convert our graph class into tuples understood by networkx # Convert our graph class into tuples understood by networkx
g_repr.add_edges_from([e.as_tuple() for e in in_graph.edges]) g_repr.add_edges_from([e.as_tuple() for e in in_graph.edges])
layout = nx.spring_layout(g_repr) layout = layout(g_repr)
fig, ax = plt.subplots() fig, ax = plt.subplots()
anim = animation.FuncAnimation(fig, update, frames=frame_count, fargs=(layout, g_repr, ax, in_graph)) fig.set_figwidth(8)
fig.set_figheight(8)
anim = animation.FuncAnimation(
fig, update, frames=frame_count, interval=500, fargs=(layout, g_repr, ax, in_graph)
)
anim.save(output_file_name) anim.save(output_file_name)
plt.style.use('seaborn')
plt.show() plt.show()
def bus_network(n=30) -> Graph: def degree_avg(edges, digits=2):
degrees = {}
for e in edges:
degrees[e.node_a] = degrees.get(e.node_a, 0) + 1
degrees[e.node_b] = degrees.get(e.node_b, 0) + 1
return round(mean(degrees.values()), digits)
def bus_network(n=30, infected_idx=0) -> tuple[Graph, float, int]:
network = Graph() network = Graph()
nodes = [Node() for _ in range(n)] nodes = [Node() for _ in range(n)]
nodes[infected_idx].is_infected = True
edges = [Edge(nodes[i], nodes[i + 1], 1.0) for i in range(n - 1)] edges = [Edge(nodes[i], nodes[i + 1], 1.0) for i in range(n - 1)]
network.add_edges(edges) network.add_edges(edges)
return network return network, degree_avg(edges), n
def rank_avg(edges, digits=2): def star_network(cluster_count=5, starsize=6, use_weights=False) -> tuple[Graph, float, int]:
ranks = {}
for e in edges:
ranks[e.node_a] = ranks.get(e.node_a, 0) + 1
ranks[e.node_b] = ranks.get(e.node_b, 0) + 1
return round(mean(ranks.values()), digits)
def star_network(cluster_count=5, starsize=6) -> tuple[Graph, float]:
node_count = cluster_count + cluster_count * starsize + 1 node_count = cluster_count + cluster_count * starsize + 1
nodes = [Node() for _ in range(node_count)] nodes = [Node() for _ in range(node_count)]
nodes[starsize-1].is_infected = True
edges = [] edges = []
for x in range(cluster_count): for x in range(cluster_count):
center_node = x * starsize + x center_node = x * starsize + x
edges += [Edge(nodes[center_node], nodes[i], 1.0) for i in range(center_node + 1, center_node + starsize + 1)] vulnerability = 1.0 if not use_weights else max(1.0, starsize)
edges += [Edge(nodes[center_node], nodes[i], vulnerability) for i in range(center_node + 1, center_node + starsize + 1)]
edges.append(Edge(nodes[-1], nodes[center_node], 1.0)) edges.append(Edge(nodes[-1], nodes[center_node], 1.0))
network = Graph() network = Graph()
network.add_edges(edges) network.add_edges(edges)
return network, rank_avg(edges) return network, degree_avg(edges), node_count
def ring_network(n=30) -> tuple[Graph, float, int]:
network = Graph()
nodes = [Node() for _ in range(n)]
nodes[0].is_infected = True
edges = [Edge(nodes[i], nodes[i + 1], 1.0) for i in range(n - 1)]
end_edge = Edge(nodes[n - 1], nodes[0], 1.0)
edges.append(end_edge)
network.add_edges(edges)
return network, degree_avg(edges), n
def summary(average_degrees: list[float], propagation_speeds: list[float]) -> None:
fig, ax = plt.subplots()
ax.plot(average_degrees, propagation_speeds)
ax.set(xlabel='Average degree', ylabel='Propagation speed', title='Summary')
fig.savefig("summary.png")
plt.show()
def bus_experiment():
degrees = []
speeds = []
sizes = [0, 8, 15]
for i in sizes:
bus, bus_avg_degree, node_count = bus_network(20 + i)
do_graph_animation(f'bus{i}.gif', bus, 90, nx.spring_layout)
speeds.append(bus.rounds_survived / node_count)
degrees.append(bus_avg_degree)
print(f"\n{node_count} NODE bus")
print(f"average degree = {bus_avg_degree}")
print(f"propagation speed = {round(speeds[-1], 2)}")
print(f"bus{i} rounds survived = {bus.rounds_survived + 1}")
summary(degrees, speeds)
def ring_experiment():
degrees = []
speeds = []
sizes = [0, 8, 15]
for i in sizes:
ring, ring_avg_degree, node_count = ring_network(20 + i)
do_graph_animation(f'ring{i}.gif', ring, 90, nx.circular_layout)
speeds.append(ring.rounds_survived / node_count)
degrees.append(ring_avg_degree)
print(f"\n{node_count} NODE ring")
print(f"average degree = {ring_avg_degree}")
print(f"propagation speed = {round(speeds[-1], 2)}")
print(f"ring{i} rounds survived = {ring.rounds_survived + 1}")
def star_experiment():
degrees = []
speeds = []
sizes = range(0, 8, 2)
for i in sizes:
star, star_avg_degree, node_count = star_network(cluster_count=3 + i, starsize=3 + i)
do_graph_animation(f'star{i}.gif', star, 120, nx.kamada_kawai_layout)
speeds.append(star.rounds_survived / node_count)
degrees.append(star_avg_degree)
print(f"\n{node_count} NODE STAR")
print(f"average degree = {star_avg_degree}")
print(f"propagation speed = {round(speeds[-1], 2)}")
print(f"star{i} rounds survived = {star.rounds_survived + 1}")
summary(degrees, speeds)
def weighted_star_experiment():
degrees = []
speeds = []
sizes = range(0, 8, 2)
for i in sizes:
star, star_avg_degree, node_count = star_network(cluster_count=3 + i, starsize=3 + i, use_weights=True)
do_graph_animation(f'star_weighted{i}.gif', star, 120, nx.kamada_kawai_layout)
speeds.append(star.rounds_survived / node_count)
degrees.append(star_avg_degree)
print(f"\n{node_count} NODE STAR")
print(f"average degree = {star_avg_degree}")
print(f"propagation speed = {round(speeds[-1], 2)}")
print(f"star{i} rounds survived = {star.rounds_survived + 1}")
summary(degrees, speeds)
def main(): def main():
network = Graph() bus_experiment()
nodes = [Node(True), Node(), Node(), Node(True), Node()] ring_experiment()
star_experiment()
network.add_edges([ weighted_star_experiment()
Edge(nodes[1], nodes[0], 0.02),
Edge(nodes[1], nodes[2], 0.2),
Edge(nodes[2], nodes[0], 0.7),
Edge(nodes[3], nodes[2], 0.2),
Edge(nodes[3], nodes[1], 0.2),
Edge(nodes[4], nodes[3], 0.2)
])
do_graph_animation('test.gif', network, 5)
bus = bus_network()
do_graph_animation('bus.gif', bus, 5)
star, star_avg_rank = star_network()
do_graph_animation('star.gif', star, 5)
if __name__ == "__main__": if __name__ == "__main__":
main() main()