# Lab C Setup — Cached Generation and GQA

## Exact environment

| Variable | Value |
|----------|-------|
| Operating system | macOS (darwin), Apple Silicon |
| Python | 3.12.10 |
| PyTorch | 2.15.0 (CPU build) |
| Device | CPU only (no CUDA, no MPS) |
| Precision | float32 (FP32) |
| Random seed | `torch.manual_seed(42)` |

## How to reproduce

```bash
cd labs/track1/03-cache-and-gqa
python3 test_logit_parity.py
python3 test_cache_growth.py
python3 test_mha_gqa_memory.py
python3 test_broken_cache_position.py
```

No package installation beyond Python 3.12 and PyTorch 2.15.0 is required. No GPU,
no model checkpoint, no API key, and no network access are needed.

## Model dimensions (deterministic)

| Symbol | Meaning | Value |
|--------|---------|-------|
| `D` | Hidden dimension | 32 |
| `H` | Query heads (and KV heads for MHA) | 2 |
| `D_HEAD` | Head dimension | 16 |
| `L` | Transformer layers | 2 |
| `V` | Vocabulary size | 50 |
| `B` | Batch size | 1 |
| `P` | Prompt length | 3 |
| `b` | Bytes per element (FP32) | 4 |

The model uses `torch.manual_seed(42)` for full determinism. Every run produces
identical output. Model runs are float32; the cache-byte table uses a stated
FP16 assumption of 2 bytes per element.

## Lab scope

- Cached vs uncached logit parity over 5 decode steps
- One KV append per layer per step (cache growth)
- Per-layer and total MHA vs GQA cache bytes calculated from model dimensions;
  GQA figures are calculated, not measured from an instantiated GQA cache
- Broken cache-position write (overwrites slot 0 instead of appending) with
  diagnostic test and repair
- Timing is optional measured local data only; not a guaranteed speedup

## Out of scope

- GPU timing or CUDA kernels
- Model checkpoint loading or weight mapping
- Production serving systems (batching, prefix caching, speculative decoding)
- MDX lesson edits or curriculum changes
