forked from mesa/mesa-examples
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodel.py
More file actions
154 lines (123 loc) · 5.26 KB
/
model.py
File metadata and controls
154 lines (123 loc) · 5.26 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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
"""
The following code was adapted from the Bank Reserves model included in Netlogo
Model information can be found at:
http://ccl.northwestern.edu/netlogo/models/BankReserves
Accessed on: November 2, 2017
Author of NetLogo code:
Wilensky, U. (1998). NetLogo Bank Reserves model.
http://ccl.northwestern.edu/netlogo/models/BankReserves.
Center for Connected Learning and Computer-Based Modeling,
Northwestern University, Evanston, IL.
"""
import mesa
import numpy as np
from agents import Bank, Person
from mesa.experimental.cell_space import OrthogonalMooreGrid
"""
If you want to perform a parameter sweep, call batch_run.py instead of run.py.
For details see batch_run.py in the same directory as run.py.
"""
# Start of datacollector functions
def get_num_rich_agents(model):
"""return number of rich agents"""
rich_agents = [a for a in model.agents if a.savings > model.rich_threshold]
return len(rich_agents)
def get_num_poor_agents(model):
"""return number of poor agents"""
poor_agents = [a for a in model.agents if a.loans > 10]
return len(poor_agents)
def get_num_mid_agents(model):
"""return number of middle class agents"""
mid_agents = [
a for a in model.agents if a.loans < 10 and a.savings < model.rich_threshold
]
return len(mid_agents)
def get_total_savings(model):
"""sum of all agents' savings"""
agent_savings = [a.savings for a in model.agents]
# return the sum of agents' savings
return np.sum(agent_savings)
def get_total_wallets(model):
"""sum of amounts of all agents' wallets"""
agent_wallets = [a.wallet for a in model.agents]
# return the sum of all agents' wallets
return np.sum(agent_wallets)
def get_total_money(model):
# sum of all agents' wallets
wallet_money = get_total_wallets(model)
# sum of all agents' savings
savings_money = get_total_savings(model)
# return sum of agents' wallets and savings for total money
return wallet_money + savings_money
def get_total_loans(model):
# list of amounts of all agents' loans
agent_loans = [a.loans for a in model.agents]
# return sum of all agents' loans
return np.sum(agent_loans)
class BankReservesModel(mesa.Model):
"""
This model is a Mesa implementation of the Bank Reserves model from NetLogo.
It is a highly abstracted, simplified model of an economy, with only one
type of agent and a single bank representing all banks in an economy. People
(represented by circles) move randomly within the grid. If two or more people
are on the same grid location, there is a 50% chance that they will trade with
each other. If they trade, there is an equal chance of giving the other agent
$5 or $2. A positive trade balance will be deposited in the bank as savings.
If trading results in a negative balance, the agent will try to withdraw from
its savings to cover the balance. If it does not have enough savings to cover
the negative balance, it will take out a loan from the bank to cover the
difference. The bank is required to keep a certain percentage of deposits as
reserves and the bank's ability to loan at any given time is a function of
the amount of deposits, its reserves, and its current total outstanding loan
amount.
"""
"""init parameters "init_people", "rich_threshold", and "reserve_percent"
are all set via Slider"""
def __init__(
self,
height=20,
width=20,
init_people=5,
rich_threshold=10,
reserve_percent=50,
):
super().__init__()
self.height = height
self.width = width
self.init_people = init_people
self.grid = OrthogonalMooreGrid(
(self.width, self.height), torus=True, random=self.random
)
# rich_threshold is the amount of savings a person needs to be considered "rich"
self.rich_threshold = rich_threshold
self.reserve_percent = reserve_percent
# see datacollector functions above
self.datacollector = mesa.DataCollector(
model_reporters={
"Rich": get_num_rich_agents,
"Poor": get_num_poor_agents,
"Middle Class": get_num_mid_agents,
"Savings": get_total_savings,
"Wallets": get_total_wallets,
"Money": get_total_money,
"Loans": get_total_loans,
},
agent_reporters={"Wealth": lambda x: getattr(x, "wealth", None)},
)
# create a single bank for the model
self.bank = Bank(self, self.reserve_percent)
# create people for the model according to number of people set by user
for _ in range(self.init_people):
# set x, y coords randomly within the grid
x = self.random.randrange(self.width)
y = self.random.randrange(self.height)
p = Person(self, True, self.bank, self.rich_threshold)
# place the Person object on the grid at coordinates (x, y)
p.move_to(self.grid[(x, y)])
self.running = True
self.datacollector.collect(self)
def step(self):
# tell all the agents in the model to run their step function
self.agents.shuffle_do("step")
# collect data
self.datacollector.collect(self)