multi-agent-rlenv 3.3.0__py3-none-any.whl → 3.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
marlenv/__init__.py CHANGED
@@ -62,7 +62,7 @@ print(env.extras_shape) # (1, )
62
62
  If you want to create a new environment, you can simply create a class that inherits from `MARLEnv`. If you want to create a wrapper around an existing `MARLEnv`, you probably want to subclass `RLEnvWrapper` which implements a default behaviour for every method.
63
63
  """
64
64
 
65
- __version__ = "3.3.0"
65
+ __version__ = "3.3.2"
66
66
 
67
67
  from . import models
68
68
  from . import wrappers
@@ -1,32 +1,42 @@
1
+ from importlib.util import find_spec
1
2
  from .pymarl_adapter import PymarlAdapter
2
- from typing import Any
3
3
 
4
- __all__ = ["PymarlAdapter"]
5
- try:
4
+ HAS_GYM = False
5
+ if find_spec("gymnasium") is not None:
6
6
  from .gym_adapter import Gym
7
7
 
8
- __all__.append("Gym")
9
- except ImportError:
10
- Gym = Any
8
+ HAS_GYM = True
11
9
 
12
- try:
10
+ HAS_PETTINGZOO = False
11
+ if find_spec("pettingzoo") is not None:
13
12
  from .pettingzoo_adapter import PettingZoo
14
13
 
15
- __all__.append("PettingZoo")
16
- except ImportError:
17
- PettingZoo = Any
14
+ HAS_PETTINGZOO = True
18
15
 
19
- try:
16
+ HAS_SMAC = False
17
+ if find_spec("smac") is not None:
20
18
  from .smac_adapter import SMAC
21
19
 
22
- __all__.append("SMAC")
23
- except ImportError:
24
- SMAC = Any
20
+ HAS_SMAC = True
25
21
 
22
+ HAS_OVERCOOKED = False
23
+ if find_spec("overcooked_ai_py.mdp") is not None:
24
+ import numpy
26
25
 
27
- try:
26
+ # Overcooked assumes a version of numpy <2.0 where np.Inf is available.
27
+ setattr(numpy, "Inf", numpy.inf)
28
28
  from .overcooked_adapter import Overcooked
29
29
 
30
- __all__.append("Overcooked")
31
- except ImportError:
32
- Overcooked = Any
30
+ HAS_OVERCOOKED = True
31
+
32
+ __all__ = [
33
+ "PymarlAdapter",
34
+ "Gym",
35
+ "PettingZoo",
36
+ "SMAC",
37
+ "Overcooked",
38
+ "HAS_GYM",
39
+ "HAS_PETTINGZOO",
40
+ "HAS_SMAC",
41
+ "HAS_OVERCOOKED",
42
+ ]
@@ -1,41 +1,72 @@
1
- import numpy as np
2
- import pygame
3
- import cv2
4
1
  import sys
5
- from marlenv.models import MARLEnv, State, Observation, Step, DiscreteActionSpace
2
+ from dataclasses import dataclass
6
3
  from typing import Literal, Sequence
4
+ from copy import deepcopy
5
+
6
+ import cv2
7
+ import numpy as np
7
8
  import numpy.typing as npt
8
- from overcooked_ai_py.mdp.overcooked_mdp import OvercookedGridworld, Action
9
+ import pygame
10
+ from marlenv.models import ContinuousSpace, DiscreteActionSpace, MARLEnv, Observation, State, Step
11
+
9
12
  from overcooked_ai_py.mdp.overcooked_env import OvercookedEnv
13
+ from overcooked_ai_py.mdp.overcooked_mdp import Action, OvercookedGridworld, OvercookedState
10
14
  from overcooked_ai_py.visualization.state_visualizer import StateVisualizer
11
- from dataclasses import dataclass
12
15
 
13
16
 
14
17
  @dataclass
15
18
  class Overcooked(MARLEnv[Sequence[int] | npt.NDArray, DiscreteActionSpace]):
19
+ horizon: int
20
+
16
21
  def __init__(self, oenv: OvercookedEnv):
17
22
  self._oenv = oenv
18
23
  assert isinstance(oenv.mdp, OvercookedGridworld)
19
24
  self._mdp = oenv.mdp
20
25
  self.visualizer = StateVisualizer()
26
+ shape = tuple(int(s) for s in self._mdp.get_lossless_state_encoding_shape())
27
+ shape = (shape[2], shape[0], shape[1])
21
28
  super().__init__(
22
- action_space=DiscreteActionSpace(n_agents=self._mdp.num_players, n_actions=Action.NUM_ACTIONS),
23
- observation_shape=(1,),
24
- state_shape=(1,),
29
+ action_space=DiscreteActionSpace(
30
+ n_agents=self._mdp.num_players,
31
+ n_actions=Action.NUM_ACTIONS,
32
+ action_names=[Action.ACTION_TO_CHAR[a] for a in Action.ALL_ACTIONS],
33
+ ),
34
+ observation_shape=shape,
35
+ extras_shape=(1,),
36
+ extras_meanings=["timestep"],
37
+ state_shape=shape,
38
+ state_extra_shape=(1,),
39
+ reward_space=ContinuousSpace.from_shape(1),
25
40
  )
41
+ self.horizon = int(self._oenv.horizon)
42
+
43
+ @property
44
+ def state(self) -> OvercookedState:
45
+ """Current state of the environment"""
46
+ return self._oenv.state
47
+
48
+ def set_state(self, state: State):
49
+ raise NotImplementedError("Not yet implemented")
50
+
51
+ @property
52
+ def time_step(self):
53
+ return self.state.timestep
26
54
 
27
55
  def _state_data(self):
28
- state = self._oenv.state
29
- state = np.array(self._mdp.lossless_state_encoding(state))
56
+ state = np.array(self._mdp.lossless_state_encoding(self.state))
30
57
  # Use axes (agents, channels, height, width) instead of (agents, height, width, channels)
31
58
  state = np.transpose(state, (0, 3, 1, 2))
32
59
  return state
33
60
 
34
61
  def get_state(self):
35
- return State(self._state_data())
62
+ return State(self._state_data()[0], np.array([self.time_step / self.horizon]))
36
63
 
37
64
  def get_observation(self) -> Observation:
38
- return Observation(self._state_data(), self.available_actions())
65
+ return Observation(
66
+ data=self._state_data(),
67
+ available_actions=self.available_actions(),
68
+ extras=np.array([[self.time_step / self.horizon]] * self.n_agents),
69
+ )
39
70
 
40
71
  def available_actions(self):
41
72
  available_actions = np.full((self.n_agents, self.n_actions), False)
@@ -57,6 +88,16 @@ class Overcooked(MARLEnv[Sequence[int] | npt.NDArray, DiscreteActionSpace]):
57
88
  info=info,
58
89
  )
59
90
 
91
+ def __deepcopy__(self, memo: dict):
92
+ mdp = deepcopy(self._mdp)
93
+ return Overcooked(OvercookedEnv.from_mdp(mdp, horizon=self.horizon))
94
+
95
+ def __getstate__(self):
96
+ return {"horizon": self.horizon, "mdp": self._mdp}
97
+
98
+ def __setstate__(self, state: dict):
99
+ self.__init__(OvercookedEnv.from_mdp(state["mdp"], horizon=state["horizon"]))
100
+
60
101
  def get_image(self):
61
102
  rewards_dict = {} # dictionary of details you want rendered in the UI
62
103
  for key, value in self._oenv.game_stats.items():
marlenv/env_builder.py CHANGED
@@ -1,32 +1,27 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Generic, Literal, Optional, TypeVar, overload
3
-
4
3
  import numpy as np
5
4
  import numpy.typing as npt
6
5
 
7
6
  from . import wrappers
7
+ from marlenv import adapters
8
8
  from .models import ActionSpace, MARLEnv
9
- from .adapters import PettingZoo
10
9
 
11
10
  A = TypeVar("A")
12
11
  AS = TypeVar("AS", bound=ActionSpace)
13
12
 
14
- try:
13
+ if adapters.HAS_PETTINGZOO:
14
+ from .adapters import PettingZoo
15
15
  from pettingzoo import ParallelEnv
16
16
 
17
17
  @overload
18
- def make(
19
- env: ParallelEnv,
20
- ) -> PettingZoo: ...
21
-
22
- HAS_PETTINGZOO = True
23
- except ImportError:
24
- HAS_PETTINGZOO = False
18
+ def make(env: ParallelEnv) -> PettingZoo: ...
25
19
 
26
20
 
27
- try:
28
- from gymnasium import Env
21
+ if adapters.HAS_GYM:
29
22
  from .adapters import Gym
23
+ from gymnasium import Env
24
+ import gymnasium
30
25
 
31
26
  @overload
32
27
  def make(env: Env) -> Gym: ...
@@ -37,25 +32,21 @@ try:
37
32
  Make an RLEnv from the `gymnasium` registry (e.g: "CartPole-v1").
38
33
  """
