# `Monty.Attention.AttentionSystem.DefaultAttentionSystem`
[🔗](https://github.com/d-led/ex.tbp.monty/blob/v0.1.0/packages/ex_tbp_monty_core/lib/monty/attention/attention_system/default_attention_system.ex#L1)

Attention that learns where looking has paid off: Monty's
`attention/attention_system.py::DefaultAttentionSystem`.

Each step it turns the sensor's proposed regions into a sparse grid of weights,
lets the previous grid decay, drops the voxels that have faded to nothing, and
merges the new grid into the old one. The merged grid is then what the goal
filter reads, so a goal is weighed against everything attention has seen, not
just against this step's proposal.

The pipeline, in Monty's order:

    proposed = regions → voxels → one pooled weight per voxel
    step:  proposed → telemetry
           decay(grid) → expire → merge(expired, proposed) → telemetry
           goal_filter(grid, goals) → goals

`expire/1` is the part that makes the grid a memory rather than an
accumulator: a weight whose magnitude has decayed below `1e-6` is dropped, so a
place that has not been looked at for long enough stops being a voxel at all.

The collaborators — `weight_pooler`, `decay`, `merge`, `goal_filter` — are
functions, which is this port's form of Monty's one-method protocols; `new/1`
turns a decay value into one for you. `telemetry` is a value it threads, because
telemetry is the one collaborator with state of its own.

# `decay`

```elixir
@type decay() :: (Monty.Attention.VoxelGrid.t() -&gt; Monty.Attention.VoxelGrid.t())
```

A decay: a grid in, the same grid one step closer to zero out.

# `goal_filter`

```elixir
@type goal_filter() :: (Monty.Attention.VoxelGrid.t(), [Monty.Cmp.Goal.t()] -&gt;
                    [Monty.Cmp.Goal.t()])
```

A goal filter: what attention knows, and the goals, in; goals to pursue, out.

# `merge`

```elixir
@type merge() :: (Monty.Attention.VoxelGrid.t(), Monty.Attention.VoxelGrid.t() -&gt;
              Monty.Attention.VoxelGrid.t())
```

A merge: two grids in, one grid out.

# `t`

```elixir
@type t() :: %Monty.Attention.AttentionSystem.DefaultAttentionSystem{
  decay: decay(),
  goal_filter: goal_filter(),
  grid: Monty.Attention.VoxelGrid.t(),
  merge: merge(),
  telemetry: term(),
  voxel_size: float(),
  weight_pooler: weight_pooler()
}
```

# `weight_pooler`

```elixir
@type weight_pooler() :: ([number()] -&gt; number())
```

A weight pooler: many weights about one voxel in, one weight out.

# `expire`

```elixir
@spec expire(Monty.Attention.VoxelGrid.t()) :: Monty.Attention.VoxelGrid.t()
```

The grid without the voxels whose weight has faded below the tolerance.

A weight whose magnitude is under `1e-6` says nothing worth remembering, and
keeping it would keep the grid growing forever.

# `new`

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

A system that has learned nothing yet.

Defaults are Monty's: 5 cm voxels, `negative_priority_max_pool`, linear decay at
Monty's default rate, `Union`, `HardGoalFilter`, and telemetry that records
nothing.

# `reset`

Forget every voxel and everything the telemetry recorded.

# `state_dict`

The grid attention has built, and what the telemetry recorded.

# `step`

Act on one step: learn where the sensors looked, and say which goals survive.

Answers the system to use next step plus the goals worth pursuing. The goals go
through the goal filter after the merge, so they are judged against the memory
including this step's proposals.

# `weight_expiration_tolerance`

```elixir
@spec weight_expiration_tolerance() :: float()
```

The weight magnitude below which a voxel is dropped from the grid.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
