-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwealth_distribution.py
More file actions
101 lines (84 loc) · 3.29 KB
/
Copy pathwealth_distribution.py
File metadata and controls
101 lines (84 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"""
Boltzmann Wealth Distribution
All agents start with equal wealth. Each step, every agent gives 1 unit
to a random neighbor. Despite fair rules, extreme inequality emerges —
the distribution converges to a Boltzmann (exponential) distribution.
This is a classic demonstration that inequality can arise from purely
random processes without any structural advantage.
The model is pure JSON: the generic "transfer" interaction effect moves
any attribute between agents — the kernel has no notion of "wealth".
"""
from agentstan import Simulation, DataCollector
spec = {
"seed": 7,
"environment": {
"type": "grid_2d",
"dimensions": {"width": 20, "height": 20, "topology": "torus"},
},
"agent_types": {
"person": {
"initial_count": 100,
"initial_state": {"wealth": 10, "perception_radius": 2},
"behavior": {"rules": [
# Give 1 unit to a random neighbor (if we have money)
{"when": {"and": [
{">": ["$wealth", 0]},
{">": [{"count": {}}, 0]},
]},
"do": [{"type": "interact",
"target": {"random": {}},
"interaction_type": "gift",
"params": {"transfer": {"attribute": "wealth", "amount": 1}}}]},
# Random walk
{"do": [{"type": "move",
"direction": [{"choice": [-1, 0, 1]}, {"choice": [-1, 0, 1]}]}]},
]},
},
},
}
def compute_gini(sim):
"""Gini coefficient: 0 = perfect equality, 1 = perfect inequality."""
wealths = sorted(a.get_attribute("wealth", 0) for a in sim.agent_manager.get_living_agents())
n = len(wealths)
if n == 0 or sum(wealths) == 0:
return 0
cumulative = 0
total = sum(wealths)
for i, w in enumerate(wealths):
cumulative += (2 * (i + 1) - n - 1) * w
return cumulative / (n * total)
def run_single():
print("=== Boltzmann Wealth Distribution ===")
print("100 agents, each starts with 10 units")
print("Each step: give 1 unit to a random neighbor")
print()
sim = Simulation(spec)
collector = DataCollector(
model_metrics={"gini": compute_gini},
agent_metrics={"wealth": lambda a: a.get_attribute("wealth", 0)},
)
sim.add_collector(collector)
sim.run(200)
data = collector.get_model_data()
agent_data = collector.get_agent_data()
print(f"Initial Gini: {data[0]['gini']:.3f}")
print(f"Final Gini: {data[-1]['gini']:.3f}")
print()
# Show Gini over time
print("Gini coefficient over time:")
for i in range(0, len(data), 25):
bar = "#" * int(data[i]["gini"] * 50)
print(f" Step {data[i]['step']:3d}: {data[i]['gini']:.3f} {bar}")
print()
# Final wealth distribution
final_step = max(d["step"] for d in agent_data)
final_wealths = sorted(
[d["wealth"] for d in agent_data if d["step"] == final_step],
reverse=True,
)
print("Final wealth distribution (top 10 / bottom 10):")
print(f" Richest 10: {final_wealths[:10]}")
print(f" Poorest 10: {final_wealths[-10:]}")
print(f" Top 10% own: {sum(final_wealths[:10]) / sum(final_wealths):.0%} of total wealth")
if __name__ == "__main__":
run_single()