Monty.Frameworks.Models.EvidenceMatching.EvidenceSlopeTracker (ExTbpMonty.Core v0.1.0)

Copy Markdown View Source

The slope of each hypothesis's evidence over a sliding window.

Mirrors tbp/monty/frameworks/models/evidence_matching/evidence_slope_tracker.py. A learning module uses it to drop hypotheses whose evidence is not merely low but falling: a hypothesis that arrived late has not had time to prove itself, so only ones older than min_age updates can be removed.

Slopes are per channel per step, so they stay comparable when the number of input channels active at a step changes. That is the whole reason the channel counts are buffered alongside the evidence: a step fed by three channels accumulates evidence three times as fast, and a slope that ignored it would make hypotheses look better simply because more sensors were on them.

The evidence is a ring of bytes shared by every hypothesis: evidence is hypotheses * window_size f64, cursor names the slot the next update overwrites — which is also the oldest value in every window — and a window in order is cursor, cursor + 1, … wrap. Every hypothesis' window slides by one slot on the same update, so recording a step writes one value per hypothesis and moves the cursor; no window is rebuilt. Sliding ten-slot lists a step was the single largest thing a matching step allocated.

An unfilled slot is a NaN — Monty's nil, which a flat window's slope of zero must not be mistaken for — so a window cannot be read as floats directly, and calculate_slopes/1 is a kernel over these bytes.

Summary

Types

t()

evidence is hypotheses * window_size f64 in ring order, channels the channel count at each window slot oldest first, and cursor the slot the next update writes.

Functions

Adds hypotheses, each with an empty window and an age of zero.

The average per-channel slope of every hypothesis, or nil for one whose window holds no two consecutive observations.

Forgets every hypothesis, keeping the window size and minimum age.

The age of every tracked hypothesis, in updates.

A tracker for window_size evidence points per hypothesis, allowing removal once a hypothesis is min_age updates old.

Which hypotheses are old enough to be considered for removal.

Removes the hypotheses at the given indices, keeping the rest in order.

Which hypotheses to keep, given a slope threshold.

How many hypotheses are tracked.

Records this step's evidence and moves every window on by one slot.

Types

t()

@type t() :: %Monty.Frameworks.Models.EvidenceMatching.EvidenceSlopeTracker{
  ages: [non_neg_integer()],
  channels: [pos_integer()],
  cursor: non_neg_integer(),
  evidence: binary(),
  min_age: non_neg_integer(),
  window_size: pos_integer()
}

evidence is hypotheses * window_size f64 in ring order, channels the channel count at each window slot oldest first, and cursor the slot the next update writes.

value()

@type value() :: float() | nil

Functions

add_hyp(tracker, count)

@spec add_hyp(t(), non_neg_integer()) :: t()

Adds hypotheses, each with an empty window and an age of zero.

A hypothesis that has never been updated is all padding: it has no slope, and calculate_slopes/1 says so with nil rather than with zero.

calculate_slopes(tracker)

@spec calculate_slopes(t()) :: [float() | nil]

The average per-channel slope of every hypothesis, or nil for one whose window holds no two consecutive observations.

Each step's difference is divided by the number of channels that contributed at the later slot of the pair, then averaged over the window's valid steps.

clear_hyp(tracker)

@spec clear_hyp(t()) :: t()

Forgets every hypothesis, keeping the window size and minimum age.

hyp_ages(evidence_slope_tracker)

@spec hyp_ages(t()) :: [non_neg_integer()]

The age of every tracked hypothesis, in updates.

new(opts \\ [])

@spec new(keyword()) :: t()

A tracker for window_size evidence points per hypothesis, allowing removal once a hypothesis is min_age updates old.

removable_indices_mask(evidence_slope_tracker)

@spec removable_indices_mask(t()) :: [boolean()]

Which hypotheses are old enough to be considered for removal.

remove_hyp(tracker, indices)

@spec remove_hyp(t(), [non_neg_integer()]) :: t()

Removes the hypotheses at the given indices, keeping the rest in order.

select_hypotheses(tracker, slope_threshold)

Which hypotheses to keep, given a slope threshold.

A hypothesis is kept when its slope is at least the threshold or when it is too young to remove: the second half is what stops a module from throwing away a hypothesis in the same step it was proposed.

total_size(evidence_slope_tracker)

@spec total_size(t()) :: non_neg_integer()

How many hypotheses are tracked.

update(tracker, values, opts \\ [])

@spec update(t(), [float()] | binary(), keyword()) ::
  {:ok, t()} | {:error, :wrong_number_of_values}

Records this step's evidence and moves every window on by one slot.

values is one evidence value per hypothesis — all of them, every step: a hypothesis that skipped a step would have a slope over a different number of steps from its neighbours, which is how slopes stop being comparable.

Returns {:error, :wrong_number_of_values} rather than raising, because the caller is a learning module mid-episode: Monty raises ValueError, and the reason is the same either way.