---
aliases:
  - structured decoding
  - guided decoding
  - structured outputs
  - constrained decoding
date: '2024-11-18'
description: structured generations in vLLM a la carte, or in general
id: structured outputs
modified: 2026-10-01 09:15:44 GMT-04:00
tags:
  - ml
  - rfc
  - vllm
title: structured outputs
transclude:
  title: false
created: '2024-11-18'
published: '2024-11-18'
pageLayout: default
slug: thoughts/structured-outputs
permalink: https://aarnphm.xyz/thoughts/structured-outputs.md
generator:
  quartz: v4.6.0
  hostedProvider: Cloudflare
  baseUrl: aarnphm.xyz
full: https://aarnphm.xyz/llms-full.txt
---
Structured decoding restricts the next token to continuations allowed by a grammar. The model still chooses the content wherever the grammar leaves a choice. A valid JSON object can contain a wrong answer.

## jump-forward decoding

Also known as fast-forward tokens, forced tokens, or [ff-strings](https://github.com/guidance-ai/llguidance/blob/main/docs/fast_forward.md#safely-converting-ff-strings-to-ff-tokens) (abbrev: ff, jf).

If every valid continuation begins with the same bytes, the engine can append those bytes without sampling them one at a time. The resulting tokens still need a forward pass to populate the KV cache before generation continues. This is where a short prefill can replace several serial decoding steps.

The tempting description is ”[[thoughts/Speculative decoding|speculative decoding]] with 100% acceptance.” That needs a qualification: a grammar can force a **string** while leaving several tokenizations possible. Choosing one tokenization can change subsequent model probabilities. Grammar validity alone does not give the distribution-preservation guarantee of an exact speculative sampler.

llguidance handles the boundary by withholding trailing tokens when a legal token could extend beyond the forced bytes. See its [fast-forward notes](https://github.com/guidance-ai/llguidance/blob/main/docs/fast_forward.md). Its [token trie](https://github.com/guidance-ai/llguidance/blob/main/docs/toktrie.md) shares work across vocabulary entries with the same byte prefix: once the recognizer rejects a prefix, the traversal skips that subtree.

## async structured outputs

Design references: [vllm-project/vllm#26866](https://github.com/vllm-project/vllm/pull/26866), <https://docs.google.com/document/d/1wmSQk3BYQU3axP4Sb0179IgVNzoMSyE68q0rPZmpdyA>

Process names from those design notes:

- `SchedulerProc`
- `WorkerProc`
- `StandaloneProc`, combining scheduler and worker

The dependency to preserve: a mask must reflect the request’s accepted tokens before it is used to sample the next token. CPU mask generation can overlap a GPU forward pass when the scheduler has already received the preceding sampled token.

## structural tags

Design reference: [docs](https://docs.google.com/document/d/1o9ZZEFofxb-dJ_cDTi_c3riOJOm4higcSGpvKKNdmtY/edit?tab=t.0#heading=h.nc4nxxczgw4w).

---

## V1 Structured Outputs Compatibility

> \[!tip\] Important
>
> Historical V1 design notes, including [RFC #11908](https://github.com/vllm-project/vllm/issues/11908), opened January 9, 2025. Structured-output support is present in the [v0.8.0 source](https://github.com/vllm-project/vllm/tree/v0.8.0/vllm/v1/structured_output). The proposals and meeting questions below record the integration work; consult [vLLM’s documentation](https://docs.vllm.ai) for the engine version being deployed.

The integration had to account for the V1 tensor-parallel execution model described in [PR #9856](https://github.com/vllm-project/vllm/pull/9856):

- The executor created $N$ worker processes, replacing V0’s $N-1$ worker processes.
- All workers ran `prepare_inputs` and the sampler. Each therefore needed the logits, using an all-gather in place of a gather to one worker.
- The executor broadcast scheduler output through shared-memory queues; one worker returned the model-runner output.
- Workers stayed in a model-execution loop with termination as the other control operation.

Design preference at the time: prioritize backend performance, then justify the compatibility cost of each additional backend.

## proposal

```jsx imports={Zoomable,GrammarBitmaskBatch}
<Zoomable label="Scheduler broadcast bitmask">
  <GrammarBitmaskBatch
    request="r2"
    workers={2}
    caption="vLLM v0.8.0 proposal sketch: four running requests and one compiling request. Each guided request gets one int32 row (4,740 words for the 151,669-token Qwen3 vocabulary), broadcast to workers and applied before sampling. Mask and probability example: Qwen/Qwen3-0.6B-Base, four-string JSON grammar, greedy sampling. Select a request or worker count."
  />
</Zoomable>
```

Split responsibilities between the scheduler and workers:

1. **Scheduler**:
   - Track which requests need constrained decoding. A request waiting for grammar compilation should not stall unrelated ready requests in the batch; see the [[posts/structured decoding#tentative plans for v1|motivation]].
   - Keep unready guided requests in a waiting queue until their grammar is compiled. Readiness makes a request eligible for scheduling; it does not by itself give that request higher priority.
   - After receiving a sampled token, advance that request’s grammar matcher and produce its next-token bitmask.
   - Overlap mask production with the next model forward pass where dependencies permit. The sketch separates scheduler-output and mask broadcasts; workers need the correct mask before sampling.
   - (P1) Investigate jump-forward support, including advancing or rolling back matcher and KV-cache state after retokenization.
2. **Worker**:
   - Apply the request’s bitmask to logits before sampling, setting disallowed entries to $-\infty$.

This moves compilation and matcher state into request scheduling. Cold compilation still contributes to that request’s time to first token (TTFT); the benefit is that other requests can proceed.

## alternatives consideration

The working-group notes rejected a worker-local logit-processor abstraction as the sole integration point. The scheduler needed request readiness and grammar state to handle compilation and future jump-forward work.

## background

```jsx imports={Zoomable,LogitsProcessorTrace}
<Zoomable label="Watergraph of current logit processor stack">
  <LogitsProcessorTrace
    guided={2}
    caption="Historical vLLM v0.5.0 path, after PR #5329: each guided row adds a Python call between forward and sampling to build a full-vocabulary mask. Change guided rows to inspect call growth."
  />
</Zoomable>
```

_reference: [vllm-project/vllm#5329](https://github.com/vllm-project/vllm/pull/5329)_

The historical V0 path applied logit processors [row by row](https://github.com/vllm-project/vllm/blob/1ea291a4173a82c537ab42487e23375be4926d30/vllm/model_executor/layers/logits_processor.py#L143). Per-request CPU work on this path could delay sampling for the batch. Grammar compilation, mask generation and applying a mask are separate costs; warming a compilation cache only removes the first of these.

SGLang’s [2024 jump-forward design](https://lmsys.org/blog/2024-02-05-compressed-fsm/#method-1-finite-state-machine-based) also skipped serial decoding over forced text. Supporting that requires coordination with token history and the KV cache, beyond changing a row of logits.

> [**@cadedaniel**](https://github.com/cadedaniel): “tree scoring in \[spec decode\] could use the same API as multi-path jump decoding.”

> \[!question\] How should we handle FSM per requests?
>
> - Different schemas can require different compiled grammars. Repeated schemas can share a compiled artifact, while each request keeps its own matcher state.
> - Original proposal: accept common schemas at server initialization, much as we configure a system prompt. How much cold-compilation work would that remove for the actual workload?

> \[!question\] Why should we follow the plugins system?
>
> - If we choose the fastest backend, what additional requirements justify supporting others?
> - Extensibility has an integration cost. Measure that cost separately from each backend’s grammar coverage and runtime.

---

## appendix.

Background for the design above. The finite-state sections cover regular constraints; recursively nested grammars need a stack or an equivalent parser.

### batched constrained decoding using pushdown automaton

Implemented in [mlc-ai/xgrammar](https://github.com/mlc-ai/xgrammar). The XGrammar paper \[@dong2025xgrammarflexibleefficientstructured\] describes a byte-level pushdown automaton (PDA) for context-free grammars. The stack records returns from nested rules. `GrammarMatcher` carries this parsing state; calling it an FSM loses the stack that makes recursion possible.

> \[!tip\] string and token distinction
>
> The model samples token IDs. The grammar checks the bytes represented by those tokens. One token may cross several grammar-rule boundaries or contain only part of a UTF-8 character.

XGrammar caches checks that depend only on the current rule position. Tokens whose validity depends on the enclosing stack need runtime checks. Each request advances its own matcher after accepting a token; batching collects the resulting masks.

#### questions

Questions from the original integration discussion, with unresolved measurements kept explicit:

- How much vocabulary preprocessing can be shared across requests using the same tokenizer?
- How much mask work depends on the full parser stack?
- Can compilation run before the request reaches the execution batch?
- Which CPU-to-GPU synchronization remains on the sampling path?

> \[!question\] worst-case scenario for grammar compilation?
>
> Measure cold compilation separately from per-token mask generation. The original mask-timing note had no grammar, tokenizer, machine or benchmark attached, so it cannot answer this question.

> \[!question\] time linearly increase for batch size?
>
> There is one matcher state per request. CPU parallelism can overlap their work; the resulting latency depends on available cores and grammar costs.

> \[!question\] do we need to parallelize on vLLM?
>
> XGrammar exposes [compiler thread controls](https://github.com/mlc-ai/xgrammar/blob/main/python/xgrammar/compiler.py). That does not settle how the serving engine schedules mask generation across requests.

> \[!question\] shape of masks?
>
> The [Python matcher API](https://github.com/mlc-ai/xgrammar/blob/main/python/xgrammar/matcher.py) uses an `int32` bitmask with shape $\left(B,\lceil |\mathcal{V}|/32\rceil\right)$ for batch size $B$ and vocabulary $\mathcal{V}$. Each vocabulary entry occupies one bit. The mask and logits must be available on the device used to apply it.

> \[!question\] supported tokenizers?
>
> Historical November 22 note: GLM was still pending. Treat this as a dated integration observation; check the tokenizer adapter for the intended release.

> \[!question\] Given that detokenizer is in a separate process with vLLM, then can we stops duplicating this process?
>
> Mask generation needs token bytes to test grammar transitions. Streaming detokenization also manages text output to the client. Shared vocabulary metadata may help, but the two operations have different state and output requirements.

#### future plans

Historical integration checklist:

- Function calling support.
- Grammar coverage, including Python. XGrammar already targets context-free grammars; which language features a particular integration accepts needs its own check.

The paper’s low-overhead serving results rely on CPU grammar work overlapping GPU inference. “Zero overhead” is a workload-dependent performance claim; compilation, transfer and mask application still perform work.

### compressed FSM for jump-ahead tokens.

Implemented in \[@zheng2024sglangefficientexecutionstructured\]. The [2024 SGLang description](https://lmsys.org/blog/2024-02-05-compressed-fsm/) motivates the following three approaches.

#### Method 1: [[thoughts/structured outputs#Guided generations with FSM.|FSM]]-based decoding

An FSM tracks the generated byte prefix. Before sampling, disallowed tokens receive logit $-\infty$, leaving only grammar-valid continuations \[@willard2023efficientguidedgenerationlarge\].

```jsx imports={Zoomable,FSMDecoding}
<Zoomable label="Decoding with FSM">
  <FSMDecoding
    preset="json"
    mode="char"
    caption="Paul/John FSM example: 21-token toy vocabulary after the LMSys (2024) figure, 10 forward passes; disallowed tokens receive $-\infty$."
  />
</Zoomable>
```

A sampled token can traverse several byte transitions. Serial token-by-token model execution comes from the decoding loop, so an FSM need not impose one neural-network call per character or per automaton state.

#### Method 2: Interleaved-based

A generation program alternates known text with constrained model output. Known text can be processed as a prefill chunk. [Guidance](https://github.com/guidance-ai/guidance#guidance-acceleration) provides this style of programming.

The difficult boundary is between the known and generated text: a model token can span both. Interpreter communication and retokenization also contribute to runtime. Expressiveness depends on the language and implementation, so interleaving alone does not imply weaker grammar support.

#### **<mark>Method 3: Jump-Forward Decoding with compressed FSM</mark>**

```jsx imports={Zoomable,FSMDecoding}
<Zoomable label="Jump-forward decoding via compressed FSM">
  <FSMDecoding
    preset="json"
    mode="compressed"
    caption="Same toy vocabulary: the compressed FSM samples only at states 9 and 24 (2 passes vs. 10). Greedy longest-match tokenization of forced text can change later probabilities."
  />
</Zoomable>
```

Follow a forced byte path until the grammar offers a choice, then process the forced text as a chunk. A path must also account for possible termination: an accepting state can permit EOS even when it has only one outgoing byte transition.

> \[!tip\]+ tokenization boundary handling
>
> Suppose the output format needs `"Hello",` and the vocabulary contains a token for `",`. Constraining the string field in isolation rejects that token because the comma lies outside the field. A grammar for the whole output can accept it.
>
> This can alter completion probabilities. It does not prove that generation must loop forever: a separate closing-quote token or a length limit may still end the step.

SGLang’s historical implementation appended forced text and retokenized the combined output, reusing the unchanged prefix’s KV cache. The cost depends on the changed suffix and the serving implementation. llguidance’s boundary treatment is described [[thoughts/structured outputs#jump-forward decoding|above]]. [^coalescence]

[^coalescence]: [[thoughts/structured outputs#Coalescence|Coalescence]] groups forced text so it can be processed without a sampling step for each token.

### Coalescence

Compress a forced path into a string-labeled edge, stopping where the grammar allows different continuations or termination.

```jsx imports={Zoomable,FSMDecoding}
<Zoomable label="Initial and compressed FSM state">
  <FSMDecoding
    preset="json"
    mode="compressed"
    view="graph"
    caption="Compressed FSM for the four Paul/John strings: 28 character states reduce to 8; edges stop at choices, merges, and acceptance."
  />
</Zoomable>
```

A token-transition index stores the result of consuming each allowed token from a given state. The lookup must use the **current** state, and its keys remain token IDs. Decoded strings are useful labels for inspection; distinct token IDs can decode to the same bytes.

```mermaid
stateDiagram-v2
    [*] --> GetProb: Prompt and initial state q
    state "next-token logits" as GetProb
    state "mask from index[q] and EOS rule" as Mask
    state "sample token ID" as SampleToken
    state "advance q with sampled token" as UpdateState
    GetProb --> Mask
    Mask --> SampleToken
    SampleToken --> UpdateState: Non-EOS token
    SampleToken --> [*]: EOS in accepting state
    UpdateState --> GetProb
```

> \[!note\]- example
>
> Suppose the vocabulary contains every nonempty substring of `name`. The following graph contains all eight segmentations of that word. This is a toy vocabulary, not a claim about a particular model’s tokenizer.
>
> ```mermaid
> stateDiagram-v2
>     direction LR
>     [*] --> q0
>     q0 --> q1: n
>     q0 --> q2: na
>     q0 --> q3: nam
>     q0 --> q4: name
>     q1 --> q2: a
>     q1 --> q3: am
>     q1 --> q4: ame
>     q2 --> q3: m
>     q2 --> q4: me
>     q3 --> q4: e
>     q4 --> [*]
> ```

There are three interior character boundaries, each either split or joined, giving $2^3=8$ segmentations:

- `["name"]`
- `["n", "a", "m", "e"]`
- `["na", "m", "e"]`
- `["nam", "e"]`
- `["n", "am", "e"]`
- `["n", "ame"]`
- `["na", "me"]`
- `["n", "a", "me"]`

For a tiny JSON language, a string-labeled index can be written as:

```python
simplified_index = {
  0: {'{"': 2},
  2: {'name': 6},
  6: {'":"': 9},
  9: {'Paul': 14, 'John': 14},
  14: {'","': 17},
  17: {'age': 20},
  20: {'":': 22},
  22: {'20': 24, '30': 24},
  24: {'}': 25},
}
```

This accepts four strings: either name paired with either age. There are two branch states, at the name and the age. The edge labels are strings of arbitrary token length, so two branches do not imply two model calls. Forced chunks still need KV-cache computation; compilation, mask production and scheduling also take time. A speedup needs an end-to-end measurement with a specified tokenizer and workload.

> \[!tip\]- difference in sampling distribution
>
> All eight paths spell `name`. Their token sequences can differ in length, positions and embeddings, which changes the model state used for the next prediction. Choosing a segmentation merely because it reaches the same grammar state can change later output probabilities.

```jsx imports={Zoomable,TokenBoundaryShift}
<Zoomable label="Variance in sampling distribution for compressed states">
  <TokenBoundaryShift
    boundary="n|a|m|e"
    caption='Qwen/Qwen3-0.6B-Base (float32, CPU), prompted for Paul/John and age 20/30. After forcing {"name":", six allowed next-token probabilities are renormalized: Paul is 21.2% with the tokenizer split and 20.3–40.4% across alternate segmentations. Data: `content/thoughts/scripts/jump_forward_boundaries.py`.'
  />
</Zoomable>
```

### Guided generations with FSM.

\[@willard2023efficientguidedgenerationlarge\], implemented at <https://github.com/dottxt-ai/outlines>.

_assumption: we are building against [[thoughts/Autoregressive models|autoregressive transformers models]]_

Let $\mathcal{V}$ be a finite vocabulary of token IDs, including $\mathrm{EOS}$. A generated sequence belongs to $\mathcal{V}^*$, where the star means finite **ordered sequences**. The permitted completed outputs form a language $\mathcal{F}\subseteq\mathcal{V}^*$ ending in EOS. A powerset would lose order and repetition.

Categorical sampling draws from the model’s next-token distribution. Greedy decoding picks its largest entry; beam search keeps several candidate prefixes. Those are different decoding procedures. [^smc]

[^smc]: \[@lew2023sequentialmontecarlosteering\] formulates controlled generation as posterior inference over sequences and develops sequential [[thoughts/Monte-Carlo|Monte Carlo steering]]. See also [[thoughts/Transformers#Feynman-Kac|Feynman-Kac transformers models]].

Here $\operatorname{LM}$ returns logits. The prompt $x$ remains fixed and $s$ contains only generated token IDs. A Boolean return value distinguishes EOS termination from exhausting the token budget.

<div class="ps-root" data-inline-macros=""><span type="button" class="clipboard-button ps-clipboard" aria-label="Copy pseudocode to clipboard"><svg width="16" height="16" viewBox="0 0 16 16" class="copy-icon"><use href="#github-copy"></use></svg><svg width="16" height="16" viewBox="0 0 16 16" class="check-icon"><use href="#github-check" fill-rule="evenodd" fill="rgb(63, 185, 80)"></use></svg></span><span class="ps-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><annotation encoding="application/x-tex">"\\begin{algorithm}\n\\caption{LLM token sampling}\n\\begin{algorithmic}\n\\Function{sample}{$x,L$}\n    \\State $s \\gets ()$\n    \\For{$i \\gets 1, L$}\n        \\State $p \\gets \\operatorname{softmax}(\\operatorname{LM}(x,s))$\n        \\State Sample $w \\sim \\operatorname{Categorical}(p)$\n        \\If{$w = \\mathrm{EOS}$}\n            \\State \\Return $(s,\\mathrm{true})$\n        \\EndIf\n        \\State $s \\gets \\operatorname{append}(s,w)$\n    \\EndFor\n    \\State \\Return $(s,\\mathrm{false})$\n\\EndFunction\n\\end{algorithmic}\n\\end{algorithm}"</annotation></semantics></math></span>
<div class="ps-algorithm with-caption">
<p class="ps-line" style="text-indent:-0.6em;padding-left:0.6em;">
<span class="ps-keyword">Algorithm 1 </span>LLM token sampling</p>
<div class="ps-algorithmic with-linenum">
<div class="ps-block" style="margin-left:1.2em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:0em;">1:</span><span class="ps-keyword">function </span><span class="ps-funcname">sample</span>(<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo separator="true">,</mo><mi>L</mi></mrow><annotation encoding="application/x-tex">x,L</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">L</span></span></span></span>)</p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">2:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mo>←</mo><mo stretchy="false">(</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">s \gets ()</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mclose">)</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">3:</span><span class="ps-keyword">for </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo>←</mo><mn>1</mn><mo separator="true">,</mo><mi>L</mi></mrow><annotation encoding="application/x-tex">i \gets 1, L</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em;"></span><span class="mord">1</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">L</span></span></span></span><span class="ps-keyword"> do</span></p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">4:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>←</mo><mi mathvariant="normal">softmax</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi mathvariant="normal">LM</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi>x</mi><mo separator="true">,</mo><mi>s</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p \gets \operatorname{softmax}(\operatorname{LM}(x,s))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mord mathrm">softmax</span></span><span class="mopen">(</span><span class="mop"><span class="mord mathrm">LM</span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">s</span><span class="mclose">))</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">5:</span>Sample <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>w</mi><mo>∼</mo><mi mathvariant="normal">Categorical</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi>p</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">w \sim \operatorname{Categorical}(p)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0269em;">w</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">∼</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mord mathrm">Categorical</span></span><span class="mopen">(</span><span class="mord mathnormal">p</span><span class="mclose">)</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">6:</span><span class="ps-keyword">if </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>w</mi><mo>=</mo><mrow><mi mathvariant="normal">E</mi><mi mathvariant="normal">O</mi><mi mathvariant="normal">S</mi></mrow></mrow><annotation encoding="application/x-tex">w = \mathrm{EOS}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0269em;">w</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord"><span class="mord mathrm">EOS</span></span></span></span></span><span class="ps-keyword"> then</span></p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-2.25em;">7:</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-2.25em;">8:</span><span class="ps-keyword">return </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>s</mi><mo separator="true">,</mo><mrow><mi mathvariant="normal">t</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">u</mi><mi mathvariant="normal">e</mi></mrow><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(s,\mathrm{true})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathrm">true</span></span><span class="mclose">)</span></span></span></span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">9:</span><span class="ps-keyword">end if</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">10:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mo>←</mo><mi mathvariant="normal">append</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi>s</mi><mo separator="true">,</mo><mi>w</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">s \gets \operatorname{append}(s,w)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mord mathrm">append</span></span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0269em;">w</span><span class="mclose">)</span></span></span></span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">11:</span><span class="ps-keyword">end for</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">12:</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">13:</span><span class="ps-keyword">return </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>s</mi><mo separator="true">,</mo><mrow><mi mathvariant="normal">f</mi><mi mathvariant="normal">a</mi><mi mathvariant="normal">l</mi><mi mathvariant="normal">s</mi><mi mathvariant="normal">e</mi></mrow><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(s,\mathrm{false})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathrm">false</span></span><span class="mclose">)</span></span></span></span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:0em;">14:</span><span class="ps-keyword">end function</span></p>
</div>
</div>
</div>
</div>

For a prefix $s$, the mask $m:\mathcal{V}^*\to\{0,1\}^{|\mathcal{V}|}$ marks tokens that can still lead to an allowed completion. EOS is allowed only when the generated text is already complete. With $p_v(s)$ the original next-token probability,

$$
Z(s)=\sum_{u\in\mathcal{V}}m_u(s)p_u(s),\qquad
\widetilde p_v(s)=\frac{m_v(s)p_v(s)}{Z(s)},\qquad
w\sim\operatorname{Categorical}(\widetilde p(s)).
$$

This requires $Z(s)>0$. For example, probabilities $(1/2,3/10,1/5)$ and mask $(1,0,1)$ give $(5/7,0,2/7)$. Applying a zero-one mask directly to logits would leave a disallowed token with logit zero and positive softmax probability. The equivalent logit operation sets disallowed entries to $-\infty$ before softmax.

Local renormalization preserves the relative probabilities of allowed **next tokens**. It generally changes the model’s distribution over whole completed outputs. If first choices `a` and `b` each have probability $1/2$, while valid suffixes have conditional probabilities $1/10$ and $9/10$, local masking keeps the first choice at $(1/2,1/2)$. Conditioning the original model on an entirely valid output would give $(1/10,9/10)$ instead.

> \[!math\] 1. augmentation upon sampling algorithm
>
> <div class="ps-root" data-inline-macros=""><span type="button" class="clipboard-button ps-clipboard" aria-label="Copy pseudocode to clipboard"><svg width="16" height="16" viewBox="0 0 16 16" class="copy-icon"><use href="#github-copy"></use></svg><svg width="16" height="16" viewBox="0 0 16 16" class="check-icon"><use href="#github-check" fill-rule="evenodd" fill="rgb(63, 185, 80)"></use></svg></span><span class="ps-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><annotation encoding="application/x-tex">"\\begin{algorithm}\n\\caption{token sampling with masking}\n\\begin{algorithmic}\n\\Function{sample}{$x,L$}\n    \\State $s \\gets ()$\n    \\For{$i \\gets 1, L$}\n        \\State $p \\gets \\operatorname{softmax}(\\operatorname{LM}(x,s))$\n        \\State $a \\gets m(s)\\odot p$\n        \\State $Z \\gets \\sum_{v\\in\\mathcal{V}} a_v$\n        \\If{$Z=0$}\n            \\State \\Return $\\mathrm{failure}$\n        \\EndIf\n        \\State Sample $w\\sim\\operatorname{Categorical}(a/Z)$\n        \\If{$w=\\mathrm{EOS}$}\n            \\State \\Return $(s,\\mathrm{true})$\n        \\EndIf\n        \\State $s\\gets\\operatorname{append}(s,w)$\n    \\EndFor\n    \\State \\Return $(s,\\mathrm{false})$\n\\EndFunction\n\\end{algorithmic}\n\\end{algorithm}"</annotation></semantics></math></span>
> <div class="ps-algorithm with-caption">
> <p class="ps-line" style="text-indent:-0.6em;padding-left:0.6em;">
> <span class="ps-keyword">Algorithm 2 </span>token sampling with masking</p>
> <div class="ps-algorithmic with-linenum">
> <div class="ps-block" style="margin-left:1.2em;">
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:0em;">1:</span><span class="ps-keyword">function </span><span class="ps-funcname">sample</span>(<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo separator="true">,</mo><mi>L</mi></mrow><annotation encoding="application/x-tex">x,L</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">L</span></span></span></span>)</p>
> <div class="ps-block" style="margin-left:0.6em;">
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-0.75em;">2:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mo>←</mo><mo stretchy="false">(</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">s \gets ()</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mclose">)</span></span></span></span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-0.75em;">3:</span><span class="ps-keyword">for </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo>←</mo><mn>1</mn><mo separator="true">,</mo><mi>L</mi></mrow><annotation encoding="application/x-tex">i \gets 1, L</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em;"></span><span class="mord">1</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">L</span></span></span></span><span class="ps-keyword"> do</span></p>
> <div class="ps-block" style="margin-left:0.6em;">
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-1.5em;">4:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>←</mo><mi mathvariant="normal">softmax</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi mathvariant="normal">LM</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi>x</mi><mo separator="true">,</mo><mi>s</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p \gets \operatorname{softmax}(\operatorname{LM}(x,s))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mord mathrm">softmax</span></span><span class="mopen">(</span><span class="mop"><span class="mord mathrm">LM</span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">s</span><span class="mclose">))</span></span></span></span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-1.5em;">5:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo>←</mo><mi>m</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>⊙</mo><mi>p</mi></mrow><annotation encoding="application/x-tex">a \gets m(s)\odot p</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">a</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">m</span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">⊙</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span></span></span></span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-1.5em;">6:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Z</mi><mo>←</mo><msub><mo>∑</mo><mrow><mi>v</mi><mo>∈</mo><mi mathvariant="script">V</mi></mrow></msub><msub><mi>a</mi><mi>v</mi></msub></mrow><annotation encoding="application/x-tex">Z \gets \sum_{v\in\mathcal{V}} a_v</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.0715em;">Z</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1.0771em;vertical-align:-0.3271em;"></span><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:0em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1786em;"><span style="top:-2.4003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em;">v</span><span class="mrel mtight">∈</span><span class="mord mathcal mtight" style="margin-right:0.0822em;">V</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3271em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.0359em;">v</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-1.5em;">7:</span><span class="ps-keyword">if </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Z</mi><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">Z=0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.0715em;">Z</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">0</span></span></span></span><span class="ps-keyword"> then</span></p>
> <div class="ps-block" style="margin-left:0.6em;">
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-2.25em;">8:</span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-2.25em;">9:</span><span class="ps-keyword">return </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">f</mi><mi mathvariant="normal">a</mi><mi mathvariant="normal">i</mi><mi mathvariant="normal">l</mi><mi mathvariant="normal">u</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">e</mi></mrow><annotation encoding="application/x-tex">\mathrm{failure}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord"><span class="mord mathrm">failure</span></span></span></span></span></p>
> </div>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-1.5em;">10:</span><span class="ps-keyword">end if</span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-1.5em;">11:</span>Sample <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>w</mi><mo>∼</mo><mi mathvariant="normal">Categorical</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi>a</mi><mi mathvariant="normal">/</mi><mi>Z</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">w\sim\operatorname{Categorical}(a/Z)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0269em;">w</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">∼</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mord mathrm">Categorical</span></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mord">/</span><span class="mord mathnormal" style="margin-right:0.0715em;">Z</span><span class="mclose">)</span></span></span></span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-1.5em;">12:</span><span class="ps-keyword">if </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>w</mi><mo>=</mo><mrow><mi mathvariant="normal">E</mi><mi mathvariant="normal">O</mi><mi mathvariant="normal">S</mi></mrow></mrow><annotation encoding="application/x-tex">w=\mathrm{EOS}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0269em;">w</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord"><span class="mord mathrm">EOS</span></span></span></span></span><span class="ps-keyword"> then</span></p>
> <div class="ps-block" style="margin-left:0.6em;">
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-2.25em;">13:</span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-2.25em;">14:</span><span class="ps-keyword">return </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>s</mi><mo separator="true">,</mo><mrow><mi mathvariant="normal">t</mi><mi mathvariant="normal">r</mi><mi mathvariant="normal">u</mi><mi mathvariant="normal">e</mi></mrow><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(s,\mathrm{true})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathrm">true</span></span><span class="mclose">)</span></span></span></span></p>
> </div>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-1.5em;">15:</span><span class="ps-keyword">end if</span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-1.5em;">16:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mo>←</mo><mi mathvariant="normal">append</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi>s</mi><mo separator="true">,</mo><mi>w</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">s\gets\operatorname{append}(s,w)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mord mathrm">append</span></span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0269em;">w</span><span class="mclose">)</span></span></span></span></p>
> </div>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-0.75em;">17:</span><span class="ps-keyword">end for</span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-0.75em;">18:</span></p>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:-0.75em;">19:</span><span class="ps-keyword">return </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>s</mi><mo separator="true">,</mo><mrow><mi mathvariant="normal">f</mi><mi mathvariant="normal">a</mi><mi mathvariant="normal">l</mi><mi mathvariant="normal">s</mi><mi mathvariant="normal">e</mi></mrow><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(s,\mathrm{false})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">s</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathrm">false</span></span><span class="mclose">)</span></span></span></span></p>
> </div>
> <p class="ps-line ps-code">
> <span class="ps-linenum" style="left:0em;">20:</span><span class="ps-keyword">end function</span></p>
> </div>
> </div>
> </div>
> </div>

A token budget can expire with a valid prefix that is still incomplete. The caller must inspect the termination status before treating the output as a complete structured value.

> \[!tip\] finite automaton
>
> A DFA is $M=(Q,\Sigma,\delta,q_0,F)$ [^automaton-definition]. For ordinary tokens, let $d:\mathcal{V}\setminus\{\mathrm{EOS}\}\to\Sigma^*$ map token IDs to byte strings. This assumes a tokenizer adapter with context-independent token-byte pieces; special tokens need explicit handling.
>
> > \[!note\]- example
> >
> > The figure after this callout uses `([0-9]*)?\.?[0-9]*{:rs}` and the toy token spellings `A`, `.`, `42`, `.2`, `1`.
> >
> > - Initially, allow `.`, `42`, `.2`, `1` and reject `A`.
> > - After `.2`, a second decimal point is forbidden. Only `42` and `1` remain among these five tokens.
> > - After `1`, allow `.`, `42`, `.2`, `1`. The spelling `.42` is absent from the vocabulary.
> >
> > This regex also accepts empty text and a bare `.`. It illustrates transitions; use `[0-9]+(?:\.[0-9]+)?{:rs}` if the intended format requires an integer part and digits after any decimal point. EOS follows the accepting-state rule separately from these five tokens.

```jsx imports={Zoomable,FSMDecoding}
<Zoomable label="FSM illustration">
  <FSMDecoding preset="number" />
</Zoomable>
```

[^automaton-definition]: [[thoughts/DFA|finite state machine]]

    - $Q$ is a finite set of states.
    - $\Sigma$ is a finite alphabet, here bytes.
    - $\delta:Q\times\Sigma\to Q$ is the transition function, including a rejecting sink for invalid transitions.
    - $q_0\in Q$ is the start state.
    - $F\subseteq Q$ is the set of accepting states.

> \[!tip\] determinism
>
> For regular constraints, precompute the token transitions from each DFA state. At runtime, looking up the current state’s row avoids rechecking every token’s bytes. Producing or applying a vocabulary-sized mask still has a cost.

Let $\delta^*$ consume a whole byte string. Keep only states $R\subseteq Q$ from which an accepting state can be reached. A token is permitted at $q$ when $\delta^*(q,d(v))\in R$. Assume ordinary tokens have nonempty byte strings and the vocabulary can express the remaining valid bytes. Otherwise, compute reachability using token transitions as well.

The following simple construction records every viable byte path. It consumes the first byte explicitly and retains the start state. The intermediate states need not be accepting: a token may end in the middle of a valid output.

<div class="ps-root" data-inline-macros=""><span type="button" class="clipboard-button ps-clipboard" aria-label="Copy pseudocode to clipboard"><svg width="16" height="16" viewBox="0 0 16 16" class="copy-icon"><use href="#github-copy"></use></svg><svg width="16" height="16" viewBox="0 0 16 16" class="check-icon"><use href="#github-check" fill-rule="evenodd" fill="rgb(63, 185, 80)"></use></svg></span><span class="ps-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><annotation encoding="application/x-tex">"\\begin{algorithm}\n\\caption{Find viable paths that consume byte string $v$}\n\\begin{algorithmic}\n\\Function{FindSubSequences}{$M,v,R$}\n    \\State $\\mathrm{res}\\gets ()$\n    \\For{$q\\in R$}\n        \\State $r\\gets q$, $p\\gets(q)$\n        \\For{$i\\gets 0,|v|-1$}\n            \\State $r\\gets\\delta(r,v_i)$\n            \\If{$r\\notin R$}\n                \\State $p\\gets()$\n                \\State \\textbf{break}\n            \\EndIf\n            \\State $p\\gets\\operatorname{append}(p,r)$\n        \\EndFor\n        \\If{$p\\ne()$}\n            \\State $\\mathrm{res}\\gets\\operatorname{append}(\\mathrm{res},p)$\n        \\EndIf\n    \\EndFor\n    \\State \\Return $\\mathrm{res}$\n\\EndFunction\n\\end{algorithmic}\n\\end{algorithm}"</annotation></semantics></math></span>
<div class="ps-algorithm with-caption">
<p class="ps-line" style="text-indent:-0.6em;padding-left:0.6em;">
<span class="ps-keyword">Algorithm 3 </span>Find viable paths that consume byte string <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi></mrow><annotation encoding="application/x-tex">v</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">v</span></span></span></span></p>
<div class="ps-algorithmic with-linenum">
<div class="ps-block" style="margin-left:1.2em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:0em;">1:</span><span class="ps-keyword">function </span><span class="ps-funcname">FindSubSequences</span>(<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>M</mi><mo separator="true">,</mo><mi>v</mi><mo separator="true">,</mo><mi>R</mi></mrow><annotation encoding="application/x-tex">M,v,R</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.109em;">M</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">v</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0077em;">R</span></span></span></span>)</p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">2:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">r</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">s</mi></mrow><mo>←</mo><mo stretchy="false">(</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\mathrm{res}\gets ()</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord"><span class="mord mathrm">res</span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mclose">)</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">3:</span><span class="ps-keyword">for </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>q</mi><mo>∈</mo><mi>R</mi></mrow><annotation encoding="application/x-tex">q\in R</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7335em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.0077em;">R</span></span></span></span><span class="ps-keyword"> do</span></p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">4:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo>←</mo><mi>q</mi></mrow><annotation encoding="application/x-tex">r\gets q</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">r</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span></span></span></span>, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>←</mo><mo stretchy="false">(</mo><mi>q</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p\gets(q)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="mclose">)</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">5:</span><span class="ps-keyword">for </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi><mo>←</mo><mn>0</mn><mo separator="true">,</mo><mi mathvariant="normal">∣</mi><mi>v</mi><mi mathvariant="normal">∣</mi><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">i\gets 0,|v|-1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6595em;"></span><span class="mord mathnormal">i</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">∣</span><span class="mord mathnormal" style="margin-right:0.0359em;">v</span><span class="mord">∣</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.6444em;"></span><span class="mord">1</span></span></span></span><span class="ps-keyword"> do</span></p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-2.25em;">6:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo>←</mo><mi>δ</mi><mo stretchy="false">(</mo><mi>r</mi><mo separator="true">,</mo><msub><mi>v</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">r\gets\delta(r,v_i)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">r</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0379em;">δ</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0278em;">r</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.0359em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3117em;"><span style="top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-2.25em;">7:</span><span class="ps-keyword">if </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo mathvariant="normal">∉</mo><mi>R</mi></mrow><annotation encoding="application/x-tex">r\notin R</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">r</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel"><span class="mord"><span class="mrel">∈</span></span><span class="mord vbox"><span class="thinbox"><span class="llap"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="inner"><span class="mord"><span class="mord">/</span><span class="mspace" style="margin-right:0.0556em;"></span></span></span><span class="fix"></span></span></span></span></span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.0077em;">R</span></span></span></span><span class="ps-keyword"> then</span></p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-3em;">8:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>←</mo><mo stretchy="false">(</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p\gets()</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mclose">)</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-3em;">9:</span><span style="font-weight:bold;">break</span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-2.25em;">10:</span><span class="ps-keyword">end if</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-2.25em;">11:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>←</mo><mi mathvariant="normal">append</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi>p</mi><mo separator="true">,</mo><mi>r</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p\gets\operatorname{append}(p,r)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mord mathrm">append</span></span><span class="mopen">(</span><span class="mord mathnormal">p</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0278em;">r</span><span class="mclose">)</span></span></span></span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">12:</span><span class="ps-keyword">end for</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">13:</span><span class="ps-keyword">if </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo mathvariant="normal">≠</mo><mo stretchy="false">(</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p\ne()</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel"><span class="mrel"><span class="mord vbox"><span class="thinbox"><span class="rlap"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="inner"><span class="mord"><span class="mrel"></span></span></span><span class="fix"></span></span></span></span></span><span class="mspace nobreak"></span><span class="mrel">=</span></span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mclose">)</span></span></span></span><span class="ps-keyword"> then</span></p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-2.25em;">14:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi mathvariant="normal">r</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">s</mi></mrow><mo>←</mo><mi mathvariant="normal">append</mi><mo>⁡</mo><mo stretchy="false">(</mo><mrow><mi mathvariant="normal">r</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">s</mi></mrow><mo separator="true">,</mo><mi>p</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\mathrm{res}\gets\operatorname{append}(\mathrm{res},p)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord"><span class="mord mathrm">res</span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mord mathrm">append</span></span><span class="mopen">(</span><span class="mord"><span class="mord mathrm">res</span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">p</span><span class="mclose">)</span></span></span></span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">15:</span><span class="ps-keyword">end if</span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">16:</span><span class="ps-keyword">end for</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">17:</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">18:</span><span class="ps-keyword">return </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">r</mi><mi mathvariant="normal">e</mi><mi mathvariant="normal">s</mi></mrow><annotation encoding="application/x-tex">\mathrm{res}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord"><span class="mord mathrm">res</span></span></span></span></span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:0em;">19:</span><span class="ps-keyword">end function</span></p>
</div>
</div>
</div>
</div>

Build both the allowed-token set $\sigma(q)$ and the next-state map $\tau(q,v)$. The transition map advances the grammar without rescanning the generated prefix. EOS is added only at accepting states and terminates generation instead of taking a byte transition.

<div class="ps-root" data-inline-macros=""><span type="button" class="clipboard-button ps-clipboard" aria-label="Copy pseudocode to clipboard"><svg width="16" height="16" viewBox="0 0 16 16" class="copy-icon"><use href="#github-copy"></use></svg><svg width="16" height="16" viewBox="0 0 16 16" class="check-icon"><use href="#github-check" fill-rule="evenodd" fill="rgb(63, 185, 80)"></use></svg></span><span class="ps-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><annotation encoding="application/x-tex">"\\begin{algorithm}\n\\caption{Index tokens by DFA start and end states}\n\\begin{algorithmic}\n\\Function{MapStatesToVocab}{$M,\\mathcal{V},d,R$}\n    \\State Initialize $\\sigma(q)\\gets\\emptyset$ for each $q\\in Q$\n    \\State Initialize an empty map $\\tau$\n    \\For{$v\\in\\mathcal{V}\\setminus\\{\\mathrm{EOS}\\}$}\n        \\State $P\\gets\\operatorname{FindSubSequences}(M,d(v),R)$\n        \\For{$p\\in P$}\n            \\State $\\sigma(p_0)\\gets\\sigma(p_0)\\cup\\{v\\}$\n            \\State $\\tau(p_0,v)\\gets p_{|p|-1}$\n        \\EndFor\n    \\EndFor\n    \\For{$q\\in F$}\n        \\State $\\sigma(q)\\gets\\sigma(q)\\cup\\{\\mathrm{EOS}\\}$\n    \\EndFor\n    \\State \\Return $(\\sigma,\\tau)$\n\\EndFunction\n\\end{algorithmic}\n\\end{algorithm}"</annotation></semantics></math></span>
<div class="ps-algorithm with-caption">
<p class="ps-line" style="text-indent:-0.6em;padding-left:0.6em;">
<span class="ps-keyword">Algorithm 4 </span>Index tokens by DFA start and end states</p>
<div class="ps-algorithmic with-linenum">
<div class="ps-block" style="margin-left:1.2em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:0em;">1:</span><span class="ps-keyword">function </span><span class="ps-funcname">MapStatesToVocab</span>(<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>M</mi><mo separator="true">,</mo><mi mathvariant="script">V</mi><mo separator="true">,</mo><mi>d</mi><mo separator="true">,</mo><mi>R</mi></mrow><annotation encoding="application/x-tex">M,\mathcal{V},d,R</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.109em;">M</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathcal" style="margin-right:0.0822em;">V</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">d</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0077em;">R</span></span></span></span>)</p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">2:</span>Initialize <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>σ</mi><mo stretchy="false">(</mo><mi>q</mi><mo stretchy="false">)</mo><mo>←</mo><mi mathvariant="normal">∅</mi></mrow><annotation encoding="application/x-tex">\sigma(q)\gets\emptyset</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">σ</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8056em;vertical-align:-0.0556em;"></span><span class="mord">∅</span></span></span></span> for each <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>q</mi><mo>∈</mo><mi>Q</mi></mrow><annotation encoding="application/x-tex">q\in Q</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7335em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8778em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">Q</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">3:</span>Initialize an empty map <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>τ</mi></mrow><annotation encoding="application/x-tex">\tau</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.4306em;"></span><span class="mord mathnormal" style="margin-right:0.1132em;">τ</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">4:</span><span class="ps-keyword">for </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi><mo>∈</mo><mi mathvariant="script">V</mi><mo>∖</mo><mo stretchy="false">{</mo><mrow><mi mathvariant="normal">E</mi><mi mathvariant="normal">O</mi><mi mathvariant="normal">S</mi></mrow><mo stretchy="false">}</mo></mrow><annotation encoding="application/x-tex">v\in\mathcal{V}\setminus\{\mathrm{EOS}\}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">v</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathcal" style="margin-right:0.0822em;">V</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">∖</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">{</span><span class="mord"><span class="mord mathrm">EOS</span></span><span class="mclose">}</span></span></span></span><span class="ps-keyword"> do</span></p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">5:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo>←</mo><mi mathvariant="normal">FindSubSequences</mi><mo>⁡</mo><mo stretchy="false">(</mo><mi>M</mi><mo separator="true">,</mo><mi>d</mi><mo stretchy="false">(</mo><mi>v</mi><mo stretchy="false">)</mo><mo separator="true">,</mo><mi>R</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P\gets\operatorname{FindSubSequences}(M,d(v),R)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.1389em;">P</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop"><span class="mord mathrm">FindSubSequences</span></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.109em;">M</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">d</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0359em;">v</span><span class="mclose">)</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0077em;">R</span><span class="mclose">)</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">6:</span><span class="ps-keyword">for </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi><mo>∈</mo><mi>P</mi></mrow><annotation encoding="application/x-tex">p\in P</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7335em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.1389em;">P</span></span></span></span><span class="ps-keyword"> do</span></p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-2.25em;">7:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>σ</mi><mo stretchy="false">(</mo><msub><mi>p</mi><mn>0</mn></msub><mo stretchy="false">)</mo><mo>←</mo><mi>σ</mi><mo stretchy="false">(</mo><msub><mi>p</mi><mn>0</mn></msub><mo stretchy="false">)</mo><mo>∪</mo><mo stretchy="false">{</mo><mi>v</mi><mo stretchy="false">}</mo></mrow><annotation encoding="application/x-tex">\sigma(p_0)\gets\sigma(p_0)\cup\{v\}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">σ</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">σ</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">∪</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">{</span><span class="mord mathnormal" style="margin-right:0.0359em;">v</span><span class="mclose">}</span></span></span></span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-2.25em;">8:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>τ</mi><mo stretchy="false">(</mo><msub><mi>p</mi><mn>0</mn></msub><mo separator="true">,</mo><mi>v</mi><mo stretchy="false">)</mo><mo>←</mo><msub><mi>p</mi><mrow><mi mathvariant="normal">∣</mi><mi>p</mi><mi mathvariant="normal">∣</mi><mo>−</mo><mn>1</mn></mrow></msub></mrow><annotation encoding="application/x-tex">\tau(p_0,v)\gets p_{|p|-1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.1132em;">τ</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">v</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.7858em;vertical-align:-0.3552em;"></span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.5198em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">∣</span><span class="mord mathnormal mtight">p</span><span class="mord mtight">∣</span><span class="mbin mtight">−</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3552em;"><span></span></span></span></span></span></span></span></span></span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">9:</span><span class="ps-keyword">end for</span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">10:</span><span class="ps-keyword">end for</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">11:</span><span class="ps-keyword">for </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>q</mi><mo>∈</mo><mi>F</mi></mrow><annotation encoding="application/x-tex">q\in F</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7335em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord mathnormal" style="margin-right:0.1389em;">F</span></span></span></span><span class="ps-keyword"> do</span></p>
<div class="ps-block" style="margin-left:0.6em;">
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-1.5em;">12:</span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>σ</mi><mo stretchy="false">(</mo><mi>q</mi><mo stretchy="false">)</mo><mo>←</mo><mi>σ</mi><mo stretchy="false">(</mo><mi>q</mi><mo stretchy="false">)</mo><mo>∪</mo><mo stretchy="false">{</mo><mrow><mi mathvariant="normal">E</mi><mi mathvariant="normal">O</mi><mi mathvariant="normal">S</mi></mrow><mo stretchy="false">}</mo></mrow><annotation encoding="application/x-tex">\sigma(q)\gets\sigma(q)\cup\{\mathrm{EOS}\}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">σ</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">←</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0359em;">σ</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0359em;">q</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">∪</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">{</span><span class="mord"><span class="mord mathrm">EOS</span></span><span class="mclose">}</span></span></span></span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">13:</span><span class="ps-keyword">end for</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">14:</span></p>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:-0.75em;">15:</span><span class="ps-keyword">return </span><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>σ</mi><mo separator="true">,</mo><mi>τ</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(\sigma,\tau)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.0359em;">σ</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal" style="margin-right:0.1132em;">τ</span><span class="mclose">)</span></span></span></span></p>
</div>
<p class="ps-line ps-code">
<span class="ps-linenum" style="left:0em;">16:</span><span class="ps-keyword">end function</span></p>
</div>
</div>
</div>
</div>

This index has a row for each finite state. A general PDA also depends on its stack, so the same finite table cannot enumerate all recursive parser configurations. That is the caching problem addressed by [[thoughts/structured outputs#batched constrained decoding using pushdown automaton|XGrammar]] above.