39
34
 
40
- HAS_GYM = True
41
- except ImportError:
42
- HAS_GYM = False
43
35
 
44
- try:
45
- from smac.env import StarCraft2Env
36
+ if adapters.HAS_SMAC:
46
37
  from .adapters import SMAC
38
+ from smac.env import StarCraft2Env
47
39
 
48
40
  @overload
49
41
  def make(env: StarCraft2Env) -> SMAC: ...
50
42
 
51
- HAS_SMAC = True
52
- except ImportError:
53
- HAS_SMAC = False
54
43
 
44
+ if adapters.HAS_OVERCOOKED:
45
+ from .adapters import Overcooked
46
+ from overcooked_ai_py.mdp.overcooked_env import OvercookedEnv
55
47
 
56
- @overload
57
- def make(env: MARLEnv[A, AS]) -> MARLEnv[A, AS]:
58
- """Why would you do this ?"""
48
+ @overload
49
+ def make(env: OvercookedEnv) -> Overcooked: ...
59
50
 
60
51
 
61
52
  def make(env, **kwargs):
@@ -64,32 +55,18 @@ def make(env, **kwargs):
64
55
  case MARLEnv():
65
56
  return env
66
57
  case str(env_id):
67
- try:
68
- import gymnasium
69
- except ImportError:
70
- raise ImportError("Gymnasium is not installed !")
71
- from marlenv.adapters import Gym
72
-
73
- gym_env = gymnasium.make(env_id, render_mode="rgb_array", **kwargs)
74
- return Gym(gym_env)
75
-
76
- try:
77
- from marlenv.adapters import PettingZoo
78
-
79
- if isinstance(env, ParallelEnv):
80
- return PettingZoo(env)
81
- except ImportError:
82
- pass
83
- try:
84
- from smac.env import StarCraft2Env
85
-
86
- from marlenv.adapters import SMAC
87
-
88
- if isinstance(env, StarCraft2Env):
89
- return SMAC(env)
90
- except ImportError:
91
- pass
92
-
58
+ if adapters.HAS_GYM:
59
+ gym_env = gymnasium.make(env_id, render_mode="rgb_array", **kwargs)
60
+ return Gym(gym_env)
61
+
62
+ if adapters.HAS_PETTINGZOO and isinstance(env, ParallelEnv):
63
+ return PettingZoo(env) # type: ignore
64
+ if adapters.HAS_SMAC and isinstance(env, StarCraft2Env):
65
+ return SMAC(env)
66
+ if adapters.HAS_OVERCOOKED and isinstance(env, OvercookedEnv):
67
+ return Overcooked(env) # type: ignore
68
+ if adapters.HAS_GYM and isinstance(env, Env):
69
+ return Gym(env)
93
70
  raise ValueError(f"Unknown environment type: {type(env)}")
