mirror of
https://github.com/gsi-upm/soil
synced 2024-11-14 23:42:29 +00:00
130 lines
4.1 KiB
Python
130 lines
4.1 KiB
Python
|
from soil.agents import FSM, NetworkAgent, state, default_state, prob
|
||
|
from soil.parameters import *
|
||
|
import logging
|
||
|
|
||
|
from soil.environment import Environment
|
||
|
|
||
|
|
||
|
class DumbViewer(FSM, NetworkAgent):
|
||
|
"""
|
||
|
A viewer that gets infected via TV (if it has one) and tries to infect
|
||
|
its neighbors once it's infected.
|
||
|
"""
|
||
|
|
||
|
has_been_infected: bool = False
|
||
|
has_tv: bool = False
|
||
|
|
||
|
@default_state
|
||
|
@state
|
||
|
def neutral(self):
|
||
|
if self.has_tv:
|
||
|
if self.prob(self.get("prob_tv_spread")):
|
||
|
return self.infected
|
||
|
if self.has_been_infected:
|
||
|
return self.infected
|
||
|
|
||
|
@state
|
||
|
def infected(self):
|
||
|
for neighbor in self.get_neighbors(state_id=self.neutral.id):
|
||
|
if self.prob(self.get("prob_neighbor_spread")):
|
||
|
neighbor.infect()
|
||
|
|
||
|
def infect(self):
|
||
|
"""
|
||
|
This is not a state. It is a function that other agents can use to try to
|
||
|
infect this agent. DumbViewer always gets infected, but other agents like
|
||
|
HerdViewer might not become infected right away
|
||
|
"""
|
||
|
self.has_been_infected = True
|
||
|
|
||
|
|
||
|
class HerdViewer(DumbViewer):
|
||
|
"""
|
||
|
A viewer whose probability of infection depends on the state of its neighbors.
|
||
|
"""
|
||
|
|
||
|
def infect(self):
|
||
|
"""Notice again that this is NOT a state. See DumbViewer.infect for reference"""
|
||
|
infected = self.count_neighbors(state_id=self.infected.id)
|
||
|
total = self.count_neighbors()
|
||
|
prob_infect = self.get("prob_neighbor_spread") * infected / total
|
||
|
self.debug("prob_infect", prob_infect)
|
||
|
if self.prob(prob_infect):
|
||
|
self.has_been_infected = True
|
||
|
|
||
|
|
||
|
class WiseViewer(HerdViewer):
|
||
|
"""
|
||
|
A viewer that can change its mind.
|
||
|
"""
|
||
|
|
||
|
@state
|
||
|
def cured(self):
|
||
|
prob_cure = self.get("prob_neighbor_cure")
|
||
|
for neighbor in self.get_neighbors(state_id=self.infected.id):
|
||
|
if self.prob(prob_cure):
|
||
|
try:
|
||
|
neighbor.cure()
|
||
|
except AttributeError:
|
||
|
self.debug("Viewer {} cannot be cured".format(neighbor.id))
|
||
|
|
||
|
def cure(self):
|
||
|
self.has_been_cured = True
|
||
|
|
||
|
@state
|
||
|
def infected(self):
|
||
|
if self.has_been_cured:
|
||
|
return self.cured
|
||
|
cured = max(self.count_neighbors(self.cured.id), 1.0)
|
||
|
infected = max(self.count_neighbors(self.infected.id), 1.0)
|
||
|
prob_cure = self.get("prob_neighbor_cure") * (cured / infected)
|
||
|
if self.prob(prob_cure):
|
||
|
return self.cured
|
||
|
|
||
|
|
||
|
class NewsSpread(Environment):
|
||
|
ratio_dumb: probability = 1,
|
||
|
ratio_herd: probability = 0,
|
||
|
ratio_wise: probability = 0,
|
||
|
prob_tv_spread: probability = 0.1,
|
||
|
prob_neighbor_spread: probability = 0.1,
|
||
|
prob_neighbor_cure: probability = 0.05,
|
||
|
|
||
|
def init(self):
|
||
|
self.populate_network([DumbViewer, HerdViewer, WiseViewer], [self.ratio_dumb, self.ratio_herd, self.ratio_wise])
|
||
|
|
||
|
|
||
|
from itertools import permutations
|
||
|
from soil import Simulation
|
||
|
|
||
|
|
||
|
# We want to investigate the effect of different agent distributions on the spread of news.
|
||
|
# To do that, we will run different simulations, with a varying ratio of DumbViewers, HerdViewers, and WiseViewers
|
||
|
# Because the effect of these agents might also depend on the network structure, we will run our simulations on two different networks:
|
||
|
# one with a small-world structure and one with a connected structure.
|
||
|
|
||
|
for [r1, r2, r3] in permutations([0, 0.5, 1.0], 3):
|
||
|
for (generator, netparams) in {
|
||
|
"barabasi_albert_graph": {"m": 5},
|
||
|
"erdos_renyi_graph": {"p": 0.1},
|
||
|
}.items():
|
||
|
print(r1, r2, r3, generator)
|
||
|
# Create new simulation
|
||
|
netparams["n"] = 500
|
||
|
sim = Simulation(
|
||
|
model=NewsSpread,
|
||
|
model_params={
|
||
|
"ratio_dumb": r1,
|
||
|
"ratio_herd": r2,
|
||
|
"ratio_wise": r3,
|
||
|
"network_generator": generator,
|
||
|
"network_params": netparams,
|
||
|
"prob_neighbor_spread": 0,
|
||
|
},
|
||
|
num_trials=50,
|
||
|
max_steps=300,
|
||
|
dry_run=True,
|
||
|
)
|
||
|
# Run all the necessary instances
|
||
|
sim.run()
|