-
Notifications
You must be signed in to change notification settings - Fork 1
/
VaccineModel.py
252 lines (201 loc) · 8.05 KB
/
VaccineModel.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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
import random
import numpy as np
import sys
import time
SUSCEPTIBLE = 0
INFECTED = 1
VACCINATED = 2
CURED = 3
DEATH = 4
def RNG(probability):
return random.random() < probability
class VaccineModel(object):
"""docstring for VaccineModel."""
def __init__(self, parametres = {}, size = [50,50], parent=None):
self.running = True
self.parent = parent
self.X, self.Y = size
self.parametres = parametres
self.createSets()
self.applyDefaultParametres()
self.population = np.full((self.Y, self.X), SUSCEPTIBLE)
self.maxInfected = 0
def setIndexState(self, index, state):
self.population[index[0]][index[1]] = state
def getIndexState(self, index):
return self.population[index[0]][index[1]]
def checkIndexState(self, index, state):
return self.population[index[0]][index[1]] == state
def clear(self):
self.running = True
self.maxInfected = 0
self.createSets()
self.population = [[SUSCEPTIBLE for i in range(self.X)] for j in range(self.Y)]
def createSets(self):
self.susceptibles = set()
#Tout le monde est susceptible au départ
for i in range(self.X):
for j in range(self.Y):
self.susceptibles.add((i,j))
self.vaccinated = set()
self.infected = set()
def buildFirstFrame(self):
self.vaccinatePopulation()
self.infectI0Susceptibles()
def changeParam(self, parametres = {}):
#prend un dictionnaire en parametres et change les valeurs de prob
self.parametres = parametres
self.applyDefaultParametres()
def applyDefaultParametres(self):
defaults =\
{'probVaccine' : 0.5,\
'probInfect' : 1,\
'probCure' : 0.13,\
'probGlobal': 1/(1000),\
'probDeath' : 0.05,\
'maxTime' : 50,\
'I0' : 1\
}
for elem in defaults.keys():
if elem not in self.parametres:
self.parametres[elem] = defaults[elem]
def cureSquare(self, ij):
self.infected.remove(ij)
self.vaccinated.add(ij)
self.setIndexState(ij, CURED)
return True
def deathSquare(self,ij):
self.infected.remove(ij)
self.setIndexState(ij, DEATH)
return True
def vaccinateSquare(self, ij):
self.vaccinated.add(ij)
self.susceptibles.remove(ij)
self.setIndexState(ij, VACCINATED)
return True
def infectSquare(self, ij):
if self.checkIndexState(ij, SUSCEPTIBLE): #infecte que le sus
self.susceptibles.remove(ij)
self.infected.add(ij)
self.setIndexState(ij, INFECTED)
self.maxInfected += 1
return True
return False
def vaccinatePopulation(self):
susceptibles = list(self.susceptibles)
random.shuffle(susceptibles)
#Nombre total de gens vacciné
toVaccine = int(self.parametres['probVaccine']*(self.X*self.Y))
for count in range(toVaccine):
self.vaccinateSquare(susceptibles.pop())
def infectI0Susceptibles(self):
susceptibles = list(self.susceptibles)
random.shuffle(susceptibles)
#Nombre total de gens vacciné
for count in range(self.parametres['I0']):
self.infectSquare(susceptibles.pop())
def spreadGlobal(self):
probGlobalDenominateur = self.parametres['probGlobal']**(-1)
probGlobal = len(self.infected)/probGlobalDenominateur
if RNG(probGlobal):
if len(self.susceptibles) >= 1:
#sample renvoie une list mais on sample que de 1 donc on prend le premier elem
return random.sample(self.susceptibles, 1)
return []
def spread(self):
if self.running:
susBefore = len(self.susceptibles)
#D'abord on soigne les infectés
stackToCure = []
stackToKill = []
stackToInfect = []
if self.parametres['probCure']:
stackToCure = self.cureIteration()
for futureCured in stackToCure:
self.cureSquare(futureCured)
if self.parametres['probDeath']:
stackToKill = self.deathIteration()
for futureDeath in stackToKill:
self.deathSquare(futureDeath)
#choisi les infectés
if len(self.infected) >= len(self.susceptibles):
stackToInfect = self.spreadFromSus()
else:
stackToInfect = self.spreadFromInf()
#puis globalement
stackToInfect = stackToInfect + self.spreadGlobal()
#puis les choisi sont infectés
for futureInfected in stackToInfect:
self.infectSquare(futureInfected)
if len(sys.argv) >= 3 and sys.argv[1] == "testing":
self.running = (len(self.infected) > 0) and len(self.susceptibles) != susBefore
else:
self.running = (len(self.infected) > 0)
#Si fin du spreading, on affiche les résultats
if not self.running:
self.printEnd()
return self.running
def spreadFromSus(self):
stack = []
for cleanGuy in self.susceptibles:
for neighbour in self.neighbours(cleanGuy):
if self.getIndexState(neighbour) == INFECTED and RNG(self.parametres['probInfect']):
stack.append(cleanGuy)
return stack
def spreadFromInf(self):
stack = []
for infected in self.infected:
for neighbour in self.neighbours(infected):
if RNG(self.parametres['probInfect']):
stack.append(neighbour)
return stack
def cureIteration(self):
stack = []
for infected in self.infected:
if RNG(self.parametres['probCure']):
stack.append(infected)
return stack
def deathIteration(self):
stack = []
for infected in self.infected:
if RNG(self.parametres['probDeath']):
stack.append(infected)
return stack
def printEnd(self):
nombreSainDépart = self.X*self.Y
nombreVacciné = int(self.parametres['probVaccine']*(self.X*self.Y))
nombreSain = len(self.susceptibles)
nombreGueri = self.maxInfected
self.trueResults = nombreSain
self.results = f"Dans une population vaccinée à {self.parametres['probVaccine']*100}%\n"
self.results += f"Parmis les {nombreSain+nombreGueri} personnes susceptibles d'être touchées au départ \n"
self.results += f"{100-100*nombreSain/(nombreSain+nombreGueri)}% ont été touchés par l'infection\n"
if not self.running:
if self.parent != None and self.parent.parent != None:
self.parent.parent.setEndMessage(self.results)
def neighbours(self, ij):
mostUp = max(ij[0]-1, 0)
mostRight = min(ij[1]+1, self.X-1)
mostDown = min(ij[0]+1, self.Y-1)
mostLeft = max(ij[1]-1, 0)
return ( (mostUp, mostLeft) , (mostUp, ij[1]) , (mostUp, mostRight),
(ij[0], mostLeft) , (ij[0], ij[1]) , (ij[0] , mostRight),
(mostDown, mostLeft), (mostDown, ij[1]), (mostDown, mostRight))
if __name__ == '__main__' and len(sys.argv) >= 3 and sys.argv[1] == "testing":
outputFileName = sys.argv[2]
nbIter = 1000
for vaccineProb in range(100):
first = time.time()
print(vaccineProb)
average = 0
for i in range(nbIter):
simulation = VaccineModel({'probVaccine' : vaccineProb/100, 'probDeath' : 0, 'probCure' : 0})
simulation.buildFirstFrame()
while simulation.spread():
pass
average += simulation.trueResults
print(i, time.time()-first)
with open(outputFileName, 'a+') as fichier:
fichier.write(str(average/nbIter) + '\n')
print(f"L'itération à pris {time.time()-first}")
print(f"Temps restant : {(100-vaccineProb)*(time.time()-first)}")