Skip to content

Commit 0d20af3

Browse files
committed
first commit, from top-cars conference
0 parents  commit 0d20af3

25 files changed

+37220
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.pdf
2+
*.data
3+
*.pyc
4+
__pycache__/

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
IFloodS - Information Flooding Simulator
2+
========================================
3+
4+
IFloodS simulates packet/information spreading in a network.
5+
Currently it comes with three distribution models:
6+
7+
* tree
8+
* epidemics with uniform probabilities
9+
* epidemics with reception-equal strategy [1]
10+
11+
IFloodS can be used to compare delay and age of information results following different distribution paradigms for a given set of network topologies.
12+
IFloodS takes as input the network topologies in the _topos/_ folder, performs the simulations and produce a CSV result file on delay reception.
13+
14+
Usage
15+
=====
16+
To compute delays:
17+
```
18+
./ifloods.py
19+
```
20+
To preprocess age of information
21+
```
22+
./analyse_aoi.py
23+
```
24+
Data can be then plotted using the script in the _img_ folder.
25+
26+
27+
Graph dataset
28+
=============
29+
30+
IFloodS uses by default topologies in the _topos/_ folder. You may use any other topologies, provided they come in __.edges__ format.
31+
In the vehicular_model folder there is a generative model for urban traffic networks, refer to the inner README file for further information.
32+
33+
Reference
34+
=========
35+
If you use this software, please cite:
36+
37+
[1] Baldesi, Luca, Leonardo Maccari, and Renato Lo Cigno. “On the Properties of Infective Flooding in Low-Duty-Cycle Networks.” In 2019 15th Annual Conference on Wireless On-Demand Network Systems and Services (WONS), 2019.
38+
39+
[2] Baldesi, Luca, Leonardo Maccari and Renato Lo Cigno. "Keep It Fresh: Reducing the Age of Information in V2X Networks", In TOP-Cars workshop, 2019.

analyse_aoi.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env python
2+
3+
import pandas as pd
4+
5+
6+
def analyse_aoi(duration):
7+
with open("ifloods_aoi.data", 'w') as f:
8+
f.write(f"seed,node,mean_aoi,mean_peak_aoi,strategy,graph\n")
9+
data = pd.read_csv("ifloods.data")
10+
for name in data['name'].unique():
11+
d0 = data[data['name'] == name]
12+
for seed in d0['seed'].unique():
13+
d1 = d0[d0['seed'] == seed]
14+
for strategy in ['turbo', 'plain']:
15+
d2 = d1[d1['strategy'] == strategy]
16+
for i in d2['node'].unique():
17+
peak_aoi = []
18+
dd = d2[d2['node'] == i]
19+
u = 0 # last received pkt ts
20+
k = 0 # last update time
21+
ti =0 # time integral
22+
for index, row in dd.iterrows():
23+
ti += (row['time'] + k - 2*u)*(row['time']-k)/2
24+
peak_aoi.append(row['time']-u)
25+
u = row['last_creat_ts']
26+
k = row['time']
27+
ti += (duration + k - 2*u)*(duration-k)/2
28+
peak_aoi.append(duration-u)
29+
30+
ti /= duration # mean aoi for peer i
31+
f.write(f"{seed},{i},{ti},{sum(peak_aoi)/len(peak_aoi)},{strategy},{name}\n")
32+
33+
34+
if __name__ == "__main__":
35+
analyse_aoi(100)

