Monty.Runtime.Step.State (ExTbpMonty.Core v0.1.0)

Copy Markdown View Source

What a step coordinator needs to know between steps, with the wiring normalised once at start, and the model-level bookkeeping Monty keeps on MontyBase.

Monty's connection matrices (sm_to_lm_matrix, lm_to_lm_matrix, lm_to_lm_vote_matrix) are lists indexed by module position in Python; here they arrive as maps keyed by module id. This struct inverts them once — for every learning module, which sensors feed it and which modules feed it from above — so the step loop reads a plain map instead of defensive lookups on every phase.

Two counts are deliberately distinct. step is how many steps this episode has taken, and is what the context carries. matching_steps and exploratory_steps count only the steps in which at least one module was given an observation — the steps in which the episode actually learned something — because those are the counts an experiment's termination rules are written in terms of.

Summary

Functions

Monty's NoopAttentionSystem: every proposed goal passes.

Monty's default vote routing: a receiver gets the votes of the modules wired to it by lm_to_lm_vote_matrix, mounted in the frame of its own sensor.

Builds the coordinator state from a model spec.

Types

id()

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

input()

@type input() :: %{sensor_modules: [id()], learning_modules: [id()]}

match_criterion()

@type match_criterion() :: {module(), term()}

module_spec()

@type module_spec() :: %{id: id(), module: module(), state: term()}

step_type()

@type step_type() :: :matching | :exploratory

t()

@type t() :: %Monty.Runtime.Step.State{
  attention: ([Monty.Cmp.Goal.t()], [Monty.Cmp.AttentionRegion.t()] ->
                [Monty.Cmp.Goal.t()]),
  call_timeout: timeout(),
  combine_votes: (map(), t() -> map()),
  done?: boolean(),
  episode_seed: non_neg_integer() | nil,
  experiment_mode:
    Monty.Frameworks.Models.AbstractMontyClasses.LearningModule.mode(),
  exploratory_steps: integer(),
  inputs: %{optional(id()) => input()},
  learning_modules: [module_spec()],
  lm_to_lm_vote: %{optional(id()) => [id()]} | nil,
  match_criterion: match_criterion(),
  matching_steps: integer(),
  min_eval_steps: non_neg_integer(),
  min_train_steps: non_neg_integer(),
  model_class: module(),
  model_id: id(),
  motor: {module(), term()} | nil,
  motor_only?: boolean(),
  motor_state: term(),
  num_exploratory_steps: non_neg_integer(),
  semantic_id_to_label: %{optional(integer()) => String.t()},
  sensor_modules: [module_spec()],
  step: non_neg_integer(),
  step_type: step_type(),
  terminal_states: %{optional(id()) => terminal_state()},
  vote_timeout: timeout()
}

terminal_state()

Functions

all_goals(goals, regions)

Monty's NoopAttentionSystem: every proposed goal passes.

combine_votes(votes, state)

@spec combine_votes(map(), t()) :: map()

Monty's default vote routing: a receiver gets the votes of the modules wired to it by lm_to_lm_vote_matrix, mounted in the frame of its own sensor.

Two calculations, told apart by the shape of a vote exactly as Monty tells them apart (isinstance(votes_per_lm[0], set) in _combine_votes): a graph module names the objects it ruled out and the answer is their union (...GraphMatching.MontyForGraphMatching.combine_votes/2), while an evidence module names the hypotheses it still believes and the answer is that vote moved into the receiver's frame (...EvidenceMatching.Model.MontyForEvidenceGraphMatching.combine_votes/2). Reading the shape rather than the config's model class is what lets one runtime step either family — and a run of the graph-matching family used to crash on its first vote round, because the union was never written.

new(options)

@spec new(map()) :: t()

Builds the coordinator state from a model spec.