# `Dsxir.Optimizer`

Behaviour and dispatcher for program optimizers.

An optimizer compiles a `Dsxir.Program.t()` against a trainset under a
`Dsxir.Metric.t()`, returning a new program plus an open `stats` map.

Implementations declare `@behaviour Dsxir.Optimizer` and implement
`compile/4`. Callers invoke an optimizer through `compile/5`, which performs
argument validation and delegates to the impl module.

The return contract is fixed across versions:

    {:ok, Dsxir.Program.t(), stats :: map()} | {:error, Exception.t()}

`stats` is an open map. Each optimizer documents the keys it populates;
consumers must tolerate unknown keys.

# `result`

```elixir
@type result() :: {:ok, Dsxir.Program.t(), stats()} | {:error, Exception.t()}
```

# `stats`

```elixir
@type stats() :: map()
```

# `compile`

```elixir
@callback compile(
  student :: Dsxir.Program.t(),
  trainset :: [Dsxir.Example.t()],
  metric :: Dsxir.Metric.t(),
  opts :: keyword()
) :: result()
```

# `compile`

```elixir
@spec compile(
  module(),
  Dsxir.Program.t(),
  [Dsxir.Example.t()],
  Dsxir.Metric.t(),
  keyword()
) :: result()
```

Dispatch to `impl.compile/4` with validated arguments.

Guards: `impl` must be an atom (module), `trainset` a list, `metric` a 3-arity
function, and `opts` a keyword list (any list satisfies the guard; impls are
expected to treat it as a keyword list).

---

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