Source code for tbp.monty.experiment.match_criteria

# Copyright 2026 Thousand Brains Project
#
# Copyright may exist in Contributors' modifications
# and/or contributions to the work.
#
# Use of this source code is governed by the MIT
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT.
from __future__ import annotations

from typing import Mapping, Protocol

from typing_extensions import Self

__all__ = ["AnyLMsMatch", "MatchCriterion", "NamedLMsMatch"]


[docs]class MatchCriterion(Protocol): """Decides whether learning modules have collectively matched the target. An individual learning module reaches its own terminal state independently of the others. The match criterion turns those per-LM terminal states into the single system-level decision of whether Monty has recognized the object. """ def __call__(self: Self, terminal_states: Mapping[str, str | None]) -> bool: """Evaluate the criterion against the given terminal states. Args: terminal_states: A mapping of learning module names to their terminal states. A value of `None` indicates that the learning module has not reached its terminal state yet. Returns: True if the criterion is met, False otherwise. """ ...
[docs]class AnyLMsMatch(MatchCriterion): """Satisifed once any `count` of learning modules have reached "match".""" _count: int
[docs] def __init__(self: Self, count: int) -> None: """Initialize the criterion. Args: count: The number of learning modules that must reach "match" for the criterion to be satisfied. Raises: ValueError: If `count` is not positive. """ if count <= 0: raise ValueError("count must be positive") self._count = count
def __call__(self: Self, terminal_states: Mapping[str, str | None]) -> bool: matched = sum(1 for state in terminal_states.values() if state == "match") return matched >= self._count
[docs]class NamedLMsMatch(MatchCriterion): """Satisifed once all learning modules with the given IDs have reached "match".""" _ids: frozenset[str]
[docs] def __init__(self: Self, ids: list[str]) -> None: """Initialize the criterion. Args: ids: The IDs of the learning modules that must reach "match" for the criterion to be satisfied. Raises: ValueError: If `ids` is empty. """ if not ids: raise ValueError("ids must not be empty") self._ids = frozenset(ids)
def __call__(self: Self, terminal_states: Mapping[str, str | None]) -> bool: return all(terminal_states[lm_id] == "match" for lm_id in self._ids)