Skip to content

Vectorized Envs

API Reference

masa.common.wrappers.VecEnvWrapperBase

VecEnvWrapperBase(env: Env)

Bases: ConstraintPersistentWrapper

Base class for simple Python-list vector environment wrappers.

Vector environments in this file expose:

  • n_envs: number of parallel environments
  • reset: returns (obs_list, info_list)
  • step: returns (obs_list, rew_list, term_list, trunc_list, info_list)
  • reset_done: reset only environments indicated by a dones mask

Parameters:

Name Type Description Default
env Env

For DummyVecWrapper, this is the single underlying env. For VecWrapper, this is set to envs[0] to preserve a Gymnasium-like API surface.

required

Attributes:

Name Type Description
n_envs int

Number of environments.

Source code in masa/common/wrappers.py
def __init__(self, env: gym.Env):
    # For DummyVecWrapper: env is the single env
    # For VecWrapper: env is envs[0]
    # For VecNormWrapper: env is a VecEnvWrapperBase
    super().__init__(env)

n_envs instance-attribute

n_envs: int

reset_done

reset_done(dones: Union[List[bool], ndarray], *, seed: int | None = None, options: Dict[str, Any] | None = None)

Reset only the environments indicated by dones.

Parameters:

Name Type Description Default
dones Union[List[bool], ndarray]

Boolean mask/list of length n_envs. Entries set to True are reset.

required
seed int | None

Optional base seed. Implementations may offset by environment index.

None
options Dict[str, Any] | None

Reset options forwarded to underlying environments.

None

Returns:

Type Description

A tuple (reset_obs, reset_infos) where:

  • reset_obs is a list of length n_envs containing reset observations at indices that were reset, and None elsewhere.
  • reset_infos is a list of length n_envs containing reset info dicts at indices that were reset, and empty dicts elsewhere.

Raises:

Type Description
NotImplementedError

If not implemented by a subclass.

Source code in masa/common/wrappers.py
def reset_done(
    self, 
    dones: Union[List[bool], np.ndarray],
    *, 
    seed: int | None = None, 
    options: Dict[str, Any] | None = None
):
    """
    Reset only the environments indicated by ``dones``.

    Args:
        dones: Boolean mask/list of length :attr:`n_envs`. Entries set to
            ``True`` are reset.
        seed: Optional base seed. Implementations may offset by environment index.
        options: Reset options forwarded to underlying environments.

    Returns:
        A tuple ``(reset_obs, reset_infos)`` where:

        * ``reset_obs`` is a list of length :attr:`n_envs` containing reset
          observations at indices that were reset, and ``None`` elsewhere.
        * ``reset_infos`` is a list of length :attr:`n_envs` containing reset
          info dicts at indices that were reset, and empty dicts elsewhere.

    Raises:
        NotImplementedError: If not implemented by a subclass.
    """
    raise NotImplementedError

masa.common.wrappers.DummyVecWrapper

DummyVecWrapper(env: Env)

Bases: VecEnvWrapperBase

Wrap a single environment with a vector-environment API (n_envs=1).

This wrapper is useful for code paths that expect list-based vector outputs, while still running a single environment instance.

Parameters:

Name Type Description Default
env Env

Base environment.

required

Attributes:

Name Type Description
n_envs

Always 1.

envs List[Env]

List containing the single wrapped environment.

Source code in masa/common/wrappers.py
def __init__(self, env: gym.Env):
    super().__init__(env)
    self.n_envs = 1
    self.envs: List[gym.Env] = [env]

n_envs instance-attribute

n_envs = 1

envs instance-attribute

envs: List[Env] = [env]

reset

reset(*, seed: int | None = None, options: Dict[str, Any] | None = None)

Reset and return vectorized lists of length 1.

Parameters:

Name Type Description Default
seed int | None

Random seed forwarded to the underlying environment.

None
options Dict[str, Any] | None

Reset options forwarded to the underlying environment.

None

Returns:

Type Description

([obs], [info]).

Source code in masa/common/wrappers.py
def reset(self, *, seed: int | None = None, options: Dict[str, Any] | None = None):
    """
    Reset and return vectorized lists of length 1.

    Args:
        seed: Random seed forwarded to the underlying environment.
        options: Reset options forwarded to the underlying environment.

    Returns:
        ``([obs], [info])``.
    """
    obs, info = self.env.reset(seed=seed, options=options)
    return [obs], [info]

