1

I am using the "mesa" library of Python to define an agent based model simulate rebellion action under censorship enviroment. Right now the model is built and successfully shown in interface, but unfortunately agents in my model can not move. I don't know whether it's because the math equation I designed has problem or it's coding logic has something wrong.

As a sociology student I'm desperate about current situationa, would someone please hlep me with it! Thank you from the bottom of my heart!

Frist of all, there are information spys and citizens in our model, and citzens possess 6 variables:

1.self.information, denote information citizen possesed at begening

2.self.censorship, they can sense the hardness of information censorship and its equally percived by all citizens

3.self.vision is the number of neighbours agent could see, it is setted as 7

  1. self.risk_preference, their risk preferenct toward rebellion act, it setted as normally randomly distributed to each citizens

5.self.shareinfo_prob,citizens information sharing problility is influenced by censorship, denoted as self.information * (1 - self.censorship)

6.self.punished_prob, to join rebellion act, they first measure their probability get punished by information, it has somthing to do with spy/rebellion citizens ratio.

7.self.sympathy, citizens sympathy towards others, it is ralte with the number of punished neighbour they could see multiple the information they could gathered from their neighbours

citizen has three status: normal citizen, rebellion citizen, punished citizen, the trasfer depends on calculation : sympathy -punished_prob+ shareinfo_prob, if the value > risk_preference, normal citizens turn into rebellion citizens

Spy won't change in our model, it walk around and punish rebellion citizens.

class Citizen (Agent):
def __init__(
    self,
    unique_id,
    model,
    pos,
    vision,
    risk_preference,
    information,
    censorship,
):
    
    super().__init__(unique_id, model)
    self.breed = "citizen"
    self.pos = pos
    self.information = random.normal(loc=0.5)
    self.censorship = censorship
    self.risk_preference = risk_preference
    self.condition = "normal citizen"
    self.vision = vision
    self.punishment_sentence = 0
    self.shareinfo_prob = self.information * (1 - self.censorship)
    self.punished_prob = None
    self.sympathy = self.update_sympathy()

"""
behavior 
"""
def step(self):
    """
    Decide whether to join rebellion acts, then move if applicable.
    """
    if self.punishment_sentence:
        self.punishment_sentence -= 1
        return  # no other changes or movements if agent is in punishment
    self.update_neighbors()
    self.update_estimated_punish_probability()
  #  print(f'{type(self.sympathy)=}')
  #  print(f'{type(self.punished_prob)=}')
  #  print(f'{type(self.shareinfo_prob)=}')
  #  print(f'{type(self.risk_preference)=}') 
    if (self.update_sympathy- self.punished_prob+ self.shareinfo_prob) > self.risk_preference:
        self.condition = "rebellion"
    else:
        self.condition = "normal citizen"
    if self.model.movement and self.empty_neighbors:
        new_pos = self.random.choice(self.empty_neighbors)
        self.model.grid.move_agent(self, new_pos)

def update_neighbors(self):
    """
    Look around and see who my neighbors are
    """
    self.neighborhood = self.model.grid.get_neighborhood(
        self.pos, moore=False, radius=1
    )
    self.neighbors = self.model.grid.get_cell_list_contents(self.neighborhood)
    self.empty_neighbors = [
        c for c in self.neighborhood if self.model.grid.is_cell_empty(c)
    ]

def update_estimated_punish_probability(self):
    """
    Based on the ratio of sps to rebellion citizen in my neighborhood, estimate the
    p(Punishment | I join collective action)=slf.punished_prob
    """
    spys_in_vision = len([c for c in self.neighbors if c.breed == "spy"])
    rebellions_in_vision = 1.0  # citizen counts herself
    for c in self.neighbors:
        if (
            c.breed == "citizen"
            and c.condition == "rebellion"
            and c.punishment_sentence == 0
        ):
            rebellions_in_vision += 1
    self.punished_prob = 1 - math.exp(
        -1 * self.model.punishment_prob_constant * (spys_in_vision / rebellions_in_vision)
    )

