Intersection Interfaces¶
See also
- More Optimization Interfaces
User guide page on the topic.
These protocols are intersections of various types of problems.
An intersection protocol indicates that a type implements all
protocols that are part of the intersection. Taking for example
OptEnv, an intersection of SingleOptimizable and Env,
you can shorten your line of base classes:
>>> from gymnasium.spaces import Box
>>> from gymnasium import Env
>>> from cernml import coi
...
>>> class Both(coi.OptEnv):
... def __init__(self, render_mode=None):
... super().__init__(render_mode)
... self.optimization_space = Box(-1, 1)
... self.observation_space = Box(-1, 1)
... self.action_space = Box(-1, 1)
...
... def get_initial_params(self): ...
...
... def compute_single_objective(self, params): ...
...
>>> env = Both()
>>> isinstance(env, coi.SingleOptimizable)
True
>>> isinstance(env, Env)
True
>>> isinstance(env, coi.OptEnv)
True
Vice versa, you can use intersection protocols to test if a class implements both protocols, even if it doesn’t directly subclass the intersection protocol:
>>> class Indirect(Env, coi.SingleOptimizable):
... def __init__(self, render_mode=None):
... super().__init__(render_mode)
... self.optimization_space = Box(-1, 1)
... self.observation_space = Box(-1, 1)
... self.action_space = Box(-1, 1)
...
... def get_initial_params(self): ...
...
... def compute_single_objective(self, params): ...
...
>>> env = Indirect()
>>> isinstance(env, coi.SingleOptimizable)
True
>>> isinstance(env, Env)
True
>>> isinstance(env, coi.OptEnv)
True
The intersection protocols of this package come with a few limitations given by the implementation:
Implementors must be real subclasses of one of the environment base classes (
Envor one of the Additional Interfaces), be it direct or indirect. Virtual subclasses are not recognized.This restriction is given by
Envnot actually being aProtocol; accordingly, it does not apply toSingleOptimizable.Static type checkers like MyPy generally don’t recognize the intersections as true protocols, even though they behave as such at runtime. Again, this is a limitation of
Envnot actually being aProtocol.Implementor classes that don’t subclass an intersection protocol must provide all three spaces [1] as attributes or
propertiesat class scope to be recognized as subclasses. Type annotations are not sufficient.This restriction is given by the fact that for protocols,
issubclass()only checks the type hints of a subclass if the subclass is itself a protocol. If the subclass is concrete (i.e. not a protocol) and also doesn’t have a protocol among its bases, there is no way for Python to verify the implementation.Implementor instances, on the other hand, merely need to define the three spaces [1]. This may happen e.g. within
__init__(). This may lead to the situation that a classMyEnvis not a subclass ofOptEnv, butMyEnv()is an instance of it. This is simply given by the dynamic nature of Python.
- class cernml.coi.OptEnv(render_mode: str | None = None)¶
Bases:
Env[ObsType,ActType],SingleOptimizable[ParamType]An intersection of
EnvandSingleOptimizable.Any class that inherits from both also inherits from this class.
- class cernml.coi.OptGoalEnv(render_mode: str | None = None)¶
Bases:
GoalEnv,SingleOptimizable[ParamType],Generic[ObsType,GoalType,ActType,ParamType]An intersection of
GoalEnvandSingleOptimizable.Any class that inherits from both also inherits from this class.
- class cernml.coi.SeparableOptEnv(render_mode: str | None = None)¶
Bases:
SeparableEnv[ObsType,ActType],SingleOptimizable[ParamType]An intersection of
SeparableEnvandSingleOptimizable.Any class that inherits from both also inherits from this class.
- class cernml.coi.SeparableOptGoalEnv(render_mode: str | None = None)¶
Bases:
SeparableGoalEnv[ObsType,GoalType,ActType],SingleOptimizable[ParamType]An intersection of
SeparableGoalEnvandSingleOptimizable.Any class that inherits from both also inherits from this class.