reset_done

reset_done(dones: Union[List[bool], ndarray], *, seed: int | None = None, options: Dict[str, Any] | None = None)

Conditionally reset the single environment.

Parameters:

Name Type Description Default
dones Union[List[bool], ndarray]

A length-1 mask. If dones[0] is True, reset.

required
seed int | None

Random seed forwarded to the underlying environment.

None
options Dict[str, Any] | None

Reset options forwarded to the underlying environment.

None

Returns:

Type Description

A pair (reset_obs, reset_infos) as described by

VecEnvWrapperBase.reset_done.

Source code in masa/common/wrappers.py
def reset_done(
    self, 
    dones: Union[List[bool], np.ndarray],
    *, 
    seed: int | None = None, 
    options: Dict[str, Any] | None = None
):
    """
    Conditionally reset the single environment.

    Args:
        dones: A length-1 mask. If ``dones[0]`` is ``True``, reset.
        seed: Random seed forwarded to the underlying environment.
        options: Reset options forwarded to the underlying environment.

    Returns:
        A pair ``(reset_obs, reset_infos)`` as described by
        :meth:`VecEnvWrapperBase.reset_done`.
    """
    dones = list(dones)
    assert len(dones) == 1
    if dones[0]:
        return self.reset(seed=seed, options=options)
    else:
        [None], [{}]

step

step(action)

Step and return vectorized lists of length 1.

Parameters:

Name Type Description Default
action

Action for the single environment.

required

Returns:

Type Description

([obs], [rew], [terminated], [truncated], [info]).

Source code in masa/common/wrappers.py
def step(self, action):
    """
    Step and return vectorized lists of length 1.

    Args:
        action: Action for the single environment.

    Returns:
        ``([obs], [rew], [terminated], [truncated], [info])``.
    """
    obs, rew, term, trunc, info = self.env.step(action)
    return [obs], [rew], [term], [trunc], [info]

masa.common.wrappers.VecWrapper

VecWrapper(envs: List[Env])

Bases: VecEnvWrapperBase

Wrap a list of environments with a simple vector-environment API.

Each underlying environment is reset/stepped sequentially in Python, and results are returned as Python lists.

Parameters:

Name Type Description Default
envs List[Env]

Non-empty list of environments.

required

Attributes:

Name Type Description
envs List[Env]

The list of wrapped environments.

n_envs

Number of wrapped environments.

Source code in masa/common/wrappers.py
def __init__(self, envs: List[gym.Env]):
    assert len(envs) > 0, "VecWrapper requires at least one environment"
    super().__init__(envs[0]) # maintain API compatibility
    self.envs: List[gym.Env] = envs
    self.n_envs = len(envs)

envs instance-attribute

envs: List[Env] = envs

n_envs instance-attribute

n_envs = len(envs)

reset

reset(*, seed: int | None = None, options: Dict[str, Any] | None = None)

Reset all environments and return lists.

Parameters:

Name Type Description Default
seed int | None

Optional base seed. If provided, environment i receives seed + i.

None
options Dict[str, Any] | None

Reset options forwarded to each environment.

None

Returns:

Type Description

A pair (obs_list, info_list) of length n_envs.

Source code in masa/common/wrappers.py
def reset(self, *, seed: int | None = None, options: Dict[str, Any] | None = None):
    """
    Reset all environments and return lists.

    Args:
        seed: Optional base seed. If provided, environment ``i`` receives ``seed + i``.
        options: Reset options forwarded to each environment.

    Returns:
        A pair ``(obs_list, info_list)`` of length :attr:`n_envs`.
    """
    obs_list, info_list = [], []
    for i, env in enumerate(self.envs):
        s = None if seed is None else seed + i
        obs, info = env.reset(seed=s, options=options)
        obs_list.append(obs)
        info_list.append(info)
    return obs_list, info_list

reset_done

reset_done(dones: Union[List[bool], ndarray], *, seed: int | None = None, options: Dict[str, Any] | None = None)

Reset only environments whose done flag is True.

