-
Notifications
You must be signed in to change notification settings - Fork 906
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: Schelling Model Neighbor Similarity Calculation #2518
base: main
Are you sure you want to change the base?
Fix: Schelling Model Neighbor Similarity Calculation #2518
Conversation
Performance benchmarks:
|
else: | ||
self.model.happy += 1 | ||
# If unhappy, move to a random empty cell | ||
if similarity_fraction < self.model.homophily / 8.0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not change homopily at the model level to be a fraction? That makes the model independent of the neighborhood size.
if hasattr(neighbor, "type") and neighbor.type == self.type | ||
] | ||
total_neighbors = [ | ||
neighbor for neighbor in neighbors if hasattr(neighbor, "type") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you iterate twice, with one check being done in both. You can make this more efficient by looping only once.
@Sahil-Chhoker Thanks for your PR. When do you expect to be able to incorporate @quaquel's feedback? If you have any question about it feel free to ask! |
Thank you, @quaquel, for your review! Could you please provide more details about the model and how can I can make changes to it? |
My feedback is quite clear, and there is a link to a more detailed description of the model in the original issue. I requested 2 well-defined changes to this PR: change From your reaction, I therefore deduce that you are not particularly familiar with agent-based modeling. |
similar_neighbors = 0 | ||
|
||
for neighbor in neighbors: | ||
if hasattr(neighbor, "type"): # Exclude empty cells |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not needed, iter_neighbors
returns a list of agents. In this model all agents have the type
attribute.
self.pos, moore=True, radius=self.model.radius | ||
) | ||
|
||
# Filter out empty cells | ||
similar_neighbors = [ | ||
neighbor | ||
for neighbor in neighbors | ||
if hasattr(neighbor, "type") and neighbor.type == self.type | ||
] | ||
total_neighbors = [ | ||
neighbor for neighbor in neighbors if hasattr(neighbor, "type") | ||
] | ||
|
||
# Calculate fraction of similar neighbors | ||
if len(total_neighbors) > 0: | ||
similarity_fraction = len(similar_neighbors) / len(total_neighbors) | ||
valid_neighbors = 0 | ||
similar_neighbors = 0 | ||
|
||
for neighbor in neighbors: | ||
if hasattr(neighbor, "type"): # Exclude empty cells | ||
valid_neighbors += 1 | ||
if neighbor.type == self.type: # Count similar neighbors | ||
similar_neighbors += 1 | ||
|
||
# Calculate the fraction of similar neighbors | ||
if valid_neighbors > 0: | ||
similarity_fraction = similar_neighbors / valid_neighbors | ||
|
||
# If unhappy, move to a random empty cell | ||
if similarity_fraction < self.model.homophily / 8.0: | ||
if similarity_fraction < self.model.homophily: | ||
self.model.grid.move_to_empty(self) | ||
else: | ||
self.model.happy += 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
neighbors = self.model.grid.get_neighbors(
self.pos, moore=True, radius=self.model.radius
)
# Count similar neighbors
similar_neighbors = len([n for n in neighbors if n.type == self.type])
# Calculate the fraction of similar neighbors
if (valid_neighbors := len(neighbors) )> 0:
similarity_fraction = similar_neighbors / valid_neighbors
# If unhappy, move to a random empty cell
if similarity_fraction < self.model.homophily:
self.model.grid.move_to_empty(self)
else:
self.model.happy += 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see my second round of feedback
Please switch from
currently, as you can see the tests fail because the model won't run. The list expression exhausts the iterator, so getting the number of valid neighbors fails. |
Performance benchmarks:
|
if (valid_neighbors := len(neighbors)) > 0: | ||
similarity_fraction = similar_neighbors / valid_neighbors | ||
|
||
# If unhappy, move to a random empty cell: | ||
if similar < self.model.homophily: | ||
self.model.grid.move_to_empty(self) | ||
else: | ||
self.model.happy += 1 | ||
# If unhappy, move to a random empty cell | ||
if similarity_fraction < self.model.homophily: | ||
self.model.grid.move_to_empty(self) | ||
else: | ||
self.model.happy += 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happens if len(neighbors)
is 0? Currently, nothing happens, which most definitely is not correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please correct me if I’m wrong, but if there are no neighbors surrounding the agent, it should be considered unhappy as it does not meet the criteria for happiness. Should I proceed with this approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have checked some literature, including the original article. It's not entirely clear. However, your reading is defendable, so I am fine with it.
Performance benchmarks:
|
Thanks for bringing this PR this far. Is the performance regression expected from the code changes, or is it bigger than expected? |
I am not surprised as indicated before, but I still want to check before merging. |
I have checked the model, and something is not quite right. Within a few steps, all agents are supposedly happy but if you check the grid manually, you see that this cannot be true. I am not yet sure what's causing this. It might be merely the order of agent activation (so an agent goes first and is happy, but some of its neighbors move afterwards, meaning it is unhappy if checked again). I need time to look more closely at this and reason true what is going on. |
Summary
Fixed #2515 Schelling segregation model to calculate agent happiness using neighbor similarity fraction, aligning with Wikipedia and NetLogo standards.
Bug / Issue
Current model incorrectly counts empty spaces as neighbors, leading to inaccurate agent happiness determination.
Implementation
Modified
SchellingAgent.step()
to: