Вирусы и питоны
Всё, что один человек написал, другой может переврать!
В прессе масса информации про разные вирусы — страшилки, наив, бесстрашие с безумием и откровенные роботексты, но проверить ничего из этого нельзя. Поэтому решил проверить сам как и какие параметры влияют на состояние, развитие и деградацию связной структуры и сделать выводы.
Перейдем к делу, у нас есть узлы(может это и люди) связанные между собой. Узлы деградируют/болеют и их можно лечить, изолировать в карантине, ну и они отключаются, увы иногда навсегда.
# количество тиков времени до попадания в карантин. # Или до выпадения из структуры компрометированного узла # т.е. узел скомпрометирован/болен, но это еще не обнаружено и он несколько тиков # времени продолжает заражать других 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, т.е. при страшной заразности и при минимуме общения массовой деградации нет. Десяток запусков конечно не статистика, но мне достаточно. А вот при infection_probably = 0.1 и max_conn = 40 погибает половина. Причем от величины quarantine это не зависит.
ссылка на оригинал статьи https://habr.com/ru/post/494092/