Parameters:

Name Type Description Default
dones Union[List[bool], ndarray]

Boolean mask/list of length n_envs.

required
seed int | None

Optional base seed. If provided, environment i receives seed + i.

None
options Dict[str, Any] | None

Reset options forwarded to environments being reset.

None

Returns:

Type Description

A tuple (reset_obs, reset_infos) where non-reset indices contain

None and {} respectively.

Source code in masa/common/wrappers.py
def reset_done(
    self, 
    dones: Union[List[bool], np.ndarray],
    *, 
    seed: int | None = None, 
    options: Dict[str, Any] | None = None
):
    """
    Reset only environments whose done flag is True.

    Args:
        dones: Boolean mask/list of length :attr:`n_envs`.
        seed: Optional base seed. If provided, environment ``i`` receives ``seed + i``.
        options: Reset options forwarded to environments being reset.

    Returns:
        A tuple ``(reset_obs, reset_infos)`` where non-reset indices contain
        ``None`` and ``{}`` respectively.
    """
    dones = list(dones)
    assert len(dones) == self.n_envs

    reset_obs = [None] * self.n_envs
    reset_infos = [{} for _ in range(self.n_envs)]

    for i, done in enumerate(dones):
        if done:
            s = None if seed is None else seed + i
            obs, info = self.envs[i].reset(seed=s, options=options)
            reset_obs[i] = obs
            reset_infos[i] = info

    return reset_obs, reset_infos

step

step(actions)

Step all environments.

Parameters:

Name Type Description Default
actions

Iterable of actions of length n_envs.

required

Returns:

Type Description

A 5-tuple of lists (obs_list, rew_list, term_list, trunc_list, info_list).

Notes

The loop expects one action per environment. If the provided actions length mismatches n_envs, Python will raise.

Source code in masa/common/wrappers.py
def step(self, actions):
    """
    Step all environments.

    Args:
        actions: Iterable of actions of length :attr:`n_envs`.

    Returns:
        A 5-tuple of lists ``(obs_list, rew_list, term_list, trunc_list, info_list)``.

    Notes:
        The loop expects one action per environment. If the provided
        ``actions`` length mismatches :attr:`n_envs`, Python will raise.
    """
    obs_list, rew_list, term_list, trunc_list, info_list = [], [], [], [], []
    for env, action in zip(self.envs, actions):
        obs, rew, term, trunc, info = env.step(action)
        obs_list.append(obs)
        rew_list.append(rew)
        term_list.append(term)
        trunc_list.append(trunc)
        info_list.append(info)

    return obs_list, rew_list, term_list, trunc_list, info_list

masa.common.wrappers.VecNormWrapper

VecNormWrapper(env: Union[Env, List[Env]], norm_obs: bool = True, norm_rew: bool = True, training: bool = True, clip_obs: float = 10.0, clip_rew: float = 10.0, gamma: float = 0.99, eps: float = 1e-08)

Bases: VecEnvWrapperBase

Normalize observations and/or rewards for a vectorized environment.

This wrapper expects an environment implementing VecEnvWrapperBase (e.g., DummyVecWrapper or VecWrapper) and applies the same normalization logic as NormWrapper, but over batches.

Observation normalization uses running statistics of the stacked observation array (shape (n_envs, *obs_shape)). Reward normalization uses running statistics of discounted returns per environment.

Parameters:

Name Type Description Default
env Union[Env, List[Env]]

A vectorized environment implementing VecEnvWrapperBase.

required
norm_obs bool

Whether to normalize observations.

True
norm_rew bool

Whether to normalize rewards.

True
training bool

If True, update running statistics; otherwise, statistics are frozen.

True
clip_obs float

Clip normalized observations to [-clip_obs, clip_obs].

10.0
clip_rew float

Clip normalized rewards to [-clip_rew, clip_rew].

10.0
gamma float

Discount factor for the running return used in reward normalization.

0.99
eps float

Small constant \(\varepsilon\) for numerical stability.

1e-08

Attributes:

Name Type Description
n_envs

Copied from the wrapped vector environment.

obs_rms

masa.common.running_mean_std.RunningMeanStd for observations.

rew_rms

masa.common.running_mean_std.RunningMeanStd for returns.

