Files
PrimAITE/src/primaite/game/agent/observations/observations.py

69 lines
2.2 KiB
Python
Raw Normal View History

"""Manages the observation space for the agent."""
from abc import ABC, abstractmethod
from typing import Any, Dict, Iterable, Type
2023-10-10 21:01:09 +01:00
from gymnasium import spaces
2024-03-31 17:31:10 +01:00
from gymnasium.core import ObsType
2024-03-27 22:11:02 +00:00
from pydantic import BaseModel, ConfigDict
2023-10-10 21:01:09 +01:00
from primaite import getLogger
2023-10-10 21:01:09 +01:00
_LOGGER = getLogger(__name__)
2024-03-29 14:14:03 +00:00
WhereType = Iterable[str | int] | None
2023-09-25 16:04:04 +01:00
2023-09-21 10:42:26 +01:00
2023-09-25 16:04:04 +01:00
class AbstractObservation(ABC):
"""Abstract class for an observation space component."""
2024-03-27 22:11:02 +00:00
class ConfigSchema(ABC, BaseModel):
2024-03-29 14:14:03 +00:00
"""Config schema for observations."""
2024-03-27 22:11:02 +00:00
model_config = ConfigDict(extra="forbid")
_registry: Dict[str, Type["AbstractObservation"]] = {}
"""Registry of observation components, with their name as key.
Automatically populated when subclasses are defined. Used for defining from_config.
"""
2024-03-31 17:31:10 +01:00
def __init__(self) -> None:
"""Initialise an observation. This method must be overwritten."""
self.default_observation: ObsType
2024-03-27 22:11:02 +00:00
def __init_subclass__(cls, identifier: str, **kwargs: Any) -> None:
"""
Register an observation type.
:param identifier: Identifier used to uniquely specify observation component types.
:type identifier: str
:raises ValueError: When attempting to create a component with a name that is already in use.
"""
super().__init_subclass__(**kwargs)
if identifier in cls._registry:
raise ValueError(f"Duplicate observation component type {identifier}")
cls._registry[identifier] = cls
@abstractmethod
2023-09-25 16:04:04 +01:00
def observe(self, state: Dict) -> Any:
"""
Return an observation based on the current state of the simulation.
:param state: Simulation state dictionary
:type state: Dict
:return: Observation
:rtype: Any
"""
pass
2023-09-21 10:42:26 +01:00
@property
@abstractmethod
def space(self) -> spaces.Space:
"""Gymnasium space object describing the observation space."""
pass
2023-09-21 10:42:26 +01:00
@classmethod
2024-03-31 17:31:10 +01:00
@abstractmethod
def from_config(cls, config: ConfigSchema, parent_where: WhereType = []) -> "AbstractObservation":
2024-03-27 22:11:02 +00:00
"""Create this observation space component form a serialised format."""
2024-03-31 17:31:10 +01:00
return cls()