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
@type step_type() :: :matching | :exploratory
@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() }
@type terminal_state() :: Monty.Frameworks.Models.AbstractMontyClasses.LearningModule.terminal_state()
Functions
@spec all_goals([Monty.Cmp.Goal.t()], [Monty.Cmp.AttentionRegion.t()]) :: [ Monty.Cmp.Goal.t() ]
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.
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.
Builds the coordinator state from a model spec.