# `Monty.Simulators.Environment`
[🔗](https://github.com/d-led/ex.tbp.monty/blob/v0.1.0/packages/ex_tbp_monty_core/lib/monty/simulators/environment.ex#L1)

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.Episode` takes 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.

# `sensor_id`

```elixir
@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`

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

Whatever an implementation needs to remember between steps.

# `new`

```elixir
@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* 

```elixir
@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`
*optional* 

```elixir
@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`

```elixir
@callback reset(t()) :: t()
```

The world a fresh episode starts in.

# `semantic_id_to_label`
*optional* 

```elixir
@callback semantic_id_to_label(t()) :: %{optional(integer()) =&gt; 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`

```elixir
@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`
*optional* 

```elixir
@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.

# `positions_itself?`

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

# `stop`

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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