def update_sympathy(self):
    self.update_neighbors()
    normal_neighbors = []
    for agent in self.neighbors:
        if (
            agent.breed == "citizen"
            and agent.condition == "normal citizen"
            and agent.punishment_sentence == 0
        ):
            normal_neighbors.append(agent)
    punished_in_vision = 0.0
    for c in self.neighbors:
        if (
                c.breed == "normal citizen"
                and c.condition  == "punished"
                and c.punishment_sentence == 0
        ):
            punished_in_vision += 1
    self.sympathy =1 - math.exp(-1*normal_neighbors.shareinfo_prob*punished_in_vision)

class Spy(Agent):
def __init__(self, unique_id, model, pos, vision):
    """
    Create a new Spy.
    Args:
        unique_id: unique int
        x, y: Grid coordinates
        vision: number of cells in each direction (N, S, E and W) that
            agent can censor. Exogenous.
        model: model instance
    """
    super().__init__(unique_id, model)
    self.breed = "spy"
    self.pos = pos
    self.vision = vision

def step(self):
    """
    Inspect local vision and punish a random active agent. Move if
    applicable.
    """
    self.update_neighbors()
    rebellion_neighbors = []
    for agent in self.neighbors:
        if (
            agent.breed == "citizen"
            and agent.condition == "rebellion"
            and agent.punishment_sentence == 0
        ):
            rebellion_neighbors.append(agent)
    if rebellion_neighbors:
        punishcollective = self.random.choice(rebellion_neighbors)
        sentencecollective = self.random.randint(0, self.model.max_punishment_term)
        punishcollective.punishment_sentence = sentencecollective
    if self.model.movement and self.empty_neighbors:
        new_pos = self.random.choice(self.empty_neighbors)
        self.model.grid.move_agent(self, new_pos)

def update_neighbors(self):
    """
    Look around and see who my neighbors are.
    """
    self.neighborhood = self.model.grid.get_neighborhood(
        self.pos, moore=False, radius=1
    )
    self.neighbors = self.model.grid.get_cell_list_contents(self.neighborhood)
    self.empty_neighbors = [
        c for c in self.neighborhood if self.model.grid.is_cell_empty(c)
    ]


from mesa import Model
from mesa.time import RandomActivation
from mesa.space import Grid
from mesa.datacollection import DataCollector
class Sympathy_CA(Model):
def __init__(
    self,
    height=40,
    width=40,
    citizen_density=0.7,
    spy_density=0.074,
#citizen vision should be adjustable
    citizen_vision=7,
    spy_vision=7,
    max_punishment_term=1000,
    punishment_prob_constant=2.3,
    censorship=0.8,
    movement=True,
    max_iters=1000,
):
    super().__init__()
    self.height = height
    self.width = width
    self.citizen_density = citizen_density
    self.spy_density = spy_density
    self.citizen_vision = citizen_vision
    self.spy_vision = spy_vision
    self.max_punishment_term = max_punishment_term
    self.punishment_prob_constant = punishment_prob_constant
    self.censorship = censorship
    self.movement = movement
    self.max_iters = max_iters
    self.iteration = 0
    self.schedule = RandomActivation(self)
    self.grid = Grid(height, width, torus=True)
    model_reporters = {
        "normal citizen": lambda m: self.count_type_citizens(m, "normal citizen"),
        "rebellion": lambda m: self.count_type_citizens(m, "rebellion"),
        "punished": lambda m: self.count_punished(m),
    }
    agent_reporters = {
        "x": lambda a: a.pos[0],
        "y": lambda a: a.pos[1],
        "breed": lambda a: a.breed,
        "punishment_sentence": lambda a: getattr(a, "punishment_sentence", None),
        "condition": lambda a: getattr(a, "condition", None),
        "punished_prob": lambda a: getattr(a, "punished_prob", None),
    }
    self.datacollector = DataCollector(
        model_reporters=model_reporters,
        agent_reporters=agent_reporters
    )
    unique_id = 0
    if self.spy_density + self.citizen_density > 1:
        raise ValueError("Spy density + citizen density must be less than 1")
    for (contents, x, y) in self.grid.coord_iter():
        #print(x)
        if self.random.random() < self.spy_density:
            spy = Spy(unique_id, self, (x, y), vision=self.spy_vision)
            unique_id += 1
            self.grid[y][x] = spy
            self.schedule.add(spy)
        elif self.random.random() < (self.spy_density + self.citizen_density):
            citizen = Citizen(
                unique_id,
                self,
                (x, y),
                vision=self.citizen_vision,
                risk_preference=random.normal(loc=0.5),
                information=random.normal(loc=0.5),
                censorship=self.censorship
            )
            unique_id += 1
            self.grid[y][x] = citizen
            self.schedule.add(citizen)
        self.running = True
    self.datacollector.collect(self)

