Source code for palaestrai.agent.actuator_information

from __future__ import annotations

import logging
import warnings
from typing import TYPE_CHECKING, Optional, Union, Any

import numpy as np

from palaestrai.types import Space
from palaestrai.util.exception import OutOfActionSpaceError

if TYPE_CHECKING:
    import palaestrai.types

LOG = logging.getLogger(__name__)


[docs] class ActuatorInformation: """Stores information about a single actuator. The actuator information class is used to transfer actuator information. It can be called to set a new value (value): .. code-block:: a = Actuator(some_space) a(42) # a.value is now 42 Parameters ---------- value : any, optional The set value for this actuator. The type is defined by the :attr:`space`. Can be skipped and set afterwards. space : :class:`palaestrai.types.Space` An instance of a palaestrai space that defines the type of the :attr:`value`. uid : int or str, optional A unique identifier for this actuator. The agents use this ID only to assign the value_ids to the correct actuator. The ID is not analyzed to gain domain knowledge. value_ids: list of str or int or None (default: None) if the actuator has multiple value_ids, the value_ids can be used to identify the value_ids, e.g., the ids can be the names of the value_ids. This should be used if value is a list or a numpy array. setpoint : int or str, optional *Deprecated* in favor of value action_space : :class:`palaestrai.types.Space` *Deprecated* in favor of space actuator_id : int or str, optional *Deprecated* in favor of uid """ def __init__( self, value: Optional[Union[int, float, np.ndarray]] = None, space: Optional[Space] = None, uid: Optional[str] = None, value_ids=None, setpoint=None, action_space: Optional[Space] = None, actuator_id=None, ): self._uid = uid if uid is not None else actuator_id self._value = value if value is not None else setpoint self._space = space if space is not None else action_space self.value_ids = value_ids assert self._uid is not None, "Must give ActuatorInformation.uid" assert self._space is not None ActuatorInformation._assert_value_in_space(self._value, self._space) @property def value_ids(self): return self._value_ids @value_ids.setter def value_ids(self, value): self._value_ids = value @property def setpoint(self): warnings.warn( f"setpoint property deprecated in class {self.__class__}. Use " f"value instead.", DeprecationWarning, stacklevel=2, ) return self.value @setpoint.setter def setpoint(self, setpoint): warnings.warn( f"setpoint property deprecated in class {self.__class__}. Use " f"value instead.", DeprecationWarning, stacklevel=2, ) self.value = setpoint @property def value(self): return self._value @value.setter def value(self, value): ActuatorInformation._assert_value_in_space(value, self.space) self._value = value
[docs] def flat_value(self, **kwargs): """Return a flat vector representation of the value""" return self.space.to_vector(np.array(self.value), **kwargs)
def __call__(self, setpoint): self.value = setpoint def __repr__(self): return "ActuatorInformation(" "value=%s, space=%s, uid=%s)" % ( self.value, repr(self.space), self.uid, ) def __len__(self): """The number of values in the space""" return len(self.space) def __eq__(self, other): return ( isinstance(other, ActuatorInformation) and self.uid == other.uid and self.value == other.value and self.space == other.space and self.value_ids == other.value_ids ) def __getstate__(self): return dict( uid=self.uid, value=( self._value.tolist() if isinstance(self._value, np.ndarray) else self._value ), space=self._space.to_string(), value_ids=self._value_ids, ) def __setstate__(self, state): self._uid = state["uid"] self._space = Space.from_string(state["space"]) assert self._space is not None self._value = ( np.array(state["value"], dtype=self._space.dtype) if isinstance(state["value"], list) else state["value"] ) self._value_ids = state["value_ids"] @property def space(self) -> Space: assert self._space is not None return self._space @space.setter def space(self, space: Space): assert space is not None ActuatorInformation._assert_value_in_space(self._value, space) self._space = space @property def action_space(self): warnings.warn( f"action_space property deprecated in class {self.__class__}. Use " f"space instead.", DeprecationWarning, stacklevel=2, ) return self.space @action_space.setter def action_space(self, space: Space): warnings.warn( f"action_space setter deprecated in class {self.__class__}. Use " f"space instead.", DeprecationWarning, stacklevel=2, ) self.space = space @property def id(self): warnings.warn( f"id property deprecated in class {self.__class__}. Use " f"uid instead.", DeprecationWarning, stacklevel=2, ) return self.uid @id.setter def id(self, value): warnings.warn( f"id property deprecated in class {self.__class__}. Use " f"uid instead.", DeprecationWarning, stacklevel=2, ) self.uid = value @property def actuator_id(self): warnings.warn( f"actuator_id property deprecated in class {self.__class__}. Use " f"uid instead.", DeprecationWarning, stacklevel=2, ) return self.uid @actuator_id.setter def actuator_id(self, value): warnings.warn( f"actuator_id property deprecated in class {self.__class__}. Use " f"uid instead.", DeprecationWarning, stacklevel=2, ) self.uid = value @property def uid(self) -> str: return self._uid @uid.setter def uid(self, value: str): self._uid = value @staticmethod def _assert_value_in_space(value: Any, space: Space): if value is None: LOG.warning( "The value to be set is None. " "Its the recommended value if wanting to share meta " "information about an information class, but " "be careful when wanting to use it as a value!" ) elif not space.contains(value): raise OutOfActionSpaceError( f'Value "{value}" not contained in space "{space}"' )