# Choices

> UForm for C

`uform_text_choose` scores each text's legal choices, one byte each, through one forward of the byte decoder.
The call appends the mask byte to every text, and a text longer than the model's `context` loses its head, never its end.
Each item's probabilities are a softmax over its own choices alone, at the calibrated inverse temperature of its `temperature_groups` entry, and land in the arena as one `f32` tape in `choices` order.
A model whose `choice_temperature_groups` is zero carries no byte decoder and reports `uform_status_unsupported_k`.

```c
uform_tape_view_t probabilities = {0};
uform_text_choose(&(uform_text_choose_t){
    .model = model, .executor = executor, .outcome = &outcome, .count = n,
    .texts = {bytes, offsets, uform_scalar_u8_k}, .choices = {letters, letter_offsets, uform_scalar_u8_k},
    .probabilities = &probabilities, .arena = arena});
```

A checkpoint stores one inverse temperature per question type as `choices.inverse_temperatures`, and one without them chooses at an inverse temperature of one.
`uform_eval <checkpoint> --calibrate <choices.jsonl> --output <calibrated.safetensors>` fits them on held-out choices, prints each group's negative log-likelihood and the top-choice calibration error before and after, and writes the calibrated copy.

`#include <uform/encode.h>`

`#include <uform/train.h>`

## uform_choices_t

SearchJev's calibrated choices over the byte decoder, the masked head's untied byte logits read at a mask byte appended to a state and restricted to the item's legal bytes.

```c
struct uform_choices_t
```

Each choice item scores `−Σt` · log(p) + brier_weight · Σ(p − t)², with `p` that restricted softmax and `t` its targets.

- `weight` `float`: The loss weight; zero trains no choices.
- `brier_weight` `float`: The Brier term's weight beside the soft cross-entropy; 0.5.

## uform_text_choose

Scores each item's legal choices through one forward, a softmax over them alone at the item's group's calibrated inverse temperature; a model without the byte decoder reports [`uform_status_unsupported_k`](https://www.unum.cloud/docs/uform/c/errors.md#uform_status_unsupported_k).

```c
void uform_text_choose(uform_text_choose_t *arguments);
```

- `model`: The model to choose with; it must carry the byte decoder, its `choice_temperature_groups` nonzero.
- `executor`: The executor the call runs on; it must share the model's residency.
- `outcome`: Output for the outcome, final once its status leaves [`uform_status_deferred_k`](https://www.unum.cloud/docs/uform/c/errors.md#uform_status_deferred_k).
- `completion`: Whether the call blocks or returns once queued; zero blocks.
- `count`: Items in `texts`, and the batch axis of every input and output.
- `texts`: UTF-8 states, one per item, each ending where the choice goes; the call appends the mask byte, and a state longer than the model's context loses its head, never its end.
- `choices`: Each item's legal choices, one byte each, [`uform_scalar_u8_k`](https://www.unum.cloud/docs/uform/c/encoding.md#uform_scalar_u8_k); an item with none chooses nothing.
- `temperature_groups`: The __optional__ question type of each item, `count` of them, below the model's `choice_temperature_groups`; `NULL` puts every item in group zero.
- `probabilities`: Output for one probability per choice in `choices` order, [`uform_scalar_f32_k`](https://www.unum.cloud/docs/uform/c/encoding.md#uform_scalar_f32_k), inside `arena:` the shape a training step reads its `choice_targets` in.
- `arena`: Memory for every output, rewound by the call.
- `progress`: The __optional__ handler, called with items scored.
- `stats`: The __optional__ report; `NULL` skips it.

