mirror of
https://github.com/gsi-upm/soil
synced 2025-08-24 03:52:20 +00:00
WIP: all tests pass
Documentation needs some improvement The API has been simplified to only allow for ONE topology per NetworkEnvironment. This covers the main use case, and simplifies the code.
This commit is contained in:
@@ -8,17 +8,12 @@ interval: 1
|
||||
seed: '1'
|
||||
model_class: social_wealth.MoneyEnv
|
||||
model_params:
|
||||
topologies:
|
||||
default:
|
||||
params:
|
||||
generator: social_wealth.graph_generator
|
||||
n: 5
|
||||
generator: social_wealth.graph_generator
|
||||
agents:
|
||||
topology: true
|
||||
distribution:
|
||||
- agent_class: social_wealth.SocialMoneyAgent
|
||||
topology: default
|
||||
weight: 1
|
||||
mesa_agent_class: social_wealth.MoneyAgent
|
||||
N: 10
|
||||
width: 50
|
||||
height: 50
|
||||
|
@@ -2,6 +2,7 @@ from mesa.visualization.ModularVisualization import ModularServer
|
||||
from soil.visualization import UserSettableParameter
|
||||
from mesa.visualization.modules import ChartModule, NetworkModule, CanvasGrid
|
||||
from social_wealth import MoneyEnv, graph_generator, SocialMoneyAgent
|
||||
import networkx as nx
|
||||
|
||||
|
||||
class MyNetwork(NetworkModule):
|
||||
@@ -13,15 +14,16 @@ def network_portrayal(env):
|
||||
# The model ensures there is 0 or 1 agent per node
|
||||
|
||||
portrayal = dict()
|
||||
wealths = {node_id: data['agent'].wealth for (node_id, data) in env.G.nodes(data=True)}
|
||||
portrayal["nodes"] = [
|
||||
{
|
||||
"id": agent_id,
|
||||
"size": env.get_agent(agent_id).wealth,
|
||||
# "color": "#CC0000" if not agents or agents[0].wealth == 0 else "#007959",
|
||||
"color": "#CC0000",
|
||||
"label": f"{agent_id}: {env.get_agent(agent_id).wealth}",
|
||||
}
|
||||
for (agent_id) in env.G.nodes
|
||||
"id": node_id,
|
||||
"size": 2*(wealth+1),
|
||||
"color": "#CC0000" if wealth == 0 else "#007959",
|
||||
# "color": "#CC0000",
|
||||
"label": f"{node_id}: {wealth}",
|
||||
} for (node_id, wealth) in wealths.items()
|
||||
|
||||
]
|
||||
|
||||
portrayal["edges"] = [
|
||||
@@ -29,7 +31,6 @@ def network_portrayal(env):
|
||||
for edge_id, (source, target) in enumerate(env.G.edges)
|
||||
]
|
||||
|
||||
|
||||
return portrayal
|
||||
|
||||
|
||||
@@ -55,7 +56,7 @@ def gridPortrayal(agent):
|
||||
}
|
||||
|
||||
|
||||
grid = MyNetwork(network_portrayal, 500, 500, library="sigma")
|
||||
grid = MyNetwork(network_portrayal, 500, 500)
|
||||
chart = ChartModule(
|
||||
[{"Label": "Gini", "Color": "Black"}], data_collector_name="datacollector"
|
||||
)
|
||||
@@ -70,7 +71,6 @@ model_params = {
|
||||
1,
|
||||
description="Choose how many agents to include in the model",
|
||||
),
|
||||
"network_agents": [{"agent_class": SocialMoneyAgent}],
|
||||
"height": UserSettableParameter(
|
||||
"slider",
|
||||
"height",
|
||||
@@ -89,12 +89,15 @@ model_params = {
|
||||
1,
|
||||
description="Grid width",
|
||||
),
|
||||
"network_params": {
|
||||
'generator': graph_generator
|
||||
},
|
||||
"agent_class": UserSettableParameter('choice', 'Agent class', value='MoneyAgent',
|
||||
choices=['MoneyAgent', 'SocialMoneyAgent']),
|
||||
"generator": graph_generator,
|
||||
}
|
||||
|
||||
canvas_element = CanvasGrid(gridPortrayal, model_params["width"].value, model_params["height"].value, 500, 500)
|
||||
|
||||
canvas_element = CanvasGrid(gridPortrayal,
|
||||
model_params["width"].value,
|
||||
model_params["height"].value, 500, 500)
|
||||
|
||||
|
||||
server = ModularServer(
|
||||
|
@@ -10,7 +10,7 @@ from mesa.batchrunner import BatchRunner
|
||||
|
||||
import networkx as nx
|
||||
|
||||
from soil import NetworkAgent, Environment
|
||||
from soil import NetworkAgent, Environment, serialization
|
||||
|
||||
def compute_gini(model):
|
||||
agent_wealths = [agent.wealth for agent in model.agents]
|
||||
@@ -19,15 +19,16 @@ def compute_gini(model):
|
||||
B = sum( xi * (N-i) for i,xi in enumerate(x) ) / (N*sum(x))
|
||||
return (1 + (1/N) - 2*B)
|
||||
|
||||
|
||||
class MoneyAgent(MesaAgent):
|
||||
"""
|
||||
A MESA agent with fixed initial wealth.
|
||||
It will only share wealth with neighbors based on grid proximity
|
||||
"""
|
||||
|
||||
def __init__(self, unique_id, model):
|
||||
def __init__(self, unique_id, model, wealth=1):
|
||||
super().__init__(unique_id=unique_id, model=model)
|
||||
self.wealth = 1
|
||||
self.wealth = wealth
|
||||
|
||||
def move(self):
|
||||
possible_steps = self.model.grid.get_neighborhood(
|
||||
@@ -45,7 +46,7 @@ class MoneyAgent(MesaAgent):
|
||||
self.wealth -= 1
|
||||
|
||||
def step(self):
|
||||
self.info("Crying wolf", self.pos)
|
||||
print("Crying wolf", self.pos)
|
||||
self.move()
|
||||
if self.wealth > 0:
|
||||
self.give_money()
|
||||
@@ -58,8 +59,8 @@ class SocialMoneyAgent(NetworkAgent, MoneyAgent):
|
||||
cellmates = set(self.model.grid.get_cell_list_contents([self.pos]))
|
||||
friends = set(self.get_neighboring_agents())
|
||||
self.info("Trying to give money")
|
||||
self.debug("Cellmates: ", cellmates)
|
||||
self.debug("Friends: ", friends)
|
||||
self.info("Cellmates: ", cellmates)
|
||||
self.info("Friends: ", friends)
|
||||
|
||||
nearby_friends = list(cellmates & friends)
|
||||
|
||||
@@ -68,14 +69,29 @@ class SocialMoneyAgent(NetworkAgent, MoneyAgent):
|
||||
other.wealth += 1
|
||||
self.wealth -= 1
|
||||
|
||||
def graph_generator(n=5):
|
||||
G = nx.Graph()
|
||||
for ix in range(n):
|
||||
G.add_edge(0, ix)
|
||||
return G
|
||||
|
||||
|
||||
class MoneyEnv(Environment):
|
||||
"""A model with some number of agents."""
|
||||
def __init__(self, width, height, *args, topologies, **kwargs):
|
||||
def __init__(self, width, height, N, generator=graph_generator,
|
||||
agent_class=SocialMoneyAgent,
|
||||
topology=None, **kwargs):
|
||||
|
||||
super().__init__(*args, topologies=topologies, **kwargs)
|
||||
generator = serialization.deserialize(generator)
|
||||
agent_class = serialization.deserialize(agent_class, globs=globals())
|
||||
topology = generator(n=N)
|
||||
super().__init__(topology=topology,
|
||||
N=N,
|
||||
**kwargs)
|
||||
self.grid = MultiGrid(width, height, False)
|
||||
|
||||
self.populate_network(agent_class=agent_class)
|
||||
|
||||
# Create agents
|
||||
for agent in self.agents:
|
||||
x = self.random.randrange(self.grid.width)
|
||||
@@ -87,17 +103,9 @@ class MoneyEnv(Environment):
|
||||
agent_reporters={"Wealth": "wealth"})
|
||||
|
||||
|
||||
def graph_generator(n=5):
|
||||
G = nx.Graph()
|
||||
for ix in range(n):
|
||||
G.add_edge(0, ix)
|
||||
return G
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
|
||||
G = graph_generator()
|
||||
fixed_params = {"topology": G,
|
||||
fixed_params = {"generator": nx.complete_graph,
|
||||
"width": 10,
|
||||
"network_agents": [{"agent_class": SocialMoneyAgent,
|
||||
'weight': 1}],
|
||||
@@ -116,4 +124,3 @@ if __name__ == '__main__':
|
||||
run_data = batch_run.get_model_vars_dataframe()
|
||||
run_data.head()
|
||||
print(run_data.Gini)
|
||||
|
||||
|
Reference in New Issue
Block a user