Monty. Frameworks. Models. Buffer. FeatureAtLocationBuffer
(ExTbpMonty.Core v0.1.0)
Copy Markdown
View Source
Features at locations arriving into one learning module, and the statistics of an episode.
Mirrors tbp/monty/frameworks/models/buffer.py::FeatureAtLocationBuffer, with
the one difference a functional language forces: the buffer is a value. Every
method that mutates in Python returns a new buffer here, so a step reads as a
pipeline rather than as a side effect, and a test can hold two versions of the
same buffer and compare them.
Two shapes need saying out loud, because numpy does them implicitly in Python:
- Rows are plain lists in step order, newest last.
locationsis a list of[x, y, z]in metres;features[channel][attr]is a list of flat rows, withpose_vectorsa 3×3 matrix flattened to nine numbers exactly as Monty flattens it before storing. - NaN padding is
nil. Monty pads a channel that sent nothing at a step with NaN so that an index means the same step in every channel, then drops those rows withnp.isnanwhen it builds a graph.nilis that padding here:pad_to_target_length/3writes it,get_all_features_on_object/1keeps it, and anything reading a row must expect it.
Monty's own tests reach into _pad_to_target_length, so it is public here:
index alignment is the behaviour this module exists to guarantee, and a test
that cannot name it can only guess at it.
Summary
Functions
Adds end-of-episode statistics, which replace rather than accumulate.
Adds one step's percepts.
Remembers a percept the buffer's learning module was given.
The features observed at one step, by channel.
The most recent displacement.
The most recent location, or nil for an empty buffer.
The most recent point-pair feature.
The length of the first observed displacement, for scale in a displacement learning module: the ppf's first element when there is one, otherwise the norm of the first displacement.
Every observed feature that was on the object, by channel and feature.
Every percept the buffer's learning module has been given.
Every location from the steps where at least one input was on the object.
The currently sensed location and orientation, as four rows: the location, then the channel's pose matrix.
Whether the last sensation was on the object.
The name of the first channel that is a sensor module.
Everything a graph update needs from the buffer.
Whether the last sensation was processed by the learning module.
The matching step at which the last goal was generated.
How many goals the learning module's goal generator has produced.
How many steps the learning module processed (exploration steps included).
The number of steps recorded.
How many matching steps have elapsed since the last output goal: all of them when there has never been one.
The percept before the last one, or nil.
A buffer with nothing in it yet.
The nth displacement (negative counts from the end, as Monty uses it).
Pads rows to target_length with nil, keeping the data at the beginning.
Empties the buffer, as Monty's reset does.
Records the terminal state of an individual learning module.
How many observations the buffer holds.
Overwrites the last entry of the named statistics (after voting, say).
Records statistics for a step.
Types
@type row() :: [float()] | nil
@type t() :: %Monty.Frameworks.Models.Buffer.FeatureAtLocationBuffer{ channel_sender_types: %{optional(String.t()) => :sm | :lm}, displacements: %{optional(String.t()) => [row()]}, features: %{optional(String.t()) => channel_features()}, input_percepts: [Monty.Cmp.Message.t()], last_location: [float()] | nil, locations: [[float()]], on_object: [boolean()], start_time: integer() | nil, stats: %{optional(String.t()) => term()} }
Functions
Adds end-of-episode statistics, which replace rather than accumulate.
@spec append(t(), [Monty.Cmp.Message.t()]) :: {:ok, t()} | {:error, term()}
Adds one step's percepts.
A step is the percepts that arrived together: its location is the mean of the sensor-module percepts (a learning module reports hypotheses, not places), and every percept teaches the buffer what kind of sender its channel is. A percept that does not carry features for the learning module — a view finder, a location-only report — contributes its location and nothing else, so its channel gets no feature rows at all.
{:error, :no_sensor_module_location} for a step with no sensor module
percept that has a location: Monty asserts on it, and a step with no place in
it cannot be indexed against the rest of the episode.
@spec append_input_percepts(t(), Monty.Cmp.Message.t()) :: t()
Remembers a percept the buffer's learning module was given.
The features observed at one step, by channel.
Mirrors __getitem__. A step a channel did not reach reads as nil rows,
because that is what the padding says about it.
The most recent displacement.
The most recent location, or nil for an empty buffer.
The most recent point-pair feature.
The length of the first observed displacement, for scale in a displacement learning module: the ppf's first element when there is one, otherwise the norm of the first displacement.
Monty reads row 1, not row 0: the first step has no displacement to measure.
@spec get_all_features_on_object(t()) :: %{optional(String.t()) => channel_features()}
Every observed feature that was on the object, by channel and feature.
Each channel is padded to the episode's length first — a channel that stopped
sending keeps its index — and then read at the steps where any input was on
the object. A row the channel did not send at such a step stays nil, which is
what Monty's NaN means here.
@spec get_all_input_percepts(t()) :: [Monty.Cmp.Message.t()]
Every percept the buffer's learning module has been given.
Every location from the steps where at least one input was on the object.
The currently sensed location and orientation, as four rows: the location, then the channel's pose matrix.
"first" means the first sensory input channel. A channel that sent no
features at this step keeps the pose from the step it did send one, so the
location and the orientation can come from different steps; Monty warns when
that happens and so does this, because the combination is a quietly wrong pose
rather than an error.
Whether the last sensation was on the object.
Monty's message carries a boolean, and a recorded one may carry the same fact
as 1.0/0.0 — so the answer is the truth of what was stored rather than the
stored value itself, which callers then combine with and.
The name of the first channel that is a sensor module.
{:error, {:no_sensory_channel, types}} when there are channels but none is a
sensor module — a learning module fed only by a view finder or by lateral
votes has nothing of its own to sense with, which Monty raises on too.
Everything a graph update needs from the buffer.
Whether the last sensation was processed by the learning module.
The matching step at which the last goal was generated.
@spec get_num_goals_generated(t()) :: non_neg_integer()
How many goals the learning module's goal generator has produced.
@spec get_num_matching_steps(t()) :: non_neg_integer()
How many steps the learning module processed (exploration steps included).
@spec get_num_observations_on_object(t()) :: non_neg_integer()
The number of steps recorded.
How many matching steps have elapsed since the last output goal: all of them when there has never been one.
@spec get_previous_input_percepts(t()) :: Monty.Cmp.Message.t() | nil
The percept before the last one, or nil.
@spec new() :: t()
A buffer with nothing in it yet.
The clock starts when the buffer does: the "time" statistic is
elapsed-since-episode-start, not a timestamp.
The nth displacement (negative counts from the end, as Monty uses it).
Pads rows to target_length with nil, keeping the data at the beginning.
:target_length defaults to the buffer's length; :width defaults to the
width the existing rows already have. A caller adding the first row of a new
feature must say how wide it is, because an empty list has no width to read.
Monty raises ValueError for the same two mistakes and so does this: a row of
the wrong width silently shifts every feature of a step.
Empties the buffer, as Monty's reset does.
Records the terminal state of an individual learning module.
Only the first time the terminal condition is met is kept: an episode ends once, and the first ending is the one that mattered.
@spec size(t()) :: non_neg_integer()
How many observations the buffer holds.
Overwrites the last entry of the named statistics (after voting, say).
Records statistics for a step.
Options mirror Monty's keyword arguments: :update_time appends the elapsed
time, :append adds a row to an existing statistic rather than replacing it,
and :init_list starts a new list for a statistic seen for the first time. A
statistic the buffer has never held is added either way: statistics are a log,
and a module that invents one is doing something Monty's own modules do.