94
71
 
95
72
 
marlenv/env_pool.py CHANGED
@@ -1,6 +1,5 @@
1
1
  from typing import Sequence
2
2
  from dataclasses import dataclass
3
- import numpy as np
4
3
  import numpy.typing as npt
5
4
  from typing_extensions import TypeVar
6
5
  import random
@@ -58,9 +58,14 @@ class Observation:
58
58
  available_actions=self.available_actions[agent_id],
59
59
  )
60
60
 
61
+ @property
62
+ def shape(self) -> tuple[int, ...]:
63
+ """The individual shape of the observation data"""
64
+ return self.data[0].shape
65
+
61
66
  @property
62
67
  def extras_shape(self) -> tuple[int, ...]:
63
- """The shape of the observation extras"""
68
+ """The individual shape of the observation extras"""
64
69
  return self.extras[0].shape
65
70
 
66
71
  def __hash__(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multi-agent-rlenv
3
- Version: 3.3.0
3
+ Version: 3.3.2
4
4
  Summary: A strongly typed Multi-Agent Reinforcement Learning framework
5
5
  Project-URL: repository, https://github.com/yamoling/multi-agent-rlenv
6
6
  Author-email: Yannick Molinghen <yannick.molinghen@ulb.be>
@@ -8,16 +8,58 @@ License-File: LICENSE
8
8
  Classifier: Operating System :: OS Independent
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Requires-Python: <4,>=3.10
11
- Requires-Dist: gymnasium>=0.29.1
12
11
  Requires-Dist: numpy>=2.0.0
13
- Requires-Dist: opencv-python>=4.10.0.84
12
+ Requires-Dist: opencv-python>=4.0
13
+ Requires-Dist: typing-extensions>=4.0
14
+ Provides-Extra: all
15
+ Requires-Dist: gymnasium>0.29.1; extra == 'all'
16
+ Requires-Dist: overcooked-ai; extra == 'all'
17
+ Requires-Dist: pettingzoo>=1.20; extra == 'all'
18
+ Requires-Dist: pymunk>=6.0; extra == 'all'
19
+ Requires-Dist: pysc2; extra == 'all'
20
+ Requires-Dist: scipy>=1.10; extra == 'all'
21
+ Requires-Dist: smac; extra == 'all'
22
+ Provides-Extra: gym
23
+ Requires-Dist: gymnasium>=0.29.1; extra == 'gym'
24
+ Provides-Extra: overcooked
25
+ Requires-Dist: overcooked-ai>=1.1.0; extra == 'overcooked'
26
+ Requires-Dist: scipy>=1.10; extra == 'overcooked'
27
+ Provides-Extra: pettingzoo
28
+ Requires-Dist: pettingzoo>=1.20; extra == 'pettingzoo'
29
+ Requires-Dist: pymunk>=6.0; extra == 'pettingzoo'
30
+ Requires-Dist: scipy>=1.10; extra == 'pettingzoo'
31
+ Provides-Extra: smac
32
+ Requires-Dist: pysc2; extra == 'smac'
33
+ Requires-Dist: smac; extra == 'smac'
14
34
  Description-Content-Type: text/markdown
15
35
 
16
- # `marlenv` - A unified interface for muti-agent reinforcement learning
36
+ # `marlenv` - A unified framework for muti-agent reinforcement learning
37
+ **Documentation: [https://yamoling.github.io/multi-agent-rlenv](https://yamoling.github.io/multi-agent-rlenv)**
38
+
17
39
  The objective of `marlenv` is to provide a common (typed) interface for many different reinforcement learning environments.
18
40
 
19
41
  As such, `marlenv` provides high level abstractions of RL concepts such as `Observation`s or `Transition`s that are commonly represented as mere (confusing) lists or tuples.
20
42
 
43
+ ## Installation
44
+ Install with you preferred package manager (`uv`, `pip`, `poetry`, ...):
45
+ ```bash
46
+ $ pip install marlenv[all] # Enable all features
47
+ $ pip install marlenv # Basic installation
48
+ ```
49
+
50
+ There are multiple optional dependencies if you want to support specific libraries and environments. Available options are:
51
+ - `smac` for StarCraft II environments
52
+ - `gym` for OpenAI Gym environments
53
+ - `pettingzoo` for PettingZoo environments
54
+ - `overcooked` for Overcooked environments
55
+
56
+ Install them with:
57
+ ```bash
58
+ $ pip install marlenv[smac] # Install SMAC
59
+ $ pip install marlenv[gym,smac] # Install Gym & smac support
60
+ ```
61
+
62
+
21
63
  ## Using `marlenv` with existing libraries
22
64
  `marlenv` unifies multiple popular libraries under a single interface. Namely, `marlenv` supports `smac`, `gymnasium` and `pettingzoo`.
23
65
 
@@ -47,7 +89,7 @@ from marlenv import RLEnv, DiscreteActionSpace, Observation
47
89
  N_AGENTS = 3
48
90
  N_ACTIONS = 5
49
91
 
50
- class CustomEnv(RLEnv[DiscreteActionSpace]):
92
+ class CustomEnv(MARLEnv[DiscreteActionSpace]):
51
93
  def __init__(self, width: int, height: int):
52
94
  super().__init__(
53
95
  action_space=DiscreteActionSpace(N_AGENTS, N_ACTIONS),
@@ -1,19 +1,19 @@
1
- marlenv/__init__.py,sha256=G_8rNDcgzG_colnRNhbX04DIwSZWMJ2Eh7GSHqgIgzo,3741
2
- marlenv/env_builder.py,sha256=YH8yMV74t_joJmyUjBaTB1JabpdugFMY9R8jp2QdRdE,5700
3
- marlenv/env_pool.py,sha256=TSSYwD5-g4G473Ea097wFVbp3tyQrawywLIAFFEJCJY,1089
1
+ marlenv/__init__.py,sha256=GFEcoE8jkA0vbuQyrVRpgsS-iLIelxjpwsB_6pGJGjs,3741
2
+ marlenv/env_builder.py,sha256=_rdwcWRqnHP7i4M4Oje1Y2nrEBKH9EzTpqOuw_PNUyw,5560
3
+ marlenv/env_pool.py,sha256=R3WIrnQ5Zvff4HR1ecfkDmuO2zl7v1ywQ0K2_nvWFzs,1070
4
4
  marlenv/exceptions.py,sha256=gJUC_2rVAvOfK_ypVFc7Myh-pIfSU3To38VBVS_0rZA,1179
5
5
  marlenv/mock_env.py,sha256=qB0fYFIfbopJf7Va8kCeVI5vsOy1-2JdEYe9gdV1Ruw,4761
6
6
  marlenv/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- marlenv/adapters/__init__.py,sha256=LMUebMfyj0Or2luiTlgeSqF2uKjp78Ez8hPDjVUrgVQ,554
7
+ marlenv/adapters/__init__.py,sha256=NEmuHPWz4SGQcgF7QuIeA0QaXK141JoYco-7mqj9Ghk,883
8
8
  marlenv/adapters/gym_adapter.py,sha256=Vx6ZrYI7kiNlJODmqyjXu9WCdbCr6trcMNot0pvYD74,2864
9
- marlenv/adapters/overcooked_adapter.py,sha256=IR2hVMb-ZUxl3BP8WELJGJJBWhSVbuJYjEgg1aBHj20,4774
9
+ marlenv/adapters/overcooked_adapter.py,sha256=Yf1xmjSgDOOSzR3QNqjxQ_ROFEdKUe_C8BF2nLlW3Us,6162
10
10
  marlenv/adapters/pettingzoo_adapter.py,sha256=9rwSc_b7qV3ChtEIevOkJvtIp7WoY3CVnu6L9DxlMB4,2852
11
11
  marlenv/adapters/pymarl_adapter.py,sha256=x__E90XpFbfSWhnBHtkcD6WYkmKki1LByNbUFoDBUcg,3416
12
12
  marlenv/adapters/smac_adapter.py,sha256=fOfKo1hL4ioKtM5qQGcwtfdkdwUEACjAZqaGmkoQUcU,8373
13
13
  marlenv/models/__init__.py,sha256=9M-rnj94nsdyO4zm_VEtyYBmde3iD2_eIY4bMB-IqCo,555
14
14
  marlenv/models/env.py,sha256=faezAKOIccBauOFeo9wu5sX32pFmP3AMmGyJzaTRJcM,7514
15
15
  marlenv/models/episode.py,sha256=ZGBx6lb2snrUhDgFEwHPV1dp-XvMA7k4quQVUNQxsP0,15140
16
- marlenv/models/observation.py,sha256=rTAesS_jaIyRlH4wjo2izEpWS0Hn5_UKjhbvdp0H4tA,2994
16
+ marlenv/models/observation.py,sha256=kAmh1hIoC2TGrZlGVzV0y4TXXCSrI7gcmG0raeoncYk,3153
17
17
  marlenv/models/spaces.py,sha256=pw8Sum_fHBkR-lyfTqUij4azMCNm8oBZrYZe4WVR7rA,7652
18
18
  marlenv/models/state.py,sha256=958PXTHadi3gtRnhGgcGtqBnF44R11kdcx62NN2gwxA,1717
19
19
  marlenv/models/step.py,sha256=LKGAV2Cu-k9Gz1hwrfvGx51l8axtQRqDE9WVL5r2A1Q,3037
@@ -31,7 +31,7 @@ marlenv/wrappers/penalty_wrapper.py,sha256=v4_H8OEN2-yujLzRb6P7W7KwmXHtjAFsxcdp3
31
31
  marlenv/wrappers/rlenv_wrapper.py,sha256=C2XekgBIM4x3Wa2Mtsn7rihRD4ymC2hORI473Af0sfw,2962
32
32
  marlenv/wrappers/time_limit.py,sha256=CDIMMJPMyIDHSFxUJaC7nb7Kd86-07NgZeFhrpZm82o,3985
33
33
  marlenv/wrappers/video_recorder.py,sha256=d5AFu6qHqby9mOcBsYWYPxAPiK1vtnfMYdZ81AnCekI,2624
34
- multi_agent_rlenv-3.3.0.dist-info/METADATA,sha256=V7uoHPEZbXppxZHkO63e1UOm8AwkQ1x5jeF16BiNoIQ,3357
35
- multi_agent_rlenv-3.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
36
- multi_agent_rlenv-3.3.0.dist-info/licenses/LICENSE,sha256=_eeiGVoIJ7kYt6l1zbIvSBQppTnw0mjnYk1lQ4FxEjE,1074
37
- multi_agent_rlenv-3.3.0.dist-info/RECORD,,
34
+ multi_agent_rlenv-3.3.2.dist-info/METADATA,sha256=s9O2h4QdJZ4Ytq1hRiBFJPsAtWV0bd1JLxDx4MChaI0,4897
35
+ multi_agent_rlenv-3.3.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
36
+ multi_agent_rlenv-3.3.2.dist-info/licenses/LICENSE,sha256=_eeiGVoIJ7kYt6l1zbIvSBQppTnw0mjnYk1lQ4FxEjE,1074
37
+ multi_agent_rlenv-3.3.2.dist-info/RECORD,,