Monty.Frameworks.Models.AbstractMontyClasses.SensorModule behaviour (ExTbpMonty.Core v0.1.0)

Copy Markdown View Source

Behaviour for a sensor module, mirroring tbp/monty/frameworks/models/abstract_monty_classes.py::SensorModule.

The callbacks are pure: they take the module's state and return the next state alongside their result. Monty.Runtime.SensorModuleServer is the thin process that holds that state; a module can be tested without a process at all.

update_state/2 is called before step/3 on every step, because a sensor module needs to know where the sensor is before it can say what it observes.

Summary

Types

Whatever a module keeps between steps; opaque to the runtime.

Callbacks

Drops the observations this sensor kept, and nothing it has learnt.

Goals this sensor proposes (a salience module proposes; a camera does not).

The region this sensor wants attended to.

Clears short-term state for a new episode.

Turns one raw observation into a percept, or nil when the sensor has nothing to say this step.

Records the sensor's pose for the step about to run.

Functions

Defaults matching Monty's base SensorModule: a plain sensor proposes no goals and attends to nothing.

Types

agent_state()

@type agent_state() :: map()

observation()

@type observation() :: map()

state()

@type state() :: term()

Whatever a module keeps between steps; opaque to the runtime.

Callbacks

clear_buffers(state)

@callback clear_buffers(state()) :: state()

Drops the observations this sensor kept, and nothing it has learnt.

Monty's NoResetEvidenceGraphMatching._reset_modules_buffers sets sm.processed_obs = [] at an object boundary: the observations will not be read again, but the delta filter's memory decides what counts as a change and has to survive, or the first patch on the new object is a sight the sensor has never had. reset/1 is the whole-episode version and is not the same thing.

The default is a sensor that keeps nothing.

propose_goals(state)

(optional)
@callback propose_goals(state()) :: {[Monty.Cmp.Goal.t()], state()}

Goals this sensor proposes (a salience module proposes; a camera does not).

propose_region(state)

(optional)
@callback propose_region(state()) :: {Monty.Cmp.AttentionRegion.t(), state()}

The region this sensor wants attended to.

reset(state)

@callback reset(state()) :: state()

Clears short-term state for a new episode.

step(observation, boolean, t, state)

@callback step(observation(), boolean(), Monty.Context.t(), state()) ::
  {Monty.Cmp.Message.t() | nil, state()}

Turns one raw observation into a percept, or nil when the sensor has nothing to say this step.

The context is the run's — its step, its mode, and through Monty.Context.rng_for/2 the random stream this sensor draws from. Monty passes one for the same reason (CameraSM.step(ctx, ...)): a sensor that adds noise needs to know which run and which step it is adding it to.

update_state(agent_state, state)

@callback update_state(agent_state(), state()) :: state()

Records the sensor's pose for the step about to run.

Functions

__using__(opts)

(macro)

Defaults matching Monty's base SensorModule: a plain sensor proposes no goals and attends to nothing.

A module uses this behaviour and overrides what it needs, which is how the Python base class reads too — and why a module that implements propose_goals/1 does not have to fight a catch-all default clause.