Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug in tutorial to calculate MRS with potential trade #33

Merged
merged 1 commit into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/sugarscape_g1mt/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ def assess_results(results, single_agent):
params = {
"width": 50,
"height": 50,
"vision_min": range(1, 3),
"metabolism_max": [3, 5],
"vision_min": range(1, 4),
"metabolism_max": [2, 3, 4, 5],
}

results_batch = mesa.batch_run(
Expand Down
18 changes: 18 additions & 0 deletions examples/sugarscape_g1mt/sugarscape_g1mt/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,24 @@ def step(self):

# collect model level data
self.datacollector.collect(self)
"""
Mesa is working on updating datacollector agent reporter
so it can collect information on specific agents from
mesa.time.RandomActivationByType.

Please see issue #1419 at
https://github.com/projectmesa/mesa/issues/1419
(contributions welcome)

Below is one way to update agent_records to get specific Trader agent data
"""
# Need to remove excess data
# Create local variable to store trade data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about projectmesa/mesa#1419 (comment) ? Which doesn't expose the internal wiring of the DataCollector.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concern with putting it in the model collector is the point of the lesson is to talk about the agent reporter. Showing the internal wiring of datacollector, I think is more consistent with the learning objectives as I show the source code in various lessons.. This leads back to your second comment that we would need to build a class for collecting DataCollectorRABT.

So in I would prefer to show the internal wiring... I don't know.. what do you think?

Copy link
Contributor

@rht rht May 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose it is fine for now as long as there is a comment that says this part is still a work in progress, with a link to #1419.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment added

agent_trades = self.datacollector._agent_records[self.schedule.steps]
# Get rid of all None to reduce data storage needs
agent_trades = [agent for agent in agent_trades if agent[2] is not None]
# Reassign the dictionary value with lean trade data
self.datacollector._agent_records[self.schedule.steps] = agent_trades

def run_model(self, step_count=1000):
for i in range(step_count):
Expand Down
24 changes: 13 additions & 11 deletions examples/sugarscape_g1mt/sugarscape_g1mt/trader_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,16 +140,16 @@ def is_starved(self):

return (self.sugar <= 0) or (self.spice <= 0)

def calculate_MRS(self):
def calculate_MRS(self, sugar, spice):
"""
Helper function for self.trade()
Helper function for
- self.trade()
- self.maybe_self_spice()

Determines what trader agent is needs and can give up
Determines what trader agent needs and can give up
"""

return (self.spice / self.metabolism_spice) / (
self.sugar / self.metabolism_sugar
)
return (spice / self.metabolism_spice) / (sugar / self.metabolism_sugar)

def calculate_sell_spice_amount(self, price):
"""
Expand Down Expand Up @@ -205,8 +205,10 @@ def maybe_sell_spice(self, other, price, welfare_self, welfare_other):
welfare_self < self.calculate_welfare(self_sugar, self_spice)
) and (welfare_other < other.calculate_welfare(other_sugar, other_spice))

# trade criteria #2 is their mrs crossing
mrs_not_crossing = self.calculate_MRS() > other.calculate_MRS()
# trade criteria #2 is their mrs crossing with potential trade
mrs_not_crossing = self.calculate_MRS(
self_sugar, self_spice
) > other.calculate_MRS(other_sugar, other_spice)

if not (both_agents_better_off and mrs_not_crossing):
return False
Expand All @@ -229,9 +231,9 @@ def trade(self, other):
assert other.sugar > 0
assert other.spice > 0

# calculate marginal rate of subsitution in Growing Artificial Socieites p. 101
mrs_self = self.calculate_MRS()
mrs_other = other.calculate_MRS()
# calculate marginal rate of substitution in Growing Artificial Societies p. 101
mrs_self = self.calculate_MRS(self.sugar, self.spice)
mrs_other = other.calculate_MRS(other.sugar, other.spice)

# calculate each agents welfare
welfare_self = self.calculate_welfare(self.sugar, self.spice)
Expand Down