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 (
Env
or one of the Additional Interfaces), be it direct or indirect. Virtual subclasses are not recognized.This restriction is given by
Env
not 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
Env
not actually being aProtocol
.Implementor classes that don’t subclass an intersection protocol must provide all three spaces [1] as attributes or
properties
at 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 classMyEnv
is 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
Env
andSingleOptimizable
.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
GoalEnv
andSingleOptimizable
.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
SeparableEnv
andSingleOptimizable
.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
SeparableGoalEnv
andSingleOptimizable
.Any class that inherits from both also inherits from this class.