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

Enhance AgentSet.get to handle undefined attributes with fallback opt… #2067

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

ai-naymul
Copy link

@ai-naymul ai-naymul commented Mar 1, 2024

Issue no : #2045
These chanegs provides a more user friendly approach to attribute retrieval, accommodating scenarios where some agents might not have all the specified attributes.

ai-naymul and others added 2 commits March 1, 2024 21:54
…ions

These chanegs provides a more user friendly approach to attribute retrieval, accommodating scenarios where some agents might not have all the specified attributes.
Copy link

github-actions bot commented Mar 1, 2024

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
Schelling small 🔵 -0.2% [-0.4%, +0.0%] 🔵 -1.0% [-1.2%, -0.7%]
Schelling large 🔵 -0.7% [-1.7%, +0.4%] 🟢 -10.3% [-13.4%, -7.1%]
WolfSheep small 🔵 +0.4% [-1.0%, +1.7%] 🔵 -0.2% [-0.4%, +0.0%]
WolfSheep large 🔵 +0.5% [+0.0%, +1.1%] 🔵 -1.5% [-3.7%, +0.4%]
BoidFlockers small 🔵 +0.2% [-0.8%, +1.2%] 🔵 -1.6% [-2.2%, -1.0%]
BoidFlockers large 🔵 +2.0% [+1.4%, +2.7%] 🔵 -0.7% [-1.3%, +0.0%]

@Corvince
Copy link
Contributor

Corvince commented Mar 2, 2024

I think the pr generally looks good, thanks for the contribution!

But I still think we can get away with just having a fallback value. The way this works is we have to set it's default value to a sentinel value and then check if the value is still the sentinel value and if not, return the fallback value. This way the fallback value can also be None.

The sentinel value could look just like

sentinel = object()

@quaquel
Copy link
Contributor

quaquel commented Mar 2, 2024

I like the basic proposed solution with the inner function. This is quite elegant. A small addition from my side: could you add some unit tests as well? The test code is here.

