What a world has to be: something a step can be taken against.
This is the Elixir side of Monty's Interface.step/1, which hands the model
the actions it chose on the previous step and answers
{observations, proprioceptive_state}. Everything that is not the world —
the model, the body, the policies, the learning modules — is written against
this and does not know which world it is talking to.
Two implementations:
Monty.Simulators.Synthetic.Environment— a stand-in with kinematics and no geometry, implementing this behaviour: its state is the struct, so a run carries the world around with it;Monty.Simulators.Port.Environment— a simulator process on the other side of a port (MuJoCo, Habitat, later a camera). Its state is a process, so it is used where a world is a function —Monty.Runtime.Episodetakes one — rather than as a value.
An environment that keeps its state in a value answers with itself, as every step in this port does, so a caller threads it and does not care whether the world behind it is a map or a process.
Summary
Types
What an experiment addresses a sensor by: Monty's own configs name them as
strings ("patch"), while a module spec built in Elixir may use an atom.
Whatever an implementation needs to remember between steps.
Callbacks
A world, from what the experiment knows to build one.
Whether the world starts an episode already positioned.
The object this episode is about, when the world is the one that chose it.
The world a fresh episode starts in.
The map from semantic id to the object's name, when the world has one.
The world after actions, with what the sensors now see.
Closes the world, if it is something that can be closed.
Types
Callbacks
A world, from what the experiment knows to build one.
Monty's Interface is configured with the agent and its sensors, and reports
every sensor it was given on every step, so a world that renders a scene is
built from that list rather than discovering sensors as it goes. A world that
is a simulator behind a port takes more than the sensors — an experiment name
picks the scene — so what a world is built from is its own to say.
@callback positions_itself?() :: boolean()
Whether the world starts an episode already positioned.
Monty positions an episode in Interface.pre_episode: the experiment's
procedures step the world until the target is in view, drawing from the
episode's random stream. Which side of the port runs them is not symmetric. A
world that is Monty's own runs Monty's pre_episode in Monty's environment,
with Monty's random stream, and gets the answer Monty would get; a world that is
a scene here has to be walked by the ported procedures.
The world says which it is, so that a run positions exactly once: positioning a placed agent again would make the episode a different one from the episode Monty ran.
The object this episode is about, when the world is the one that chose it.
Monty's evaluation experiments sample an object, place it, and tell the model
what it is; a world that does that in its own process is the only thing that
knows the answer, and nil is the honest answer for a world that does not — a
model told nothing keeps whatever it knew rather than being told a guess.
The world a fresh episode starts in.
The map from semantic id to the object's name, when the world has one.
Monty's OneObjectPerEpisodeInterface.semantic_id_to_label: what turns the
semantic id a sensor reads at a pixel into the object a log can name. A world
without semantics says nothing here, which is the same as an empty map.
@callback step(t(), [Monty.Frameworks.Actions.Action.t()]) :: {observations :: map(), proprioceptive_state :: map(), t()}
The world after actions, with what the sensors now see.
@callback stop(t()) :: :ok
Closes the world, if it is something that can be closed.
A world kept in a value has nothing behind it. A world that is a simulator
process does — a peer that outlives its run is a process nobody will ask about
again — so it answers stop/1, and a run stops its world the same way it stops
its model.