ifloods.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env python
2+
3+
import random
4+
import os
5+
import networkx as nx
6+
import numpy as nm
7+
import tandem_queue as tq
8+
import matplotlib.pyplot as plt
9+
import multiprocessing as mp
10+
11+
12+
def optimize(A, turbo):
13+
n = A.shape[0]
14+
u = nm.ravel(nm.ones((n, 1)))
15+
d = nm.ravel(u.dot(A))
16+
M = A.dot(nm.linalg.inv(nm.diag(d)))
17+
if turbo:
18+
M = nm.transpose(M)
19+
t = nm.ravel(u.dot(M))
20+
M = M.dot(nm.linalg.inv(nm.diag(t)))
21+
else:
22+
t = u
23+
return (M, t)
24+
25+
26+
def random_choice(n, probs):
27+
s = sum(probs)
28+
choice = None
29+
if s > 0:
30+
for i in range(n):
31+
probs[i] /= s
32+
choice = nm.random.choice(range(n), 1, p=probs)[0]
33+
return choice
34+
35+
def random_dest(A, j, smart_send):
36+
n = A.shape[0]
37+
choice = random_choice(n, nm.ravel(A[:, j]))
38+
if smart_send:
39+
A[choice, j] = 0
40+
A[j, choice] = 0
41+
return choice
42+
43+
44+
def sending_attempt(e, f, seed):
45+
propagation_time = 1./100 # 1 hundredth of time cycle
46+
i, M, t, S, sched, alpha = e
47+
48+
dest = random_dest(M, i, False)
49+
if S[dest] < S[i]:
50+
# print(f"{sched.elapsed_time()}: {i} sends to {dest}")
51+
sched.schedule_event(propagation_time, (-2,dest,S[i]))
52+
53+
sched.schedule_event(1./(alpha*t[i]), (i, M, t, S, sched, alpha))
54+
55+
56+
def spanning_tree(A, seed):
57+
n = A.shape[0]
58+
S1 = set([(None, seed)])
59+
S2 = set([seed])
60+
T = set()
61+
while len(S1) > 0:
62+
parent,node = S1.pop()
63+
S2.remove(node)
64+
for i in range(n):
65+
if A[i, node] > 0:
66+
if i in T or i in S2:
67+
A[i, node] = 0
68+
else:
69+
S1.add((node, i))
70+
S2.add(i)
71+
if parent is not None:
72+
A[parent, node] = 1
73+
T.add(node)
74+
return optimize(A, False)
75+
76+
77+
def simulate_flooding(G, dist, f, alpha=1, duration=100, lambdy=1, seed=None, name="culo"):
78+
A = nx.to_numpy_matrix(G)
79+
n = A.shape[0]
80+
if seed is None:
81+
seed = random.sample(range(n), 1)[0]
82+
if dist == "turbo":
83+
M, t = optimize(A, True)
84+
if dist == "plain":
85+
M, t = optimize(A, False)
86+
if dist == "tree":
87+
M, t = spanning_tree(A, seed)
88+
89+
print(f"Simulating on {name}, {dist} distribution on graph with {n} nodes, seed {seed}")
90+
sched = tq.EventScheduler()
91+
S = {}
92+
93+
for i in range(n):
94+
S[i] = 0 # last packet received timestamp
95+
sched.schedule_event(1./(alpha*t[i]), (i, M, t, S, sched, alpha))
96+
97+
sched.schedule_event(lambdy, (-1,))
98+
99+
while sched.elapsed_time() < duration:
100+
e = sched.pop_event()
101+
if e[0] == -1:
102+
S[seed] = sched.elapsed_time()
103+
sched.schedule_event(lambdy, (-1,))
104+
elif e[0] == -2:
105+
if S[e[1]] < e[2]:
106+
S[e[1]] = e[2]
107+
f.write(f"{seed},{sched.elapsed_time()},{e[1]},{S[e[1]]},{dist},{el}\n")
108+
else:
109+
sending_attempt(e, f, seed)
110+
111+
if __name__ == "__main__":
112+
duration = 100
113+
input_list = []
114+
pool = mp.Pool(8)
115+
with open("ifloods.data", "w") as f:
116+
f.write("seed,time,node,last_creat_ts,strategy,name\n")
117+
for folder in ["topos/"]:
118+
for el in os.listdir(folder):
119+
if el.endswith(".edges"):
120+
G = nx.read_weighted_edgelist(folder + el)
121+
n = len(G.nodes())
122+
for seed in range(3): # random.sample(range(n), 10):
123+
simulate_flooding(G, "turbo", f, seed=seed, duration=duration, name=el.split('.')[0])
124+
simulate_flooding(G, "plain", f, seed=seed, duration=duration, name=el.split('.')[0])

