Вирусы и питоны
Всё, что один человек написал, другой может переврать!
В прессе масса информации про разные вирусы — страшилки, наив, бесстрашие с безумием и откровенные роботексты, но проверить ничего из этого нельзя. Поэтому решил проверить сам как и какие параметры влияют на состояние, развитие и деградацию связной структуры и сделать выводы.
Перейдем к делу, у нас есть узлы(может это и люди) связанные между собой. Узлы деградируют/болеют и их можно лечить, изолировать в карантине, ну и они отключаются, увы иногда навсегда.
# количество тиков времени до попадания в карантин.
# Или до выпадения из структуры компрометированного узла
# т.е. узел скомпрометирован/болен, но это еще не обнаружено и он несколько тиков
# времени продолжает заражать других
quarantine = 2
# если после стольких дней узел не исправлен - удаляем окончательно
dead = 14
# вероятность деградации узла, заражения здорового, появления вируса и т.д.
# за один тик времени при общении с зараженным узлом вне карантина
infection_probably = 0.5
# вероятность починки узла, выздоровления больного,
# исчезновения вируса и т.д. за один тик времени
pr_recover = 0.5
# число узлов/жителей
w_size = 1024 * 32
# связность, пытаемся создать у каждого узла не более max_conn связей
max_conn = 6
import numpy as np
from tqdm import tqdm
map_conn = []
# храним тут состояние узла. =0 исправен, >0 но <quarantine то заразен
# и не изолирован, >quarantine то изолирован, >dead - отключен
# <0 - вылечен и обладает иммунитетом/патч применен
map_stat = np.zeros((w_size), dtype="int16")
# храним связную структуру в виде списка списков связности.
# Т.е. map_conn[i] - список с номерами узлов связанных с узлом i
for i in range(w_size):
map_conn.append([])
for i in tqdm(range(w_size)):
t = np.random.randint(0, max_conn//2)
tt = np.random.randint(0, w_size, (t))
for j in tt:
map_conn[i].append(j)
map_conn[j].append(i)
for i in range(w_size):
map_conn[i] = list(set(map_conn[i]))
# очевидно, что возможно и больше max_conn связей.
# Мы создаем случайно для каждого узла max_conn//2 связей,
# но связность симметрична.
# состояние узла. Если 0 то здоров, если <0 переболел, восстановлен и
# не будет больше болеть
# если >0 то инфицирован/деградирует, если >quarantine, то в изоляции
# если >dead отключен окончательно, увы.
map_stat[:] = 0
# в начале все здоровы
map_stat[np.random.randint(1, w_size)] = 1
# случайный узел деградировал, первый день деградации.
day = 1
print("map num ", w_size)
while True:
tmp_map_conn = map_conn.copy()
tmp_map_stat = map_stat.copy()
# тут сохраняем структуру во временное хранилище и
# начнем вычислять новое состояние
for i in range(w_size):
# если узел был инфицирован и восстановлен.
# Болел - выздоровел/патч накатили - иммунитет
# состояние сохраняется
if tmp_map_stat[i] < 0:
map_stat[i] = tmp_map_stat[i]
continue
# если узел был инфицирован и более чем quarantine тиков времени/дней
# увеличиваем счетчик тиков на 1
if tmp_map_stat[i] >= quarantine:
map_stat[i] = tmp_map_stat[i] + 1
continue
# если узел был инфицирован и менее чем quarantine тиков времни/дней
# то он выздоравливает с вероятностью pr_recover
# или счетчик тиков деградации увеличивается на один
if tmp_map_stat[i] > 0:
if np.random.rand() < pr_recover:
map_stat[i] = -tmp_map_stat[i]
else:
map_stat[i] = tmp_map_stat[i] + 1
# если узел в деградации больше quarantine тиков,
# то наверно это обнаружится и узел изолируют и начнут восстанавливать
# и все его связи исчезнут и связи с ним тоже
if map_stat[i] >= quarantine:
for j in tmp_map_conn[i]:
if i in map_conn[j]:
map_conn[j].remove(i)
map_conn[i] = []
continue
# если узел здоров, то в общении со своим контактом может
# заразиться с вероятностью infection_probably
if tmp_map_stat[i] == 0:
map_stat[i] = 0
for j in tmp_map_conn[i]:
t = np.random.rand()
if (
t < infection_probably
and tmp_map_stat[j] > 0
and tmp_map_stat[j] < quarantine
):
map_stat[i] = 1
break
# считаем число элементов до 0, от 0 до quarantine
# от quarantine до dead
immun = np.count_nonzero(map_stat < 0)
quar = np.count_nonzero((map_stat >= quarantine) & (map_stat < dead))
dead_s = np.count_nonzero(map_stat >= dead)
infl = np.sum((map_stat > 0) & (map_stat < dead))
print(
"day {0:3d} infl {1:6d} immun {2:6d} quarantine {3:6d} dead {4:6d}".format(
day, infl, immun, quar, dead_s
)
)
# если больных нет, считать прекращаем
if infl == 0:
break
# и так далее
day += 1
Тут самое время сказать — ну и что, что такого могут открыть десяток строк питона!
Мне же результат был интересен и полезен.
Получилось вот что (и был бы рад, если кто проверит и ткнет в ошибку): при infection_probably = 0.9 и max_conn = 4, т.е. при страшной заразности и при минимуме общения — 4 контакта в день — массовой деградации нет. Десяток запусков конечно не статистика, но мне достаточно.
А вот при infection_probably = 0.1 и max_conn = 40 погибает половина. Т.е. слабозаразная напасть при большой связности сообщества губит половину её членов. Причем от величины quarantine это не зависит.
Специально для сайта ITWORLD.UZ. Новость взята с сайта Хабр