returns

Vector of length n_envs storing per-env discounted returns.

Source code in masa/common/wrappers.py
def __init__(
    self, 
    env: Union[gym.Env, List[gym.Env]], 
    norm_obs: bool = True,
    norm_rew: bool = True,
    training: bool = True,
    clip_obs: float = 10.0,
    clip_rew: float = 10.0,
    gamma: float = 0.99,
    eps: float = 1e-8
):
    assert isinstance(
        env, VecEnvWrapperBase
    ), "VecNormWrapper expects a vectorized environment (DummyVecWrapper / VecWrapper)."

    assert norm_obs and isinstance(
        env.observation_space, spaces.Box
    ), "VecNormWrapper only supports Box observation spaces when norm_obs=True."

    super().__init__(env)

    self.n_envs = env.n_envs
    self.norm_obs = norm_obs
    self.norm_rew = norm_rew
    self.training = training
    self.clip_obs = clip_obs
    self.clip_rew = clip_rew
    self.gamma = gamma
    self.eps = eps

    self.obs_rms = RunningMeanStd(shape=self.observation_space.shape)
    self.rew_rms = RunningMeanStd(shape=())

    self.returns = np.zeros(self.n_envs, dtype=np.float32)

n_envs instance-attribute

n_envs = env.n_envs

norm_obs instance-attribute

norm_obs = norm_obs

norm_rew instance-attribute

norm_rew = norm_rew

training instance-attribute

training = training

clip_obs instance-attribute

clip_obs = clip_obs

clip_rew instance-attribute

clip_rew = clip_rew

gamma instance-attribute

gamma = gamma

eps instance-attribute

eps = eps

obs_rms instance-attribute

obs_rms = RunningMeanStd(shape=self.observation_space.shape)

rew_rms instance-attribute

rew_rms = RunningMeanStd(shape=())

returns instance-attribute

returns = np.zeros(self.n_envs, dtype=np.float32)

_normalize_obs

_normalize_obs(obs_list: List[ndarray]) -> List[np.ndarray]

Normalize and clip a list of observations.

Parameters:

Name Type Description Default
obs_list List[ndarray]

List of raw observations of length n_envs.

required

Returns:

Type Description
List[ndarray]

List of normalized observations.

Source code in masa/common/wrappers.py
def _normalize_obs(self, obs_list: List[np.ndarray]) -> List[np.ndarray]:
    """
    Normalize and clip a list of observations.

    Args:
        obs_list: List of raw observations of length :attr:`n_envs`.

    Returns:
        List of normalized observations.
    """
    obs_arr = np.asarray(obs_list, dtype=np.float32)
    norm = (obs_arr - self.obs_rms.mean) / np.sqrt(self.obs_rms.var + self.eps)
    norm = np.clip(norm, -self.clip_obs, self.clip_obs)
    return norm.tolist()

_normalize_rew

_normalize_rew(rew_list: List[float]) -> List[float]

Normalize and clip a list of rewards.

Parameters:

Name Type Description Default
rew_list List[float]

List of raw rewards of length n_envs.

required

Returns:

Type Description
List[float]

List of normalized rewards.

Source code in masa/common/wrappers.py
def _normalize_rew(self, rew_list: List[float]) -> List[float]:
    """
    Normalize and clip a list of rewards.

    Args:
        rew_list: List of raw rewards of length :attr:`n_envs`.

    Returns:
        List of normalized rewards.
    """
    rew_arr = np.asarray(rew_list, dtype=np.float32)
    norm = rew_arr / np.sqrt(self.rew_rms.var + self.eps)
    norm = np.clip(norm, -self.clip_rew, self.clip_rew)
    return norm.tolist()

reset

reset(*, seed: int | None = None, options: Dict[str, Any] | None = None)

Reset all environments and normalize observations.

Parameters:

Name Type Description Default
seed int | None

Optional base seed forwarded to the underlying vector env.

None
options Dict[str, Any] | None

Reset options forwarded to the underlying vector env.

None

Returns:

Type Description

A pair (obs_list, info_list). Observations may be normalized.

