Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion PONS.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,26 @@
"parameters"
]
},
"outputs": [],
"outputs": [
{
"ename": "ModuleNotFoundError",
"evalue": "No module named 'matplotlib'",
"output_type": "error",
"traceback": [
"\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
"\u001B[0;31mModuleNotFoundError\u001B[0m Traceback (most recent call last)",
"Cell \u001B[0;32mIn[1], line 10\u001B[0m\n\u001B[1;32m 8\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mpandas\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m \u001B[38;5;21;01mpd\u001B[39;00m\n\u001B[1;32m 9\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mnumpy\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m \u001B[38;5;21;01mnp\u001B[39;00m\n\u001B[0;32m---> 10\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mmatplotlib\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mpyplot\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m \u001B[38;5;21;01mplt\u001B[39;00m\n\u001B[1;32m 11\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mseaborn\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m \u001B[38;5;21;01msns\u001B[39;00m\n\u001B[1;32m 13\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mpons\u001B[39;00m\n",
"\u001B[0;31mModuleNotFoundError\u001B[0m: No module named 'matplotlib'"
]
}
],
"source": [
"import random\n",
"import math\n",
"import time\n",
"import simpy\n",
"import json\n",
"\n",
"import copy\n",
"import pandas as pd\n",
"import numpy as np\n",
Expand Down
1 change: 1 addition & 0 deletions pons/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .simulation import NetSim
from .events import EventManager, Event, EventType
from .mobility import generate_randomwaypoint_movement, OneMovement, OneMovementManager
from .node import generate_nodes, Node, NetworkSettings, Message, BROADCAST_ADDR
from .routing import Router, EpidemicRouter
Expand Down
96 changes: 96 additions & 0 deletions pons/events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from enum import Enum
from typing import List, Dict, Set
import pons
import simpy


class EventType(Enum):
RECEIVED = 0
DELIVERED = 1
CREATED = 2
CONNECTION_UP = 3
CONNECTION_DOWN = 4
DROPPED = 5
RELAY_STARTED = 6


class Event:
"""Simulation Events"""

def __init__(self, type: EventType, node: int, from_node: int, message: "pons.Message", time: float):
self.type: EventType = type
self.node: int = node
self.from_node: int = from_node
self.message: pons.Message = message
self.time: float = time

def __str__(self):
if self.type == EventType.RECEIVED:
return f"{self.time}: Message relayed {self.from_node} <-> {self.node} {self.message.id}"
if self.type == EventType.DELIVERED:
return f"{self.time}: Message delivered {self.from_node} <-> {self.node} {self.message.id}"
if self.type == EventType.CREATED:
return f"{self.time}: Message created {self.node} {self.message.id}"
if self.type == EventType.CONNECTION_UP:
return f"{self.time}: Connection UP {self.node} <-> {self.from_node}"
if self.type == EventType.CONNECTION_DOWN:
return f"{self.time}: Connection DOWN {self.node} <-> {self.from_node}"
if self.type == EventType.DROPPED:
return f"{self.time}: Message dropped {self.node} {self.message.id}"
if self.type == EventType.RELAY_STARTED:
return f"{self.time}: Message relay started {self.node} {self.message.id}"

return ""

def __eq__(self, other):
if not isinstance(other, Event):
return False
if other.type != self.type:
return False
if other.time != self.time:
return False
if self.type in [EventType.RECEIVED, EventType.DELIVERED]:
return self.node == other.node and self.from_node == other.from_node and self.message == other.message
if self.type in [EventType.CREATED, EventType.DROPPED, EventType.RELAY_STARTED]:
return self.node == other.node and self.message == other.message
return self.node == other.node and self.from_node == other.from_node or self.node == other.from_node and self.from_node == other.node

def __hash__(self):
return self.type.value + self.node + self.from_node + hash(self.message) + int(self.time)


class EventManager:
def __init__(self, env: simpy.Environment, nodes: "List[pons.Node]"):
self._env: simpy.Environment = env
self.events: Set[Event] = set()
self._last_peers: Dict[int, Set[int]] = {node.id: set() for node in nodes}
self._current_peers: Dict[int, Set[int]] = {node.id: set() for node in nodes}

def on_message_received(self, node: int, from_node: int, msg: "pons.Message"):
self.events.add(Event(EventType.RECEIVED, node, from_node, msg, self._env.now))

def on_message_delivered(self, node: int, from_node: int, msg: "pons.Message"):
self.events.add(Event(EventType.DELIVERED, node, from_node, msg, self._env.now))

def on_message_created(self, node: int, msg: "pons.Message"):
self.events.add(Event(EventType.CREATED, node, node, msg, self._env.now))

def on_message_dropped(self, node: int, msg: "pons.Message"):
self.events.add(Event(EventType.DROPPED, node, node, msg, self._env.now))

def on_peer_discovery(self, node1: int, node2: int):
if node2 not in self._last_peers[node1] and node1 not in self._last_peers[node2]:
self.events.add(Event(EventType.CONNECTION_UP, node1, node2, None, self._env.now))
self._current_peers[node1].add(node2)
self._current_peers[node2].add(node1)

def on_before_scan(self, node: int):
lost_peers = [peer for peer in self._last_peers[node] if peer not in self._current_peers[node]]
events = [Event(EventType.CONNECTION_DOWN, node, peer, None, self._env.now) for peer in lost_peers]
for event in events:
self.events.add(event)
self._last_peers[node] = self._current_peers[node].copy()
self._current_peers[node].clear()
for peer in lost_peers:
if node in self._current_peers[peer]:
self._current_peers[peer].remove(node)
25 changes: 1 addition & 24 deletions pons/routing/directdelivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ def __init__(self, scan_interval=2.0, capacity=0):
def __str__(self):
return "DirectDeliveryRouter"

def add(self, msg):
# print("adding new msg to store")
if self.store_add(msg):
self.forward(msg)

def forward(self, msg):
if msg.dst in self.peers and not self.msg_already_spread(msg, msg.dst):
# self.log("sending directly to receiver")
Expand All @@ -25,24 +20,6 @@ def forward(self, msg):

def on_peer_discovered(self, peer_id):
# self.log("peer discovered: %d" % peer_id)
super().on_peer_discovered(peer_id)
for msg in self.store:
self.forward(msg)

def on_msg_received(self, msg, remote_id):
# self.log("msg received: %s from %d" % (msg, remote_id))
self.netsim.routing_stats['relayed'] += 1
if not self.is_msg_known(msg):
self.remember(remote_id, msg)
msg.hops += 1
self.store_add(msg)
if msg.dst == self.my_id:
# self.log("msg arrived", self.my_id)
self.netsim.routing_stats['delivered'] += 1
self.netsim.routing_stats['hops'] += msg.hops
self.netsim.routing_stats['latency'] += self.env.now - msg.created
else:
# self.log("msg not arrived yet", self.my_id)
self.forward(msg)
else:
# self.log("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1
25 changes: 1 addition & 24 deletions pons/routing/epidemic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ def __init__(self, scan_interval=2.0, capacity=0):
def __str__(self):
return "EpidemicRouter"

def add(self, msg):
# self.log("adding new msg to store")
if self.store_add(msg):
self.forward(msg)

def forward(self, msg):
if msg.dst in self.peers and not self.msg_already_spread(msg, msg.dst):
# self.log("sending directly to receiver")
Expand All @@ -35,27 +30,9 @@ def forward(self, msg):

def on_peer_discovered(self, peer_id):
# self.log("peer discovered: %d" % peer_id)
super().on_peer_discovered(peer_id)
for msg in self.store:
if msg.is_expired(self.netsim.env.now):
self.store_del(msg)
else:
self.forward(msg)

def on_msg_received(self, msg, remote_id):
# self.log("msg received: %s from %d" % (msg, remote_id))
self.netsim.routing_stats['relayed'] += 1
if not self.is_msg_known(msg):
self.remember(remote_id, msg)
msg.hops += 1
self.store_add(msg)
if msg.dst == self.my_id:
# self.log("msg arrived %s" % msg)
self.netsim.routing_stats['delivered'] += 1
self.netsim.routing_stats['hops'] += msg.hops
self.netsim.routing_stats['latency'] += self.env.now - msg.created
else:
# self.log("msg not arrived yet", self.my_id)
self.forward(msg)
else:
# self.log("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1
25 changes: 1 addition & 24 deletions pons/routing/firstcontact.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ def __init__(self, scan_interval=2.0):
def __str__(self):
return "FirstContactRouter"

def add(self, msg):
# print("adding new msg to store")
if self.store_add(msg):
self.forward(msg)

def forward(self, msg):
if msg.dst in self.peers and not self.msg_already_spread(msg, msg.dst):
# self.log("sending directly to receiver")
Expand All @@ -38,24 +33,6 @@ def forward(self, msg):

def on_peer_discovered(self, peer_id):
# self.log("peer discovered: %d" % peer_id)
super().on_peer_discovered(peer_id)
for msg in self.store:
self.forward(msg)

def on_msg_received(self, msg, remote_id):
# self.log("msg received: %s from %d" % (msg, remote_id))
self.netsim.routing_stats['relayed'] += 1
if not self.is_msg_known(msg):
self.remember(remote_id, msg)
msg.hops += 1
self.store_add(msg)
if msg.dst == self.my_id:
# self.log("msg arrived", self.my_id)
self.netsim.routing_stats['delivered'] += 1
self.netsim.routing_stats['hops'] += msg.hops
self.netsim.routing_stats['latency'] += self.env.now - msg.created
else:
# self.log("msg not arrived yet", self.my_id)
self.forward(msg)
else:
# self.log("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1
33 changes: 28 additions & 5 deletions pons/routing/router.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@

from copy import copy
import pons

HELLO_MSG_SIZE = 42
Expand All @@ -25,7 +23,11 @@ def log(self, msg):
print("[%s : %s] %s" % (self.my_id, self, msg))

def add(self, msg: pons.Message):
self.store_add(msg)
if self.store_add(msg):
self.forward(msg)

def forward(self, msg):
pass

def store_add(self, msg: pons.Message):
if self.capacity > 0 and self.used + msg.size > self.capacity:
Expand All @@ -38,11 +40,13 @@ def store_add(self, msg: pons.Message):
# self.log("store cleaned up, made room for msg %s" % msg.id)
self.store.append(msg)
self.used += msg.size
self.netsim.event_manager.on_message_created(self.my_id, msg)
return True

def store_del(self, msg: pons.Message):
self.used -= msg.size
self.store.remove(msg)
self.netsim.event_manager.on_message_dropped(self.my_id, msg)

def store_cleanup(self):
# [self.store_del(msg)
Expand Down Expand Up @@ -81,6 +85,7 @@ def scan(self):
# self.on_peer_discovered(peer)

# do actual peer discovery with a hello message
self.netsim.event_manager.on_before_scan(self.my_id)
self.peers.clear()
self.netsim.nodes[self.my_id].send(self.netsim, pons.BROADCAST_ADDR, pons.Message(
"HELLO", self.my_id, pons.BROADCAST_ADDR, HELLO_MSG_SIZE, self.netsim.env.now))
Expand All @@ -98,10 +103,28 @@ def on_scan_received(self, msg: pons.Message, remote_id: int):
# self.log("DUP PEER: %d" % remote_id)

def on_peer_discovered(self, peer_id):
self.log("peer discovered: %d" % peer_id)
#self.log("peer discovered: %d" % peer_id)
self.netsim.event_manager.on_peer_discovery(self.my_id, peer_id)

def on_msg_received(self, msg: pons.Message, remote_id: int):
self.log("msg received: %s from %d" % (msg, remote_id))
self.netsim.routing_stats['relayed'] += 1
if not self.is_msg_known(msg):
self.remember(remote_id, msg)
msg.hops += 1
self.store_add(msg)
if msg.dst == self.my_id:
# print("msg arrived", self.my_id)
self.netsim.routing_stats['delivered'] += 1
self.netsim.routing_stats['hops'] += msg.hops
self.netsim.routing_stats['latency'] += self.env.now - msg.created
self.netsim.event_manager.on_message_delivered(self.my_id, remote_id, msg)
else:
# print("msg not arrived yet", self.my_id)
self.netsim.event_manager.on_message_received(self.my_id, remote_id, msg)
self.forward(msg)
else:
# print("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1

def remember(self, peer_id, msg: pons.Message):
if msg.id not in self.history:
Expand Down
24 changes: 2 additions & 22 deletions pons/routing/sprayandwait.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ def __str__(self):
def add(self, msg):
# print("adding new msg to store")
msg.metadata['copies'] = self.copies
if self.store_add(msg):
self.forward(msg)
super().add(msg)

def forward(self, msg):
if msg.dst in self.peers and not self.msg_already_spread(msg, msg.dst):
Expand Down Expand Up @@ -54,25 +53,6 @@ def forward(self, msg):
self.remember(peer, msg)

def on_peer_discovered(self, peer_id):
# self.log("peer discovered: %d" % peer_id)
super().on_peer_discovered(peer_id)
for msg in self.store:
self.forward(msg)

def on_msg_received(self, msg, remote_id):
# self.log("msg received: %s from %d" % (msg, remote_id))
self.netsim.routing_stats['relayed'] += 1
if not self.is_msg_known(msg):
self.remember(remote_id, msg)
msg.hops += 1
self.store_add(msg)
if msg.dst == self.my_id:
# print("msg arrived", self.my_id)
self.netsim.routing_stats['delivered'] += 1
self.netsim.routing_stats['hops'] += msg.hops
self.netsim.routing_stats['latency'] += self.env.now - msg.created
else:
# print("msg not arrived yet", self.my_id)
self.forward(msg)
else:
# print("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1
14 changes: 9 additions & 5 deletions pons/simulation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import simpy
import time
from typing import List, Dict

import simpy

import pons


Expand All @@ -21,6 +24,7 @@ def __init__(self, duration, world, nodes, movements=[], msggens=None, config=No
'latency': 0.0, 'started': 0, 'relayed': 0, 'removed': 0, 'aborted': 0, 'dups': 0,
'latency_avg': 0.0, 'delivery_prob': 0.0, 'hops_avg': 0.0, 'overhead_ratio': 0.0}
self.router_stats = {}
self.event_manager: pons.EventManager = pons.EventManager(self.env, nodes)

self.mover = pons.OneMovementManager(
self.env, self.nodes, self.movements)
Expand Down Expand Up @@ -107,14 +111,14 @@ def run(self):

if self.routing_stats["delivered"] > 0:
self.routing_stats["latency_avg"] = self.routing_stats["latency"] / \
self.routing_stats["delivered"]
self.routing_stats["delivered"]
self.routing_stats["hops_avg"] = self.routing_stats["hops"] / \
self.routing_stats["delivered"]
self.routing_stats["delivered"]
self.routing_stats["overhead_ratio"] = (self.routing_stats["relayed"] - self.routing_stats["delivered"]) / \
self.routing_stats["delivered"]
self.routing_stats["delivered"]

self.routing_stats["delivery_prob"] = self.routing_stats["delivered"] / \
self.routing_stats["created"]
self.routing_stats["created"]

# delete entry "hops" and "latency" from routing_stats as they are only used for calculating the average
del self.routing_stats["hops"]
Expand Down
4 changes: 4 additions & 0 deletions ui/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .components.layout import layout_component
from .config import config, ROUTERS
from .data import DataManager
from .visualization import Visualization
Loading