mirror of
https://github.com/gsi-upm/soil
synced 2024-11-14 23:42:29 +00:00
73282530fd
All test pass, except for the TestConfig suite, which is not too critical as the plan for this version onwards is to avoid configuration as much as possible.
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()
|