Source code in masa/common/wrappers.py
def reset(self, *, seed: int | None = None, options: Dict[str, Any] | None = None):
    """
    Reset all environments and normalize observations.

    Args:
        seed: Optional base seed forwarded to the underlying vector env.
        options: Reset options forwarded to the underlying vector env.

    Returns:
        A pair ``(obs_list, info_list)``. Observations may be normalized.
    """
    obs_list, info_list = self.env.reset(seed=seed, options=options)

    if self.norm_obs and self.training:
        self.obs_rms.update(np.asarray(obs_list, dtype=np.float32))

    self.returns[:] = 0.0

    if self.norm_obs:
        obs_list = self._normalize_obs(obs_list)

    return obs_list, info_list

reset_done

reset_done(dones: Union[List[bool], ndarray], *, seed: int | None = None, options: Dict[str, Any] | None = None)

Reset only environments indicated by dones and normalize those observations.

Parameters:

Name Type Description Default
dones Union[List[bool], ndarray]

Boolean mask/list of length n_envs.

required
seed int | None

Optional base seed forwarded to the underlying vector env.

None
options Dict[str, Any] | None

Reset options forwarded to the underlying vector env.

None

Returns:

Type Description

A tuple (reset_obs, reset_infos) as described by

VecEnvWrapperBase.reset_done, with reset observations optionally

normalized.

Source code in masa/common/wrappers.py
def reset_done(
    self, 
    dones: Union[List[bool], np.ndarray],
    *, 
    seed: int | None = None, 
    options: Dict[str, Any] | None = None
):
    """
    Reset only environments indicated by ``dones`` and normalize those observations.

    Args:
        dones: Boolean mask/list of length :attr:`n_envs`.
        seed: Optional base seed forwarded to the underlying vector env.
        options: Reset options forwarded to the underlying vector env.

    Returns:
        A tuple ``(reset_obs, reset_infos)`` as described by
        :meth:`VecEnvWrapperBase.reset_done`, with reset observations optionally
        normalized.
    """
    reset_obs, reset_infos = self.env.reset_done(
        dones, seed=seed, options=options
    )

    obs_arr = np.asarray(
        [o for o in reset_obs if o is not None],
        dtype=np.float32,
    ) if any(o is not None for o in reset_obs) else None

    if self.norm_obs and self.training and obs_arr is not None:
        self.obs_rms.update(obs_arr)

    for i, done in enumerate(dones):
        if done:
            self.returns[i] = 0.0

    if self.norm_obs:
        norm_reset_obs: List[Any] = list(reset_obs)
        # Only normalize indices that were reset
        for i, done in enumerate(dones):
            if done and reset_obs[i] is not None:
                o = np.asarray(reset_obs[i], dtype=np.float32)
                norm = (o - self.obs_rms.mean) / np.sqrt(self.obs_rms.var + self.eps)
                norm = np.clip(norm, -self.clip_obs, self.clip_obs)
                norm_reset_obs[i] = norm
        reset_obs = norm_reset_obs

    return reset_obs, reset_infos

step

step(actions)

Step all environments and apply observation/reward normalization.

Parameters:

Name Type Description Default
actions

Iterable of actions of length n_envs.

required

Returns:

Type Description

A 5-tuple (obs_list, rew_list, term_list, trunc_list, infos), where

observations and/or rewards may be normalized.

Source code in masa/common/wrappers.py
def step(self, actions):
    """
    Step all environments and apply observation/reward normalization.

    Args:
        actions: Iterable of actions of length :attr:`n_envs`.

    Returns:
        A 5-tuple ``(obs_list, rew_list, term_list, trunc_list, infos)``, where
        observations and/or rewards may be normalized.
    """
    obs_list, rew_list, term_list, trunc_list, infos = self.env.step(actions)

    obs_arr = np.asarray(obs_list, dtype=np.float32)
    rew_arr = np.asarray(rew_list, dtype=np.float32)

    if self.norm_obs and self.training:
        self.obs_rms.update(obs_arr)

    if self.norm_rew:
        self.returns = self.returns * self.gamma + rew_arr
        if self.training:
            self.rew_rms.update(self.returns)

        rew_list = self._normalize_rew(rew_list)

    if self.norm_obs:
        obs_list = self._normalize_obs(obs_list)

    return obs_list, rew_list, term_list, trunc_list, infos