From f53f7f08438185c1d135412b2534893a73367895 Mon Sep 17 00:00:00 2001 From: Italo Amaral Date: Mon, 29 Dec 2025 19:36:36 -0300 Subject: [PATCH 1/2] Adding a new example into the folder --- examples/ideology_diffusion/Readme.md | 27 +++++++++++++ examples/ideology_diffusion/__init__.py | 0 examples/ideology_diffusion/agents.py | 31 +++++++++++++++ examples/ideology_diffusion/app.py | 47 +++++++++++++++++++++++ examples/ideology_diffusion/model.py | 51 +++++++++++++++++++++++++ 5 files changed, 156 insertions(+) create mode 100644 examples/ideology_diffusion/Readme.md create mode 100644 examples/ideology_diffusion/__init__.py create mode 100644 examples/ideology_diffusion/agents.py create mode 100644 examples/ideology_diffusion/app.py create mode 100644 examples/ideology_diffusion/model.py diff --git a/examples/ideology_diffusion/Readme.md b/examples/ideology_diffusion/Readme.md new file mode 100644 index 000000000..d14f29095 --- /dev/null +++ b/examples/ideology_diffusion/Readme.md @@ -0,0 +1,27 @@ +# Ideological Diffusion Under Economic Stress + +--- + +## Overview + +Historical analysis reveals that authoritarian regimes often gain momentum by exploiting acute **socio-economic crises**. These movements leverage public dissatisfaction to shift political paradigms and consolidate power by convincing the population that radical measures are the only solution to systemic failures. + +This **Agent-Based Model (ABM)** simulates how a population, when faced with adverse conditions such as high unemployment and economic instability, becomes vulnerable to extremist influence. The model explores the transition from neutral or moderate positions to radical ideologies, highlighting how external stressors and propaganda can drive political alignment—often as a desperate response to environmental pressure. + +--- + +## Key Features + +* **Ideological Evolution:** Agents move through three stages (Neutral, Moderate, and Radical) based on cumulative pressure. +* **Socio-Economic Stressors:** Global variables like economic crises and unemployment rates act as catalysts for dissatisfaction. +* **Media Influence:** Simulates the impact of propaganda based on individual susceptibility. +* **State Dynamics:** Includes government repression logic, which can either suppress or inadvertently accelerate radicalization (the "backfire effect"). + +--- + +## How to Run + +To run the model interactively, ensure you have `mesa` and `solara` installed, then run the following command in the project root: + +```bash +solara run app.py \ No newline at end of file diff --git a/examples/ideology_diffusion/__init__.py b/examples/ideology_diffusion/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/examples/ideology_diffusion/agents.py b/examples/ideology_diffusion/agents.py new file mode 100644 index 000000000..927e62eee --- /dev/null +++ b/examples/ideology_diffusion/agents.py @@ -0,0 +1,31 @@ +from mesa import Agent + + +class Person(Agent): + def __init__(self, model, opinion="neutral"): + super().__init__(model) + self.opinion = opinion + self.resistance = self.random.uniform(0.2, 0.8) + self.susceptibility = self.random.uniform(0.0, 1.0) + + def step(self): + # External pressure + external_pressure = ( + self.model.economic_crisis + self.model.propaganda + ) * self.susceptibility + + # Social pressure + neighbors = self.model.grid.get_neighbors(self.pos, moore=True) + if neighbors: + radicals = sum(1 for n in neighbors if n.opinion == "radical") + social_pressure = radicals / len(neighbors) + else: + social_pressure = 0 + + influence = external_pressure + social_pressure - self.resistance + + if influence > 0.4: + if self.opinion == "neutral": + self.opinion = "moderate" + elif self.opinion == "moderate": + self.opinion = "radical" diff --git a/examples/ideology_diffusion/app.py b/examples/ideology_diffusion/app.py new file mode 100644 index 000000000..995e695d6 --- /dev/null +++ b/examples/ideology_diffusion/app.py @@ -0,0 +1,47 @@ +import solara +from model import IdeologyModel + +from mesa.experimental.solara_viz import ( + SolaraViz, + make_plot_component, + make_space_component, +) + + +def agent_portrayal(agent): + color = { + "neutral": "gray", + "moderate": "orange", + "radical": "red", + }[agent.opinion] + + return { + "color": color, + "size": 40, + } + + +model_params = { + "N": solara.SliderInt(10, 300, value=120, label="Population"), + "economic_crisis": solara.SliderFloat(0.0, 1.0, value=0.5, label="Economic Crisis"), + "propaganda": solara.SliderFloat(0.0, 1.0, value=0.2, label="Propaganda"), +} + +space = make_space_component(agent_portrayal) +plot = make_plot_component( + { + "Neutrals": "gray", + "Moderates": "orange", + "Radicals": "red", + } +) + + +@solara.component +def App(): + SolaraViz( + IdeologyModel, + components=[space, plot], + model_params=model_params, + name="Ideology Diffusion Model", + ) diff --git a/examples/ideology_diffusion/model.py b/examples/ideology_diffusion/model.py new file mode 100644 index 000000000..7892acdd7 --- /dev/null +++ b/examples/ideology_diffusion/model.py @@ -0,0 +1,51 @@ +from agents import Person + +from mesa import Model +from mesa.datacollection import DataCollector +from mesa.space import MultiGrid +from mesa.time import RandomActivation + + +class IdeologyModel(Model): + def __init__( + self, + n=120, + width=15, + height=15, + economic_crisis=0.5, + propaganda=0.2, + seed=None, + ): + super().__init__(seed=seed) + + self.grid = MultiGrid(width, height, torus=True) + self.schedule = RandomActivation(self) + + self.economic_crisis = economic_crisis + self.propaganda = propaganda + + for _ in range(n): + agent = Person(self) + self.schedule.add(agent) + + x = self.random.randrange(width) + y = self.random.randrange(height) + self.grid.place_agent(agent, (x, y)) + + self.datacollector = DataCollector( + { + "Neutrals": lambda m: sum( + a.opinion == "neutral" for a in m.schedule.agents + ), + "Moderates": lambda m: sum( + a.opinion == "moderate" for a in m.schedule.agents + ), + "Radicals": lambda m: sum( + a.opinion == "radical" for a in m.schedule.agents + ), + } + ) + + def step(self): + self.datacollector.collect(self) + self.schedule.step() From b78b6ce880ba610e0714856f6a358c6cc78419b1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 29 Dec 2025 22:44:44 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- examples/ideology_diffusion/app.py | 3 +-- examples/ideology_diffusion/model.py | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/ideology_diffusion/app.py b/examples/ideology_diffusion/app.py index 995e695d6..a577d39bb 100644 --- a/examples/ideology_diffusion/app.py +++ b/examples/ideology_diffusion/app.py @@ -1,11 +1,10 @@ import solara -from model import IdeologyModel - from mesa.experimental.solara_viz import ( SolaraViz, make_plot_component, make_space_component, ) +from model import IdeologyModel def agent_portrayal(agent): diff --git a/examples/ideology_diffusion/model.py b/examples/ideology_diffusion/model.py index 7892acdd7..eb74ad209 100644 --- a/examples/ideology_diffusion/model.py +++ b/examples/ideology_diffusion/model.py @@ -1,5 +1,4 @@ from agents import Person - from mesa import Model from mesa.datacollection import DataCollector from mesa.space import MultiGrid