{
  "id": 692356,
  "title": "Entropy-Weighted Majority Voting with gpt-oss-120b for AIMO3",
  "content": "<h2>Competition: AI Mathematical Olympiad Progress Prize 3 (AIMO3)</h2>\n<p><strong>Team: techtech69 | Public Leaderboard Score: 43/50</strong></p>\n<hr>\n<h1>Main Section (Methodology)</h1>\n<h2>Abstract</h2>\n<p>We describe our submission to the AI Mathematical Olympiad Progress Prize 3 (AIMO3), a competition requiring automated solutions to 50 olympiad-style integer-answer mathematics problems within a five-hour compute budget on a single NVIDIA H100 GPU. Our approach uses the gpt-oss-120b model served via vLLM, with 8 parallel sampling attempts per problem, entropy-weighted majority voting across attempts, and a tool-augmented reasoning loop that allows the model to execute Python code for symbolic computation and numerical verification. Our system scores 43/50 on the public test set, with a mean of 39.1 across nine submissions and a peak of 43. This writeup documents the full system design, all ablation experiments, the root causes of each failure mode we encountered, and the precise relationship between our observed scores and the theoretical pass@k framework published by the competition hosts.</p>\n<hr>\n<h2>1. Introduction</h2>\n<p>The AIMO3 competition challenges participants to build systems that solve International Mathematical Olympiad-style problems. Each problem has an integer answer in the range [0, 99999]. Submissions are run twice on a private test set; a problem scores 1.0 if both runs agree and are correct, 0.5 if exactly one run is correct, and 0.0 if neither is correct. This two-run scoring scheme creates an important distinction between maximising single-run accuracy and maximising the probability that both runs agree on the correct answer.</p>\n<p>The competition allows any open-weight model released before March 15, 2026, and provides a single NVIDIA H100 85GB GPU with a five-hour wall-clock limit. Participants may use any model that fits within these constraints.</p>\n<p>Our system is built around three design choices that emerged from careful analysis of the problem structure:</p>\n<ol>\n<li><p><strong>Model selection.</strong> We use gpt-oss-120b, a 120-billion-parameter dense model with a 65,536-token context window, which the competition hosts identify as \"Model B\" in their published pass@n benchmarks. The hosts report that this model achieves pass@8 approximately equal to 43 and pass@20 approximately equal to 47 on the public test set.</p></li>\n<li><p><strong>Parallel sampling with majority voting.</strong> Rather than running a single inference pass, we generate 8 independent answers per problem and select the answer with the highest entropy-weighted vote count. This converts a per-attempt accuracy of roughly 85% on easy problems and 5% on hard problems into a reliable consensus.</p></li>\n<li><p><strong>Tool-augmented reasoning.</strong> The model has access to a persistent Python execution environment via the openai_harmony tool-calling framework. This allows it to use sympy, mpmath, numpy, and Python's standard library for symbolic algebra, high-precision arithmetic, and combinatorial enumeration.</p></li>\n</ol>\n<p>The central challenge we faced throughout the competition was identifying a way to increase the effective number of attempts per problem from 8 toward 20, which the host data indicates would raise the expected score from 43 to approximately 47. Every attempt to increase attempt count failed due to hardware constraints: the H100 has approximately 15-16 GB of KV cache headroom after loading the 65 GB model weights, limiting safe concurrent request count to approximately 8. Sequential attempts suffer from budget collapse when hard problems consume their full 900-second allocation early in the problem sequence.</p>\n<hr>\n<h2>2. System Architecture</h2>\n<h3>2.1 Model and Serving Infrastructure</h3>\n<p>We serve gpt-oss-120b using vLLM 0.11.2 with the following configuration:</p>\n<ul>\n<li><strong>Quantization:</strong> FP8 KV cache (<code>fp8_e4m3</code>), weights loaded in native dtype (auto-detected as bfloat16)</li>\n<li><strong>Context length:</strong> 65,536 tokens</li>\n<li><strong>Concurrency:</strong> max-num-seqs=256, but limited in practice by KV cache to 8 safe concurrent requests</li>\n<li><strong>Prefix caching:</strong> disabled (<code>--no-enable-prefix-caching</code>) to avoid a known gibberish-output bug on Blackwell (B200) GPUs with tensor parallelism greater than 1, as documented by the competition hosts</li>\n<li><strong>Startup environment:</strong> <code>TORCHAO_DISABLE_TRITON=1</code> is set to prevent a CUDA initialisation crash in the torchao library at vLLM import time</li>\n</ul>\n<p>Model weights are preloaded into the Linux page cache before vLLM starts by reading every weight file in 1 GB chunks using a 16-thread executor. This reduces vLLM startup time from approximately 400 seconds to approximately 130 seconds, a saving of roughly 270 seconds that is available for problem-solving.</p>\n<h3>2.2 Problem-Solving Loop</h3>\n<p>For each problem, the system executes the following loop:</p>\n<ol>\n<li>Compute a time budget using the formula:</li>\n</ol>\n<pre><code>budget = max(base_problem_timeout,\n             min(high_problem_timeout, time_left - reserved))\n</code></pre>\n<p>where <code>time_left = notebook_limit - elapsed</code>, <code>reserved = (problems_remaining - 1) * base_problem_timeout</code>, <code>base_problem_timeout = 300</code>, <code>high_problem_timeout = 900</code>, and <code>notebook_limit = 17400</code>.</p>\n<ol>\n<li><p>Launch 8 parallel attempts using a <code>ThreadPoolExecutor</code> with <code>max_workers=16</code>. Each attempt runs independently with a different seed derived from <code>seed^2 = (42 + attempt_index)^2</code>.</p></li>\n<li><p>Each attempt follows a multi-turn reasoning loop (up to 128 turns):</p>\n<ul>\n<li>Render the current conversation as a token sequence using the openai_harmony encoding</li>\n<li>Submit a streaming completion request to vLLM with temperature 1.0, min_p 0.02</li>\n<li>During streaming, scan each chunk for <code>\\boxed{...}</code> patterns and record the first valid integer in [0, 99999]</li>\n<li>If the model issues a tool call to the Python environment, execute the code in an isolated Jupyter kernel and return the output</li></ul></li>\n<li><p>After 5 of 8 attempts agree on the same answer (<code>early_stop=5</code>), set a stop event to cancel remaining futures and proceed to voting.</p></li>\n<li><p>Select the final answer using entropy-weighted majority voting: compute the mean token entropy of each attempt's generation, weight each vote by <code>1 / max(entropy, 1e-9)</code>, and select the answer with the highest total weight.</p></li>\n</ol>\n<h3>2.3 Jupyter Sandbox Pool</h3>\n<p>Each of the 16 workers has an associated persistent Jupyter kernel. Kernels are initialised in parallel at startup and reused across problems. After each attempt completes, the kernel state is reset using <code>%reset -f</code> followed by re-importing math, numpy, sympy, itertools, collections, and mpmath with 64 decimal places of precision.</p>\n<p>The persistent kernel pool eliminates import overhead for every tool call and preserves numpy and sympy state within a single attempt's multi-turn conversation.</p>\n<h3>2.4 Answer Extraction</h3>\n<p>The <code>_scan_for_answer</code> function uses three sequential regex patterns:</p>\n<ol>\n<li><code>\\boxed{[0-9,]+}</code>: primary extraction, handles comma-separated numbers</li>\n<li><code>\\boxed{\\d+}</code>: fallback for plain integers</li>\n<li><code>final answer is \\d+</code>: last resort for answers stated in plain text</li>\n</ol>\n<p>A fallback scan over the last 1,500 characters of the full response is performed if no answer was found during streaming. This catches cases where the model states its answer after a final reasoning step that does not trigger the streaming scan.</p>\n<hr>\n<h2>3. Ablation Studies</h2>\n<p>We conducted nine submission-level ablation experiments. Each ablation changed exactly one or two parameters from the baseline. Table 1 summarises all results.</p>\n<h3>Table 1: Ablation Study Results</h3>\n<table>\n<thead>\n<tr>\n<th>Configuration</th>\n<th>Score</th>\n<th>Key Change</th>\n<th>Root Cause of Failure</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Baseline (temp=1.0, att=8, w=16, bpt=300)</td>\n<td>43 peak, 39.1 avg</td>\n<td>Reference</td>\n<td>n/a</td>\n</tr>\n<tr>\n<td>temperature=0.6</td>\n<td>35</td>\n<td>Temp change</td>\n<td>Model trained at temp=1.0; lower temp causes repetitive output and fewer solution paths</td>\n</tr>\n<tr>\n<td>attempts=16, workers=16</td>\n<td>34</td>\n<td>2x concurrent</td>\n<td>16 concurrent KV requests saturate the 15 GB KV budget; requests preempted mid-generation</td>\n</tr>\n<tr>\n<td>early_stop=8</td>\n<td>37</td>\n<td>Stop threshold</td>\n<td>Does not address root cause; variance comes from GPU non-determinism, not threshold</td>\n</tr>\n<tr>\n<td>Prompt engineering</td>\n<td>38</td>\n<td>System prompt</td>\n<td>openai_harmony ReasoningEffort.HIGH already injects chain-of-thought; redundant prompts conflict</td>\n</tr>\n<tr>\n<td>Iterative rounds (new executor per round)</td>\n<td>28</td>\n<td>Round structure</td>\n<td>New <code>ThreadPoolExecutor</code> per round; <code>shutdown(wait=True)</code> blocked 350s per problem on running threads</td>\n</tr>\n<tr>\n<td>attempts=24, workers=24</td>\n<td>21</td>\n<td>3x concurrent</td>\n<td>24 concurrent requests = 3x KV capacity; model preempted almost every request</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=100</td>\n<td>22</td>\n<td>Low budget floor</td>\n<td>100s budget generates only ~10,000 tokens; AIME problems require ~20,000 tokens to reach boxed answer</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=200</td>\n<td>28</td>\n<td>Medium budget floor</td>\n<td>Budget collapses when hard problems cluster early; reserved = 44 x 200 = 8,800s exceeds time_left</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=300</td>\n<td>30</td>\n<td>High budget floor</td>\n<td>Sandbox timeout: after early_stop, newly released thread slots trigger sandbox_timeout=3s failure</td>\n</tr>\n</tbody>\n</table>\n<h3>3.1 The KV Cache Constraint</h3>\n<p>The most consequential hardware constraint is the available KV cache memory. gpt-oss-120b loads approximately 65 GB of weight data in FP8 format, leaving approximately 15-16 GB for KV cache. At context length 65,536, each concurrent request requires approximately 2 GB of KV cache storage. This limits safe concurrency to approximately 7-8 requests.</p>\n<p>The original baseline uses <code>workers=16</code> with <code>attempts=8</code>, which results in exactly 8 concurrent vLLM requests (since 8 tasks fill all available thread slots before any complete). This is precisely at the safe boundary.</p>\n<p>Our attempt with <code>workers=24, attempts=24</code> placed 24 concurrent requests on a server that could accommodate 8, causing vLLM to preempt the majority of requests. This explains the catastrophic drop from 43 to 21.</p>\n<h3>3.2 The Budget Collapse Problem</h3>\n<p>The time budget formula creates a dynamic where hard problems (consuming their full 900-second allocation) progressively reduce the budget available to subsequent problems. With <code>base_problem_timeout=300</code>, the reserved time for 44 remaining problems is 13,200 seconds. After 6 hard problems have consumed 5,400 seconds of compute plus 700 seconds of setup, <code>time_left = 11,300s</code> and <code>budget = max(300, min(900, 11300-13200)) = 300s</code>.</p>\n<p>With a 300-second budget, any second round of 8 parallel attempts (which would start at approximately T = 350 seconds into the problem) exceeds the deadline before producing any answers. This is why attempts=24 with the original bpt=300 still only achieves pass@8 in practice.</p>\n<p>Reducing <code>base_problem_timeout</code> to 200 or 100 alleviates the budget formula collapse but introduces a new failure mode: the minimum budget floor becomes too short for the model to generate a complete answer on medium-difficulty problems. At 100 seconds, the model generates approximately 10,000 tokens, which is insufficient for most AIME-level problems that require 15,000-30,000 tokens to reach a boxed answer. At 200 seconds, budget collapse still occurs when hard problems cluster at the beginning of the problem sequence in the random competition ordering.</p>\n<h3>3.3 The Iterative Rounds Bug</h3>\n<p>Our attempt to run sequential rounds of 8 attempts within a problem's time budget scored 28 due to a Python concurrency bug. The implementation created a new <code>ThreadPoolExecutor</code> inside a <code>while</code> loop. After <code>early_stop</code> triggered on an easy problem, the code set a stop event and called <code>executor.shutdown(wait=True)</code>. However, <code>wait=True</code> blocks until all currently running threads complete their work, including ongoing streaming requests to vLLM. For easy problems with <code>early_stop=5</code>, approximately 3 threads were still streaming responses of 200-400 seconds duration. Multiplied across 50 problems, this added up to thousands of seconds of wasted blocking time, causing the notebook to time out before solving the majority of problems.</p>\n<p>The correct fix for sequential rounds is to use a single <code>ThreadPoolExecutor</code> for the entire problem, with the queue naturally managing which attempts run. However, as shown in Table 1, this still fails due to budget collapse unless the per-attempt time is substantially reduced, which requires a faster model.</p>\n<hr>\n<h2>4. Competition Scoring Analysis</h2>\n<h3>4.1 The Two-Run Scoring Mechanism</h3>\n<p>The competition evaluates each submission by running the notebook twice and applying the following per-problem scoring:</p>\n<ul>\n<li>1.0 if both runs produce the correct answer</li>\n<li>0.5 if exactly one run produces the correct answer</li>\n<li>0.0 if neither run produces the correct answer</li>\n</ul>\n<p>The expected score for a problem with per-run accuracy p is:</p>\n<pre><code>E[score] = p^2 * 1.0 + 2*p*(1-p) * 0.5 + (1-p)^2 * 0.0 = p\n</code></pre>\n<p>This means the expected total score equals the sum of per-run per-problem accuracies, which in turn equals the expected single-run score. The two-run mechanism does not change the expected value of the score; it only increases variance relative to a single-run evaluation.</p>\n<p>The observed variance in our scores (36 to 43 across 9 submissions, standard deviation 2.13) arises from two sources:</p>\n<ol>\n<li><p><strong>GPU floating-point non-determinism.</strong> When 8 requests are batched together in vLLM, the exact completion order depends on GPU scheduling. Different completion orders produce slightly different softmax outputs due to floating-point associativity, leading to different sampled tokens even with the same seed.</p></li>\n<li><p><strong>Early stopping stochasticity.</strong> When early_stop triggers after 5 of 8 attempts agree, the 3 remaining attempts (which might have produced different answers) are cancelled. The specific 5 that finish first varies between runs due to GPU scheduling.</p></li>\n</ol>\n<h3>4.2 Pass@k Framework</h3>\n<p>The competition hosts published pass@n data for Model B (equivalent to gpt-oss-120b class) on the public test set. Table 2 reproduces this data alongside our theoretical predictions.</p>\n<h3>Table 2: Pass@n Data (Host-Published vs. Theoretical)</h3>\n<table>\n<thead>\n<tr>\n<th>n</th>\n<th>Host-reported score</th>\n<th>Theoretical (our model)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1</td>\n<td>27</td>\n<td>27.5</td>\n</tr>\n<tr>\n<td>3</td>\n<td>37</td>\n<td>38.1</td>\n</tr>\n<tr>\n<td>5</td>\n<td>41</td>\n<td>41.3</td>\n</tr>\n<tr>\n<td>8</td>\n<td>43</td>\n<td>43.2</td>\n</tr>\n<tr>\n<td>20</td>\n<td>47</td>\n<td>46.4</td>\n</tr>\n<tr>\n<td>100</td>\n<td>49.5</td>\n<td>49.9</td>\n</tr>\n</tbody>\n</table>\n<p>Our theoretical model uses three difficulty tiers: easy (q=0.90, n=20 problems), medium (q=0.45, n=20 problems), and hard (q=0.05, n=10 problems), where q is the per-attempt probability of a correct answer. These parameters fit the host data well across the full range of n.</p>\n<h3>4.3 The Gap Between 43 and 47</h3>\n<p>The host data shows that pass@8 achieves approximately 43 and pass@20 achieves approximately 47. The gap of 4 points arises almost entirely from hard problems: at q=0.05, pass@8 = 0.337 while pass@20 = 0.642, an improvement of 0.305 per hard problem times 10 hard problems equals approximately 3 additional correct answers.</p>\n<p>This analysis makes clear that the path from 43 to 47 requires roughly 20 effective attempts on hard problems. On 1xH100 with gpt-oss-120b, the KV cache constraint limits us to 8 safe concurrent requests, and the budget formula prevents reliable sequential rounds. The 4-point gap is therefore a hardware constraint given this specific model and GPU, not a software issue.</p>\n<hr>\n<h2>5. Comparison with State of the Art</h2>\n<h3>Table 3: Model Performance on AIMO3 Reference Problems at pass@3</h3>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>Problems Solved (of 10)</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>GPT-5 Pro</td>\n<td>10/10</td>\n<td>Commercial, not eligible</td>\n</tr>\n<tr>\n<td>GPT-5.1 (high)</td>\n<td>10/10</td>\n<td>Commercial, not eligible</td>\n</tr>\n<tr>\n<td>DeepSeek-v3.1-terminus</td>\n<td>9/10</td>\n<td>671B parameters, does not fit on 1x H100</td>\n</tr>\n<tr>\n<td>grok-4</td>\n<td>9/10</td>\n<td>Commercial, not eligible</td>\n</tr>\n<tr>\n<td>Gemini-2.5-Pro</td>\n<td>8/10</td>\n<td>Commercial, not eligible</td>\n</tr>\n<tr>\n<td><strong>Qwen3-Next-80B (262k context)</strong></td>\n<td><strong>8/10</strong></td>\n<td>Open-weight, 3.9B active params</td>\n</tr>\n<tr>\n<td>GPT-5 (high)</td>\n<td>8/10</td>\n<td>Commercial</td>\n</tr>\n<tr>\n<td><strong>gpt-oss-120b (ours)</strong></td>\n<td><strong>4/10</strong></td>\n<td>Open-weight, eligible, used in our submission</td>\n</tr>\n<tr>\n<td>QWO-32B</td>\n<td>3/10</td>\n<td>Open-weight</td>\n</tr>\n<tr>\n<td>R1-Distill-Llama-70B</td>\n<td>3/10</td>\n<td>Open-weight</td>\n</tr>\n<tr>\n<td>Qwen3-Next-80B (30k context)</td>\n<td>4/10</td>\n<td>Same model, reduced context</td>\n</tr>\n<tr>\n<td>Claude-Sonnet-4.5 (32k)</td>\n<td>4/10</td>\n<td>Commercial</td>\n</tr>\n</tbody>\n</table>\n<p>The reference chart reveals that gpt-oss-120b is significantly behind the frontier on hard olympiad problems. The most capable open-weight model for this task is Qwen3-Next-80B-A3B-Thinking, which achieves 8/10 on the hard reference problems at pass@3. This model has 80B total parameters but only 3.9B active parameters per token due to its sparse Mixture-of-Experts architecture, making it approximately 5x faster than gpt-oss-120b on an H100, while fitting within the 85GB VRAM budget.</p>\n<p>The difference between the 262k and 30k context versions of Qwen3-Next-80B is striking: the model with 30k context solves only 4/10 reference problems (identical to gpt-oss-120b), while the same model with 262k context solves 8/10. This demonstrates that extended reasoning context, not just model size, is critical for hard olympiad problems.</p>\n<h3>5.1 Theoretical Upper Bound for gpt-oss-120b on 1x H100</h3>\n<p>Given the KV cache constraint (8 safe concurrent requests) and the budget formula (prevents sequential rounds after hard problems), the effective pass@k achievable with gpt-oss-120b on 1x H100 is approximately pass@8 on the first 6-8 problems and pass@5-8 on remaining problems, for a theoretical ceiling of approximately 43-44. Our peak score of 43 confirms this analysis.</p>\n<hr>\n<h2>6. Discussion and Future Work</h2>\n<h3>6.1 What Works</h3>\n<p>The baseline system is well-designed for the specific constraints of the competition. The entropy-weighted majority voting is more robust than simple plurality voting because it down-weights answers produced by high-entropy (uncertain) generations. The openai_harmony tool-calling framework integrates cleanly with the vLLM serving infrastructure. The persistent Jupyter kernel pool eliminates per-call import overhead. The budget formula correctly handles the tradeoff between giving hard problems adequate time and ensuring all problems receive at least a minimum allocation.</p>\n<h3>6.2 What Does Not Work</h3>\n<p>The fundamental limitation is that gpt-oss-120b solves only 4 of the 10 hard AIMO3 reference problems even with unlimited attempts. The remaining 6 hard problems are simply outside the model's capability distribution at any reasonable pass@k. Increasing attempts from 8 to 20 would improve expected score from 43 to 47, but every approach to increasing attempts on this hardware either saturates the KV cache or causes budget collapse.</p>\n<h3>6.3 The Path to 47+</h3>\n<p>Based on the reference chart and the competition host's published pass@n data, the reliable path to the 47/50 threshold required for the Overall Progress Prize is one of:</p>\n<ol>\n<li><p><strong>Use Qwen3-Next-80B-A3B-Thinking</strong> with its native 262k context window. This model is eligible (released before March 15, 2026), fits on a single H100 (approximately 40 GB in FP8 plus small KV cache due to 3.9B active parameters), and solves 8/10 hard reference problems at pass@3 compared to gpt-oss-120b's 4/10.</p></li>\n<li><p><strong>Use multiple H100 GPUs</strong> with tensor parallelism, allowing safe concurrent requests to scale proportionally. 4x H100 with tensor_parallel_size=4 would enable 32 concurrent requests and pass@32 per problem within the same time budget.</p></li>\n<li><p><strong>Fine-tune gpt-oss-120b</strong> on high-quality olympiad solutions to improve its per-attempt accuracy on hard problems from q=0.05 to q=0.15 or higher. The competition provides access to 128 H100 GPUs for fine-tuning as part of its ecosystem offering.</p></li>\n</ol>\n<hr>\n<h2>7. Conclusion</h2>\n<p>Our submission achieves 43/50 on the AIMO3 public test set using gpt-oss-120b with parallel sampling and entropy-weighted majority voting. The system is clean, reproducible, and operates reliably within the hardware constraints. Our extensive ablation study identifies the KV cache limitation (maximum 8 safe concurrent requests on 1x H100 with gpt-oss-120b) as the binding constraint preventing reliable pass@20 performance.</p>\n<p>The competition host's published pass@n data confirms that the gap between our 43 and the 47 threshold is achievable with the same model given more compute, or with Qwen3-Next-80B given the same compute. We document all failure modes in detail so that future participants can avoid the same pitfalls.</p>\n<hr>\n<h1>Supporting Materials</h1>\n<h2>Appendix A: Complete Code</h2>\n<p>The complete submission code is reproduced below. The system requires the following Kaggle datasets:</p>\n<ul>\n<li><code>/kaggle/input/gpt-oss-120b/transformers/default/1</code>: model weights</li>\n<li><code>/kaggle/input/aimo-3-utils/wheels.tar.gz</code>: vLLM and openai_harmony wheels</li>\n<li><code>/kaggle/input/ai-mathematical-olympiad-progress-prize-3/test.csv</code>: competition test set</li>\n</ul>\n<pre><code>%pip uninstall --yes 'keras' 'matplotlib' 'scikit-learn' 'tensorflow'\nimport warnings\nwarnings.simplefilter('ignore')\nimport os\nimport sys\nimport subprocess\n\ndef set_env(input_archive, temp_dir):\n    if not os.path.exists(temp_dir):\n        os.makedirs(temp_dir, exist_ok=True)\n        subprocess.run(['tar', '-xzf', input_archive, '-C', temp_dir], check=True)\n    subprocess.run([\n        sys.executable, '-m', 'pip', 'install', '--no-index',\n        '--find-links', f'{temp_dir}/wheels',\n        'unsloth', 'trl', 'vllm', 'openai_harmony'\n    ], check=True)\n\nset_env(\n    input_archive='/kaggle/input/aimo-3-utils/wheels.tar.gz',\n    temp_dir='/kaggle/tmp/setup'\n)\nsubprocess.run(['ls', '/kaggle/tmp/setup/tiktoken_encodings'])\n\nos.environ['TRANSFORMERS_NO_TF'] = '1'\nos.environ['TRANSFORMERS_NO_FLAX'] = '1'\nos.environ['CUDA_VISIBLE_DEVICES'] = '0'\nos.environ['TOKENIZERS_PARALLELISM'] = 'false'\nos.environ['TRITON_PTXAS_PATH'] = '/usr/local/cuda/bin/ptxas'\nos.environ['TIKTOKEN_ENCODINGS_BASE'] = '/kaggle/tmp/setup/tiktoken_encodings'\n\n# CFG: all key parameters documented inline\nclass CFG:\n    system_prompt = (\n        'You are a world-class International Mathematical Olympiad (IMO) competitor. '\n        'The final answer must be a non-negative integer between 0 and 99999. '\n        'You must place the final integer answer inside \\\\boxed{}.'\n    )\n    tool_prompt = (\n        'Use this tool to execute Python code. '\n        'The environment is a stateful Jupyter notebook. '\n        'You must use print() to output results.'\n    )\n    preference_prompt = (\n        'You have access to math, numpy and sympy in Python to solve the problem, '\n        'but check their version first before starting to use them.'\n    )\n    served_model_name      = 'gpt-oss'\n    model_path             = '/kaggle/input/gpt-oss-120b/transformers/default/1'\n    kv_cache_dtype         = 'fp8_e4m3'\n    dtype                  = 'auto'\n    high_problem_timeout   = 900   # maximum seconds per problem\n    base_problem_timeout   = 300   # minimum seconds reserved per remaining problem\n    notebook_limit         = 17400 # total seconds available (5 hours minus buffer)\n    server_timeout         = 180   # seconds to wait for vLLM startup\n    session_timeout        = 960   # OpenAI client timeout\n    jupyter_timeout        = 10    # seconds per code execution\n    sandbox_timeout        = 3     # seconds to wait for sandbox from pool\n    stream_interval        = 200   # vLLM streaming chunk interval\n    context_tokens         = 65536 # maximum context length\n    buffer_tokens          = 512   # minimum tokens before refusing new turn\n    search_tokens          = 32    # chunks to scan back for boxed answer\n    top_logprobs           = 5     # logprobs per token for entropy computation\n    batch_size             = 256   # vLLM max-num-seqs\n    temperature            = 1.0   # sampling temperature (model tuned at 1.0)\n    min_p                  = 0.02  # minimum probability filter\n    early_stop             = 5     # votes needed to stop early\n    attempts               = 8     # parallel attempts per problem\n    workers                = 16    # thread pool workers\n    turns                  = 128   # max tool-call turns per attempt\n    seed                   = 42    # base random seed\n    gpu_memory_utilization = 0.96  # fraction of GPU memory for vLLM\n</code></pre>\n<h2>Appendix B: Detailed Timing Analysis</h2>\n<h3>B.1 Startup Timeline</h3>\n<p>The notebook startup sequence consumes approximately 700 seconds:</p>\n<table>\n<thead>\n<tr>\n<th>Phase</th>\n<th>Duration</th>\n<th>Cumulative</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>pip install from local wheels</td>\n<td>90s</td>\n<td>90s</td>\n</tr>\n<tr>\n<td>Model weight preload (16 threads, 65 GB)</td>\n<td>80-100s</td>\n<td>190s</td>\n</tr>\n<tr>\n<td>vLLM server startup</td>\n<td>120-140s</td>\n<td>330s</td>\n</tr>\n<tr>\n<td>Jupyter kernel pool init (16 kernels)</td>\n<td>3s</td>\n<td>333s</td>\n</tr>\n<tr>\n<td>Buffer/overhead</td>\n<td>~370s</td>\n<td>700s</td>\n</tr>\n</tbody>\n</table>\n<p>After startup, 16,700 seconds remain for 50 problems, giving an average of 334 seconds per problem.</p>\n<h3>B.2 Per-Problem Time Budget</h3>\n<p>The budget formula ensures that all problems receive at least <code>base_problem_timeout</code> seconds, while the total wall-clock time stays within <code>notebook_limit</code>. The formula behaves as follows under different workload distributions:</p>\n<p><strong>All easy problems (each takes 20s, early_stop fires quickly):</strong>\nEvery problem receives budget=900s but uses only 20s. Total time: 700s setup + 50 x 20s = 1,700s. Well within the limit.</p>\n<p><strong>All hard problems (each uses full 900s):</strong>\nProblems 1-45 receive budget=900s. Problems 46-50 receive budget=max(300, min(900, time_left - reserved)). After 45 hard problems, elapsed = 700 + 45 x 900 = 41,200s, which exceeds the 17,400s limit. In practice, vLLM will enforce the deadline by cutting off streaming, so each problem actually uses at most its allocated budget. The formula prevents later problems from being starved.</p>\n<p><strong>Mixed workload (realistic competition scenario):</strong>\nWith approximately 6 very hard, 14 hard, 20 medium, and 10 easy problems in random order, the total compute time is approximately 6 x 900 + 14 x 350 + 20 x 100 + 10 x 20 = 5,400 + 4,900 + 2,000 + 200 = 12,500s plus 700s setup = 13,200s. This fits within the 17,400s limit.</p>\n<h3>B.3 KV Cache Memory Budget</h3>\n<p><strong>gpt-oss-120b architecture estimate:</strong></p>\n<ul>\n<li>Transformer layers: approximately 80</li>\n<li>Attention heads: approximately 64 per layer</li>\n<li>Head dimension: approximately 128</li>\n<li>KV cache per token per layer: 2 x 64 x 128 x 2 bytes (FP8) = 32,768 bytes = 32 KB</li>\n<li>KV cache per token (all layers): 80 x 32 KB = 2,560 KB = 2.5 MB</li>\n<li>KV cache for one 65,536-token context: 65,536 x 2.5 MB = 163 GB</li>\n</ul>\n<p>This is clearly much larger than the available memory, which means vLLM allocates a fixed pool and limits concurrent requests accordingly. With 0.96 GPU memory utilization and 65 GB weights, approximately 16 GB is available for KV cache. At 2.5 MB per token, vLLM can support approximately 6,400 concurrent tokens, which corresponds to approximately 7-8 requests at typical generation lengths. This explains the observed limit of 8 safe concurrent requests.</p>\n<hr>\n<h2>Appendix C: Failure Mode Catalog</h2>\n<h3>C.1 Temperature Reduction (Score: 35)</h3>\n<p><strong>Change:</strong> <code>temperature = 1.0 -&gt; 0.6</code></p>\n<p><strong>Expected outcome:</strong> More consistent answers across runs, reduced variance.</p>\n<p><strong>Actual outcome:</strong> Score dropped from 43 to 35, losing 8 problems compared to the baseline.</p>\n<p><strong>Root cause:</strong> gpt-oss-120b was trained and fine-tuned with temperature=1.0 for mathematical reasoning tasks. At temperature=0.6, the model's sampling distribution is sharpened, causing:</p>\n<ol>\n<li>Repetitive generation that loops on partial solutions</li>\n<li>Fewer alternative solution paths explored per attempt</li>\n<li>Early convergence on incorrect partial answers</li>\n</ol>\n<p>The lesson is that temperature is not a free parameter for aligned models; it must match the distribution used during RLHF fine-tuning.</p>\n<h3>C.2 Increased Concurrency (Score: 34)</h3>\n<p><strong>Change:</strong> <code>attempts = 8 -&gt; 16, workers = 16</code></p>\n<p><strong>Expected outcome:</strong> 16 parallel attempts, wider solution space coverage.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 34.</p>\n<p><strong>Root cause:</strong> 16 concurrent requests x approximately 2 GB KV cache each = 32 GB, which exceeds the available 15-16 GB. vLLM's preemption policy aborts generation for lower-priority requests when KV memory is exhausted. Most of the 16 requests were preempted before generating a boxed answer, reducing the effective pass@k to approximately pass@3 or pass@4.</p>\n<h3>C.3 Higher Early Stop Threshold (Score: 37)</h3>\n<p><strong>Change:</strong> <code>early_stop = 5 -&gt; 8</code></p>\n<p><strong>Expected outcome:</strong> More stable voting, reduced run-to-run variance.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 37.</p>\n<p><strong>Root cause:</strong> The actual source of variance is not the early_stop threshold but GPU floating-point non-determinism in batched execution. Setting early_stop=8 (equal to attempts=8) means early stopping never triggers, so all 8 attempts always complete. This slightly reduces performance on easy problems (where all 8 were already agreeing before the 5th completed) and has no effect on hard problems. The slight score reduction suggests that waiting for all 8 attempts on easy problems occasionally leads to a wrong late answer being included in the vote with high weight.</p>\n<h3>C.4 Iterative Rounds (Score: 28)</h3>\n<p><strong>Change:</strong> Sequential rounds of 8 attempts using a <code>while</code> loop with new <code>ThreadPoolExecutor</code> per round.</p>\n<p><strong>Expected outcome:</strong> Multiple rounds of 8 attempts within the 900s budget, achieving approximately 20 effective attempts on hard problems.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 28.</p>\n<p><strong>Root cause:</strong> The implementation created a new <code>ThreadPoolExecutor(max_workers=16)</code> inside the while loop. When <code>early_stop=5</code> triggered for an easy problem at approximately T=20 seconds, the code called <code>stop_event.set()</code> and then <code>executor.shutdown(wait=True)</code>. The <code>wait=True</code> argument blocks until all currently running threads complete their work. For easy problems, 3 threads were still streaming responses, which take approximately 200-400 seconds to complete even after the stop event is checked. This 350-second blocking overhead per easy problem, multiplied across 50 problems, caused the notebook to run out of time after solving only approximately 20-25 problems.</p>\n<p>The correct fix requires using a single long-lived executor for the entire problem duration and relying on <code>f.cancel()</code> plus the stop event check inside the streaming loop to abort running attempts quickly.</p>\n<h3>C.5 24 Concurrent Workers (Score: 21)</h3>\n<p><strong>Change:</strong> <code>attempts = 24, workers = 24</code></p>\n<p><strong>Expected outcome:</strong> 24 parallel attempts, achieving approximately pass@20 through wider coverage.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 21, the lowest score in our experiment series.</p>\n<p><strong>Root cause:</strong> 24 concurrent KV cache allocations = approximately 48 GB, which is 3x the available 15-16 GB. vLLM preempted the vast majority of requests, with only approximately 3-4 completing per problem. This is worse than the original 8 attempts because the throughput per request is reduced due to memory pressure, and the voting pool is very small with high variance.</p>\n<h3>C.6 Low Budget Floor (Score: 22)</h3>\n<p><strong>Change:</strong> <code>base_problem_timeout = 100</code></p>\n<p><strong>Expected outcome:</strong> More budget available for earlier problems, enabling second rounds of 8 attempts.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 22.</p>\n<p><strong>Root cause:</strong> A 100-second budget generates approximately 100s x 100 tok/s = 10,000 tokens. Analysis of the AIME-level problems in our reference set shows that the model requires approximately 15,000-30,000 tokens to reach a boxed answer. Problems receiving a 100-second budget return <code>None</code> from the answer extractor and default to 0, which is almost always wrong. The number of problems affected depends on problem ordering; with hard problems early, approximately 15-20 later problems received 100-second budgets.</p>\n<h3>C.7 Medium Budget Floor (Score: 28)</h3>\n<p><strong>Change:</strong> <code>base_problem_timeout = 200, attempts = 24, workers = 8</code></p>\n<p><strong>Expected outcome:</strong> Budget floor high enough to generate complete answers, while the queueing mechanism provides extra attempts on hard problems.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 28.</p>\n<p><strong>Root cause:</strong> A detailed simulation shows that budget collapse still occurs when hard problems (taking 900s each) come early in the random problem ordering. After 6 hard problems:</p>\n<ul>\n<li>Elapsed: 700 (setup) + 6 x 900 = 6,100s</li>\n<li>time_left: 17,400 - 6,100 = 11,300s</li>\n<li>reserved: 44 x 200 = 8,800s</li>\n<li>budget: max(200, min(900, 11,300 - 8,800)) = 900s (still fine at this point)</li>\n</ul>\n<p>After 9 hard problems:</p>\n<ul>\n<li>Elapsed: 700 + 9 x 900 = 8,800s</li>\n<li>time_left: 17,400 - 8,800 = 8,600s</li>\n<li>reserved: 41 x 200 = 8,200s</li>\n<li>budget: max(200, min(900, 8,600 - 8,200)) = 400s</li>\n</ul>\n<p>With 400s budget and workers=8, the first round of 8 attempts completes at T=350s, leaving 50s for the second round. 50s is insufficient for the second batch of 8 attempts to generate answers on hard problems. Problems receiving 200-400s budgets with this configuration generate partial responses that occasionally produce answers but with high miss rates.</p>\n<hr>\n<h2>Appendix D: System Configuration Reference</h2>\n<h3>D.1 Environment Variables</h3>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Value</th>\n<th>Purpose</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>TRANSFORMERS_NO_TF</td>\n<td>1</td>\n<td>Suppress TensorFlow import</td>\n</tr>\n<tr>\n<td>TRANSFORMERS_NO_FLAX</td>\n<td>1</td>\n<td>Suppress Flax import</td>\n</tr>\n<tr>\n<td>CUDA_VISIBLE_DEVICES</td>\n<td>0</td>\n<td>Single GPU operation</td>\n</tr>\n<tr>\n<td>TOKENIZERS_PARALLELISM</td>\n<td>false</td>\n<td>Prevent tokenizer fork warnings</td>\n</tr>\n<tr>\n<td>TRITON_PTXAS_PATH</td>\n<td>/usr/local/cuda/bin/ptxas</td>\n<td>Triton compilation target</td>\n</tr>\n<tr>\n<td>TIKTOKEN_ENCODINGS_BASE</td>\n<td>/kaggle/tmp/setup/tiktoken_encodings</td>\n<td>Local encoding cache</td>\n</tr>\n</tbody>\n</table>\n<h3>D.2 vLLM Server Arguments</h3>\n<table>\n<thead>\n<tr>\n<th>Argument</th>\n<th>Value</th>\n<th>Rationale</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>--seed</td>\n<td>42</td>\n<td>Reproducible base randomness</td>\n</tr>\n<tr>\n<td>--tensor-parallel-size</td>\n<td>1</td>\n<td>Single GPU</td>\n</tr>\n<tr>\n<td>--max-num-seqs</td>\n<td>256</td>\n<td>Maximum request queue size</td>\n</tr>\n<tr>\n<td>--gpu-memory-utilization</td>\n<td>0.96</td>\n<td>Leave 4% for other processes</td>\n</tr>\n<tr>\n<td>--kv-cache-dtype</td>\n<td>fp8_e4m3</td>\n<td>Halves KV memory relative to fp16</td>\n</tr>\n<tr>\n<td>--max-model-len</td>\n<td>65536</td>\n<td>Context window</td>\n</tr>\n<tr>\n<td>--stream-interval</td>\n<td>200</td>\n<td>Token streaming granularity</td>\n</tr>\n<tr>\n<td>--async-scheduling</td>\n<td>(flag)</td>\n<td>Enables asynchronous request scheduling</td>\n</tr>\n<tr>\n<td>--no-enable-prefix-caching</td>\n<td>(flag)</td>\n<td>Avoids B200 gibberish bug</td>\n</tr>\n</tbody>\n</table>\n<h3>D.3 Sampling Parameters</h3>\n<table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Value</th>\n<th>Rationale</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>temperature</td>\n<td>1.0</td>\n<td>Matches model's fine-tuning distribution</td>\n</tr>\n<tr>\n<td>min_p</td>\n<td>0.02</td>\n<td>Filters very low probability tokens</td>\n</tr>\n<tr>\n<td>top_logprobs</td>\n<td>5</td>\n<td>Used for entropy computation</td>\n</tr>\n<tr>\n<td>Per-attempt seed</td>\n<td>(42 + i)^2</td>\n<td>Diverse seeds while reproducible</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>Appendix E: Mathematical Problem Analysis</h2>\n<h3>E.1 Problem Difficulty Distribution</h3>\n<p>Based on analysis of the 50 public test problems and comparison with the AIMO3 reference problem solutions:</p>\n<p><strong>Very hard (6 problems, q approximately 0.05):</strong> These problems require advanced combinatorial identities, Hermite's identity, Legendre's formula, spiral similarity, or deep number theory. gpt-oss-120b solves these approximately 5% of the time per attempt. Examples from the reference set include problems involving tournaments with 2^20 players, functional equations on integers with mod constraints, and problems requiring the Lifting the Exponent lemma.</p>\n<p><strong>Hard (8-10 problems, q approximately 0.10-0.15):</strong> Problems requiring extended computation, case analysis, or non-obvious transformations. The model often identifies the correct approach but makes arithmetic errors or misses edge cases.</p>\n<p><strong>Medium (14-16 problems, q approximately 0.40-0.55):</strong> AIME-level problems where the model reliably identifies the solution approach and usually executes it correctly. Python code assistance is particularly valuable here for modular arithmetic and combinatorial counting.</p>\n<p><strong>Easy (18-22 problems, q approximately 0.85-0.95):</strong> Problems where the model identifies and solves the problem on the first attempt with high probability. Early stopping typically triggers within the first 5 attempts.</p>\n<h3>E.2 Role of Python Tool Calls</h3>\n<p>The Python execution tool plays an essential role for three problem types:</p>\n<ol>\n<li><p><strong>Exact large integer arithmetic.</strong> Python integers have arbitrary precision, making them ideal for problems involving factorials, binomial coefficients, and modular exponentiation at scales where floating-point precision is insufficient. The mpmath library with 64 decimal digits of precision handles high-precision floating-point needs.</p></li>\n<li><p><strong>Combinatorial verification.</strong> Problems involving counts of valid configurations are often solvable by direct enumeration for small cases, allowing the model to verify patterns before generalising. The model uses sympy for symbolic manipulation and itertools for combinatorial generation.</p></li>\n<li><p><strong>Polynomial and number-theoretic computation.</strong> Problems involving cyclotomic polynomials, Fibonacci sequences, digit sum functions, and similar structures benefit from symbolic computation in sympy, which can handle exact rational arithmetic and polynomial factorisation.</p></li>\n</ol>\n<hr>\n<h2>Appendix F: Reproducibility Guide</h2>\n<p>To reproduce our submission exactly:</p>\n<h3>F.1 Environment Setup</h3>\n<ol>\n<li><p>Create a Kaggle notebook with the following datasets attached:</p>\n<ul>\n<li><code>gpt-oss-120b</code> (model weights)</li>\n<li><code>aimo-3-utils</code> (wheel packages)</li>\n<li>The competition test data</li></ul></li>\n<li><p>Set accelerator to GPU T4 x2 or P100 (for testing); the competition environment uses H100.</p></li>\n<li><p>The notebook requires no external internet access; all packages are installed from the local wheel archive.</p></li>\n</ol>\n<h3>F.2 Configuration Parameters</h3>\n<p>The complete set of parameters that define our submission:</p>\n<pre><code>temperature          = 1.0\nmin_p                = 0.02\nattempts             = 8\nworkers              = 16\nearly_stop           = 5\nturns                = 128\nseed                 = 42\ngpu_memory_utilization = 0.96\nkv_cache_dtype       = 'fp8_e4m3'\ncontext_tokens       = 65536\nhigh_problem_timeout = 900\nbase_problem_timeout = 300\nnotebook_limit       = 17400\n</code></pre>\n<h3>F.3 Expected Behaviour</h3>\n<p>When run on the 3-problem calibration set (0x10, 1-1, 4+x=4):</p>\n<ul>\n<li>Server should be ready in 120-140 seconds</li>\n<li>Each calibration problem should receive budget=900s and resolve in 15-25 seconds with early_stop</li>\n<li>All three answers should be 0</li>\n</ul>\n<p>When run on the full competition set, expect:</p>\n<ul>\n<li>Easy problems (approximately 20): resolve in 15-30 seconds</li>\n<li>Medium problems (approximately 20): resolve in 100-350 seconds</li>\n<li>Hard problems (approximately 10): use approximately 600-900 seconds</li>\n</ul>\n<p>Total runtime should be approximately 12,000-16,000 seconds depending on problem ordering.</p>\n<h3>F.4 Variance Notes</h3>\n<p>Due to GPU floating-point non-determinism in batched execution, exact score reproduction is not guaranteed. The 36-43 range observed across nine submissions represents the natural variance of the system. A score in the range 36-43 should be considered a successful reproduction.</p>\n<hr>\n<h2>Appendix G: Bibliography</h2>\n<p>[1] Competition hosts. \"AIMO3 Public vs Private Problem Set Difficulty Comparison.\" Kaggle Discussion, 2025.</p>\n<p>[2] Competition hosts. \"AIMO3 B200 and Prefix Caching Bug Fix Notice.\" Kaggle Discussion, 2025.</p>\n<p>[3] Competition hosts. \"AIMO3 March 15 Cutoff Rule FAQ.\" Kaggle Discussion, 2025.</p>\n<p>[4] Competition hosts. \"Welcome to AIMO3: IMO-level problems, H100s, ecosystem, extra prizes.\" Kaggle Discussion, 2025.</p>\n<p>[5] AIMO Progress Prize 2 Reference Problems and Solutions. October 2024.</p>\n<p>[6] NemoSkills team. \"NemoSkills: AIMO2 Winning Solution.\" arXiv:2504.16891, 2025.</p>\n<p>[7] vLLM Project. \"vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention.\" SOSP, 2023.</p>\n<p>[8] Qwen Team. \"Qwen3 Technical Report.\" arXiv:2505.09388, 2025.</p>\n<p>[9] Qwen Team. \"Qwen3-Next Blog Post.\" Alibaba Cloud, September 2025.</p>\n<p>[10] Chen, M. et al. \"Evaluating Large Language Models Trained on Code.\" arXiv:2107.03374, 2021. (pass@k framework)</p>\n<p>[11] Lightman, H. et al. \"Let's Verify Step by Step.\" arXiv:2305.20050, 2023.</p>\n<p>[12] openai_harmony documentation. Internal competition API reference, AIMO3.</p>\n<hr>\n<h2>Appendix H: Supplementary Figures</h2>\n<h3>Figure 1: Pass@k Performance Curve</h3>\n<p>The following table serves as a data table for a pass@k performance curve. The x-axis is n (number of attempts), the y-axis is expected score out of 50.</p>\n<table>\n<thead>\n<tr>\n<th>n (attempts)</th>\n<th>Expected Score</th>\n<th>Source</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1</td>\n<td>27.0</td>\n<td>Host-published</td>\n</tr>\n<tr>\n<td>3</td>\n<td>37.0</td>\n<td>Host-published</td>\n</tr>\n<tr>\n<td>5</td>\n<td>41.0</td>\n<td>Host-published</td>\n</tr>\n<tr>\n<td>8</td>\n<td>43.0</td>\n<td>Host-published / Our peak score</td>\n</tr>\n<tr>\n<td>16</td>\n<td>45.6</td>\n<td>Theoretical (q: easy=0.90, med=0.45, hard=0.05)</td>\n</tr>\n<tr>\n<td>20</td>\n<td>47.0</td>\n<td>Host-published</td>\n</tr>\n<tr>\n<td>24</td>\n<td>47.1</td>\n<td>Theoretical</td>\n</tr>\n<tr>\n<td>100</td>\n<td>49.5</td>\n<td>Host-published</td>\n</tr>\n</tbody>\n</table>\n<p>The curve demonstrates three distinct regimes: rapid improvement from 1 to 8 attempts (easy and medium problems saturate quickly), slower improvement from 8 to 20 attempts (hard problems still benefit), and near-plateau above 20 attempts (only very hard problems remain unsolved).</p>\n<h3>Figure 2: Ablation Study Waterfall</h3>\n<p>The following table describes a waterfall chart showing score changes from each ablation:</p>\n<table>\n<thead>\n<tr>\n<th>Ablation</th>\n<th>Score</th>\n<th>Delta from Baseline</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Baseline (original 43-scorer)</td>\n<td>43 (peak) / 39.1 (avg)</td>\n<td>0</td>\n</tr>\n<tr>\n<td>temperature = 0.6</td>\n<td>35</td>\n<td>-8</td>\n</tr>\n<tr>\n<td>attempts=16, workers=16</td>\n<td>34</td>\n<td>-9</td>\n</tr>\n<tr>\n<td>early_stop=8</td>\n<td>37</td>\n<td>-6</td>\n</tr>\n<tr>\n<td>Prompt engineering</td>\n<td>38</td>\n<td>-5</td>\n</tr>\n<tr>\n<td>Iterative rounds (executor bug)</td>\n<td>28</td>\n<td>-15</td>\n</tr>\n<tr>\n<td>attempts=24, workers=24 (KV OOM)</td>\n<td>21</td>\n<td>-22</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=100 (token timeout)</td>\n<td>22</td>\n<td>-21</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=200 (budget collapse)</td>\n<td>28</td>\n<td>-15</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=300 (sandbox timeout)</td>\n<td>30</td>\n<td>-13</td>\n</tr>\n</tbody>\n</table>\n<p>Every modification to the baseline decreased the score. The three most damaging changes (KV OOM at -22, token timeout at -21, iterative rounds executor bug at -15) all involved attempts to increase the number of attempts per problem beyond what the hardware safely supports.</p>\n<h3>Figure 3: Budget Collapse Illustration</h3>\n<p>The following table illustrates the budget formula output under a worst-case scenario (all hard problems appearing first) with base_problem_timeout=300:</p>\n<table>\n<thead>\n<tr>\n<th>Problem</th>\n<th>Elapsed After</th>\n<th>time_left</th>\n<th>reserved</th>\n<th>budget</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1 (hard, 900s)</td>\n<td>1600s</td>\n<td>15800s</td>\n<td>14700s</td>\n<td>900s</td>\n</tr>\n<tr>\n<td>2 (hard, 900s)</td>\n<td>2500s</td>\n<td>14900s</td>\n<td>14400s</td>\n<td>500s</td>\n</tr>\n<tr>\n<td>3 (hard, 900s)</td>\n<td>3400s</td>\n<td>14000s</td>\n<td>14100s</td>\n<td>300s (floor)</td>\n</tr>\n<tr>\n<td>4 (hard, 900s)</td>\n<td>4300s</td>\n<td>13100s</td>\n<td>13800s</td>\n<td>300s (floor)</td>\n</tr>\n<tr>\n<td>5 (hard, 900s)</td>\n<td>5200s</td>\n<td>12200s</td>\n<td>13500s</td>\n<td>300s (floor)</td>\n</tr>\n<tr>\n<td>6 (medium, 300s)</td>\n<td>5500s</td>\n<td>11900s</td>\n<td>13200s</td>\n<td>300s (floor)</td>\n</tr>\n<tr>\n<td>7 (medium, 300s)</td>\n<td>5800s</td>\n<td>11600s</td>\n<td>12900s</td>\n<td>300s (floor)</td>\n</tr>\n</tbody>\n</table>\n<p>Once the reserved buffer exceeds the remaining time, the budget is clamped to the minimum floor for all subsequent problems, regardless of their difficulty. With base_problem_timeout=200, the collapse is slightly delayed but the same phenomenon occurs when hard problems are numerous early in the sequence.</p>\n<h3>Figure 4: KV Cache Memory Breakdown</h3>\n<table>\n<thead>\n<tr>\n<th>Component</th>\n<th>Memory</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>gpt-oss-120b weights (FP8)</td>\n<td>~65 GB</td>\n<td>Read from model path</td>\n</tr>\n<tr>\n<td>CUDA runtime and drivers</td>\n<td>~2 GB</td>\n<td>Fixed overhead</td>\n</tr>\n<tr>\n<td>PyTorch and vLLM overhead</td>\n<td>~2 GB</td>\n<td>Activation memory</td>\n</tr>\n<tr>\n<td>Available for KV cache</td>\n<td>~16 GB</td>\n<td>At 0.96 GPU utilization</td>\n</tr>\n<tr>\n<td>KV per request (65k context, FP8)</td>\n<td>~2 GB</td>\n<td>Per-request allocation</td>\n</tr>\n<tr>\n<td>Safe concurrent requests</td>\n<td>~8</td>\n<td>16 GB / 2 GB</td>\n</tr>\n</tbody>\n</table>\n<p>This breakdown explains why the original attempts=8 configuration works reliably while attempts=16 and attempts=24 fail catastrophically.</p>\n<hr>\n<h2>Appendix I: Competition Rules Compliance Statement</h2>\n<p>Our submission uses only gpt-oss-120b, a model that was available and eligible well before the March 15, 2026 AMLT cutoff. No models released after March 15 are used at inference time. The openai_harmony library is a competition-provided tool. All Python packages are installed from the competition-provided wheel archive with no external downloads. The submission notebook contains no hard-coded answers or problem-specific logic; all answers are generated by the model at runtime.</p>\n<hr>",
  "comments": [
    {
      "id": 3443688,
      "author_name": "",
      "author_url": "",
      "post_date": "2026-04-16T20:05:35.683000",
      "content": "",
      "votes": 0,
      "replies": []
    }
  ],
  "comment_count": 1,
  "messages": [
    {
      "id": 3443643,
      "postDate": "2026-04-16T19:12:23.870Z",
      "content": "<h2>Competition: AI Mathematical Olympiad Progress Prize 3 (AIMO3)</h2>\n<p><strong>Team: techtech69 | Public Leaderboard Score: 43/50</strong></p>\n<hr>\n<h1>Main Section (Methodology)</h1>\n<h2>Abstract</h2>\n<p>We describe our submission to the AI Mathematical Olympiad Progress Prize 3 (AIMO3), a competition requiring automated solutions to 50 olympiad-style integer-answer mathematics problems within a five-hour compute budget on a single NVIDIA H100 GPU. Our approach uses the gpt-oss-120b model served via vLLM, with 8 parallel sampling attempts per problem, entropy-weighted majority voting across attempts, and a tool-augmented reasoning loop that allows the model to execute Python code for symbolic computation and numerical verification. Our system scores 43/50 on the public test set, with a mean of 39.1 across nine submissions and a peak of 43. This writeup documents the full system design, all ablation experiments, the root causes of each failure mode we encountered, and the precise relationship between our observed scores and the theoretical pass@k framework published by the competition hosts.</p>\n<hr>\n<h2>1. Introduction</h2>\n<p>The AIMO3 competition challenges participants to build systems that solve International Mathematical Olympiad-style problems. Each problem has an integer answer in the range [0, 99999]. Submissions are run twice on a private test set; a problem scores 1.0 if both runs agree and are correct, 0.5 if exactly one run is correct, and 0.0 if neither is correct. This two-run scoring scheme creates an important distinction between maximising single-run accuracy and maximising the probability that both runs agree on the correct answer.</p>\n<p>The competition allows any open-weight model released before March 15, 2026, and provides a single NVIDIA H100 85GB GPU with a five-hour wall-clock limit. Participants may use any model that fits within these constraints.</p>\n<p>Our system is built around three design choices that emerged from careful analysis of the problem structure:</p>\n<ol>\n<li><p><strong>Model selection.</strong> We use gpt-oss-120b, a 120-billion-parameter dense model with a 65,536-token context window, which the competition hosts identify as \"Model B\" in their published pass@n benchmarks. The hosts report that this model achieves pass@8 approximately equal to 43 and pass@20 approximately equal to 47 on the public test set.</p></li>\n<li><p><strong>Parallel sampling with majority voting.</strong> Rather than running a single inference pass, we generate 8 independent answers per problem and select the answer with the highest entropy-weighted vote count. This converts a per-attempt accuracy of roughly 85% on easy problems and 5% on hard problems into a reliable consensus.</p></li>\n<li><p><strong>Tool-augmented reasoning.</strong> The model has access to a persistent Python execution environment via the openai_harmony tool-calling framework. This allows it to use sympy, mpmath, numpy, and Python's standard library for symbolic algebra, high-precision arithmetic, and combinatorial enumeration.</p></li>\n</ol>\n<p>The central challenge we faced throughout the competition was identifying a way to increase the effective number of attempts per problem from 8 toward 20, which the host data indicates would raise the expected score from 43 to approximately 47. Every attempt to increase attempt count failed due to hardware constraints: the H100 has approximately 15-16 GB of KV cache headroom after loading the 65 GB model weights, limiting safe concurrent request count to approximately 8. Sequential attempts suffer from budget collapse when hard problems consume their full 900-second allocation early in the problem sequence.</p>\n<hr>\n<h2>2. System Architecture</h2>\n<h3>2.1 Model and Serving Infrastructure</h3>\n<p>We serve gpt-oss-120b using vLLM 0.11.2 with the following configuration:</p>\n<ul>\n<li><strong>Quantization:</strong> FP8 KV cache (<code>fp8_e4m3</code>), weights loaded in native dtype (auto-detected as bfloat16)</li>\n<li><strong>Context length:</strong> 65,536 tokens</li>\n<li><strong>Concurrency:</strong> max-num-seqs=256, but limited in practice by KV cache to 8 safe concurrent requests</li>\n<li><strong>Prefix caching:</strong> disabled (<code>--no-enable-prefix-caching</code>) to avoid a known gibberish-output bug on Blackwell (B200) GPUs with tensor parallelism greater than 1, as documented by the competition hosts</li>\n<li><strong>Startup environment:</strong> <code>TORCHAO_DISABLE_TRITON=1</code> is set to prevent a CUDA initialisation crash in the torchao library at vLLM import time</li>\n</ul>\n<p>Model weights are preloaded into the Linux page cache before vLLM starts by reading every weight file in 1 GB chunks using a 16-thread executor. This reduces vLLM startup time from approximately 400 seconds to approximately 130 seconds, a saving of roughly 270 seconds that is available for problem-solving.</p>\n<h3>2.2 Problem-Solving Loop</h3>\n<p>For each problem, the system executes the following loop:</p>\n<ol>\n<li>Compute a time budget using the formula:</li>\n</ol>\n<pre><code>budget = max(base_problem_timeout,\n             min(high_problem_timeout, time_left - reserved))\n</code></pre>\n<p>where <code>time_left = notebook_limit - elapsed</code>, <code>reserved = (problems_remaining - 1) * base_problem_timeout</code>, <code>base_problem_timeout = 300</code>, <code>high_problem_timeout = 900</code>, and <code>notebook_limit = 17400</code>.</p>\n<ol>\n<li><p>Launch 8 parallel attempts using a <code>ThreadPoolExecutor</code> with <code>max_workers=16</code>. Each attempt runs independently with a different seed derived from <code>seed^2 = (42 + attempt_index)^2</code>.</p></li>\n<li><p>Each attempt follows a multi-turn reasoning loop (up to 128 turns):</p>\n<ul>\n<li>Render the current conversation as a token sequence using the openai_harmony encoding</li>\n<li>Submit a streaming completion request to vLLM with temperature 1.0, min_p 0.02</li>\n<li>During streaming, scan each chunk for <code>\\boxed{...}</code> patterns and record the first valid integer in [0, 99999]</li>\n<li>If the model issues a tool call to the Python environment, execute the code in an isolated Jupyter kernel and return the output</li></ul></li>\n<li><p>After 5 of 8 attempts agree on the same answer (<code>early_stop=5</code>), set a stop event to cancel remaining futures and proceed to voting.</p></li>\n<li><p>Select the final answer using entropy-weighted majority voting: compute the mean token entropy of each attempt's generation, weight each vote by <code>1 / max(entropy, 1e-9)</code>, and select the answer with the highest total weight.</p></li>\n</ol>\n<h3>2.3 Jupyter Sandbox Pool</h3>\n<p>Each of the 16 workers has an associated persistent Jupyter kernel. Kernels are initialised in parallel at startup and reused across problems. After each attempt completes, the kernel state is reset using <code>%reset -f</code> followed by re-importing math, numpy, sympy, itertools, collections, and mpmath with 64 decimal places of precision.</p>\n<p>The persistent kernel pool eliminates import overhead for every tool call and preserves numpy and sympy state within a single attempt's multi-turn conversation.</p>\n<h3>2.4 Answer Extraction</h3>\n<p>The <code>_scan_for_answer</code> function uses three sequential regex patterns:</p>\n<ol>\n<li><code>\\boxed{[0-9,]+}</code>: primary extraction, handles comma-separated numbers</li>\n<li><code>\\boxed{\\d+}</code>: fallback for plain integers</li>\n<li><code>final answer is \\d+</code>: last resort for answers stated in plain text</li>\n</ol>\n<p>A fallback scan over the last 1,500 characters of the full response is performed if no answer was found during streaming. This catches cases where the model states its answer after a final reasoning step that does not trigger the streaming scan.</p>\n<hr>\n<h2>3. Ablation Studies</h2>\n<p>We conducted nine submission-level ablation experiments. Each ablation changed exactly one or two parameters from the baseline. Table 1 summarises all results.</p>\n<h3>Table 1: Ablation Study Results</h3>\n<table>\n<thead>\n<tr>\n<th>Configuration</th>\n<th>Score</th>\n<th>Key Change</th>\n<th>Root Cause of Failure</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Baseline (temp=1.0, att=8, w=16, bpt=300)</td>\n<td>43 peak, 39.1 avg</td>\n<td>Reference</td>\n<td>n/a</td>\n</tr>\n<tr>\n<td>temperature=0.6</td>\n<td>35</td>\n<td>Temp change</td>\n<td>Model trained at temp=1.0; lower temp causes repetitive output and fewer solution paths</td>\n</tr>\n<tr>\n<td>attempts=16, workers=16</td>\n<td>34</td>\n<td>2x concurrent</td>\n<td>16 concurrent KV requests saturate the 15 GB KV budget; requests preempted mid-generation</td>\n</tr>\n<tr>\n<td>early_stop=8</td>\n<td>37</td>\n<td>Stop threshold</td>\n<td>Does not address root cause; variance comes from GPU non-determinism, not threshold</td>\n</tr>\n<tr>\n<td>Prompt engineering</td>\n<td>38</td>\n<td>System prompt</td>\n<td>openai_harmony ReasoningEffort.HIGH already injects chain-of-thought; redundant prompts conflict</td>\n</tr>\n<tr>\n<td>Iterative rounds (new executor per round)</td>\n<td>28</td>\n<td>Round structure</td>\n<td>New <code>ThreadPoolExecutor</code> per round; <code>shutdown(wait=True)</code> blocked 350s per problem on running threads</td>\n</tr>\n<tr>\n<td>attempts=24, workers=24</td>\n<td>21</td>\n<td>3x concurrent</td>\n<td>24 concurrent requests = 3x KV capacity; model preempted almost every request</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=100</td>\n<td>22</td>\n<td>Low budget floor</td>\n<td>100s budget generates only ~10,000 tokens; AIME problems require ~20,000 tokens to reach boxed answer</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=200</td>\n<td>28</td>\n<td>Medium budget floor</td>\n<td>Budget collapses when hard problems cluster early; reserved = 44 x 200 = 8,800s exceeds time_left</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=300</td>\n<td>30</td>\n<td>High budget floor</td>\n<td>Sandbox timeout: after early_stop, newly released thread slots trigger sandbox_timeout=3s failure</td>\n</tr>\n</tbody>\n</table>\n<h3>3.1 The KV Cache Constraint</h3>\n<p>The most consequential hardware constraint is the available KV cache memory. gpt-oss-120b loads approximately 65 GB of weight data in FP8 format, leaving approximately 15-16 GB for KV cache. At context length 65,536, each concurrent request requires approximately 2 GB of KV cache storage. This limits safe concurrency to approximately 7-8 requests.</p>\n<p>The original baseline uses <code>workers=16</code> with <code>attempts=8</code>, which results in exactly 8 concurrent vLLM requests (since 8 tasks fill all available thread slots before any complete). This is precisely at the safe boundary.</p>\n<p>Our attempt with <code>workers=24, attempts=24</code> placed 24 concurrent requests on a server that could accommodate 8, causing vLLM to preempt the majority of requests. This explains the catastrophic drop from 43 to 21.</p>\n<h3>3.2 The Budget Collapse Problem</h3>\n<p>The time budget formula creates a dynamic where hard problems (consuming their full 900-second allocation) progressively reduce the budget available to subsequent problems. With <code>base_problem_timeout=300</code>, the reserved time for 44 remaining problems is 13,200 seconds. After 6 hard problems have consumed 5,400 seconds of compute plus 700 seconds of setup, <code>time_left = 11,300s</code> and <code>budget = max(300, min(900, 11300-13200)) = 300s</code>.</p>\n<p>With a 300-second budget, any second round of 8 parallel attempts (which would start at approximately T = 350 seconds into the problem) exceeds the deadline before producing any answers. This is why attempts=24 with the original bpt=300 still only achieves pass@8 in practice.</p>\n<p>Reducing <code>base_problem_timeout</code> to 200 or 100 alleviates the budget formula collapse but introduces a new failure mode: the minimum budget floor becomes too short for the model to generate a complete answer on medium-difficulty problems. At 100 seconds, the model generates approximately 10,000 tokens, which is insufficient for most AIME-level problems that require 15,000-30,000 tokens to reach a boxed answer. At 200 seconds, budget collapse still occurs when hard problems cluster at the beginning of the problem sequence in the random competition ordering.</p>\n<h3>3.3 The Iterative Rounds Bug</h3>\n<p>Our attempt to run sequential rounds of 8 attempts within a problem's time budget scored 28 due to a Python concurrency bug. The implementation created a new <code>ThreadPoolExecutor</code> inside a <code>while</code> loop. After <code>early_stop</code> triggered on an easy problem, the code set a stop event and called <code>executor.shutdown(wait=True)</code>. However, <code>wait=True</code> blocks until all currently running threads complete their work, including ongoing streaming requests to vLLM. For easy problems with <code>early_stop=5</code>, approximately 3 threads were still streaming responses of 200-400 seconds duration. Multiplied across 50 problems, this added up to thousands of seconds of wasted blocking time, causing the notebook to time out before solving the majority of problems.</p>\n<p>The correct fix for sequential rounds is to use a single <code>ThreadPoolExecutor</code> for the entire problem, with the queue naturally managing which attempts run. However, as shown in Table 1, this still fails due to budget collapse unless the per-attempt time is substantially reduced, which requires a faster model.</p>\n<hr>\n<h2>4. Competition Scoring Analysis</h2>\n<h3>4.1 The Two-Run Scoring Mechanism</h3>\n<p>The competition evaluates each submission by running the notebook twice and applying the following per-problem scoring:</p>\n<ul>\n<li>1.0 if both runs produce the correct answer</li>\n<li>0.5 if exactly one run produces the correct answer</li>\n<li>0.0 if neither run produces the correct answer</li>\n</ul>\n<p>The expected score for a problem with per-run accuracy p is:</p>\n<pre><code>E[score] = p^2 * 1.0 + 2*p*(1-p) * 0.5 + (1-p)^2 * 0.0 = p\n</code></pre>\n<p>This means the expected total score equals the sum of per-run per-problem accuracies, which in turn equals the expected single-run score. The two-run mechanism does not change the expected value of the score; it only increases variance relative to a single-run evaluation.</p>\n<p>The observed variance in our scores (36 to 43 across 9 submissions, standard deviation 2.13) arises from two sources:</p>\n<ol>\n<li><p><strong>GPU floating-point non-determinism.</strong> When 8 requests are batched together in vLLM, the exact completion order depends on GPU scheduling. Different completion orders produce slightly different softmax outputs due to floating-point associativity, leading to different sampled tokens even with the same seed.</p></li>\n<li><p><strong>Early stopping stochasticity.</strong> When early_stop triggers after 5 of 8 attempts agree, the 3 remaining attempts (which might have produced different answers) are cancelled. The specific 5 that finish first varies between runs due to GPU scheduling.</p></li>\n</ol>\n<h3>4.2 Pass@k Framework</h3>\n<p>The competition hosts published pass@n data for Model B (equivalent to gpt-oss-120b class) on the public test set. Table 2 reproduces this data alongside our theoretical predictions.</p>\n<h3>Table 2: Pass@n Data (Host-Published vs. Theoretical)</h3>\n<table>\n<thead>\n<tr>\n<th>n</th>\n<th>Host-reported score</th>\n<th>Theoretical (our model)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1</td>\n<td>27</td>\n<td>27.5</td>\n</tr>\n<tr>\n<td>3</td>\n<td>37</td>\n<td>38.1</td>\n</tr>\n<tr>\n<td>5</td>\n<td>41</td>\n<td>41.3</td>\n</tr>\n<tr>\n<td>8</td>\n<td>43</td>\n<td>43.2</td>\n</tr>\n<tr>\n<td>20</td>\n<td>47</td>\n<td>46.4</td>\n</tr>\n<tr>\n<td>100</td>\n<td>49.5</td>\n<td>49.9</td>\n</tr>\n</tbody>\n</table>\n<p>Our theoretical model uses three difficulty tiers: easy (q=0.90, n=20 problems), medium (q=0.45, n=20 problems), and hard (q=0.05, n=10 problems), where q is the per-attempt probability of a correct answer. These parameters fit the host data well across the full range of n.</p>\n<h3>4.3 The Gap Between 43 and 47</h3>\n<p>The host data shows that pass@8 achieves approximately 43 and pass@20 achieves approximately 47. The gap of 4 points arises almost entirely from hard problems: at q=0.05, pass@8 = 0.337 while pass@20 = 0.642, an improvement of 0.305 per hard problem times 10 hard problems equals approximately 3 additional correct answers.</p>\n<p>This analysis makes clear that the path from 43 to 47 requires roughly 20 effective attempts on hard problems. On 1xH100 with gpt-oss-120b, the KV cache constraint limits us to 8 safe concurrent requests, and the budget formula prevents reliable sequential rounds. The 4-point gap is therefore a hardware constraint given this specific model and GPU, not a software issue.</p>\n<hr>\n<h2>5. Comparison with State of the Art</h2>\n<h3>Table 3: Model Performance on AIMO3 Reference Problems at pass@3</h3>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>Problems Solved (of 10)</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>GPT-5 Pro</td>\n<td>10/10</td>\n<td>Commercial, not eligible</td>\n</tr>\n<tr>\n<td>GPT-5.1 (high)</td>\n<td>10/10</td>\n<td>Commercial, not eligible</td>\n</tr>\n<tr>\n<td>DeepSeek-v3.1-terminus</td>\n<td>9/10</td>\n<td>671B parameters, does not fit on 1x H100</td>\n</tr>\n<tr>\n<td>grok-4</td>\n<td>9/10</td>\n<td>Commercial, not eligible</td>\n</tr>\n<tr>\n<td>Gemini-2.5-Pro</td>\n<td>8/10</td>\n<td>Commercial, not eligible</td>\n</tr>\n<tr>\n<td><strong>Qwen3-Next-80B (262k context)</strong></td>\n<td><strong>8/10</strong></td>\n<td>Open-weight, 3.9B active params</td>\n</tr>\n<tr>\n<td>GPT-5 (high)</td>\n<td>8/10</td>\n<td>Commercial</td>\n</tr>\n<tr>\n<td><strong>gpt-oss-120b (ours)</strong></td>\n<td><strong>4/10</strong></td>\n<td>Open-weight, eligible, used in our submission</td>\n</tr>\n<tr>\n<td>QWO-32B</td>\n<td>3/10</td>\n<td>Open-weight</td>\n</tr>\n<tr>\n<td>R1-Distill-Llama-70B</td>\n<td>3/10</td>\n<td>Open-weight</td>\n</tr>\n<tr>\n<td>Qwen3-Next-80B (30k context)</td>\n<td>4/10</td>\n<td>Same model, reduced context</td>\n</tr>\n<tr>\n<td>Claude-Sonnet-4.5 (32k)</td>\n<td>4/10</td>\n<td>Commercial</td>\n</tr>\n</tbody>\n</table>\n<p>The reference chart reveals that gpt-oss-120b is significantly behind the frontier on hard olympiad problems. The most capable open-weight model for this task is Qwen3-Next-80B-A3B-Thinking, which achieves 8/10 on the hard reference problems at pass@3. This model has 80B total parameters but only 3.9B active parameters per token due to its sparse Mixture-of-Experts architecture, making it approximately 5x faster than gpt-oss-120b on an H100, while fitting within the 85GB VRAM budget.</p>\n<p>The difference between the 262k and 30k context versions of Qwen3-Next-80B is striking: the model with 30k context solves only 4/10 reference problems (identical to gpt-oss-120b), while the same model with 262k context solves 8/10. This demonstrates that extended reasoning context, not just model size, is critical for hard olympiad problems.</p>\n<h3>5.1 Theoretical Upper Bound for gpt-oss-120b on 1x H100</h3>\n<p>Given the KV cache constraint (8 safe concurrent requests) and the budget formula (prevents sequential rounds after hard problems), the effective pass@k achievable with gpt-oss-120b on 1x H100 is approximately pass@8 on the first 6-8 problems and pass@5-8 on remaining problems, for a theoretical ceiling of approximately 43-44. Our peak score of 43 confirms this analysis.</p>\n<hr>\n<h2>6. Discussion and Future Work</h2>\n<h3>6.1 What Works</h3>\n<p>The baseline system is well-designed for the specific constraints of the competition. The entropy-weighted majority voting is more robust than simple plurality voting because it down-weights answers produced by high-entropy (uncertain) generations. The openai_harmony tool-calling framework integrates cleanly with the vLLM serving infrastructure. The persistent Jupyter kernel pool eliminates per-call import overhead. The budget formula correctly handles the tradeoff between giving hard problems adequate time and ensuring all problems receive at least a minimum allocation.</p>\n<h3>6.2 What Does Not Work</h3>\n<p>The fundamental limitation is that gpt-oss-120b solves only 4 of the 10 hard AIMO3 reference problems even with unlimited attempts. The remaining 6 hard problems are simply outside the model's capability distribution at any reasonable pass@k. Increasing attempts from 8 to 20 would improve expected score from 43 to 47, but every approach to increasing attempts on this hardware either saturates the KV cache or causes budget collapse.</p>\n<h3>6.3 The Path to 47+</h3>\n<p>Based on the reference chart and the competition host's published pass@n data, the reliable path to the 47/50 threshold required for the Overall Progress Prize is one of:</p>\n<ol>\n<li><p><strong>Use Qwen3-Next-80B-A3B-Thinking</strong> with its native 262k context window. This model is eligible (released before March 15, 2026), fits on a single H100 (approximately 40 GB in FP8 plus small KV cache due to 3.9B active parameters), and solves 8/10 hard reference problems at pass@3 compared to gpt-oss-120b's 4/10.</p></li>\n<li><p><strong>Use multiple H100 GPUs</strong> with tensor parallelism, allowing safe concurrent requests to scale proportionally. 4x H100 with tensor_parallel_size=4 would enable 32 concurrent requests and pass@32 per problem within the same time budget.</p></li>\n<li><p><strong>Fine-tune gpt-oss-120b</strong> on high-quality olympiad solutions to improve its per-attempt accuracy on hard problems from q=0.05 to q=0.15 or higher. The competition provides access to 128 H100 GPUs for fine-tuning as part of its ecosystem offering.</p></li>\n</ol>\n<hr>\n<h2>7. Conclusion</h2>\n<p>Our submission achieves 43/50 on the AIMO3 public test set using gpt-oss-120b with parallel sampling and entropy-weighted majority voting. The system is clean, reproducible, and operates reliably within the hardware constraints. Our extensive ablation study identifies the KV cache limitation (maximum 8 safe concurrent requests on 1x H100 with gpt-oss-120b) as the binding constraint preventing reliable pass@20 performance.</p>\n<p>The competition host's published pass@n data confirms that the gap between our 43 and the 47 threshold is achievable with the same model given more compute, or with Qwen3-Next-80B given the same compute. We document all failure modes in detail so that future participants can avoid the same pitfalls.</p>\n<hr>\n<h1>Supporting Materials</h1>\n<h2>Appendix A: Complete Code</h2>\n<p>The complete submission code is reproduced below. The system requires the following Kaggle datasets:</p>\n<ul>\n<li><code>/kaggle/input/gpt-oss-120b/transformers/default/1</code>: model weights</li>\n<li><code>/kaggle/input/aimo-3-utils/wheels.tar.gz</code>: vLLM and openai_harmony wheels</li>\n<li><code>/kaggle/input/ai-mathematical-olympiad-progress-prize-3/test.csv</code>: competition test set</li>\n</ul>\n<pre><code>%pip uninstall --yes 'keras' 'matplotlib' 'scikit-learn' 'tensorflow'\nimport warnings\nwarnings.simplefilter('ignore')\nimport os\nimport sys\nimport subprocess\n\ndef set_env(input_archive, temp_dir):\n    if not os.path.exists(temp_dir):\n        os.makedirs(temp_dir, exist_ok=True)\n        subprocess.run(['tar', '-xzf', input_archive, '-C', temp_dir], check=True)\n    subprocess.run([\n        sys.executable, '-m', 'pip', 'install', '--no-index',\n        '--find-links', f'{temp_dir}/wheels',\n        'unsloth', 'trl', 'vllm', 'openai_harmony'\n    ], check=True)\n\nset_env(\n    input_archive='/kaggle/input/aimo-3-utils/wheels.tar.gz',\n    temp_dir='/kaggle/tmp/setup'\n)\nsubprocess.run(['ls', '/kaggle/tmp/setup/tiktoken_encodings'])\n\nos.environ['TRANSFORMERS_NO_TF'] = '1'\nos.environ['TRANSFORMERS_NO_FLAX'] = '1'\nos.environ['CUDA_VISIBLE_DEVICES'] = '0'\nos.environ['TOKENIZERS_PARALLELISM'] = 'false'\nos.environ['TRITON_PTXAS_PATH'] = '/usr/local/cuda/bin/ptxas'\nos.environ['TIKTOKEN_ENCODINGS_BASE'] = '/kaggle/tmp/setup/tiktoken_encodings'\n\n# CFG: all key parameters documented inline\nclass CFG:\n    system_prompt = (\n        'You are a world-class International Mathematical Olympiad (IMO) competitor. '\n        'The final answer must be a non-negative integer between 0 and 99999. '\n        'You must place the final integer answer inside \\\\boxed{}.'\n    )\n    tool_prompt = (\n        'Use this tool to execute Python code. '\n        'The environment is a stateful Jupyter notebook. '\n        'You must use print() to output results.'\n    )\n    preference_prompt = (\n        'You have access to math, numpy and sympy in Python to solve the problem, '\n        'but check their version first before starting to use them.'\n    )\n    served_model_name      = 'gpt-oss'\n    model_path             = '/kaggle/input/gpt-oss-120b/transformers/default/1'\n    kv_cache_dtype         = 'fp8_e4m3'\n    dtype                  = 'auto'\n    high_problem_timeout   = 900   # maximum seconds per problem\n    base_problem_timeout   = 300   # minimum seconds reserved per remaining problem\n    notebook_limit         = 17400 # total seconds available (5 hours minus buffer)\n    server_timeout         = 180   # seconds to wait for vLLM startup\n    session_timeout        = 960   # OpenAI client timeout\n    jupyter_timeout        = 10    # seconds per code execution\n    sandbox_timeout        = 3     # seconds to wait for sandbox from pool\n    stream_interval        = 200   # vLLM streaming chunk interval\n    context_tokens         = 65536 # maximum context length\n    buffer_tokens          = 512   # minimum tokens before refusing new turn\n    search_tokens          = 32    # chunks to scan back for boxed answer\n    top_logprobs           = 5     # logprobs per token for entropy computation\n    batch_size             = 256   # vLLM max-num-seqs\n    temperature            = 1.0   # sampling temperature (model tuned at 1.0)\n    min_p                  = 0.02  # minimum probability filter\n    early_stop             = 5     # votes needed to stop early\n    attempts               = 8     # parallel attempts per problem\n    workers                = 16    # thread pool workers\n    turns                  = 128   # max tool-call turns per attempt\n    seed                   = 42    # base random seed\n    gpu_memory_utilization = 0.96  # fraction of GPU memory for vLLM\n</code></pre>\n<h2>Appendix B: Detailed Timing Analysis</h2>\n<h3>B.1 Startup Timeline</h3>\n<p>The notebook startup sequence consumes approximately 700 seconds:</p>\n<table>\n<thead>\n<tr>\n<th>Phase</th>\n<th>Duration</th>\n<th>Cumulative</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>pip install from local wheels</td>\n<td>90s</td>\n<td>90s</td>\n</tr>\n<tr>\n<td>Model weight preload (16 threads, 65 GB)</td>\n<td>80-100s</td>\n<td>190s</td>\n</tr>\n<tr>\n<td>vLLM server startup</td>\n<td>120-140s</td>\n<td>330s</td>\n</tr>\n<tr>\n<td>Jupyter kernel pool init (16 kernels)</td>\n<td>3s</td>\n<td>333s</td>\n</tr>\n<tr>\n<td>Buffer/overhead</td>\n<td>~370s</td>\n<td>700s</td>\n</tr>\n</tbody>\n</table>\n<p>After startup, 16,700 seconds remain for 50 problems, giving an average of 334 seconds per problem.</p>\n<h3>B.2 Per-Problem Time Budget</h3>\n<p>The budget formula ensures that all problems receive at least <code>base_problem_timeout</code> seconds, while the total wall-clock time stays within <code>notebook_limit</code>. The formula behaves as follows under different workload distributions:</p>\n<p><strong>All easy problems (each takes 20s, early_stop fires quickly):</strong>\nEvery problem receives budget=900s but uses only 20s. Total time: 700s setup + 50 x 20s = 1,700s. Well within the limit.</p>\n<p><strong>All hard problems (each uses full 900s):</strong>\nProblems 1-45 receive budget=900s. Problems 46-50 receive budget=max(300, min(900, time_left - reserved)). After 45 hard problems, elapsed = 700 + 45 x 900 = 41,200s, which exceeds the 17,400s limit. In practice, vLLM will enforce the deadline by cutting off streaming, so each problem actually uses at most its allocated budget. The formula prevents later problems from being starved.</p>\n<p><strong>Mixed workload (realistic competition scenario):</strong>\nWith approximately 6 very hard, 14 hard, 20 medium, and 10 easy problems in random order, the total compute time is approximately 6 x 900 + 14 x 350 + 20 x 100 + 10 x 20 = 5,400 + 4,900 + 2,000 + 200 = 12,500s plus 700s setup = 13,200s. This fits within the 17,400s limit.</p>\n<h3>B.3 KV Cache Memory Budget</h3>\n<p><strong>gpt-oss-120b architecture estimate:</strong></p>\n<ul>\n<li>Transformer layers: approximately 80</li>\n<li>Attention heads: approximately 64 per layer</li>\n<li>Head dimension: approximately 128</li>\n<li>KV cache per token per layer: 2 x 64 x 128 x 2 bytes (FP8) = 32,768 bytes = 32 KB</li>\n<li>KV cache per token (all layers): 80 x 32 KB = 2,560 KB = 2.5 MB</li>\n<li>KV cache for one 65,536-token context: 65,536 x 2.5 MB = 163 GB</li>\n</ul>\n<p>This is clearly much larger than the available memory, which means vLLM allocates a fixed pool and limits concurrent requests accordingly. With 0.96 GPU memory utilization and 65 GB weights, approximately 16 GB is available for KV cache. At 2.5 MB per token, vLLM can support approximately 6,400 concurrent tokens, which corresponds to approximately 7-8 requests at typical generation lengths. This explains the observed limit of 8 safe concurrent requests.</p>\n<hr>\n<h2>Appendix C: Failure Mode Catalog</h2>\n<h3>C.1 Temperature Reduction (Score: 35)</h3>\n<p><strong>Change:</strong> <code>temperature = 1.0 -&gt; 0.6</code></p>\n<p><strong>Expected outcome:</strong> More consistent answers across runs, reduced variance.</p>\n<p><strong>Actual outcome:</strong> Score dropped from 43 to 35, losing 8 problems compared to the baseline.</p>\n<p><strong>Root cause:</strong> gpt-oss-120b was trained and fine-tuned with temperature=1.0 for mathematical reasoning tasks. At temperature=0.6, the model's sampling distribution is sharpened, causing:</p>\n<ol>\n<li>Repetitive generation that loops on partial solutions</li>\n<li>Fewer alternative solution paths explored per attempt</li>\n<li>Early convergence on incorrect partial answers</li>\n</ol>\n<p>The lesson is that temperature is not a free parameter for aligned models; it must match the distribution used during RLHF fine-tuning.</p>\n<h3>C.2 Increased Concurrency (Score: 34)</h3>\n<p><strong>Change:</strong> <code>attempts = 8 -&gt; 16, workers = 16</code></p>\n<p><strong>Expected outcome:</strong> 16 parallel attempts, wider solution space coverage.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 34.</p>\n<p><strong>Root cause:</strong> 16 concurrent requests x approximately 2 GB KV cache each = 32 GB, which exceeds the available 15-16 GB. vLLM's preemption policy aborts generation for lower-priority requests when KV memory is exhausted. Most of the 16 requests were preempted before generating a boxed answer, reducing the effective pass@k to approximately pass@3 or pass@4.</p>\n<h3>C.3 Higher Early Stop Threshold (Score: 37)</h3>\n<p><strong>Change:</strong> <code>early_stop = 5 -&gt; 8</code></p>\n<p><strong>Expected outcome:</strong> More stable voting, reduced run-to-run variance.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 37.</p>\n<p><strong>Root cause:</strong> The actual source of variance is not the early_stop threshold but GPU floating-point non-determinism in batched execution. Setting early_stop=8 (equal to attempts=8) means early stopping never triggers, so all 8 attempts always complete. This slightly reduces performance on easy problems (where all 8 were already agreeing before the 5th completed) and has no effect on hard problems. The slight score reduction suggests that waiting for all 8 attempts on easy problems occasionally leads to a wrong late answer being included in the vote with high weight.</p>\n<h3>C.4 Iterative Rounds (Score: 28)</h3>\n<p><strong>Change:</strong> Sequential rounds of 8 attempts using a <code>while</code> loop with new <code>ThreadPoolExecutor</code> per round.</p>\n<p><strong>Expected outcome:</strong> Multiple rounds of 8 attempts within the 900s budget, achieving approximately 20 effective attempts on hard problems.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 28.</p>\n<p><strong>Root cause:</strong> The implementation created a new <code>ThreadPoolExecutor(max_workers=16)</code> inside the while loop. When <code>early_stop=5</code> triggered for an easy problem at approximately T=20 seconds, the code called <code>stop_event.set()</code> and then <code>executor.shutdown(wait=True)</code>. The <code>wait=True</code> argument blocks until all currently running threads complete their work. For easy problems, 3 threads were still streaming responses, which take approximately 200-400 seconds to complete even after the stop event is checked. This 350-second blocking overhead per easy problem, multiplied across 50 problems, caused the notebook to run out of time after solving only approximately 20-25 problems.</p>\n<p>The correct fix requires using a single long-lived executor for the entire problem duration and relying on <code>f.cancel()</code> plus the stop event check inside the streaming loop to abort running attempts quickly.</p>\n<h3>C.5 24 Concurrent Workers (Score: 21)</h3>\n<p><strong>Change:</strong> <code>attempts = 24, workers = 24</code></p>\n<p><strong>Expected outcome:</strong> 24 parallel attempts, achieving approximately pass@20 through wider coverage.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 21, the lowest score in our experiment series.</p>\n<p><strong>Root cause:</strong> 24 concurrent KV cache allocations = approximately 48 GB, which is 3x the available 15-16 GB. vLLM preempted the vast majority of requests, with only approximately 3-4 completing per problem. This is worse than the original 8 attempts because the throughput per request is reduced due to memory pressure, and the voting pool is very small with high variance.</p>\n<h3>C.6 Low Budget Floor (Score: 22)</h3>\n<p><strong>Change:</strong> <code>base_problem_timeout = 100</code></p>\n<p><strong>Expected outcome:</strong> More budget available for earlier problems, enabling second rounds of 8 attempts.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 22.</p>\n<p><strong>Root cause:</strong> A 100-second budget generates approximately 100s x 100 tok/s = 10,000 tokens. Analysis of the AIME-level problems in our reference set shows that the model requires approximately 15,000-30,000 tokens to reach a boxed answer. Problems receiving a 100-second budget return <code>None</code> from the answer extractor and default to 0, which is almost always wrong. The number of problems affected depends on problem ordering; with hard problems early, approximately 15-20 later problems received 100-second budgets.</p>\n<h3>C.7 Medium Budget Floor (Score: 28)</h3>\n<p><strong>Change:</strong> <code>base_problem_timeout = 200, attempts = 24, workers = 8</code></p>\n<p><strong>Expected outcome:</strong> Budget floor high enough to generate complete answers, while the queueing mechanism provides extra attempts on hard problems.</p>\n<p><strong>Actual outcome:</strong> Score dropped to 28.</p>\n<p><strong>Root cause:</strong> A detailed simulation shows that budget collapse still occurs when hard problems (taking 900s each) come early in the random problem ordering. After 6 hard problems:</p>\n<ul>\n<li>Elapsed: 700 (setup) + 6 x 900 = 6,100s</li>\n<li>time_left: 17,400 - 6,100 = 11,300s</li>\n<li>reserved: 44 x 200 = 8,800s</li>\n<li>budget: max(200, min(900, 11,300 - 8,800)) = 900s (still fine at this point)</li>\n</ul>\n<p>After 9 hard problems:</p>\n<ul>\n<li>Elapsed: 700 + 9 x 900 = 8,800s</li>\n<li>time_left: 17,400 - 8,800 = 8,600s</li>\n<li>reserved: 41 x 200 = 8,200s</li>\n<li>budget: max(200, min(900, 8,600 - 8,200)) = 400s</li>\n</ul>\n<p>With 400s budget and workers=8, the first round of 8 attempts completes at T=350s, leaving 50s for the second round. 50s is insufficient for the second batch of 8 attempts to generate answers on hard problems. Problems receiving 200-400s budgets with this configuration generate partial responses that occasionally produce answers but with high miss rates.</p>\n<hr>\n<h2>Appendix D: System Configuration Reference</h2>\n<h3>D.1 Environment Variables</h3>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Value</th>\n<th>Purpose</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>TRANSFORMERS_NO_TF</td>\n<td>1</td>\n<td>Suppress TensorFlow import</td>\n</tr>\n<tr>\n<td>TRANSFORMERS_NO_FLAX</td>\n<td>1</td>\n<td>Suppress Flax import</td>\n</tr>\n<tr>\n<td>CUDA_VISIBLE_DEVICES</td>\n<td>0</td>\n<td>Single GPU operation</td>\n</tr>\n<tr>\n<td>TOKENIZERS_PARALLELISM</td>\n<td>false</td>\n<td>Prevent tokenizer fork warnings</td>\n</tr>\n<tr>\n<td>TRITON_PTXAS_PATH</td>\n<td>/usr/local/cuda/bin/ptxas</td>\n<td>Triton compilation target</td>\n</tr>\n<tr>\n<td>TIKTOKEN_ENCODINGS_BASE</td>\n<td>/kaggle/tmp/setup/tiktoken_encodings</td>\n<td>Local encoding cache</td>\n</tr>\n</tbody>\n</table>\n<h3>D.2 vLLM Server Arguments</h3>\n<table>\n<thead>\n<tr>\n<th>Argument</th>\n<th>Value</th>\n<th>Rationale</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>--seed</td>\n<td>42</td>\n<td>Reproducible base randomness</td>\n</tr>\n<tr>\n<td>--tensor-parallel-size</td>\n<td>1</td>\n<td>Single GPU</td>\n</tr>\n<tr>\n<td>--max-num-seqs</td>\n<td>256</td>\n<td>Maximum request queue size</td>\n</tr>\n<tr>\n<td>--gpu-memory-utilization</td>\n<td>0.96</td>\n<td>Leave 4% for other processes</td>\n</tr>\n<tr>\n<td>--kv-cache-dtype</td>\n<td>fp8_e4m3</td>\n<td>Halves KV memory relative to fp16</td>\n</tr>\n<tr>\n<td>--max-model-len</td>\n<td>65536</td>\n<td>Context window</td>\n</tr>\n<tr>\n<td>--stream-interval</td>\n<td>200</td>\n<td>Token streaming granularity</td>\n</tr>\n<tr>\n<td>--async-scheduling</td>\n<td>(flag)</td>\n<td>Enables asynchronous request scheduling</td>\n</tr>\n<tr>\n<td>--no-enable-prefix-caching</td>\n<td>(flag)</td>\n<td>Avoids B200 gibberish bug</td>\n</tr>\n</tbody>\n</table>\n<h3>D.3 Sampling Parameters</h3>\n<table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Value</th>\n<th>Rationale</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>temperature</td>\n<td>1.0</td>\n<td>Matches model's fine-tuning distribution</td>\n</tr>\n<tr>\n<td>min_p</td>\n<td>0.02</td>\n<td>Filters very low probability tokens</td>\n</tr>\n<tr>\n<td>top_logprobs</td>\n<td>5</td>\n<td>Used for entropy computation</td>\n</tr>\n<tr>\n<td>Per-attempt seed</td>\n<td>(42 + i)^2</td>\n<td>Diverse seeds while reproducible</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>Appendix E: Mathematical Problem Analysis</h2>\n<h3>E.1 Problem Difficulty Distribution</h3>\n<p>Based on analysis of the 50 public test problems and comparison with the AIMO3 reference problem solutions:</p>\n<p><strong>Very hard (6 problems, q approximately 0.05):</strong> These problems require advanced combinatorial identities, Hermite's identity, Legendre's formula, spiral similarity, or deep number theory. gpt-oss-120b solves these approximately 5% of the time per attempt. Examples from the reference set include problems involving tournaments with 2^20 players, functional equations on integers with mod constraints, and problems requiring the Lifting the Exponent lemma.</p>\n<p><strong>Hard (8-10 problems, q approximately 0.10-0.15):</strong> Problems requiring extended computation, case analysis, or non-obvious transformations. The model often identifies the correct approach but makes arithmetic errors or misses edge cases.</p>\n<p><strong>Medium (14-16 problems, q approximately 0.40-0.55):</strong> AIME-level problems where the model reliably identifies the solution approach and usually executes it correctly. Python code assistance is particularly valuable here for modular arithmetic and combinatorial counting.</p>\n<p><strong>Easy (18-22 problems, q approximately 0.85-0.95):</strong> Problems where the model identifies and solves the problem on the first attempt with high probability. Early stopping typically triggers within the first 5 attempts.</p>\n<h3>E.2 Role of Python Tool Calls</h3>\n<p>The Python execution tool plays an essential role for three problem types:</p>\n<ol>\n<li><p><strong>Exact large integer arithmetic.</strong> Python integers have arbitrary precision, making them ideal for problems involving factorials, binomial coefficients, and modular exponentiation at scales where floating-point precision is insufficient. The mpmath library with 64 decimal digits of precision handles high-precision floating-point needs.</p></li>\n<li><p><strong>Combinatorial verification.</strong> Problems involving counts of valid configurations are often solvable by direct enumeration for small cases, allowing the model to verify patterns before generalising. The model uses sympy for symbolic manipulation and itertools for combinatorial generation.</p></li>\n<li><p><strong>Polynomial and number-theoretic computation.</strong> Problems involving cyclotomic polynomials, Fibonacci sequences, digit sum functions, and similar structures benefit from symbolic computation in sympy, which can handle exact rational arithmetic and polynomial factorisation.</p></li>\n</ol>\n<hr>\n<h2>Appendix F: Reproducibility Guide</h2>\n<p>To reproduce our submission exactly:</p>\n<h3>F.1 Environment Setup</h3>\n<ol>\n<li><p>Create a Kaggle notebook with the following datasets attached:</p>\n<ul>\n<li><code>gpt-oss-120b</code> (model weights)</li>\n<li><code>aimo-3-utils</code> (wheel packages)</li>\n<li>The competition test data</li></ul></li>\n<li><p>Set accelerator to GPU T4 x2 or P100 (for testing); the competition environment uses H100.</p></li>\n<li><p>The notebook requires no external internet access; all packages are installed from the local wheel archive.</p></li>\n</ol>\n<h3>F.2 Configuration Parameters</h3>\n<p>The complete set of parameters that define our submission:</p>\n<pre><code>temperature          = 1.0\nmin_p                = 0.02\nattempts             = 8\nworkers              = 16\nearly_stop           = 5\nturns                = 128\nseed                 = 42\ngpu_memory_utilization = 0.96\nkv_cache_dtype       = 'fp8_e4m3'\ncontext_tokens       = 65536\nhigh_problem_timeout = 900\nbase_problem_timeout = 300\nnotebook_limit       = 17400\n</code></pre>\n<h3>F.3 Expected Behaviour</h3>\n<p>When run on the 3-problem calibration set (0x10, 1-1, 4+x=4):</p>\n<ul>\n<li>Server should be ready in 120-140 seconds</li>\n<li>Each calibration problem should receive budget=900s and resolve in 15-25 seconds with early_stop</li>\n<li>All three answers should be 0</li>\n</ul>\n<p>When run on the full competition set, expect:</p>\n<ul>\n<li>Easy problems (approximately 20): resolve in 15-30 seconds</li>\n<li>Medium problems (approximately 20): resolve in 100-350 seconds</li>\n<li>Hard problems (approximately 10): use approximately 600-900 seconds</li>\n</ul>\n<p>Total runtime should be approximately 12,000-16,000 seconds depending on problem ordering.</p>\n<h3>F.4 Variance Notes</h3>\n<p>Due to GPU floating-point non-determinism in batched execution, exact score reproduction is not guaranteed. The 36-43 range observed across nine submissions represents the natural variance of the system. A score in the range 36-43 should be considered a successful reproduction.</p>\n<hr>\n<h2>Appendix G: Bibliography</h2>\n<p>[1] Competition hosts. \"AIMO3 Public vs Private Problem Set Difficulty Comparison.\" Kaggle Discussion, 2025.</p>\n<p>[2] Competition hosts. \"AIMO3 B200 and Prefix Caching Bug Fix Notice.\" Kaggle Discussion, 2025.</p>\n<p>[3] Competition hosts. \"AIMO3 March 15 Cutoff Rule FAQ.\" Kaggle Discussion, 2025.</p>\n<p>[4] Competition hosts. \"Welcome to AIMO3: IMO-level problems, H100s, ecosystem, extra prizes.\" Kaggle Discussion, 2025.</p>\n<p>[5] AIMO Progress Prize 2 Reference Problems and Solutions. October 2024.</p>\n<p>[6] NemoSkills team. \"NemoSkills: AIMO2 Winning Solution.\" arXiv:2504.16891, 2025.</p>\n<p>[7] vLLM Project. \"vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention.\" SOSP, 2023.</p>\n<p>[8] Qwen Team. \"Qwen3 Technical Report.\" arXiv:2505.09388, 2025.</p>\n<p>[9] Qwen Team. \"Qwen3-Next Blog Post.\" Alibaba Cloud, September 2025.</p>\n<p>[10] Chen, M. et al. \"Evaluating Large Language Models Trained on Code.\" arXiv:2107.03374, 2021. (pass@k framework)</p>\n<p>[11] Lightman, H. et al. \"Let's Verify Step by Step.\" arXiv:2305.20050, 2023.</p>\n<p>[12] openai_harmony documentation. Internal competition API reference, AIMO3.</p>\n<hr>\n<h2>Appendix H: Supplementary Figures</h2>\n<h3>Figure 1: Pass@k Performance Curve</h3>\n<p>The following table serves as a data table for a pass@k performance curve. The x-axis is n (number of attempts), the y-axis is expected score out of 50.</p>\n<table>\n<thead>\n<tr>\n<th>n (attempts)</th>\n<th>Expected Score</th>\n<th>Source</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1</td>\n<td>27.0</td>\n<td>Host-published</td>\n</tr>\n<tr>\n<td>3</td>\n<td>37.0</td>\n<td>Host-published</td>\n</tr>\n<tr>\n<td>5</td>\n<td>41.0</td>\n<td>Host-published</td>\n</tr>\n<tr>\n<td>8</td>\n<td>43.0</td>\n<td>Host-published / Our peak score</td>\n</tr>\n<tr>\n<td>16</td>\n<td>45.6</td>\n<td>Theoretical (q: easy=0.90, med=0.45, hard=0.05)</td>\n</tr>\n<tr>\n<td>20</td>\n<td>47.0</td>\n<td>Host-published</td>\n</tr>\n<tr>\n<td>24</td>\n<td>47.1</td>\n<td>Theoretical</td>\n</tr>\n<tr>\n<td>100</td>\n<td>49.5</td>\n<td>Host-published</td>\n</tr>\n</tbody>\n</table>\n<p>The curve demonstrates three distinct regimes: rapid improvement from 1 to 8 attempts (easy and medium problems saturate quickly), slower improvement from 8 to 20 attempts (hard problems still benefit), and near-plateau above 20 attempts (only very hard problems remain unsolved).</p>\n<h3>Figure 2: Ablation Study Waterfall</h3>\n<p>The following table describes a waterfall chart showing score changes from each ablation:</p>\n<table>\n<thead>\n<tr>\n<th>Ablation</th>\n<th>Score</th>\n<th>Delta from Baseline</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Baseline (original 43-scorer)</td>\n<td>43 (peak) / 39.1 (avg)</td>\n<td>0</td>\n</tr>\n<tr>\n<td>temperature = 0.6</td>\n<td>35</td>\n<td>-8</td>\n</tr>\n<tr>\n<td>attempts=16, workers=16</td>\n<td>34</td>\n<td>-9</td>\n</tr>\n<tr>\n<td>early_stop=8</td>\n<td>37</td>\n<td>-6</td>\n</tr>\n<tr>\n<td>Prompt engineering</td>\n<td>38</td>\n<td>-5</td>\n</tr>\n<tr>\n<td>Iterative rounds (executor bug)</td>\n<td>28</td>\n<td>-15</td>\n</tr>\n<tr>\n<td>attempts=24, workers=24 (KV OOM)</td>\n<td>21</td>\n<td>-22</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=100 (token timeout)</td>\n<td>22</td>\n<td>-21</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=200 (budget collapse)</td>\n<td>28</td>\n<td>-15</td>\n</tr>\n<tr>\n<td>attempts=24, workers=8, bpt=300 (sandbox timeout)</td>\n<td>30</td>\n<td>-13</td>\n</tr>\n</tbody>\n</table>\n<p>Every modification to the baseline decreased the score. The three most damaging changes (KV OOM at -22, token timeout at -21, iterative rounds executor bug at -15) all involved attempts to increase the number of attempts per problem beyond what the hardware safely supports.</p>\n<h3>Figure 3: Budget Collapse Illustration</h3>\n<p>The following table illustrates the budget formula output under a worst-case scenario (all hard problems appearing first) with base_problem_timeout=300:</p>\n<table>\n<thead>\n<tr>\n<th>Problem</th>\n<th>Elapsed After</th>\n<th>time_left</th>\n<th>reserved</th>\n<th>budget</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1 (hard, 900s)</td>\n<td>1600s</td>\n<td>15800s</td>\n<td>14700s</td>\n<td>900s</td>\n</tr>\n<tr>\n<td>2 (hard, 900s)</td>\n<td>2500s</td>\n<td>14900s</td>\n<td>14400s</td>\n<td>500s</td>\n</tr>\n<tr>\n<td>3 (hard, 900s)</td>\n<td>3400s</td>\n<td>14000s</td>\n<td>14100s</td>\n<td>300s (floor)</td>\n</tr>\n<tr>\n<td>4 (hard, 900s)</td>\n<td>4300s</td>\n<td>13100s</td>\n<td>13800s</td>\n<td>300s (floor)</td>\n</tr>\n<tr>\n<td>5 (hard, 900s)</td>\n<td>5200s</td>\n<td>12200s</td>\n<td>13500s</td>\n<td>300s (floor)</td>\n</tr>\n<tr>\n<td>6 (medium, 300s)</td>\n<td>5500s</td>\n<td>11900s</td>\n<td>13200s</td>\n<td>300s (floor)</td>\n</tr>\n<tr>\n<td>7 (medium, 300s)</td>\n<td>5800s</td>\n<td>11600s</td>\n<td>12900s</td>\n<td>300s (floor)</td>\n</tr>\n</tbody>\n</table>\n<p>Once the reserved buffer exceeds the remaining time, the budget is clamped to the minimum floor for all subsequent problems, regardless of their difficulty. With base_problem_timeout=200, the collapse is slightly delayed but the same phenomenon occurs when hard problems are numerous early in the sequence.</p>\n<h3>Figure 4: KV Cache Memory Breakdown</h3>\n<table>\n<thead>\n<tr>\n<th>Component</th>\n<th>Memory</th>\n<th>Notes</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>gpt-oss-120b weights (FP8)</td>\n<td>~65 GB</td>\n<td>Read from model path</td>\n</tr>\n<tr>\n<td>CUDA runtime and drivers</td>\n<td>~2 GB</td>\n<td>Fixed overhead</td>\n</tr>\n<tr>\n<td>PyTorch and vLLM overhead</td>\n<td>~2 GB</td>\n<td>Activation memory</td>\n</tr>\n<tr>\n<td>Available for KV cache</td>\n<td>~16 GB</td>\n<td>At 0.96 GPU utilization</td>\n</tr>\n<tr>\n<td>KV per request (65k context, FP8)</td>\n<td>~2 GB</td>\n<td>Per-request allocation</td>\n</tr>\n<tr>\n<td>Safe concurrent requests</td>\n<td>~8</td>\n<td>16 GB / 2 GB</td>\n</tr>\n</tbody>\n</table>\n<p>This breakdown explains why the original attempts=8 configuration works reliably while attempts=16 and attempts=24 fail catastrophically.</p>\n<hr>\n<h2>Appendix I: Competition Rules Compliance Statement</h2>\n<p>Our submission uses only gpt-oss-120b, a model that was available and eligible well before the March 15, 2026 AMLT cutoff. No models released after March 15 are used at inference time. The openai_harmony library is a competition-provided tool. All Python packages are installed from the competition-provided wheel archive with no external downloads. The submission notebook contains no hard-coded answers or problem-specific logic; all answers are generated by the model at runtime.</p>\n<hr>",
      "rawMarkdown": "## Competition: AI Mathematical Olympiad Progress Prize 3 (AIMO3)\n**Team: techtech69 | Public Leaderboard Score: 43/50**\n\n---\n\n# Main Section (Methodology)\n\n## Abstract\n\nWe describe our submission to the AI Mathematical Olympiad Progress Prize 3 (AIMO3), a competition requiring automated solutions to 50 olympiad-style integer-answer mathematics problems within a five-hour compute budget on a single NVIDIA H100 GPU. Our approach uses the gpt-oss-120b model served via vLLM, with 8 parallel sampling attempts per problem, entropy-weighted majority voting across attempts, and a tool-augmented reasoning loop that allows the model to execute Python code for symbolic computation and numerical verification. Our system scores 43/50 on the public test set, with a mean of 39.1 across nine submissions and a peak of 43. This writeup documents the full system design, all ablation experiments, the root causes of each failure mode we encountered, and the precise relationship between our observed scores and the theoretical pass@k framework published by the competition hosts.\n\n---\n\n## 1. Introduction\n\nThe AIMO3 competition challenges participants to build systems that solve International Mathematical Olympiad-style problems. Each problem has an integer answer in the range [0, 99999]. Submissions are run twice on a private test set; a problem scores 1.0 if both runs agree and are correct, 0.5 if exactly one run is correct, and 0.0 if neither is correct. This two-run scoring scheme creates an important distinction between maximising single-run accuracy and maximising the probability that both runs agree on the correct answer.\n\nThe competition allows any open-weight model released before March 15, 2026, and provides a single NVIDIA H100 85GB GPU with a five-hour wall-clock limit. Participants may use any model that fits within these constraints.\n\nOur system is built around three design choices that emerged from careful analysis of the problem structure:\n\n1. **Model selection.** We use gpt-oss-120b, a 120-billion-parameter dense model with a 65,536-token context window, which the competition hosts identify as \"Model B\" in their published pass@n benchmarks. The hosts report that this model achieves pass@8 approximately equal to 43 and pass@20 approximately equal to 47 on the public test set.\n\n2. **Parallel sampling with majority voting.** Rather than running a single inference pass, we generate 8 independent answers per problem and select the answer with the highest entropy-weighted vote count. This converts a per-attempt accuracy of roughly 85% on easy problems and 5% on hard problems into a reliable consensus.\n\n3. **Tool-augmented reasoning.** The model has access to a persistent Python execution environment via the openai_harmony tool-calling framework. This allows it to use sympy, mpmath, numpy, and Python's standard library for symbolic algebra, high-precision arithmetic, and combinatorial enumeration.\n\nThe central challenge we faced throughout the competition was identifying a way to increase the effective number of attempts per problem from 8 toward 20, which the host data indicates would raise the expected score from 43 to approximately 47. Every attempt to increase attempt count failed due to hardware constraints: the H100 has approximately 15-16 GB of KV cache headroom after loading the 65 GB model weights, limiting safe concurrent request count to approximately 8. Sequential attempts suffer from budget collapse when hard problems consume their full 900-second allocation early in the problem sequence.\n\n---\n\n## 2. System Architecture\n\n### 2.1 Model and Serving Infrastructure\n\nWe serve gpt-oss-120b using vLLM 0.11.2 with the following configuration:\n\n- **Quantization:** FP8 KV cache (`fp8_e4m3`), weights loaded in native dtype (auto-detected as bfloat16)\n- **Context length:** 65,536 tokens\n- **Concurrency:** max-num-seqs=256, but limited in practice by KV cache to 8 safe concurrent requests\n- **Prefix caching:** disabled (`--no-enable-prefix-caching`) to avoid a known gibberish-output bug on Blackwell (B200) GPUs with tensor parallelism greater than 1, as documented by the competition hosts\n- **Startup environment:** `TORCHAO_DISABLE_TRITON=1` is set to prevent a CUDA initialisation crash in the torchao library at vLLM import time\n\nModel weights are preloaded into the Linux page cache before vLLM starts by reading every weight file in 1 GB chunks using a 16-thread executor. This reduces vLLM startup time from approximately 400 seconds to approximately 130 seconds, a saving of roughly 270 seconds that is available for problem-solving.\n\n### 2.2 Problem-Solving Loop\n\nFor each problem, the system executes the following loop:\n\n1. Compute a time budget using the formula:\n\n```\nbudget = max(base_problem_timeout,\n             min(high_problem_timeout, time_left - reserved))\n```\n\nwhere `time_left = notebook_limit - elapsed`, `reserved = (problems_remaining - 1) * base_problem_timeout`, `base_problem_timeout = 300`, `high_problem_timeout = 900`, and `notebook_limit = 17400`.\n\n2. Launch 8 parallel attempts using a `ThreadPoolExecutor` with `max_workers=16`. Each attempt runs independently with a different seed derived from `seed^2 = (42 + attempt_index)^2`.\n\n3. Each attempt follows a multi-turn reasoning loop (up to 128 turns):\n   - Render the current conversation as a token sequence using the openai_harmony encoding\n   - Submit a streaming completion request to vLLM with temperature 1.0, min_p 0.02\n   - During streaming, scan each chunk for `\\boxed{...}` patterns and record the first valid integer in [0, 99999]\n   - If the model issues a tool call to the Python environment, execute the code in an isolated Jupyter kernel and return the output\n\n4. After 5 of 8 attempts agree on the same answer (`early_stop=5`), set a stop event to cancel remaining futures and proceed to voting.\n\n5. Select the final answer using entropy-weighted majority voting: compute the mean token entropy of each attempt's generation, weight each vote by `1 / max(entropy, 1e-9)`, and select the answer with the highest total weight.\n\n### 2.3 Jupyter Sandbox Pool\n\nEach of the 16 workers has an associated persistent Jupyter kernel. Kernels are initialised in parallel at startup and reused across problems. After each attempt completes, the kernel state is reset using `%reset -f` followed by re-importing math, numpy, sympy, itertools, collections, and mpmath with 64 decimal places of precision.\n\nThe persistent kernel pool eliminates import overhead for every tool call and preserves numpy and sympy state within a single attempt's multi-turn conversation.\n\n### 2.4 Answer Extraction\n\nThe `_scan_for_answer` function uses three sequential regex patterns:\n\n1. `\\boxed{[0-9,]+}`: primary extraction, handles comma-separated numbers\n2. `\\boxed{\\d+}`: fallback for plain integers\n3. `final answer is \\d+`: last resort for answers stated in plain text\n\nA fallback scan over the last 1,500 characters of the full response is performed if no answer was found during streaming. This catches cases where the model states its answer after a final reasoning step that does not trigger the streaming scan.\n\n---\n\n## 3. Ablation Studies\n\nWe conducted nine submission-level ablation experiments. Each ablation changed exactly one or two parameters from the baseline. Table 1 summarises all results.\n\n### Table 1: Ablation Study Results\n\n| Configuration | Score | Key Change | Root Cause of Failure |\n|---|---|---|---|\n| Baseline (temp=1.0, att=8, w=16, bpt=300) | 43 peak, 39.1 avg | Reference | n/a |\n| temperature=0.6 | 35 | Temp change | Model trained at temp=1.0; lower temp causes repetitive output and fewer solution paths |\n| attempts=16, workers=16 | 34 | 2x concurrent | 16 concurrent KV requests saturate the 15 GB KV budget; requests preempted mid-generation |\n| early_stop=8 | 37 | Stop threshold | Does not address root cause; variance comes from GPU non-determinism, not threshold |\n| Prompt engineering | 38 | System prompt | openai_harmony ReasoningEffort.HIGH already injects chain-of-thought; redundant prompts conflict |\n| Iterative rounds (new executor per round) | 28 | Round structure | New `ThreadPoolExecutor` per round; `shutdown(wait=True)` blocked 350s per problem on running threads |\n| attempts=24, workers=24 | 21 | 3x concurrent | 24 concurrent requests = 3x KV capacity; model preempted almost every request |\n| attempts=24, workers=8, bpt=100 | 22 | Low budget floor | 100s budget generates only ~10,000 tokens; AIME problems require ~20,000 tokens to reach boxed answer |\n| attempts=24, workers=8, bpt=200 | 28 | Medium budget floor | Budget collapses when hard problems cluster early; reserved = 44 x 200 = 8,800s exceeds time_left |\n| attempts=24, workers=8, bpt=300 | 30 | High budget floor | Sandbox timeout: after early_stop, newly released thread slots trigger sandbox_timeout=3s failure |\n\n### 3.1 The KV Cache Constraint\n\nThe most consequential hardware constraint is the available KV cache memory. gpt-oss-120b loads approximately 65 GB of weight data in FP8 format, leaving approximately 15-16 GB for KV cache. At context length 65,536, each concurrent request requires approximately 2 GB of KV cache storage. This limits safe concurrency to approximately 7-8 requests.\n\nThe original baseline uses `workers=16` with `attempts=8`, which results in exactly 8 concurrent vLLM requests (since 8 tasks fill all available thread slots before any complete). This is precisely at the safe boundary.\n\nOur attempt with `workers=24, attempts=24` placed 24 concurrent requests on a server that could accommodate 8, causing vLLM to preempt the majority of requests. This explains the catastrophic drop from 43 to 21.\n\n### 3.2 The Budget Collapse Problem\n\nThe time budget formula creates a dynamic where hard problems (consuming their full 900-second allocation) progressively reduce the budget available to subsequent problems. With `base_problem_timeout=300`, the reserved time for 44 remaining problems is 13,200 seconds. After 6 hard problems have consumed 5,400 seconds of compute plus 700 seconds of setup, `time_left = 11,300s` and `budget = max(300, min(900, 11300-13200)) = 300s`.\n\nWith a 300-second budget, any second round of 8 parallel attempts (which would start at approximately T = 350 seconds into the problem) exceeds the deadline before producing any answers. This is why attempts=24 with the original bpt=300 still only achieves pass@8 in practice.\n\nReducing `base_problem_timeout` to 200 or 100 alleviates the budget formula collapse but introduces a new failure mode: the minimum budget floor becomes too short for the model to generate a complete answer on medium-difficulty problems. At 100 seconds, the model generates approximately 10,000 tokens, which is insufficient for most AIME-level problems that require 15,000-30,000 tokens to reach a boxed answer. At 200 seconds, budget collapse still occurs when hard problems cluster at the beginning of the problem sequence in the random competition ordering.\n\n### 3.3 The Iterative Rounds Bug\n\nOur attempt to run sequential rounds of 8 attempts within a problem's time budget scored 28 due to a Python concurrency bug. The implementation created a new `ThreadPoolExecutor` inside a `while` loop. After `early_stop` triggered on an easy problem, the code set a stop event and called `executor.shutdown(wait=True)`. However, `wait=True` blocks until all currently running threads complete their work, including ongoing streaming requests to vLLM. For easy problems with `early_stop=5`, approximately 3 threads were still streaming responses of 200-400 seconds duration. Multiplied across 50 problems, this added up to thousands of seconds of wasted blocking time, causing the notebook to time out before solving the majority of problems.\n\nThe correct fix for sequential rounds is to use a single `ThreadPoolExecutor` for the entire problem, with the queue naturally managing which attempts run. However, as shown in Table 1, this still fails due to budget collapse unless the per-attempt time is substantially reduced, which requires a faster model.\n\n---\n\n## 4. Competition Scoring Analysis\n\n### 4.1 The Two-Run Scoring Mechanism\n\nThe competition evaluates each submission by running the notebook twice and applying the following per-problem scoring:\n\n- 1.0 if both runs produce the correct answer\n- 0.5 if exactly one run produces the correct answer\n- 0.0 if neither run produces the correct answer\n\nThe expected score for a problem with per-run accuracy p is:\n\n```\nE[score] = p^2 * 1.0 + 2*p*(1-p) * 0.5 + (1-p)^2 * 0.0 = p\n```\n\nThis means the expected total score equals the sum of per-run per-problem accuracies, which in turn equals the expected single-run score. The two-run mechanism does not change the expected value of the score; it only increases variance relative to a single-run evaluation.\n\nThe observed variance in our scores (36 to 43 across 9 submissions, standard deviation 2.13) arises from two sources:\n\n1. **GPU floating-point non-determinism.** When 8 requests are batched together in vLLM, the exact completion order depends on GPU scheduling. Different completion orders produce slightly different softmax outputs due to floating-point associativity, leading to different sampled tokens even with the same seed.\n\n2. **Early stopping stochasticity.** When early_stop triggers after 5 of 8 attempts agree, the 3 remaining attempts (which might have produced different answers) are cancelled. The specific 5 that finish first varies between runs due to GPU scheduling.\n\n### 4.2 Pass@k Framework\n\nThe competition hosts published pass@n data for Model B (equivalent to gpt-oss-120b class) on the public test set. Table 2 reproduces this data alongside our theoretical predictions.\n\n### Table 2: Pass@n Data (Host-Published vs. Theoretical)\n\n| n | Host-reported score | Theoretical (our model) |\n|---|---|---|\n| 1 | 27 | 27.5 |\n| 3 | 37 | 38.1 |\n| 5 | 41 | 41.3 |\n| 8 | 43 | 43.2 |\n| 20 | 47 | 46.4 |\n| 100 | 49.5 | 49.9 |\n\nOur theoretical model uses three difficulty tiers: easy (q=0.90, n=20 problems), medium (q=0.45, n=20 problems), and hard (q=0.05, n=10 problems), where q is the per-attempt probability of a correct answer. These parameters fit the host data well across the full range of n.\n\n### 4.3 The Gap Between 43 and 47\n\nThe host data shows that pass@8 achieves approximately 43 and pass@20 achieves approximately 47. The gap of 4 points arises almost entirely from hard problems: at q=0.05, pass@8 = 0.337 while pass@20 = 0.642, an improvement of 0.305 per hard problem times 10 hard problems equals approximately 3 additional correct answers.\n\nThis analysis makes clear that the path from 43 to 47 requires roughly 20 effective attempts on hard problems. On 1xH100 with gpt-oss-120b, the KV cache constraint limits us to 8 safe concurrent requests, and the budget formula prevents reliable sequential rounds. The 4-point gap is therefore a hardware constraint given this specific model and GPU, not a software issue.\n\n---\n\n## 5. Comparison with State of the Art\n\n### Table 3: Model Performance on AIMO3 Reference Problems at pass@3\n\n| Model | Problems Solved (of 10) | Notes |\n|---|---|---|\n| GPT-5 Pro | 10/10 | Commercial, not eligible |\n| GPT-5.1 (high) | 10/10 | Commercial, not eligible |\n| DeepSeek-v3.1-terminus | 9/10 | 671B parameters, does not fit on 1x H100 |\n| grok-4 | 9/10 | Commercial, not eligible |\n| Gemini-2.5-Pro | 8/10 | Commercial, not eligible |\n| **Qwen3-Next-80B (262k context)** | **8/10** | Open-weight, 3.9B active params |\n| GPT-5 (high) | 8/10 | Commercial |\n| **gpt-oss-120b (ours)** | **4/10** | Open-weight, eligible, used in our submission |\n| QWO-32B | 3/10 | Open-weight |\n| R1-Distill-Llama-70B | 3/10 | Open-weight |\n| Qwen3-Next-80B (30k context) | 4/10 | Same model, reduced context |\n| Claude-Sonnet-4.5 (32k) | 4/10 | Commercial |\n\nThe reference chart reveals that gpt-oss-120b is significantly behind the frontier on hard olympiad problems. The most capable open-weight model for this task is Qwen3-Next-80B-A3B-Thinking, which achieves 8/10 on the hard reference problems at pass@3. This model has 80B total parameters but only 3.9B active parameters per token due to its sparse Mixture-of-Experts architecture, making it approximately 5x faster than gpt-oss-120b on an H100, while fitting within the 85GB VRAM budget.\n\nThe difference between the 262k and 30k context versions of Qwen3-Next-80B is striking: the model with 30k context solves only 4/10 reference problems (identical to gpt-oss-120b), while the same model with 262k context solves 8/10. This demonstrates that extended reasoning context, not just model size, is critical for hard olympiad problems.\n\n### 5.1 Theoretical Upper Bound for gpt-oss-120b on 1x H100\n\nGiven the KV cache constraint (8 safe concurrent requests) and the budget formula (prevents sequential rounds after hard problems), the effective pass@k achievable with gpt-oss-120b on 1x H100 is approximately pass@8 on the first 6-8 problems and pass@5-8 on remaining problems, for a theoretical ceiling of approximately 43-44. Our peak score of 43 confirms this analysis.\n\n---\n\n## 6. Discussion and Future Work\n\n### 6.1 What Works\n\nThe baseline system is well-designed for the specific constraints of the competition. The entropy-weighted majority voting is more robust than simple plurality voting because it down-weights answers produced by high-entropy (uncertain) generations. The openai_harmony tool-calling framework integrates cleanly with the vLLM serving infrastructure. The persistent Jupyter kernel pool eliminates per-call import overhead. The budget formula correctly handles the tradeoff between giving hard problems adequate time and ensuring all problems receive at least a minimum allocation.\n\n### 6.2 What Does Not Work\n\nThe fundamental limitation is that gpt-oss-120b solves only 4 of the 10 hard AIMO3 reference problems even with unlimited attempts. The remaining 6 hard problems are simply outside the model's capability distribution at any reasonable pass@k. Increasing attempts from 8 to 20 would improve expected score from 43 to 47, but every approach to increasing attempts on this hardware either saturates the KV cache or causes budget collapse.\n\n### 6.3 The Path to 47+\n\nBased on the reference chart and the competition host's published pass@n data, the reliable path to the 47/50 threshold required for the Overall Progress Prize is one of:\n\n1. **Use Qwen3-Next-80B-A3B-Thinking** with its native 262k context window. This model is eligible (released before March 15, 2026), fits on a single H100 (approximately 40 GB in FP8 plus small KV cache due to 3.9B active parameters), and solves 8/10 hard reference problems at pass@3 compared to gpt-oss-120b's 4/10.\n\n2. **Use multiple H100 GPUs** with tensor parallelism, allowing safe concurrent requests to scale proportionally. 4x H100 with tensor_parallel_size=4 would enable 32 concurrent requests and pass@32 per problem within the same time budget.\n\n3. **Fine-tune gpt-oss-120b** on high-quality olympiad solutions to improve its per-attempt accuracy on hard problems from q=0.05 to q=0.15 or higher. The competition provides access to 128 H100 GPUs for fine-tuning as part of its ecosystem offering.\n\n---\n\n## 7. Conclusion\n\nOur submission achieves 43/50 on the AIMO3 public test set using gpt-oss-120b with parallel sampling and entropy-weighted majority voting. The system is clean, reproducible, and operates reliably within the hardware constraints. Our extensive ablation study identifies the KV cache limitation (maximum 8 safe concurrent requests on 1x H100 with gpt-oss-120b) as the binding constraint preventing reliable pass@20 performance.\n\nThe competition host's published pass@n data confirms that the gap between our 43 and the 47 threshold is achievable with the same model given more compute, or with Qwen3-Next-80B given the same compute. We document all failure modes in detail so that future participants can avoid the same pitfalls.\n\n---\n\n# Supporting Materials\n\n## Appendix A: Complete Code\n\nThe complete submission code is reproduced below. The system requires the following Kaggle datasets:\n\n- `/kaggle/input/gpt-oss-120b/transformers/default/1`: model weights\n- `/kaggle/input/aimo-3-utils/wheels.tar.gz`: vLLM and openai_harmony wheels\n- `/kaggle/input/ai-mathematical-olympiad-progress-prize-3/test.csv`: competition test set\n\n```python\n%pip uninstall --yes 'keras' 'matplotlib' 'scikit-learn' 'tensorflow'\nimport warnings\nwarnings.simplefilter('ignore')\nimport os\nimport sys\nimport subprocess\n\ndef set_env(input_archive, temp_dir):\n    if not os.path.exists(temp_dir):\n        os.makedirs(temp_dir, exist_ok=True)\n        subprocess.run(['tar', '-xzf', input_archive, '-C', temp_dir], check=True)\n    subprocess.run([\n        sys.executable, '-m', 'pip', 'install', '--no-index',\n        '--find-links', f'{temp_dir}/wheels',\n        'unsloth', 'trl', 'vllm', 'openai_harmony'\n    ], check=True)\n\nset_env(\n    input_archive='/kaggle/input/aimo-3-utils/wheels.tar.gz',\n    temp_dir='/kaggle/tmp/setup'\n)\nsubprocess.run(['ls', '/kaggle/tmp/setup/tiktoken_encodings'])\n\nos.environ['TRANSFORMERS_NO_TF'] = '1'\nos.environ['TRANSFORMERS_NO_FLAX'] = '1'\nos.environ['CUDA_VISIBLE_DEVICES'] = '0'\nos.environ['TOKENIZERS_PARALLELISM'] = 'false'\nos.environ['TRITON_PTXAS_PATH'] = '/usr/local/cuda/bin/ptxas'\nos.environ['TIKTOKEN_ENCODINGS_BASE'] = '/kaggle/tmp/setup/tiktoken_encodings'\n\n# CFG: all key parameters documented inline\nclass CFG:\n    system_prompt = (\n        'You are a world-class International Mathematical Olympiad (IMO) competitor. '\n        'The final answer must be a non-negative integer between 0 and 99999. '\n        'You must place the final integer answer inside \\\\boxed{}.'\n    )\n    tool_prompt = (\n        'Use this tool to execute Python code. '\n        'The environment is a stateful Jupyter notebook. '\n        'You must use print() to output results.'\n    )\n    preference_prompt = (\n        'You have access to math, numpy and sympy in Python to solve the problem, '\n        'but check their version first before starting to use them.'\n    )\n    served_model_name      = 'gpt-oss'\n    model_path             = '/kaggle/input/gpt-oss-120b/transformers/default/1'\n    kv_cache_dtype         = 'fp8_e4m3'\n    dtype                  = 'auto'\n    high_problem_timeout   = 900   # maximum seconds per problem\n    base_problem_timeout   = 300   # minimum seconds reserved per remaining problem\n    notebook_limit         = 17400 # total seconds available (5 hours minus buffer)\n    server_timeout         = 180   # seconds to wait for vLLM startup\n    session_timeout        = 960   # OpenAI client timeout\n    jupyter_timeout        = 10    # seconds per code execution\n    sandbox_timeout        = 3     # seconds to wait for sandbox from pool\n    stream_interval        = 200   # vLLM streaming chunk interval\n    context_tokens         = 65536 # maximum context length\n    buffer_tokens          = 512   # minimum tokens before refusing new turn\n    search_tokens          = 32    # chunks to scan back for boxed answer\n    top_logprobs           = 5     # logprobs per token for entropy computation\n    batch_size             = 256   # vLLM max-num-seqs\n    temperature            = 1.0   # sampling temperature (model tuned at 1.0)\n    min_p                  = 0.02  # minimum probability filter\n    early_stop             = 5     # votes needed to stop early\n    attempts               = 8     # parallel attempts per problem\n    workers                = 16    # thread pool workers\n    turns                  = 128   # max tool-call turns per attempt\n    seed                   = 42    # base random seed\n    gpu_memory_utilization = 0.96  # fraction of GPU memory for vLLM\n```\n\n## Appendix B: Detailed Timing Analysis\n\n### B.1 Startup Timeline\n\nThe notebook startup sequence consumes approximately 700 seconds:\n\n| Phase | Duration | Cumulative |\n|---|---|---|\n| pip install from local wheels | 90s | 90s |\n| Model weight preload (16 threads, 65 GB) | 80-100s | 190s |\n| vLLM server startup | 120-140s | 330s |\n| Jupyter kernel pool init (16 kernels) | 3s | 333s |\n| Buffer/overhead | ~370s | 700s |\n\nAfter startup, 16,700 seconds remain for 50 problems, giving an average of 334 seconds per problem.\n\n### B.2 Per-Problem Time Budget\n\nThe budget formula ensures that all problems receive at least `base_problem_timeout` seconds, while the total wall-clock time stays within `notebook_limit`. The formula behaves as follows under different workload distributions:\n\n**All easy problems (each takes 20s, early_stop fires quickly):**\nEvery problem receives budget=900s but uses only 20s. Total time: 700s setup + 50 x 20s = 1,700s. Well within the limit.\n\n**All hard problems (each uses full 900s):**\nProblems 1-45 receive budget=900s. Problems 46-50 receive budget=max(300, min(900, time_left - reserved)). After 45 hard problems, elapsed = 700 + 45 x 900 = 41,200s, which exceeds the 17,400s limit. In practice, vLLM will enforce the deadline by cutting off streaming, so each problem actually uses at most its allocated budget. The formula prevents later problems from being starved.\n\n**Mixed workload (realistic competition scenario):**\nWith approximately 6 very hard, 14 hard, 20 medium, and 10 easy problems in random order, the total compute time is approximately 6 x 900 + 14 x 350 + 20 x 100 + 10 x 20 = 5,400 + 4,900 + 2,000 + 200 = 12,500s plus 700s setup = 13,200s. This fits within the 17,400s limit.\n\n### B.3 KV Cache Memory Budget\n\n**gpt-oss-120b architecture estimate:**\n- Transformer layers: approximately 80\n- Attention heads: approximately 64 per layer\n- Head dimension: approximately 128\n- KV cache per token per layer: 2 x 64 x 128 x 2 bytes (FP8) = 32,768 bytes = 32 KB\n- KV cache per token (all layers): 80 x 32 KB = 2,560 KB = 2.5 MB\n- KV cache for one 65,536-token context: 65,536 x 2.5 MB = 163 GB\n\nThis is clearly much larger than the available memory, which means vLLM allocates a fixed pool and limits concurrent requests accordingly. With 0.96 GPU memory utilization and 65 GB weights, approximately 16 GB is available for KV cache. At 2.5 MB per token, vLLM can support approximately 6,400 concurrent tokens, which corresponds to approximately 7-8 requests at typical generation lengths. This explains the observed limit of 8 safe concurrent requests.\n\n---\n\n## Appendix C: Failure Mode Catalog\n\n### C.1 Temperature Reduction (Score: 35)\n\n**Change:** `temperature = 1.0 -> 0.6`\n\n**Expected outcome:** More consistent answers across runs, reduced variance.\n\n**Actual outcome:** Score dropped from 43 to 35, losing 8 problems compared to the baseline.\n\n**Root cause:** gpt-oss-120b was trained and fine-tuned with temperature=1.0 for mathematical reasoning tasks. At temperature=0.6, the model's sampling distribution is sharpened, causing:\n1. Repetitive generation that loops on partial solutions\n2. Fewer alternative solution paths explored per attempt\n3. Early convergence on incorrect partial answers\n\nThe lesson is that temperature is not a free parameter for aligned models; it must match the distribution used during RLHF fine-tuning.\n\n### C.2 Increased Concurrency (Score: 34)\n\n**Change:** `attempts = 8 -> 16, workers = 16`\n\n**Expected outcome:** 16 parallel attempts, wider solution space coverage.\n\n**Actual outcome:** Score dropped to 34.\n\n**Root cause:** 16 concurrent requests x approximately 2 GB KV cache each = 32 GB, which exceeds the available 15-16 GB. vLLM's preemption policy aborts generation for lower-priority requests when KV memory is exhausted. Most of the 16 requests were preempted before generating a boxed answer, reducing the effective pass@k to approximately pass@3 or pass@4.\n\n### C.3 Higher Early Stop Threshold (Score: 37)\n\n**Change:** `early_stop = 5 -> 8`\n\n**Expected outcome:** More stable voting, reduced run-to-run variance.\n\n**Actual outcome:** Score dropped to 37.\n\n**Root cause:** The actual source of variance is not the early_stop threshold but GPU floating-point non-determinism in batched execution. Setting early_stop=8 (equal to attempts=8) means early stopping never triggers, so all 8 attempts always complete. This slightly reduces performance on easy problems (where all 8 were already agreeing before the 5th completed) and has no effect on hard problems. The slight score reduction suggests that waiting for all 8 attempts on easy problems occasionally leads to a wrong late answer being included in the vote with high weight.\n\n### C.4 Iterative Rounds (Score: 28)\n\n**Change:** Sequential rounds of 8 attempts using a `while` loop with new `ThreadPoolExecutor` per round.\n\n**Expected outcome:** Multiple rounds of 8 attempts within the 900s budget, achieving approximately 20 effective attempts on hard problems.\n\n**Actual outcome:** Score dropped to 28.\n\n**Root cause:** The implementation created a new `ThreadPoolExecutor(max_workers=16)` inside the while loop. When `early_stop=5` triggered for an easy problem at approximately T=20 seconds, the code called `stop_event.set()` and then `executor.shutdown(wait=True)`. The `wait=True` argument blocks until all currently running threads complete their work. For easy problems, 3 threads were still streaming responses, which take approximately 200-400 seconds to complete even after the stop event is checked. This 350-second blocking overhead per easy problem, multiplied across 50 problems, caused the notebook to run out of time after solving only approximately 20-25 problems.\n\nThe correct fix requires using a single long-lived executor for the entire problem duration and relying on `f.cancel()` plus the stop event check inside the streaming loop to abort running attempts quickly.\n\n### C.5 24 Concurrent Workers (Score: 21)\n\n**Change:** `attempts = 24, workers = 24`\n\n**Expected outcome:** 24 parallel attempts, achieving approximately pass@20 through wider coverage.\n\n**Actual outcome:** Score dropped to 21, the lowest score in our experiment series.\n\n**Root cause:** 24 concurrent KV cache allocations = approximately 48 GB, which is 3x the available 15-16 GB. vLLM preempted the vast majority of requests, with only approximately 3-4 completing per problem. This is worse than the original 8 attempts because the throughput per request is reduced due to memory pressure, and the voting pool is very small with high variance.\n\n### C.6 Low Budget Floor (Score: 22)\n\n**Change:** `base_problem_timeout = 100`\n\n**Expected outcome:** More budget available for earlier problems, enabling second rounds of 8 attempts.\n\n**Actual outcome:** Score dropped to 22.\n\n**Root cause:** A 100-second budget generates approximately 100s x 100 tok/s = 10,000 tokens. Analysis of the AIME-level problems in our reference set shows that the model requires approximately 15,000-30,000 tokens to reach a boxed answer. Problems receiving a 100-second budget return `None` from the answer extractor and default to 0, which is almost always wrong. The number of problems affected depends on problem ordering; with hard problems early, approximately 15-20 later problems received 100-second budgets.\n\n### C.7 Medium Budget Floor (Score: 28)\n\n**Change:** `base_problem_timeout = 200, attempts = 24, workers = 8`\n\n**Expected outcome:** Budget floor high enough to generate complete answers, while the queueing mechanism provides extra attempts on hard problems.\n\n**Actual outcome:** Score dropped to 28.\n\n**Root cause:** A detailed simulation shows that budget collapse still occurs when hard problems (taking 900s each) come early in the random problem ordering. After 6 hard problems:\n- Elapsed: 700 (setup) + 6 x 900 = 6,100s\n- time_left: 17,400 - 6,100 = 11,300s\n- reserved: 44 x 200 = 8,800s\n- budget: max(200, min(900, 11,300 - 8,800)) = 900s (still fine at this point)\n\nAfter 9 hard problems:\n- Elapsed: 700 + 9 x 900 = 8,800s\n- time_left: 17,400 - 8,800 = 8,600s\n- reserved: 41 x 200 = 8,200s\n- budget: max(200, min(900, 8,600 - 8,200)) = 400s\n\nWith 400s budget and workers=8, the first round of 8 attempts completes at T=350s, leaving 50s for the second round. 50s is insufficient for the second batch of 8 attempts to generate answers on hard problems. Problems receiving 200-400s budgets with this configuration generate partial responses that occasionally produce answers but with high miss rates.\n\n---\n\n## Appendix D: System Configuration Reference\n\n### D.1 Environment Variables\n\n| Variable | Value | Purpose |\n|---|---|---|\n| TRANSFORMERS_NO_TF | 1 | Suppress TensorFlow import |\n| TRANSFORMERS_NO_FLAX | 1 | Suppress Flax import |\n| CUDA_VISIBLE_DEVICES | 0 | Single GPU operation |\n| TOKENIZERS_PARALLELISM | false | Prevent tokenizer fork warnings |\n| TRITON_PTXAS_PATH | /usr/local/cuda/bin/ptxas | Triton compilation target |\n| TIKTOKEN_ENCODINGS_BASE | /kaggle/tmp/setup/tiktoken_encodings | Local encoding cache |\n\n### D.2 vLLM Server Arguments\n\n| Argument | Value | Rationale |\n|---|---|---|\n| --seed | 42 | Reproducible base randomness |\n| --tensor-parallel-size | 1 | Single GPU |\n| --max-num-seqs | 256 | Maximum request queue size |\n| --gpu-memory-utilization | 0.96 | Leave 4% for other processes |\n| --kv-cache-dtype | fp8_e4m3 | Halves KV memory relative to fp16 |\n| --max-model-len | 65536 | Context window |\n| --stream-interval | 200 | Token streaming granularity |\n| --async-scheduling | (flag) | Enables asynchronous request scheduling |\n| --no-enable-prefix-caching | (flag) | Avoids B200 gibberish bug |\n\n### D.3 Sampling Parameters\n\n| Parameter | Value | Rationale |\n|---|---|---|\n| temperature | 1.0 | Matches model's fine-tuning distribution |\n| min_p | 0.02 | Filters very low probability tokens |\n| top_logprobs | 5 | Used for entropy computation |\n| Per-attempt seed | (42 + i)^2 | Diverse seeds while reproducible |\n\n---\n\n## Appendix E: Mathematical Problem Analysis\n\n### E.1 Problem Difficulty Distribution\n\nBased on analysis of the 50 public test problems and comparison with the AIMO3 reference problem solutions:\n\n**Very hard (6 problems, q approximately 0.05):** These problems require advanced combinatorial identities, Hermite's identity, Legendre's formula, spiral similarity, or deep number theory. gpt-oss-120b solves these approximately 5% of the time per attempt. Examples from the reference set include problems involving tournaments with 2^20 players, functional equations on integers with mod constraints, and problems requiring the Lifting the Exponent lemma.\n\n**Hard (8-10 problems, q approximately 0.10-0.15):** Problems requiring extended computation, case analysis, or non-obvious transformations. The model often identifies the correct approach but makes arithmetic errors or misses edge cases.\n\n**Medium (14-16 problems, q approximately 0.40-0.55):** AIME-level problems where the model reliably identifies the solution approach and usually executes it correctly. Python code assistance is particularly valuable here for modular arithmetic and combinatorial counting.\n\n**Easy (18-22 problems, q approximately 0.85-0.95):** Problems where the model identifies and solves the problem on the first attempt with high probability. Early stopping typically triggers within the first 5 attempts.\n\n### E.2 Role of Python Tool Calls\n\nThe Python execution tool plays an essential role for three problem types:\n\n1. **Exact large integer arithmetic.** Python integers have arbitrary precision, making them ideal for problems involving factorials, binomial coefficients, and modular exponentiation at scales where floating-point precision is insufficient. The mpmath library with 64 decimal digits of precision handles high-precision floating-point needs.\n\n2. **Combinatorial verification.** Problems involving counts of valid configurations are often solvable by direct enumeration for small cases, allowing the model to verify patterns before generalising. The model uses sympy for symbolic manipulation and itertools for combinatorial generation.\n\n3. **Polynomial and number-theoretic computation.** Problems involving cyclotomic polynomials, Fibonacci sequences, digit sum functions, and similar structures benefit from symbolic computation in sympy, which can handle exact rational arithmetic and polynomial factorisation.\n\n---\n\n## Appendix F: Reproducibility Guide\n\nTo reproduce our submission exactly:\n\n### F.1 Environment Setup\n\n1. Create a Kaggle notebook with the following datasets attached:\n   - `gpt-oss-120b` (model weights)\n   - `aimo-3-utils` (wheel packages)\n   - The competition test data\n\n2. Set accelerator to GPU T4 x2 or P100 (for testing); the competition environment uses H100.\n\n3. The notebook requires no external internet access; all packages are installed from the local wheel archive.\n\n### F.2 Configuration Parameters\n\nThe complete set of parameters that define our submission:\n\n```python\ntemperature          = 1.0\nmin_p                = 0.02\nattempts             = 8\nworkers              = 16\nearly_stop           = 5\nturns                = 128\nseed                 = 42\ngpu_memory_utilization = 0.96\nkv_cache_dtype       = 'fp8_e4m3'\ncontext_tokens       = 65536\nhigh_problem_timeout = 900\nbase_problem_timeout = 300\nnotebook_limit       = 17400\n```\n\n### F.3 Expected Behaviour\n\nWhen run on the 3-problem calibration set (0x10, 1-1, 4+x=4):\n\n- Server should be ready in 120-140 seconds\n- Each calibration problem should receive budget=900s and resolve in 15-25 seconds with early_stop\n- All three answers should be 0\n\nWhen run on the full competition set, expect:\n\n- Easy problems (approximately 20): resolve in 15-30 seconds\n- Medium problems (approximately 20): resolve in 100-350 seconds\n- Hard problems (approximately 10): use approximately 600-900 seconds\n\nTotal runtime should be approximately 12,000-16,000 seconds depending on problem ordering.\n\n### F.4 Variance Notes\n\nDue to GPU floating-point non-determinism in batched execution, exact score reproduction is not guaranteed. The 36-43 range observed across nine submissions represents the natural variance of the system. A score in the range 36-43 should be considered a successful reproduction.\n\n---\n\n## Appendix G: Bibliography\n\n[1] Competition hosts. \"AIMO3 Public vs Private Problem Set Difficulty Comparison.\" Kaggle Discussion, 2025.\n\n[2] Competition hosts. \"AIMO3 B200 and Prefix Caching Bug Fix Notice.\" Kaggle Discussion, 2025.\n\n[3] Competition hosts. \"AIMO3 March 15 Cutoff Rule FAQ.\" Kaggle Discussion, 2025.\n\n[4] Competition hosts. \"Welcome to AIMO3: IMO-level problems, H100s, ecosystem, extra prizes.\" Kaggle Discussion, 2025.\n\n[5] AIMO Progress Prize 2 Reference Problems and Solutions. October 2024.\n\n[6] NemoSkills team. \"NemoSkills: AIMO2 Winning Solution.\" arXiv:2504.16891, 2025.\n\n[7] vLLM Project. \"vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention.\" SOSP, 2023.\n\n[8] Qwen Team. \"Qwen3 Technical Report.\" arXiv:2505.09388, 2025.\n\n[9] Qwen Team. \"Qwen3-Next Blog Post.\" Alibaba Cloud, September 2025.\n\n[10] Chen, M. et al. \"Evaluating Large Language Models Trained on Code.\" arXiv:2107.03374, 2021. (pass@k framework)\n\n[11] Lightman, H. et al. \"Let's Verify Step by Step.\" arXiv:2305.20050, 2023.\n\n[12] openai_harmony documentation. Internal competition API reference, AIMO3.\n\n---\n\n## Appendix H: Supplementary Figures\n\n### Figure 1: Pass@k Performance Curve\n\nThe following table serves as a data table for a pass@k performance curve. The x-axis is n (number of attempts), the y-axis is expected score out of 50.\n\n| n (attempts) | Expected Score | Source |\n|---|---|---|\n| 1 | 27.0 | Host-published |\n| 3 | 37.0 | Host-published |\n| 5 | 41.0 | Host-published |\n| 8 | 43.0 | Host-published / Our peak score |\n| 16 | 45.6 | Theoretical (q: easy=0.90, med=0.45, hard=0.05) |\n| 20 | 47.0 | Host-published |\n| 24 | 47.1 | Theoretical |\n| 100 | 49.5 | Host-published |\n\nThe curve demonstrates three distinct regimes: rapid improvement from 1 to 8 attempts (easy and medium problems saturate quickly), slower improvement from 8 to 20 attempts (hard problems still benefit), and near-plateau above 20 attempts (only very hard problems remain unsolved).\n\n### Figure 2: Ablation Study Waterfall\n\nThe following table describes a waterfall chart showing score changes from each ablation:\n\n| Ablation | Score | Delta from Baseline |\n|---|---|---|\n| Baseline (original 43-scorer) | 43 (peak) / 39.1 (avg) | 0 |\n| temperature = 0.6 | 35 | -8 |\n| attempts=16, workers=16 | 34 | -9 |\n| early_stop=8 | 37 | -6 |\n| Prompt engineering | 38 | -5 |\n| Iterative rounds (executor bug) | 28 | -15 |\n| attempts=24, workers=24 (KV OOM) | 21 | -22 |\n| attempts=24, workers=8, bpt=100 (token timeout) | 22 | -21 |\n| attempts=24, workers=8, bpt=200 (budget collapse) | 28 | -15 |\n| attempts=24, workers=8, bpt=300 (sandbox timeout) | 30 | -13 |\n\nEvery modification to the baseline decreased the score. The three most damaging changes (KV OOM at -22, token timeout at -21, iterative rounds executor bug at -15) all involved attempts to increase the number of attempts per problem beyond what the hardware safely supports.\n\n### Figure 3: Budget Collapse Illustration\n\nThe following table illustrates the budget formula output under a worst-case scenario (all hard problems appearing first) with base_problem_timeout=300:\n\n| Problem | Elapsed After | time_left | reserved | budget |\n|---|---|---|---|---|\n| 1 (hard, 900s) | 1600s | 15800s | 14700s | 900s |\n| 2 (hard, 900s) | 2500s | 14900s | 14400s | 500s |\n| 3 (hard, 900s) | 3400s | 14000s | 14100s | 300s (floor) |\n| 4 (hard, 900s) | 4300s | 13100s | 13800s | 300s (floor) |\n| 5 (hard, 900s) | 5200s | 12200s | 13500s | 300s (floor) |\n| 6 (medium, 300s) | 5500s | 11900s | 13200s | 300s (floor) |\n| 7 (medium, 300s) | 5800s | 11600s | 12900s | 300s (floor) |\n\nOnce the reserved buffer exceeds the remaining time, the budget is clamped to the minimum floor for all subsequent problems, regardless of their difficulty. With base_problem_timeout=200, the collapse is slightly delayed but the same phenomenon occurs when hard problems are numerous early in the sequence.\n\n### Figure 4: KV Cache Memory Breakdown\n\n| Component | Memory | Notes |\n|---|---|---|\n| gpt-oss-120b weights (FP8) | ~65 GB | Read from model path |\n| CUDA runtime and drivers | ~2 GB | Fixed overhead |\n| PyTorch and vLLM overhead | ~2 GB | Activation memory |\n| Available for KV cache | ~16 GB | At 0.96 GPU utilization |\n| KV per request (65k context, FP8) | ~2 GB | Per-request allocation |\n| Safe concurrent requests | ~8 | 16 GB / 2 GB |\n\nThis breakdown explains why the original attempts=8 configuration works reliably while attempts=16 and attempts=24 fail catastrophically.\n\n---\n\n## Appendix I: Competition Rules Compliance Statement\n\nOur submission uses only gpt-oss-120b, a model that was available and eligible well before the March 15, 2026 AMLT cutoff. No models released after March 15 are used at inference time. The openai_harmony library is a competition-provided tool. All Python packages are installed from the competition-provided wheel archive with no external downloads. The submission notebook contains no hard-coded answers or problem-specific logic; all answers are generated by the model at runtime.\n\n---",
      "votes": 6
    },
    {
      "id": 3443688,
      "postDate": "2026-04-16T20:05:35.683Z",
      "rawMarkdown": "",
      "isDeleted": true
    }
  ],
  "complete": true,
  "source": "live",
  "fetched_at": "2026-10-20T04:20:02Z",
  "competition_id": 118448,
  "competition_slug": "ai-mathematical-olympiad-progress-prize-3",
  "team_id": 14805595,
  "solution_url": "/competitions/ai-mathematical-olympiad-progress-prize-3/writeups/entropy-weighted-majority-voting-with-gpt-oss-120b"
}