mesa/agent.py Outdated
"""
Retrieve the specified attribute(s) from each agent in the AgentSet.

Args:
attr_names (str | list[str]): The name(s) of the attribute(s) to retrieve from each agent.
handle_undefined (bool, optional): If False, use fallback_value for undefined attributes. Defaults to True.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be clearer is it is called error_when_undefined, or if there is a more concise naming for it.

Copy link
Author

Choose a reason for hiding this comment

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

Hi @rht ,

Made some changes into the latest commit could you please have a look and let me know if is there anything to change :)

@ai-naymul
Copy link
Author

I like the basic proposed solution with the inner function. This is quite elegant. A small addition from my side: could you add some unit tests as well? The test code is here.

Hi there,
I will add those shortly...
Thanks a lot for your feedback 💯

@ai-naymul
Copy link
Author

I think the pr generally looks good, thanks for the contribution!

But I still think we can get away with just having a fallback value. The way this works is we have to set it's default value to a sentinel value and then check if the value is still the sentinel value and if not, return the fallback value. This way the fallback value can also be None.

The sentinel value could look just like

sentinel = object()

Hi @Corvince ,

Could you please have a look at the latest commit and let me know if is that fine, let me know...

@Corvince
Copy link
Contributor

Corvince commented Mar 3, 2024

Hi, yes! Thats exactly how I meant it. Now you could remove the "error_when_undefined" boolean, because you can either raise an Error if the fallback_value is undefined or use the fallback value.

I also think its not necessary to include the sentinel value in the docstrings and documentation. Its purely an implementation detail and not something the user needs to be aware of. So its enough to state that, if provided, the fallback value will be used if an attribute error is encountered and otherwise an error is raised.

@Corvince
Copy link
Contributor

Corvince commented Mar 3, 2024

You might be wondering: If you leave fallback_value undefined and turn off error when undefined, it might appear the code is just returning nothing. But it will actually return None, so its the same as setting fallback_value to None, so error_when_undefined doesn't provide any additional functionality and thats why I think it can be removed.

@ai-naymul
Copy link
Author

You might be wondering: If you leave fallback_value undefined and turn off error when undefined, it might appear the code is just returning nothing. But it will actually return None, so its the same as setting fallback_value to None, so error_when_undefined doesn't provide any additional functionality and thats why I think it can be removed.

Yeah, you are right!

@ai-naymul
Copy link
Author

Hi, yes! Thats exactly how I meant it. Now you could remove the "error_when_undefined" boolean, because you can either raise an Error if the fallback_value is undefined or use the fallback value.

I also think its not necessary to include the sentinel value in the docstrings and documentation. Its purely an implementation detail and not something the user needs to be aware of. So its enough to state that, if provided, the fallback value will be used if an attribute error is encountered and otherwise an error is raised.

Hey I have done some changes according to your preference.Let me know if its perfect or not...

Thank you 👍

mesa/agent.py Outdated
@@ -90,7 +90,7 @@ class AgentSet(MutableSet, Sequence):

Methods:
__len__, __iter__, __contains__, select, shuffle, sort, _update, do, get, __getitem__,
add, discard, remove, __getstate__, __setstate__, random
add, discard, remove, __getstate__, __setstate__, random, group_by
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess this is from another branch?

Copy link
Author

Choose a reason for hiding this comment

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

I think thats was a mistake by me. Let me fix it :)

mesa/agent.py Outdated
def get_attr(agent, attr_name):
try:
return getattr(agent, attr_name)
except AttributeError:
Copy link
Contributor

Choose a reason for hiding this comment

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

Catching an exception is comparatively costly in terms of performance. Normally this isn't something to worry about, but if we run into this frequently (which users might do) it could become a problem. I think it would be better to first check for the sentinel value and then either return getattr(agent, attr_name) or getattr(agent, attr_name, fallback_value).

Copy link
Author

Choose a reason for hiding this comment

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

Hey facing some attribute error in the build after the changes, any ideas.....

@Corvince
Copy link
Contributor

Corvince commented Mar 6, 2024

Hi, yes! Thats exactly how I meant it. Now you could remove the "error_when_undefined" boolean, because you can either raise an Error if the fallback_value is undefined or use the fallback value.
I also think its not necessary to include the sentinel value in the docstrings and documentation. Its purely an implementation detail and not something the user needs to be aware of. So its enough to state that, if provided, the fallback value will be used if an attribute error is encountered and otherwise an error is raised.

Hey I have done some changes according to your preference.Let me know if its perfect or not...

Thank you 👍

Almost 🙈 One more comment/consideration

ai-naymul and others added 2 commits March 9, 2024 00:16
fix the typo and remove exception and handle the exception using if else
@ai-naymul
Copy link
Author

Hi, yes! Thats exactly how I meant it. Now you could remove the "error_when_undefined" boolean, because you can either raise an Error if the fallback_value is undefined or use the fallback value.
I also think its not necessary to include the sentinel value in the docstrings and documentation. Its purely an implementation detail and not something the user needs to be aware of. So its enough to state that, if provided, the fallback value will be used if an attribute error is encountered and otherwise an error is raised.

Hey I have done some changes according to your preference.Let me know if its perfect or not...
Thank you 👍

Almost 🙈 One more comment/consideration

Hi could you please have a look at the recent commit and let me know if is there any issue...

@quaquel
Copy link
Contributor

quaquel commented Mar 19, 2024

Hi could you please have a look at the recent commit and let me know if is there any issue...

All existing tests are failing, and no tests have been added for the new functionality. Both issues need addressing. If you need help or tips, please let us know.

@ai-naymul
Copy link
Author

Hi could you please have a look at the recent commit and let me know if is there any issue...

All existing tests are failing, and no tests have been added for the new functionality. Both issues need addressing. If you need help or tips, please let us know.

Actually after this commit(fe6fea3) all test are failing. And regardin the test need to add for the changes I will add that shortly after the build is succeed. Sorry for the inconvenience :(

@ai-naymul
Copy link
Author

@EwoutH,
any ideas on how can fix the build issue?

@EwoutH
Copy link
Contributor

EwoutH commented Apr 22, 2024

Yes, it seems that currently one of the tests fail. It’s test_agentset_get_attribute, which indicates something is changed in the AgentSet.get() method that breaks that test. The test code is located here:

def test_agentset_get_attribute():

Most likely a failing test points to a break in current functionality. But it could also be that the test is unnecessary (strict).

so either the code needs to be fixed to pass the test, or the test modified.

I hope this helps. If you have further questions (or want me to just fix the test). You will learn a lot working through these issues though!

@ai-naymul
Copy link
Author

Yes, it seems that currently one of the tests fail. It’s test_agentset_get_attribute, which indicates something is changed in the AgentSet.get() method that breaks that test. The test code is located here:

def test_agentset_get_attribute():

Most likely a failing test points to a break in current functionality. But it could also be that the test is unnecessary (strict).
so either the code needs to be fixed to pass the test, or the test modified.

I hope this helps. If you have further questions (or want me to just fix the test). You will learn a lot working through these issues though!

Yeah, Let me try to fix that issue ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants