Monty.Simulators.Environment behaviour (ExTbpMonty.Core v0.1.0)

Copy Markdown View Source

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:

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.

t()

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

sensor_id()

@type sensor_id() :: atom() | String.t()

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.

t()

@type t() :: struct() | map()

Whatever an implementation needs to remember between steps.

Callbacks

new(what)

@callback new(what :: term()) :: t()

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.

positions_itself?()

(optional)
@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.

primary_target(t)

(optional)
@callback primary_target(t()) :: map() | nil

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.

reset(t)

@callback reset(t()) :: t()

The world a fresh episode starts in.

semantic_id_to_label(t)

(optional)
@callback semantic_id_to_label(t()) :: %{optional(integer()) => String.t()}

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.

step(t, list)

@callback step(t(), [Monty.Frameworks.Actions.Action.t()]) ::
  {observations :: map(), proprioceptive_state :: map(), t()}

The world after actions, with what the sensors now see.

stop(t)

(optional)
@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.

Functions

positions_itself?(env)

@spec positions_itself?(t()) :: boolean()

stop(env)

@spec stop(t()) :: :ok