Source code for verigym.abstraction.gym_utils.transform_action
from collections.abc import Callable
from typing import Any
import gymnasium as gym
import numpy as np
import numpy.typing as npt
from gymnasium.core import ActType, ObsType
from gymnasium.wrappers import TransformAction
from verigym.abstraction.discretization import (
BinEdges,
generate_box_bins,
BinEdgeGenFunc,
)
from verigym.abstraction.gym_utils.spaces import is_bounded_space
__all__ = [
"DiscretizeBoxAction",
]
[docs]
class DiscretizeBoxAction(TransformAction):
"""Discretization Wrapper for Box action spaces
Parameters
----------
env : gym.Env
The environment containing a continuous action space
n_samples : optional, int | npt.NDarray[np.integer], default=None
The number of bins to use for each dimension.
If `n_samples` is an array it must have the same shape as the
action space.
If `n_samples` is not provided, then a valid Bins array must be
provided
bin_edges : BinEdges
A valid BinEdges array describing how to discretize each dimension
use_box_space : bool,default=True
Whether to keep using the Box space or construct a discrete space
(setting this to False will change the action space)
**kwargs
Additional keyword arguments that are forwarded to `generate_box_bins`
Raises
------
AssertionError
Raises an AssertionError if the action space is not
a continuous Box space or if one of the boundaries is infinite
"""
def __init__(
self,
env: gym.Env[ObsType, ActType],
n_samples: int | npt.NDArray[np.integer[Any]] | None = None,
bin_edges: BinEdges | BinEdgeGenFunc = np.linspace,
use_box_space: bool = True,
**kwargs,
):
# assert that action space is finite/bounded
is_bounded_space(env.action_space)
if isinstance(bin_edges, Callable):
assert n_samples is not None, (
"If bin_edges is defined as a callable, n_samples must be either a valid integer\
or a numpy array with the same shape as the space"
)
bin_func = bin_edges
bin_edges = generate_box_bins(
env.action_space, bin_func, n_samples, **kwargs
)
space = env.action_space
if use_box_space:
# maps from action space (the original Box) onto the bin edges.
to_continuous = bin_edges.orig_to_value
else:
# The space becomes the discrete bin-index space; maps
# an index back to the continuous value the env expects, i.e.
# I -> V
space = gym.spaces.MultiDiscrete(bin_edges.n_bins)
to_continuous = bin_edges.idx_to_value
self._bin_edges = bin_edges
super().__init__(env, to_continuous, space)
@property
def bin_edges(self):
return self._bin_edges