img/aoi_preproc.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env python
2+
3+
import sys
4+
import pandas as pd
5+
import numpy as nm
6+
7+
8+
def data_preproc(pivot, measure, name):
9+
data = pd.read_csv("../ifloods_aoi.data")
10+
# seed,node,mean_aoi,mean_peak_aoi,strategy
11+
dd = data[data["graph"] == name]
12+
data_p = dd[dd["strategy"] == "plain"]
13+
data_t = dd[dd["strategy"] == "turbo"]
14+
rows = []
15+
for seed in set(dd[pivot]):
16+
part = data_p[data_p[pivot] == seed][measure]
17+
meanplain = part.mean()
18+
minplain = part.min()
19+
maxplain = part.max()
20+
plain10p = nm.percentile(part, 10)
21+
plain90p = nm.percentile(part, 90)
22+
23+
part = data_t[data_t[pivot] == seed][measure]
24+
meanturbo = part.mean()
25+
minturbo = part.min()
26+
maxturbo = part.max()
27+
turbo10p = nm.percentile(part, 10)
28+
turbo90p = nm.percentile(part, 90)
29+
30+
rows.append({"graph": name, pivot: seed, "minplain": minplain, "10pplain": plain10p, "meanplain": meanplain, "90pplain": plain90p, "maxplain": maxplain,
31+
"minturbo": minturbo, "10pturbo": turbo10p, "meanturbo": meanturbo, "90pturbo": turbo90p, "maxturbo": maxturbo})
32+
f = pd.DataFrame(rows)
33+
f.sort_values(by=["meanturbo"], inplace=True)
34+
f = f[::2]
35+
36+
print(f"graph,seed,minplain,plain10p,meanplain,plain90p,maxplain,minturbo,turbo10p,meanturbo,turbo90p,maxturbo")
37+
for index, row in f.iterrows():
38+
print(f"{row['graph']},{row[pivot]},{row['minplain']},{row['10pplain']},{row['meanplain']},{row['90pplain']},{row['maxplain']},{row['minturbo']},{row['10pturbo']},{row['meanturbo']},{row['90pturbo']},{row['maxturbo']}")
39+
40+
if __name__ == "__main__":
41+
target = "sender"
42+
measure = "mean_aoi"
43+
name = "100_384_PL_0.edges"
44+
if len(sys.argv) > 1:
45+
target = sys.argv[1]
46+
if len(sys.argv) > 2:
47+
measure = sys.argv[2]
48+
if len(sys.argv) > 3:
49+
measure = sys.argv[3]
50+
51+
if target == "sender":
52+
data_preproc("seed", measure, name)
53+
elif target == "receiver":
54+
data_preproc("node", measure, name)

img/colors.gnuplot

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
C1 = "#0003ff";
2+
C2 = "#00bfff";
3+
C3 = "#4fffff";
4+
C4 = "#00000a";
5+
6+
#C1 = "#ff0300";
7+
#C2 = "#bfff00";
8+
#C3 = "#4fffff";
9+
#C4 = "#00000a";

img/conf_interval.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash
2+
3+
import sys
4+
import pandas as pd
5+
import numpy as np
6+
import scipy as sp
7+
import scipy.stats
8+
9+
10+
def mean_confidence_interval(data, confidence=0.99):
11+
a = 1.0*np.array(data)
12+
n = len(a)
13+
m, se = np.mean(a), scipy.stats.sem(a)
14+
h = se * sp.stats.t._ppf((1+confidence)/2., n-1)
15+
return m, m-h, m+h
16+
17+
18+
if __name__ == "__main__":
19+
data = pd.read_csv(sys.argv[1])
20+
ind_var = (sys.argv[2])
21+
dep_var = (sys.argv[3])
22+
23+
print("id,mean,leftint,rightint")
24+
for iv in sorted(set(data[ind_var])):
25+
part = data[data[ind_var] == iv]
26+
conf = mean_confidence_interval(np.array(part[dep_var]))
27+
print("{},{}".format(iv, ",".join([str(v) for v in conf])))

img/generic.gnuplot

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
reset
2+
load 'colors.gnuplot'
3+
# set terminal postscript eps enhanced solid "Helvetica" 20
4+
set terminal pdfcairo enhanced font "Helvetica,18"
5+
# set terminal pdf enhanced dashed
6+
# set termoption linewidth 3 font "Helvetica, 14"
7+
set datafile separator ","
8+
set lmargin 8
9+
set rmargin 2
10+
11+
ptpbound(x) = real(system(sprintf("./p2p_bound.py %f", x)))
12+
lower_bound(x) = real(system(sprintf("./lower_bound.py %f", x)))
13+
upper_bound(x) = real(system(sprintf("./upper_bound.py %f", x)))
14+
seed_turbo_average(x) = real(system(sprintf("cat %s | python perc_interval.py /dev/stdin seed_pos turbo_time | awk -F ',' 'BEGIN{sum=0;n=0}{sum+=$2;n+=1}END{print sum/n;}'", x)))

