-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAlgorithm.py
193 lines (173 loc) · 5.29 KB
/
Algorithm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
from Event import InjectEvent, SentEvent, ErrorEvent
class LinkError(BaseException):
pass
class Algorithm:
algorithmType = "ALG"
def __init__(self, model):
self.sending, self.model = None, model
self.queue = dict((packet, 0) for packet in model.packets)
self.generator = self.generate()
def __lt__(self, other):
return False
def __str__(self):
return self.__class__.__name__
def notify(self, event):
if isinstance(event, InjectEvent):
self.queue[event.packet] += 1
elif isinstance(event, SentEvent) and event.algorithm == self:
self.sending = None
elif isinstance(event, ErrorEvent):
if self.sending: self.queue[self.sending] += 1
self.sending = None
self.error = event
def schedule(self):
assert not self.sending
packet = self.generator.__next__()
assert packet is None or self.queue[packet]
if packet: self.queue[packet] -= 1
self.sending = packet
return self.sending
class SL(Algorithm):
def generate(self):
while True:
send = ([packet for packet in self.model.packets if self.queue[packet]] or [None])[0]
yield send
class LL(Algorithm):
def generate(self):
while True:
send = ([packet for packet in reversed(self.model.packets) if self.queue[packet]] or [None])[0]
yield send
class SLPreamble(Algorithm):
def generate(self):
assert len(self.model.packets) == 2
gamma = int(self.model.packets[-1] / self.model.packets[0])
while True:
self.error = None
try:
if self.queue[self.model.packets[0]] >= gamma:
for _ in range(gamma):
if self.error: raise LinkError()
yield self.model.packets[0]
while True:
if self.error: raise LinkError()
send = ([packet for packet in reversed(self.model.packets) if self.queue[packet]] or [None])[0]
yield send
except LinkError:
pass
class CSLPreamble(Algorithm):
def generate(self):
assert len(self.model.packets) == 2
l1 = self.model.packets[0]
p = self.model.probability(l1)
# there should be smarter way to do it
return self.generate_SL() if self.model.rate * l1 * p > 0.5 else self.generate_SLPreamble()
def generate_SL(self):
while True:
send = ([packet for packet in self.model.packets if self.queue[packet]] or [None])[0]
yield send
def generate_SLPreamble(self):
assert len(self.model.packets) == 2
gamma = int(self.model.packets[-1] / self.model.packets[0])
while True:
self.error = None
try:
if self.queue[self.model.packets[0]] >= gamma:
for _ in range(gamma):
if self.error: raise LinkError()
yield self.model.packets[0]
while True:
if self.error: raise LinkError()
send = ([packet for packet in reversed(self.model.packets) if self.queue[packet]] or [None])[0]
yield send
except LinkError:
pass
class Greedy(Algorithm):
def generate(self):
stack, n = [], len(self.model.packets)
while True:
if self.totalLength(n) < self.model.packets[-1]:
yield None
else:
stack.append(n)
while stack:
j = stack.pop()
# print('transmitGroup', j)
if self.totalLength(j-1) >= self.model.packets[j-1]:
for _ in range(int(self.model.packets[j-1] / self.model.packets[j-2])):
stack.append(j-1)
else:
yield self.model.packets[j-1]
def totalLength(self, k):
return sum(map(lambda l: self.queue[l] * l, self.model.packets[:k]))
class Prudent(Algorithm):
def generate(self):
lk = self.model.packets[-1]
while True:
self.error = None
try:
toSend = self.selectToSend(lk, lk)
if not toSend:
yield None
else:
i = toSend[0]
if i < lk:
li1 = self.nextLonger(i)
for _ in range(int(li1/i)):
yield i
if self.error: raise LinkError()
lsent = li1
while lsent < lk:
j = self.selectToSend(lk - lsent, lsent)[-1]
lj1 = self.nextLonger(j)
for _ in range(int(lj1/j)):
yield j
if self.error: raise LinkError()
lsent = lsent + lj1
while True:
# LL
send = ([packet for packet in reversed(self.model.packets) if self.queue[packet]] or [None])[0]
yield send
if self.error: raise LinkError()
except LinkError:
pass
def selectToSend(self, lk, longest):
return [l for l in self.model.packets if l * self.queue[l] >= lk and l <= longest]
def nextLonger(self, li):
return self.model.packets[self.model.packets.index(li)+1]
class ESLPreamble(Algorithm):
def generate(self):
assert len(self.model.packets) == 3
l1, l2, l3 = self.model.packets
# gamma = int(self.model.packets[-1] / self.model.packets[0])
while True:
self.error = None
try:
# enough l1 to send l2
if self.queue[l1] * l1 >= l2:
for _ in range(int(l2/l1)):
yield l1
if self.error: raise LinkError()
# enough l1 and l2 to send l3
if self.queue[l1] * l1 + self.queue[l2] * l2 >= l3:
lsent = 0
while lsent < l3:
if self.queue[l1]:
lsent = lsent + l1
yield l1
else:
lsent = lsent + l2
yield l2
if self.error: raise LinkError()
# LL
while True:
if self.error: raise LinkError()
send = ([packet for packet in reversed(self.model.packets) if self.queue[packet]] or [None])[0]
yield send
except LinkError:
pass
class OnlySL(Algorithm):
def generate(self):
assert len(self.model.packets) == 2
l1, l2 = self.model.packets
while True:
yield l1 if self.queue[l1] else None