Use Observation Functions
Using any environment, the observation 1 received by the user to take the
next action can be customized changing the ObservationFunction
used by the solver.
The environment is not extracting data directly but delegates that responsibility to an
ObservationFunction
object.
The object has complete access to the solver and extract the data it needs.
Specifying an observation function is as easy as specifying a parameter when
creating an environment.
For instance with the Branching
environment:
>>> env = ecole.environment.Branching(observation_function=ecole.observation.Nothing())
>>> env.observation_function
ecole.observation.Nothing()
>>> obs, _, _, _, _ = env.reset("path/to/problem")
>>> obs is None
True
Environments have an observation function set as default parameter for convenience.
>>> env = ecole.environment.Branching()
>>> env.observation_function
ecole.observation.NodeBipartite()
>>> obs, _, _, _, _ = env.reset("path/to/problem")
>>> obs
ecole.observation.NodeBipartiteObs(...)
See the reference for the list of available observation functions, as well as the documention for explanation on how to create one.
No Observation Function
To not use any observation function, for instance for learning with a bandit algorithm,
you can explicitly pass None
to the environment constructor.
>>> env = ecole.environment.Branching(observation_function=None)
>>> env.observation_function
ecole.observation.nothing()
>>> obs, _, _, _, _ = env.reset("path/to/problem")
>>> obs is None
True
Multiple Observation Functions
To use multiple observation functions, wrap them in a list
or dict
.
>>> obs_func = {
... "some_name": ecole.observation.NodeBipartite(),
... "other_name": ecole.observation.Nothing(),
... }
>>> env = ecole.environment.Branching(observation_function=obs_func)
>>> obs, _, _, _, _ = env.reset("path/to/problem")
>>> obs
{'some_name': ecole.observation.NodeBipartiteObs(), 'other_name': None}
Similarily with a tuple
>>> obs_func = (ecole.observation.NodeBipartite(), ecole.observation.Nothing())
>>> env = ecole.environment.Branching(observation_function=obs_func)
>>> obs, _, _, _, _ = env.reset("path/to/problem")
>>> obs
[ecole.observation.NodeBipartiteObs(), None]
- 1
We use the term observation rather than state since the state is really the whole state of the solver, which is unaccessible. Thus, mathematically, we really have a Partially Observable Markov Decision Process.