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

Permit AgentIDs other than str #1071

Merged
merged 9 commits into from
Aug 22, 2023
Merged

Conversation

pimpale
Copy link
Contributor

@pimpale pimpale commented Aug 20, 2023

Description

Adds the feature described in #1070, by making ParallelEnv and AECEnv generic over AgentID.

Type of change

  • New feature (non-breaking change which adds functionality)

Checklist:

  • I have run the pre-commit checks with pre-commit run --all-files (see CONTRIBUTING.md instructions to set it up)
  • I have run pytest -v and no errors are present.
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I solved any possible warnings that pytest -v has generated that are related to my code to the best of my knowledge.
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@pimpale
Copy link
Contributor Author

pimpale commented Aug 21, 2023

Hi, @elliottower. I believe this PR is ready to be reviewed. For testing, I copied the environments in example_env, but made them use non-string AgentIDs, since those demonstrate termination, addition, and other behaviors. Let me know if that testing is sufficient, or if there are other tests you would like to see.

@elliottower
Copy link
Contributor

I wonder if there's a way to make a wrapper to change the agent ID's to be something custom like a string? That seems more elegant than rewriting an entire environment changing like a single attribute. Then we could have it be similar to the unwrapped or pickle tests where we can easily iterate over different envs and ensure different ones work with the changes. But for now this seems pretty good.

Looks like the tutorial tests and pre-commit failed when I ran it this first time, can you run pre-commit run --all-files and pytest -v locally? I'm happy to click run workflows on here and test with CI but it's usually easier to just get everything to pass locally first

@elliottower
Copy link
Contributor

Another potential idea although it wouldn't be as clean, would be to have a wrapper that converts into string agent IDs so that the highest level user facing environment would be interactable using integers for agent id, but then in every subsequent level beneath that it would be cast to a string so the other wrappers and functionality works normally.

Only problem is certain things you may not want to convert to a string, but inherently string types are sort of the type which everything can be converted into so I don't see it being a huge problem

@elliottower
Copy link
Contributor

Also I'm going to be very busy with things this week so I won't be able to help much with this

) -> tuple[
ObsDict, dict[str, float], dict[str, bool], dict[str, bool], dict[str, dict]
dict[AgentID, ObsType],
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems cleaner than ObsDict type

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 the consequence of this is that it's now somewhat backwards incompatible, but I guess even I agreed that it seemed cleaner to be explicit that it's a dict of agentID and obstype

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah okay looking back at that full file I think you're probably right that we should just make a shimmy update and try to be more clear, we don't have RewardDict or anything like that anyways, so it's simplest to make all of these types fully clear when you see them in the type hint and know what to expect without having to cross reference 'oh what is an ObsDict'. And I think I'm probably one of the only people who uses ObsDict anyways

Copy link
Contributor

@elliottower elliottower left a comment

Choose a reason for hiding this comment

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

Looks pretty much good but a few little questions and nitpicks, thanks so much for this, this sort of stronger typing and more consistency with Gymnasium is really important

@elliottower
Copy link
Contributor

Looks like it's saying type is not subscriptable /~https://github.com/Farama-Foundation/PettingZoo/actions/runs/5929053382/job/16077967033?pr=1071

@elliottower
Copy link
Contributor

I believe the type errors will go away if you add this line:
from __future__ import annotations

@pimpale
Copy link
Contributor Author

pimpale commented Aug 21, 2023

I've added annotations on all files where I saw the error occur.

@elliottower
Copy link
Contributor

I've added annotations on all files where I saw the error occur.

Sounds good, thanks

@elliottower
Copy link
Contributor

It may not be that ideal to have to import annotations on any internal file which deals with calling these environments, but that's a cost I'm willing to pay. Plus I believe in 3.9 you don't need to import them anymore, so once 3.12 is out next year and 3.8 is phased out I think it will no longer be necessary.

@elliottower
Copy link
Contributor

Tag me when you want me to re-run the tests or review again, this looks almost perfect but just a few little nitpicks I noted above. Thanks again for this, great work paying such close attention to detail and fixing all of the little issues.

@pimpale
Copy link
Contributor Author

pimpale commented Aug 21, 2023

It looks like all tests have passed. From my end, I'm ready to merge.

@pimpale
Copy link
Contributor Author

pimpale commented Aug 22, 2023

@elliottower Following up on this.

@elliottower elliottower merged commit ab6e543 into Farama-Foundation:master Aug 22, 2023
@elliottower
Copy link
Contributor

@pimpale could you look into this? Looks like your removal of obs dict caused an issue with shimmy. Maybe it should be added back in a patch? Farama-Foundation/Shimmy#106

@@ -177,7 +173,7 @@ def agent_iter(self, max_iter: int = 2**63) -> AECIterable:

def last(
self, observe: bool = True
) -> tuple[ObsType | None, float, bool, bool, dict[AgentID, dict[str, Any]]]:
) -> tuple[ObsType | None, float, bool, bool, dict[str, Any]]:
Copy link
Contributor

Choose a reason for hiding this comment

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

Also looking at before and after this line looks incorrect, it should use AgentID, but also simpler to just keep the ObsDict type at the top of the file and define it to use AgentID, which you changed ofc. That way if agent id gets changed again this will not need to be changed as it just references it. And prevents breaking code like the shimmy bug.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason I changed that line was because we return self.infos[agent] for the info dict, and self.infos has the type dict[AgentID, dict[str, Any]].

That line was producing a type error previously.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm a little confused why it needs to be dict[str] here though instead of agent ID

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 has to do with the other PR up right now which talks about infos and the correct syntax for it. What I gather is that parallel envs need to have the dict be indexed by agent ID and have sub dicts with info for each agent, but I guess in AEC environments you just need any dict and it's assumed that it's the info only for that agent on that timestep. So it shouldn't be nested dict like the original code, but I think it should still be dict[AgentID, Any]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well in this case, (last()) we're only returning the info for the current agent, so I don't understand why the it should be indexed by AgentID.

If someone wants to use int to index their agents, but still have an info that looks like { "extra_info": 1, "extra_info2": 2 }, (per agent) then that seems fine to me.

@pimpale
Copy link
Contributor Author

pimpale commented Aug 25, 2023

Can we instead create a PR to shimmy to fix the issue? To me it seems like ObsDict and ActionDict were just type aliases, and it should be fairly straightforward to replace.

@elliottower
Copy link
Contributor

Is there a principled reason that ObsDict and ActionDict need to be removed though? I don't really see a reason why we shouldn't include them just in case people already use them and like the convenience or whatever

@elliottower
Copy link
Contributor

Just looked and it seems like 21 different repositories use the ObsDict type... guess I'm not the only one. I can see an argument for keeping the ObsDict defined for backwards compatibility but internally still doing your changes which I think are more clean. (TLDR: just re-add the two lines defining ActionDict and ObsDict but we don't need to use them internally)

@pimpale
Copy link
Contributor Author

pimpale commented Aug 25, 2023

Hmm. In that case I agree with you, I'll add them back for backwards compatibility.

Although technically, since pettingzoo released a new major version, breaking changes are to be expected.

@elliottower
Copy link
Contributor

Yeah but we want to minimize them when possible and make the upgrade process as easy as can be

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.

2 participants