img/ifloods_aoi.gnuplot

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
load 'generic.gnuplot'
2+
3+
bound_mean(x) = real(system(sprintf("./upper_bound.py %f", x))) + 0.5
4+
bound_peak(x) = real(system(sprintf("./upper_bound.py %f", x))) + 1
5+
6+
set termoption lw 3
7+
set boxwidth 0.1
8+
9+
set style fill solid
10+
11+
set key over
12+
set xrange[0.5:3.5]
13+
14+
set ylabel "{/Symbol @^{/=35-}D} (cycles)" font ", 18" offset 1.0,0
15+
set xlabel "Graph ID"
16+
17+
set xtics (1,2,3)
18+
set output 'ifloods_mean_aoi.pdf'
19+
plot "< cat ../ifloods_aoi.data |awk '/strategy|plain/{print}' | python perc_interval.py /dev/stdin graph mean_aoi"\
20+
using ($0-0.15):3:2:6:5 lc rgb C3 with candlesticks title '{/Symbol @^{/=35-}D}, SE_f' whiskerbars,\
21+
"< cat ../ifloods_aoi.data |awk '/strategy|turbo/{print}' | python perc_interval.py /dev/stdin graph mean_aoi"\
22+
using ($0+0.15):3:2:6:5 lc rgb C4 with candlesticks title '{/Symbol @^{/=35-}D}, RE_f' whiskerbars,\
23+
bound_mean(x) with lines lc rgb C1 title "{/Symbol g}"
24+
25+
unset xtics
26+
set xtics
27+
set terminal pdfcairo enhanced font "Helvetica,10" size 5,1.5
28+
29+
set lmargin 3
30+
set rmargin 1
31+
32+
set tics scale 0
33+
34+
set xrange[0:51]
35+
set termoption lw 1
36+
set boxwidth 0.25
37+
38+
set style fill solid
39+
unset ylabel
40+
41+
#set ylabel "Mean AoI (cycles)" font ", 12" offset 1.0,0
42+
set xlabel "Sender"
43+
set output 'ifloods_mean_aoi_senders.pdf'
44+
plot "< python3 aoi_preproc.py sender mean_aoi"\
45+
using ($0-0.25):4:3:7:6 lc rgb C3 with candlesticks title '{/Symbol @^{/=20-}D}, SE_f' whiskerbars,\
46+
"" using ($0+0.25):9:8:12:11 lc rgb C4 with candlesticks title '{/Symbol @^{/=20-}D}, RE_f' whiskerbars,\
47+
bound_mean(100) with lines lc rgb C1 title "{/Symbol g} "
48+
49+
set xlabel "Receiver"
50+
set output 'ifloods_mean_aoi_receivers.pdf'
51+
plot "< python3 aoi_preproc.py receiver mean_aoi"\
52+
using ($0-0.25):4:3:7:6 lc rgb C3 with candlesticks title '{/Symbol @^{/=20-}D}, SE_f' whiskerbars,\
53+
"" using ($0+0.25):9:8:12:11 lc rgb C4 with candlesticks title '{/Symbol @^{/=20-}D}, RE_f' whiskerbars,\
54+
bound_mean(100) with lines lc rgb C1 title "{/Symbol g}"
55+
56+
#set ylabel "Mean Peak AoI (cycles)" font ", 12" offset 1.0,0
57+
58+
set xlabel "Sender"
59+
set output 'ifloods_mean_peak_aoi_senders.pdf'
60+
plot "< python3 aoi_preproc.py sender mean_peak_aoi"\
61+
using ($0-0.25):4:3:7:6 lc rgb C2 with candlesticks title 'Mean peak AoI, plain' whiskerbars,\
62+
"" using ($0+0.25):9:8:12:11 lc rgb C1 with candlesticks title 'Mean peak AoI, turbo' whiskerbars,\
63+
bound_peak(100) with lines lc rgb C4 title "AoI stochastic bound"
64+
65+
set xlabel "Receiver"
66+
set output 'ifloods_mean_peak_aoi_receivers.pdf'
67+
plot "< python3 aoi_preproc.py receiver mean_peak_aoi"\
68+
using ($0-0.25):4:3:7:6 lc rgb C2 with candlesticks title 'Mean peak AoI, plain' whiskerbars,\
69+
"" using ($0+0.25):9:8:12:11 lc rgb C1 with candlesticks title 'Mean peak AoI, turbo' whiskerbars,\
70+
bound_peak(100) with lines lc rgb C4 title "AoI stochastic bound"

0 commit comments

Comments
 (0)