def step(self):
    """
    Advance the model by one step and collect data.
    """
    self.schedule.step()
    self.datacollector.collect(self)
    self.iteration += 1
    if self.iteration > self.max_iters:
        self.running = False

@staticmethod
def count_type_citizens(model, condition, exclude_punished=True):
    """
    Helper method to count agents by rebellion/normal citizen
    """
    count = 0
    for agent in model.schedule.agents:
        if agent.breed == "spy":
            continue
        if exclude_punished and agent.punishment_sentence:
            continue
        if agent.condition == condition:
            count += 1
    return count

@staticmethod
def count_punished(model):
    """
    Helper method to count punished agents.
    """
    count = 0
    for agent in model.schedule.agents:
        if agent.breed == "citizen" and agent.punishment_sentence:
            count += 1
    return count

SPY_COLOR = "#000000"


from mesa.visualization.ModularVisualization import ModularServer
from mesa.visualization.UserParam import UserSettableParameter
from mesa.visualization.modules import CanvasGrid
def citizen_spy_portrayal(agent):
if agent is None:
    return

portrayal = {
    "Shape": "circle",
    "x": agent.pos[0],
    "y": agent.pos[1],
    "Filled": "true",
}

if type(agent) is Citizen:
    color = (
        AGENT_NORMAL_COLOR if agent.condition == "normal citizen" else AGENT_REBELLION_COLOR
    )
    color = PUNISHED_COLOR if agent.punishment_sentence else color
    portrayal["Color"] = color
    portrayal["r"] = 0.8
    portrayal["Layer"] = 0

elif type(agent) is Spy:
    portrayal["Color"] = SPY_COLOR
    portrayal["r"] = 0.5
    portrayal["Layer"] = 1
return portrayal

model_params = {
"height": 40,
"width": 40,
"censorship": UserSettableParameter(
    "slider",
    "censorship",
    0.8,
    0.1,
    1.0,
    0.1
),
"citizen_density": UserSettableParameter(
    "slider",
    "citizen_density",
    0.7,
    0.1,
    1.0,
    0.1
),
"spy_density": UserSettableParameter(
    "slider",
    "spy_density",
    0.074,
    0.001,
    0.300,
    0.001
),}

canvas_element = CanvasGrid(citizen_spy_portrayal, 40, 40, 480, 480)
server = ModularServer(Sympathy_CA,[canvas_element], "Sympathy_CA", model_params)

server.launch()

when I run this model, it shows:

  Socket opened!
  {"type":"reset"}
  WARNING:tornado.access:404 GET /favicon.ico (127.0.0.1) 1.02ms
  {"type":"get_step","step":1}
  ERROR:tornado.application:Uncaught exception GET /ws (127.0.0.1)
  HTTPServerRequest(protocol='http', host='127.0.0.1:8521', method='GET', uri='/ws', 
  version='HTTP/1.1', remote_ip='127.0.0.1')
  Traceback (most recent call last):
   File "C:\Users\ug\AppData\Local\Programs\Python\Python39\lib\site-packages\tornado\websocket.py", line 647, in _run_callback
  result = callback(*args, **kwargs)
File "C:\Users\ug\AppData\Local\Programs\Python\Python39\lib\site-packages\mesa\visualization\ModularVisualization.py", line 207, in on_message
  self.application.model.step()
File "d:\CAprogram\sympathy.py", line 261, in step
  self.schedule.step()
File "C:\Users\ug\AppData\Local\Programs\Python\Python39\lib\site-packages\mesa\time.py", line 127, in step
  agent.step()
File "d:\CAprogram\sympathy.py", line 53, in step
  if (self.update_sympathy- self.punished_prob+ self.shareinfo_prob) > self.risk_preference:
TypeError: unsupported operand type(s) for -: 'method' and 'float'

0 Answers0