Instructions to use Voidstackloop/Tessera-125B-MoE with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use Voidstackloop/Tessera-125B-MoE with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf Voidstackloop/Tessera-125B-MoE:IQ2_S # Run inference directly in the terminal: llama cli -hf Voidstackloop/Tessera-125B-MoE:IQ2_S
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf Voidstackloop/Tessera-125B-MoE:IQ2_S # Run inference directly in the terminal: llama cli -hf Voidstackloop/Tessera-125B-MoE:IQ2_S
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf Voidstackloop/Tessera-125B-MoE:IQ2_S # Run inference directly in the terminal: ./llama-cli -hf Voidstackloop/Tessera-125B-MoE:IQ2_S
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf Voidstackloop/Tessera-125B-MoE:IQ2_S # Run inference directly in the terminal: ./build/bin/llama-cli -hf Voidstackloop/Tessera-125B-MoE:IQ2_S
Use Docker
docker model run hf.co/Voidstackloop/Tessera-125B-MoE:IQ2_S
- Llama new
- LM Studio
- Jan
- Ollama
How to use Voidstackloop/Tessera-125B-MoE with Ollama:
ollama run hf.co/Voidstackloop/Tessera-125B-MoE:IQ2_S
- Unsloth Desktop
- Pi
How to use Voidstackloop/Tessera-125B-MoE with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf Voidstackloop/Tessera-125B-MoE:IQ2_S
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "Voidstackloop/Tessera-125B-MoE:IQ2_S" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use Voidstackloop/Tessera-125B-MoE with Docker Model Runner:
docker model run hf.co/Voidstackloop/Tessera-125B-MoE:IQ2_S
- Lemonade
How to use Voidstackloop/Tessera-125B-MoE with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull Voidstackloop/Tessera-125B-MoE:IQ2_S
Run and chat with the model
lemonade run user.Tessera-125B-MoE-IQ2_S
List all available models
lemonade list
- Hermes Agent
How to use Voidstackloop/Tessera-125B-MoE with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf Voidstackloop/Tessera-125B-MoE:IQ2_S
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default Voidstackloop/Tessera-125B-MoE:IQ2_S
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use Voidstackloop/Tessera-125B-MoE with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf Voidstackloop/Tessera-125B-MoE:IQ2_S
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "Voidstackloop/Tessera-125B-MoE:IQ2_S" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
Add benchmark tables, scripts and report
Browse files- benchmarks/REPORT.md +272 -0
- benchmarks/SPEED_PC.md +27 -0
- benchmarks/results/k448_code_nothink_a100_compact.csv +121 -0
- benchmarks/results/k448_code_think16k_full_compact.csv +121 -0
- benchmarks/results/k448_code_think16k_redo_compact.csv +22 -0
- benchmarks/results/k448_code_think16k_retry_compact.csv +11 -0
- benchmarks/results/k448_code_think32k_redo_compact.csv +12 -0
- benchmarks/results/k448_code_think_compact.csv +121 -0
- benchmarks/results/k448_reason_nothink_compact.csv +61 -0
- benchmarks/results/k448_reason_think16k_compact.csv +11 -0
- benchmarks/results/k448_reason_think4k_compact.csv +11 -0
- benchmarks/results/k448_swe_compact.csv +21 -0
- benchmarks/results/k448_swe_t100_compact.csv +9 -0
- benchmarks/scripts/07_domain_eval.py +630 -0
- benchmarks/scripts/09_big_suite.py +309 -0
- benchmarks/scripts/10_code_hard.py +321 -0
- benchmarks/scripts/13_swe_native.py +288 -0
- benchmarks/scripts/14_msg_proxy.py +87 -0
benchmarks/REPORT.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# k448 ("Tessera", Qwen3.8-Flash-Next, 448 experts) - capability lab and speed report, 2026-10-25
|
| 2 |
+
|
| 3 |
+
All quality numbers: Colab L4 VM, llama.cpp, 120-task hard suite (HumanEval+, MATH-500, MMLU-Pro; 40 each; seed 1).
|
| 4 |
+
Wording rule used throughout: "beats Q4" only if the paired sign test is p < 0.05 in our favour.
|
| 5 |
+
|
| 6 |
+
## 1. Verdict against Q4 (unsloth UD-IQ4_XS, 87 GiB)
|
| 7 |
+
- Hard test, no-think greedy: Q4 103/120, k448 101/120 (code 39/40 both, math 35/40 both, reasoning 29 vs 27).
|
| 8 |
+
- Paired sign test p = 0.754. **k448 MATCHES Q4 within noise. It does not beat it.**
|
| 9 |
+
- Speed with llama.cpp on the VM: 11.7 vs 8.2 tokens/s (+43%). Memory while running: 41.9 GiB resident, of which 6.3 GiB is real working memory and 35.5 GiB is the mapped model file; the 26.8 GiB n-gram table is lazy.
|
| 10 |
+
- Not compared: Strata's own ISTA-DASLab packs (IQ2_XS 39.2 GB, IQ3_XXS 47 GB) are the real size peers; k448 keeps about 47 GB resident.
|
| 11 |
+
|
| 12 |
+
## 2. What raised capability (weights unchanged, run-time settings only)
|
| 13 |
+
| Setting | Result |
|
| 14 |
+
|---|---|
|
| 15 |
+
| Thinking, reasoning budget 4096, temp 0.6 / top_p 0.95 / top_k 20 | rescued 8 of 12 tasks the greedy run failed (math 5/5, reasoning 3/7); 9/15 on the full redo. About 3.8k tokens per task. |
|
| 16 |
+
| Resampling control (temp 0.6, no thinking) | 2/12 |
|
| 17 |
+
| 3-vote majority (temp 0.7) | 2/12, the same two tasks as resampling; no gain from voting |
|
| 18 |
+
| Thinking vs resampling, paired | 6 vs 0, exact sign test p = 0.031 (small n = 12, tasks pre-selected as failures) |
|
| 19 |
+
| 14 active experts instead of 10 | math 37 vs 35, reasoning 27 vs 27, p = 0.688: no significant gain; perplexity gap to Q4 shrinks but KLD to Q4 does not |
|
| 20 |
+
| MTP draft (llama.cpp) | x1.34 speed with identical answers |
|
| 21 |
+
|
| 22 |
+
Recommended profile: everyday use no-think greedy, 10 experts, MTP on. For hard math or reasoning turn thinking on with a 4096 budget (about twice the tokens). Do not use voting or 14 experts.
|
| 23 |
+
|
| 24 |
+
## 3. Speed with Strata's engine (github.com/Niko1221/Strata, MIT, engine 0.1.51)
|
| 25 |
+
Same Colab VM (L4, 12 vCPU with AVX2 only, 54 GB RAM), k448 packed with Strata's own tool, no MTP head loaded:
|
| 26 |
+
| Run | Decode tokens/s |
|
| 27 |
+
|---|---|
|
| 28 |
+
| llama.cpp, no MTP | 11.7 |
|
| 29 |
+
| llama.cpp with MTP | about 16 |
|
| 30 |
+
| Strata, 256 tokens, `--spec 4` | 15.4 |
|
| 31 |
+
| Strata, 256 tokens, `--spec 2` | 18.4 |
|
| 32 |
+
| Strata, 1024 tokens, `--spec 2` | **27.2** |
|
| 33 |
+
- The 27.2 figure includes lookup drafting (37.5% of drafted tokens accepted) on a repetitive code answer; prose will gain less.
|
| 34 |
+
- Output of the 256-token run was coherent, correct Python. Quality of the Strata path has NOT been run through the hard suite.
|
| 35 |
+
- NOT measured on the RTX 4060 laptop. The VM's slow disk (12 MB/s random reads) and small RAM held Strata back here; the PC may differ either way.
|
| 36 |
+
|
| 37 |
+
Steps that worked on the VM (a source build; no installer scripts were run):
|
| 38 |
+
1. `cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DSTRATA_ENABLE_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=89 && cmake --build build --target strata -j4`
|
| 39 |
+
2. `STRATA_GGUF_PY=build/_deps/strata_llamacpp-src/gguf-py python3 tools/iq_pack.py --gguf <k448.gguf> --out packs/k448 --compat-bf16` (under a minute; 303 tensors served natively, 195 small tensors rounded to BF16, max error 0.0144)
|
| 40 |
+
3. `python3 tools/make_profile.py --no-base --n-expert 448 --out k448-profile.bin` (the shipped profile is for 512 experts)
|
| 41 |
+
4. `./build/strata --pack packs/k448 --tokens-file prompt.txt --native <k448.gguf> --ple-gguf <k448.gguf> --ple-io mmap --max-new 1024 --max-context 4096 --expert-profile k448-profile.bin --expert-cache auto --kv int8 --spec 2 --prefill 512`
|
| 42 |
+
(the binary takes no subcommand; native packs require `--native`, `--spec T>=2` and `--prefill`; on a fast NVMe drop `--ple-io mmap`)
|
| 43 |
+
|
| 44 |
+
## 4. Open items
|
| 45 |
+
- Strata's MTP draft layer: needs about 5-6 GB fetched from the public Qwen/Qwen3.8-Flash-Next repo (tools/mtp_fetch.py). Not downloaded; awaiting the user's yes. Our llama.cpp-format MTP file cannot be used by Strata.
|
| 46 |
+
- Measure on the user's PC (the user downloads the k448 file themselves; no token is ever entered by Claude).
|
| 47 |
+
- Run the hard suite through Strata's server to confirm quality parity.
|
| 48 |
+
- Compare k448 against Strata's ISTA IQ3_XXS / IQ2_XS on the same tasks.
|
| 49 |
+
- Autonomous (agent-style) coding was never tested; only function-level tasks.
|
| 50 |
+
|
| 51 |
+
## 5. The big test suite (`09_big_suite.py`, built 2026-10-25)
|
| 52 |
+
Why: 120 tasks only detect differences of about 10 points. This set has 4 domains x 300 tasks = 1200, all public benchmarks, every answer checked by code.
|
| 53 |
+
|
| 54 |
+
| Domain | 300 tasks = | Check |
|
| 55 |
+
|---|---|---|
|
| 56 |
+
| code | 120 HumanEval+ (all but HumanEval/32, whose own reference fails) + 180 MBPP sanitized | unit tests on the model's function |
|
| 57 |
+
| math | 225 MATH-500 integer answers (levels 2-5) + 75 AIME (AI-MO/aimo-validation-aime) | final line `#### <integer>` |
|
| 58 |
+
| reasoning | 200 MMLU-Pro (14 subjects round-robin, 10 options) + 100 BIG-Bench Hard (8 tasks) | final line `Answer: <x>` |
|
| 59 |
+
| English | 100 RACE-high reading comprehension + 100 CoLA grammar (half acceptable) + 100 writing prompts with machine-checked rules (15 rule types: word counts, paragraphs, bullets, case, keywords, start/end text, quotes, title, commas, P.S., letter count) | `Answer:` line, or the rules in code |
|
| 60 |
+
|
| 61 |
+
- **Nested**: the first 60 tasks of every domain are a prefix of the 300 (`--hard-n 60` = quick set, 240 tasks; `--hard-n 300` = full set). Results of the two can be pooled.
|
| 62 |
+
- **Checked**: selftest passes locally and on the VM (references pass, garbage fails, each rule checker passes its own good/bad example); all 420 code reference solutions run; the VM file has the same sha256 prefix as the local one (`5700b5f8682b8978`).
|
| 63 |
+
- **Run it**: `python3 07x_domain_eval.py run --suite big --hard-n 60 --seed 1 --no-think --name <n> --out results_<n>.json` plus the usual `--bin/--model/--ot/--extra` flags; compare with `07x_domain_eval.py compare a.json b.json` (paired sign test per domain).
|
| 64 |
+
- **Power** (paired exact sign test, 5%): about 5 points per domain at 300 tasks, about 10 points at 60, about 2.5 points when the four domains are pooled (1200). Treat the English rule-following prompts as a relative measure only: they are our own set, not IFEval, so they cannot be compared with published numbers.
|
| 65 |
+
- **Smoke run** (3 tasks per domain, llama.cpp + MTP, no-think, Colab L4): 12/12 pass, 4781 tokens in 471 s = about 400 tokens and 39 s per task, 10.2 tokens/s overall. That puts the quick set (240 tasks) at about 2.6 hours and the full set (1200 tasks) at about 13 hours for one setting and one model; thinking mode costs roughly 5-10x more tokens per task. A 12-task sample, so treat the times as rough; Strata at about 27 tokens/s on this machine would cut them by more than half, but it has not been run through this suite.
|
| 66 |
+
- **Known limits**: code is already near the ceiling (39/40 on HumanEval+), so code gains will be small; there is no agent-style coding test.
|
| 67 |
+
|
| 68 |
+
## 6. Quick-set baseline (run 2026-10-25)
|
| 69 |
+
k448 + MTP draft, llama.cpp, no-think greedy, Colab L4, big suite `--hard-n 60` (60 tasks per domain = 240, seed 1). 137,690 tokens in 9,799 s (14.1 tokens/s overall, about 570 tokens and 41 s per task).
|
| 70 |
+
|
| 71 |
+
| Domain | Pass | Parts |
|
| 72 |
+
|---|---|---|
|
| 73 |
+
| code | 55/60 (91.7%) | HumanEval+ 22/24, MBPP 33/36 |
|
| 74 |
+
| math | 39/60 (65.0%) | MATH-500 39/45, AIME 0/15 |
|
| 75 |
+
| reasoning | 51/60 (85.0%) | MMLU-Pro 31/40, BBH 20/20 |
|
| 76 |
+
| English | 52/60 (86.7%) | RACE 18/20, CoLA 17/20, rule-following 17/20 |
|
| 77 |
+
| **All** | **197/240 (82.1%)** | |
|
| 78 |
+
|
| 79 |
+
- **AIME 0/15 is a token-cap result, not a measure of ability.** The no-think runs on this suite are capped at 2048 tokens (the harness raises `--max-tokens` to at least 2048), and the AIME answers used 2048 tokens on average, so every one ran to the cap. MATH-500 averaged 1,024 tokens, so some of its misses are probably cut off too. Math is the domain where thinking mode (budget 4096) should move the number most.
|
| 80 |
+
- Strongest domain is code (HumanEval+ and MBPP are near the ceiling, as noted in section 5); BBH is a clean 20/20.
|
| 81 |
+
- With 60 tasks per domain only differences of about 10 points are detectable (section 5), so this is a reference point for later changes, not a ranking. It has not been run on Q4 yet, so it says nothing about k448 vs Q4 on this suite.
|
| 82 |
+
- Raw per-task results: `results_big60_k448.json` on the L4 VM (`/content/q38/eval/`); compare later runs with `07x_domain_eval.py compare`.
|
| 83 |
+
|
| 84 |
+
## 7. The harder coding suite (`10_code_hard.py`, built 2026-10-25)
|
| 85 |
+
Why: HumanEval+ and MBPP (92% for k448) are small textbook functions that top models already pass. These two are the harder, widely used replacements that we can run and score by code without a token.
|
| 86 |
+
|
| 87 |
+
| Benchmark | What it tests | In the suite |
|
| 88 |
+
|---|---|---|
|
| 89 |
+
| LiveCodeBench (code_generation_lite, release 6) | contest programming: the model writes a whole program (AtCoder, stdin/stdout) or a LeetCode class; every one of about 40 hidden tests must pass | 175 problems from 2025-01 to 2025-04 (newer than most training data); ids carry the difficulty (easy 43, medium 52, hard 80) |
|
| 90 |
+
| CRUXEval | code understanding: predict the output of a function for an input (CRUXEval-O), or find an input that gives a given output (CRUXEval-I) | 800 functions, half O and half I per task list |
|
| 91 |
+
|
| 92 |
+
- **Run it**: `python3 07x_domain_eval.py run --suite codehard --hard-n 60 --max-tokens 4096 --ctx 8192 --no-think --seed 1 ...` (60 = quick set: 60 LiveCodeBench + 60 CRUXEval; nested prefixes, so `--hard-n 100` extends it). New categories `lcb` and `crux` in the compare table.
|
| 93 |
+
- **Checked**: selftest passes locally and on the VM (lookup-table "solutions" pass every test of 4 stdin and 4 LeetCode-style problems and a wrong solution fails; CRUXEval references pass, garbage fails); all 800 CRUXEval references run; all 175 LiveCodeBench test sets decode (the private tests are a pickled string, loaded with a loader that refuses every global, so a dataset cannot run code). The VM file has the same sha256 prefix as the local one (`2c9c82f1effce90a`).
|
| 94 |
+
- **Expect low numbers**: contest problems are hard. Without thinking, most hard AtCoder problems will fail; thinking mode will matter far more here than on the old sets. The release is recent, but the model's training cutoff is unknown, so some problems may still be familiar.
|
| 95 |
+
- **Time**: LiveCodeBench answers are long (about 1-2k tokens). Roughly 2 hours for the 60+60 quick set and 3.5 hours for 100+100 at llama.cpp speeds; thinking mode several times that.
|
| 96 |
+
- **Not included, and why**: SWE-bench Verified and the Aider polyglot benchmark need a Docker or multi-language toolchain and an agent loop that edits real repositories, which the Colab VM cannot host; BigCodeBench-Hard (148 library-heavy tasks) needs dozens of heavy libraries installed first and is the next candidate if we want one more.
|
| 97 |
+
|
| 98 |
+
## 8. Hard coding results (run 2026-10-26, Colab A100, llama.cpp + MTP draft, seed 1)
|
| 99 |
+
60 LiveCodeBench problems + 60 CRUXEval tasks, the same 120 tasks in both runs. Thinking: budget 4,096 tokens, temperature 0.6, top-p 0.95, top-k 20. No-think: greedy. Both: 8,192-token answer cap, all experts on the GPU. Per-task tables: `results/k448_code_think_compact.csv`, `results/k448_code_nothink_a100_compact.csv`.
|
| 100 |
+
|
| 101 |
+
| | Thinking (4k budget) | No-think (greedy) |
|
| 102 |
+
|---|---|---|
|
| 103 |
+
| **All 120** | **99/120 (82.5%)** | **96/120 (80.0%)** |
|
| 104 |
+
| LiveCodeBench | 41/60 (68.3%) | 38/60 (63.3%) |
|
| 105 |
+
| - easy / medium / hard | 12/12, 15/20, 14/28 | 12/12, 15/20, 11/28 |
|
| 106 |
+
| CRUXEval | 58/60 (96.7%) | 58/60 (96.7%) |
|
| 107 |
+
| - CRUX-O / CRUX-I | 28/30, 30/30 | 28/30, 30/30 |
|
| 108 |
+
| Tokens (per task) | 277,274 (2,310) | 262,258 (2,185) |
|
| 109 |
+
| Time (per task), A100 | 3,689 s (31 s) | 2,888 s (24 s) |
|
| 110 |
+
|
| 111 |
+
- **Thinking does not beat no-think here.** Paired exact sign test: only thinking passes 6 tasks (CRUX-O 155; LCB hard 3777, abc388_g, arc192_d; LCB medium 3722, 3779), only no-think passes 3 (CRUX-O 445; LCB medium 3805, abc400_d), p = 0.508. Both runs are inside each other's noise; the earlier thinking gain (section 2) was on math and reasoning tasks that greedy had already failed, not on coding.
|
| 112 |
+
- **CRUXEval is at its ceiling** (96.7% both ways), so the room for improvement is in LiveCodeBench, mostly the hard problems (about half of the 60 problems, 46% of the pool).
|
| 113 |
+
- **Both modes lose their points by running out of room.** Thinking: all 19 LiveCodeBench failures used the whole 4,096-token budget (4,268 tokens or more); problems that finished thinking earlier went 18 for 18, budget-hit problems 23 for 42. No-think: 17 of its 22 LiveCodeBench failures ran to the 8,192-token answer cap (13 of the 28 hard problems and 5 of the 20 medium ones hit the cap). The budget is correlated with difficulty, so this shows where the failures sit, not by itself that more room would fix them; the 16k-budget rerun (below) tests that.
|
| 114 |
+
- **Why the 19 thinking-run LiveCodeBench failures failed** (re-running the problem's visible sample tests on the model's last answer): 12 give a wrong answer on a sample, 4 crash at run time, 2 pass the samples but fail hidden tests, 1 has no code block (it ran to the 8,192 cap). So 16 of 19 fail the problem's own examples, which the model never checked; this is the case a run-the-tests-and-repair loop (the Claude Code harness) is built for. The two that pass the samples get no feedback from `--retry`.
|
| 115 |
+
- **Speed.** Overall 75 tokens/s thinking and 91 tokens/s no-think on the A100 with all experts on the GPU; the L4 managed about 14 tokens/s overall and your PC has not been measured, so a 16k budget could cost many minutes per hard problem.
|
| 116 |
+
- **Caveat.** 60 problems per benchmark: the 95% interval on a LiveCodeBench rate is about +/-12 points, and six tasks of difference between two runs is within sampling noise.
|
| 117 |
+
|
| 118 |
+
### 8.1 Rerun of the failed tasks with a 16,384-token thinking budget (run 2026-10-26, A100)
|
| 119 |
+
The 21 tasks the 4k-budget thinking run failed (19 LiveCodeBench + 2 CRUXEval) were run again with `--reasoning-budget 16384` (context 24,576, answer cap 20,480, same temperature and sampling). Table: `results/k448_code_think16k_redo_compact.csv`.
|
| 120 |
+
|
| 121 |
+
| | Rescued | Still failing |
|
| 122 |
+
|---|---|---|
|
| 123 |
+
| LiveCodeBench medium (5 failed before) | **5 of 5** | 0 |
|
| 124 |
+
| LiveCodeBench hard (14 failed before) | **4 of 14** | 10 |
|
| 125 |
+
| CRUXEval (2 failed before) | 0 of 2 | 2 (both finished early; the budget was not their problem) |
|
| 126 |
+
| **Total** | **9 of 21** | 12 |
|
| 127 |
+
|
| 128 |
+
- **Estimate, not a measurement of all 120:** adding the 9 rescues to the 99 earlier passes gives **108/120 (90%)**, with LiveCodeBench at **50/60 (83.3%, 95% interval about 72-91%)**, so 105/120 is reached on this basis. The 99 tasks that passed before were not rerun; some of the 23 that passed on the very edge of the 4k budget could flip either way under a different sample. A clean figure needs all 120 tasks rerun at 16k (about 2 hours of A100 time; not run).
|
| 129 |
+
- **Mostly the budget, not luck.** A plain resample rescued 2 of 12 failures in an earlier control (about 17%), which would predict about 3 of 19 here; 9 of 19 is well above that. Some of the 9 are still likely luck.
|
| 130 |
+
- **The budget gets used up either way.** All 19 LiveCodeBench tasks used 16,400 tokens or more (average 17,300), including the 9 that passed and one that hit the 20,480 cap. So 16k is not a "finish early" budget for hard problems; a larger budget (32k) may rescue more of the remaining 10, which has not been tested.
|
| 131 |
+
- **Cost.** 333,605 tokens in 4,516 s for the 21 tasks (238 s per LiveCodeBench task at about 74 tokens/s on the A100), about 4 times the tokens per task of the 4k run. On the L4 earlier (14 tokens/s) this would be about 20 minutes per hard problem; your PC has not been measured.
|
| 132 |
+
|
| 133 |
+
### 8.2 Retry on top of the 16k budget (run 2026-10-26, A100)
|
| 134 |
+
The 10 LiveCodeBench problems still unsolved after the 16,384-token rerun were given up to 2 repair turns (`--retry 2`). After a failed answer the model is shown its first failing VISIBLE sample test (the problem's own examples; hidden tests are used only for the final score) and asked for a corrected solution, again with a 16,384-token thinking budget. The first attempt was the stored 16k answer, so any rescue comes from the repair turns. Table: `results/k448_code_think16k_retry_compact.csv`.
|
| 135 |
+
|
| 136 |
+
| Result | Tasks |
|
| 137 |
+
|---|---|
|
| 138 |
+
| Rescued by 1 repair turn | arc194_d, 3674 |
|
| 139 |
+
| Rescued by 2 repair turns | arc192_e, arc196_b |
|
| 140 |
+
| Still failing after 2 turns | arc196_d, abc398_g, arc190_c, arc193_b |
|
| 141 |
+
| No feedback possible (the code already passes the visible samples, so the loop has nothing to show) | abc392_f, abc387_f |
|
| 142 |
+
|
| 143 |
+
- **4 of 10 rescued (all hard problems).** Combined estimate: 99 (4k run) + 9 (16k budget) + 4 (repair turns) = **112/120 (93.3%)**, LiveCodeBench **54/60 (90.0%)**, CRUXEval 58/60. That is above the 105/120 target and, on this sample, close to the published LiveCodeBench v6 figures in section 9 (88.8 to 91.9).
|
| 144 |
+
- **Caveats, stated plainly.** (1) This is a chain of estimates: the 99 tasks that passed in the first run were never rerun under the 16k or retry settings. A clean number needs all 120 tasks rerun (run 5, below). (2) The repair turns are an agent-style loop with test feedback; the published single-shot figures are not, so the comparison favours k448. (3) Selection effect: only previously failed tasks were retried, and plain resampling alone rescues some (2 of 12 in an earlier control). (4) 60 problems: the 95% interval on 54/60 is about 80-95%.
|
| 145 |
+
- **The two failure kinds the loop cannot help** are visible in the data: 2 of 10 tasks produce code that passes the examples and fails hidden tests, and 4 of 10 never get right even with feedback.
|
| 146 |
+
- **Cost.** 240,734 tokens in 3,411 s for the 10 tasks (341 s per task on the A100), all of it in repair turns because the first answers were reused.
|
| 147 |
+
|
| 148 |
+
### 8.3 Clean rerun of all 120 tasks with a 16,384-token thinking budget (run 2026-10-26, A100)
|
| 149 |
+
The same 120 tasks as section 8, all of them rerun with `--reasoning-budget 16384` (context 24,576, answer cap 20,480, temperature 0.6 / top-p 0.95 / top-k 20, single attempt, no repair turns). This replaces the chained estimate of 8.1. Table: `results/k448_code_think16k_full_compact.csv`.
|
| 150 |
+
|
| 151 |
+
| | 4k budget (section 8) | **16k budget, clean rerun** | No-think |
|
| 152 |
+
|---|---|---|---|
|
| 153 |
+
| **All 120** | 99 (82.5%) | **107 (89.2%)** | 96 (80.0%) |
|
| 154 |
+
| LiveCodeBench (60) | 41 (68.3%) | **49 (81.7%, interval about 70-90%)** | 38 (63.3%) |
|
| 155 |
+
| - easy / medium / hard | 12/12, 15/20, 14/28 | 12/12, 19/20, 18/28 | 12/12, 15/20, 11/28 |
|
| 156 |
+
| CRUXEval (60) | 58 | 58 | 58 |
|
| 157 |
+
| Tokens (per task) | 277,274 (2,310) | 723,767 (6,031) | 262,258 (2,185) |
|
| 158 |
+
| Time (per task), A100 | 3,689 s (31 s) | 9,992 s (83 s) | 2,888 s (24 s) |
|
| 159 |
+
|
| 160 |
+
- **A longer thinking budget helps, and the gain is statistically solid.** Paired exact sign test, 16k vs 4k on the same 120 tasks: only the 16k run passes 9 tasks, only the 4k run passes 1, **p = 0.021**. That is the first coding result in this report that clears p < 0.05. The earlier chained estimate (99 + 9 rescues = 108, section 8.1) held: the clean run gave 107.
|
| 161 |
+
- **The gain is all in LiveCodeBench, and mostly medium and hard problems** (medium 15 -> 19 of 20, hard 14 -> 18 of 28). CRUXEval did not move (58/60 at every setting), as expected: those answers finish early.
|
| 162 |
+
- **It costs 2.6 times the tokens**: about 6,000 tokens and 83 s per task on the A100 (about 16,000 tokens per medium or hard LiveCodeBench problem; easy problems and CRUXEval stay short). On the 14 tokens/s measured on the L4 earlier that is about 20 minutes per hard problem; your PC has not been measured.
|
| 163 |
+
- **11 LiveCodeBench problems still fail**: arc192_e, arc196_d, arc194_d, abc392_f, abc398_g, arc190_c, abc387_f, abc393_e, medium arc192_a, arc193_b, 3674. Three of them (arc192_e, arc194_d, 3674) were rescued by repair turns in the earlier retry run (section 8.2, a different sample of answers), so repair turns on top of 16k would probably add a few more tasks (roughly 110/120), but that combination was not rerun cleanly.
|
| 164 |
+
- **Noise.** Single run per setting; 60 problems per benchmark. Run-to-run sampling noise on LiveCodeBench is a few problems, which is why the paired test (p = 0.021) matters more than the raw 8-task gap.
|
| 165 |
+
|
| 166 |
+
### 8.4 A 32,768-token budget on the problems that still fail at 16k (run 2026-10-26, A100)
|
| 167 |
+
The 11 LiveCodeBench problems that failed in the clean 16k rerun (section 8.3) were run again with `--reasoning-budget 32768` (context 40,960, answer cap 36,864, single attempt). Table: `results/k448_code_think32k_redo_compact.csv`.
|
| 168 |
+
|
| 169 |
+
- **2 of 11 pass** (`abc393_e` and the medium problem `arc192_a`). Both had passed in other runs of the same model at a smaller budget (`abc393_e` at 4k, `arc192_a` at 16k in the 21-task rerun), so they are better read as sampling luck on borderline problems than as a gain from the larger budget. The **nine hard problems that failed at 16k still fail at 32k**: arc192_e, arc196_d, arc194_d, abc392_f, abc398_g, arc190_c, abc387_f, arc193_b, 3674.
|
| 170 |
+
- **Every one of the 11 used the whole 32k budget** (33,000 to 35,300 tokens). The model keeps thinking until it is stopped rather than converging on an answer for these problems.
|
| 171 |
+
- **Cost:** 373,556 tokens in 5,438 s (about 34,000 tokens and 494 s per problem). Doubling the budget again cost twice as much per problem for no measurable gain.
|
| 172 |
+
- **Conclusion:** the budget gain stops between 16k and 32k on this set. 16k is the sensible setting; for the remaining hard problems the repair-turn loop of section 8.2 (feedback from the problem's own sample tests) rescued more (4 of 10) than a bigger budget did (0 of 9 hard ones).
|
| 173 |
+
|
| 174 |
+
## 9. Comparison with strong models (published numbers, and where k448 sits)
|
| 175 |
+
Source: the Qwen3.8-Flash-Next model card on Hugging Face (August 2026). All numbers are vendor-reported, not independently verified; the card does not say whether a score is thinking or non-thinking (the model thinks by default) and does not state the thinking budget.
|
| 176 |
+
|
| 177 |
+
| Benchmark | Flash-Next (parent, full precision) | Qwen3.8-27B | Qwen3.7-Plus | DeepSeek-V4-Flash-0731 | Claude-Opus-4.6 (Max) |
|
| 178 |
+
|---|---|---|---|---|---|
|
| 179 |
+
| LiveCodeBench v6 | 91.9 | 90.3 | 89.6 | 90.6 | 88.8 |
|
| 180 |
+
| k448, thinking 4k budget (ours, 60-problem sample) | 68.3 (95% interval 56-79) | | | | |
|
| 181 |
+
| k448, no-think (ours, same 60 problems) | 63.3 (95% interval 51-74) | | | | |
|
| 182 |
+
| k448, 16k budget, clean rerun of all 60 problems (section 8.3) | **81.7 (interval about 70-90)** | | | | |
|
| 183 |
+
| k448, 16k budget on the failed tasks (estimate, section 8.1) | 83.3 (interval about 72-91) | | | | |
|
| 184 |
+
| k448, 16k budget + test-feedback repair turns (estimate, section 8.2; an agent-style loop, not single-shot) | 90.0 (interval about 80-95) | | | | |
|
| 185 |
+
|
| 186 |
+
- **Only LiveCodeBench lines up.** CRUXEval, HumanEval, MBPP, MATH-500, MMLU-Pro and BBH are not in the card, so no published figure for those is quoted here.
|
| 187 |
+
- **Not like for like.** Our LiveCodeBench is 60 problems sampled from a 175-problem slice (2025-01 to 2025-04) of the release 6 data, answered with a 4,096-token thinking budget and an 8,192-token answer cap; the vendor figure is the full v6 set, presumably with a far longer budget. With 60 problems one run has a 95% interval of roughly +/-12 points. Expect our number to sit below the published one; the gap mixes quantization, budget and sampling, and cannot be split without running the full-precision model (or Q4) through the same harness.
|
| 188 |
+
- **Where k448 sits.** With a 4,096-token thinking budget k448 scores 68.3% on LiveCodeBench against the published 91.9% for the full-precision parent and 88.8% for Claude-Opus-4.6 (Max). With a 16,384-token budget, rerun cleanly on all 60 problems (section 8.3), it scores **81.7% (interval about 70-90%)**: a significant improvement over 4k (paired p = 0.021), and the published 91.9 now sits just above the top of our interval, while the other published figures (88.8 to 90.6) sit inside it. So with a long enough thinking budget k448 is plausibly within the range of the published models on this benchmark, but 60 problems cannot separate it from them. Adding up to two repair turns with the problems' own sample tests (section 8.2) would add a few more problems, but that is an agent-style loop with feedback, which the published single-shot numbers do not use, and it was measured on a different sample of answers. What remains could be quantization, a still longer budget (32k test: section 8.4, which found no gain over 16k), or sampling noise; separating them needs a Q4 or full-precision run on the same harness.
|
| 189 |
+
- **We did not run the other models ourselves** (no API access from this setup), so every competitor number above is as published.
|
| 190 |
+
|
| 191 |
+
## 10. Reasoning: does a bigger thinking budget help? (run 2026-10-26, A100)
|
| 192 |
+
Quick reasoning set from the big suite (`--hard-n 60 --only reason`): 40 MMLU-Pro questions (10 answer options, 14 subjects) and 20 BIG-Bench Hard tasks, seed 1, same tasks every run. The no-think run is the baseline; the 10 questions it failed were then redone with thinking at two budgets (the 50 it passed were not rerun). Tables: `results/k448_reason_nothink_compact.csv`, `..._think4k_compact.csv`, `..._think16k_compact.csv`.
|
| 193 |
+
|
| 194 |
+
| Setting | Result | Tokens (per task) |
|
| 195 |
+
|---|---|---|
|
| 196 |
+
| No-think, 2,048-token cap (60 tasks) | **50/60 (83.3%)**: BBH 20/20, MMLU-Pro 30/40 | 40,632 (677) in 468 s |
|
| 197 |
+
| Thinking, 4,096 budget, the 10 failures | **5 of 10 rescued** | 31,492 (3,149) in 393 s |
|
| 198 |
+
| Thinking, 16,384 budget, the 10 failures | **3 of 10 rescued** | 106,193 (10,619) in 1,315 s |
|
| 199 |
+
|
| 200 |
+
- **Every failure was an MMLU-Pro question.** BBH (logic puzzles, tracking, date and fallacy questions) was 20/20 without thinking; there is nothing to gain there. 6 of the 10 failures ran into the 2,048-token cap without producing an answer, so part of the no-think failure is just running out of room.
|
| 201 |
+
- **Thinking at 4k rescued 5 of the 10** (mmlu11759, 4613, 12187, 11789, 11236). Applied to the whole set that would be about 55/60 (91.7%), but only the failures were redone, so that is an estimate. The earlier lab on the L4 found the same thing (thinking at 4k rescued 3 of 7 reasoning failures).
|
| 202 |
+
- **A 16k budget did not help more; it rescued fewer (3 of 10)** at 3.4 times the tokens. Rescued at 16k: mmlu11759, 12187, 11236 (all three also rescued at 4k). On MMLU-Pro, which mostly tests knowledge and short multi-step reasoning, thinking longer than a few thousand tokens just does not buy accuracy; this is the opposite of the coding result (section 8.3), where the extra budget mattered.
|
| 203 |
+
- **How much is luck?** Resampling alone rescued 2 of 12 failures in an earlier control (about 17%). Against that rate, 5 of 10 is unlikely by chance (rough one-sided binomial p about 0.016) and 3 of 10 is not (p about 0.22). The 10 questions and the 17% control rate are both small, so treat this as suggestive, not proven. A proper test would rerun all 60 under each setting.
|
| 204 |
+
- **Two failures never flipped** (mmlu527, mmlu4987): short wrong answers in every setting, probably knowledge gaps or ambiguous questions rather than a budget problem.
|
| 205 |
+
- **Recommendation for reasoning:** thinking with a 4,096-token budget, not more. Use 16k only for coding (section 8.3).
|
| 206 |
+
|
| 207 |
+
## 12. Agentic coding on SWE-bench Verified Mini through Claude Code (run 2026-10-26, A100)
|
| 208 |
+
The real Claude Code CLI (2.1.197, headless `claude -p`, run as an unprivileged user) was pointed at k448 (llama-server, `/v1/messages`, thinking off, 65,536-token context, MTP draft) and given 20 instances of SWE-bench Verified Mini: 10 django and 10 sphinx whose own gold patch reproduces without Docker here (37 of the 50 instances do: 25 django + 12 sphinx; the 13 old sphinx 3.x instances fail even with the gold patch and are excluded). Grading uses swebench 4.0.4's own log parsers on FAIL_TO_PASS and PASS_TO_PASS. Runner `13_swe_native.py`, proxy `14_msg_proxy.py`. Tables: `results/k448_swe_compact.csv` (50-turn pass) and `results/k448_swe_t100_compact.csv` (100-turn rerun of the 8 misses).
|
| 209 |
+
|
| 210 |
+
| | Result |
|
| 211 |
+
|---|---|
|
| 212 |
+
| As run, 50-turn cap | **12/20 (60%)**: django 8/10, sphinx 4/10 |
|
| 213 |
+
| The 8 misses rerun with a 100-turn cap | +3 (django-11790, sphinx-9229, sphinx-9230) |
|
| 214 |
+
| As run, combined (a second attempt for the misses) | **15/20 (75%)**, 95% interval about 53-89% |
|
| 215 |
+
| **Resolved with no lookup of the upstream project on the internet** | **7/20 (35%)**, interval about 18-57%: 6 at 50 turns (django 11880, 11951, 11999, 12039, 12050; sphinx 9367) plus django-11790 in the rerun |
|
| 216 |
+
|
| 217 |
+
### The headline number is not clean: the agent went to the internet
|
| 218 |
+
The sandbox had open internet and Claude Code had its normal tools (Bash, WebFetch, WebSearch). The transcripts show it used them to look for the upstream fix:
|
| 219 |
+
- In the first django-11790 run the agent searched GitHub for the upstream pull request and went to fetch it (it wrote that it had found the upstream PR and would fetch the actual fix).
|
| 220 |
+
- **8 of the 15 resolved instances consulted the internet**: django-11848 (downloaded raw files from GitHub), 11885 (listed and cloned upstream django), 11964 (fetched django 3.1.3's `enums.py`, which already contains the fix), sphinx-10323 (listed and cloned upstream sphinx, one WebFetch), 10466 (WebFetch plus a GitHub issue lookup), 9320 (GitHub issue and timeline lookups), 9229 (fetched sphinx 4.1.0 source and searched issues), 9230 (nine WebFetch calls and an issue search). The other 7 resolved without any such lookup (django-11790's rerun only downloaded dependency packages).
|
| 221 |
+
- Not checked: whether the local git clone still holds future commits. Several transcripts ran `git log --all` or `git show <sha>`.
|
| 222 |
+
- So **7/20 is a floor** (a lookup does not prove it was needed) and **15/20 is a ceiling**; the true no-help rate is somewhere between. The 15 is also a best of two attempts for the 8 reruns.
|
| 223 |
+
- Official SWE-bench style runs do not give the agent the web, so the as-run number cannot be compared with leaderboard figures.
|
| 224 |
+
|
| 225 |
+
### Numbers
|
| 226 |
+
- **Tool calls:** 912 in the 50-turn pass, 62 errors (6.8%); 694 in the rerun, 36 errors (5.2%).
|
| 227 |
+
- **Turns and time:** 45.8 turns and 343 s per instance on average at the 50-turn cap; 87.1 turns and 668 s in the rerun. The 28 agent runs took 12,191 s (3.4 h) of A100 time, about 23 compute units.
|
| 228 |
+
- **When the agent stopped on its own it was usually right:** 9 of 20 runs ended with the agent declaring it was done, and 8 of those 9 were resolved. The 11 runs cut off by the turn cap resolved 4.
|
| 229 |
+
|
| 230 |
+
### Failure modes (per-instance results plus the transcripts I read)
|
| 231 |
+
1. **Turn cap with the work unfinished:** 11 of 20 in the first pass, 7 of those unresolved.
|
| 232 |
+
2. **Context overflow in long runs:** 5 of the 8 reruns (sphinx-10435, 10673, 11510, 8265, 9229) died with HTTP 400, "request (65,5xx to 66,3xx tokens) exceeds the available context size (65,536 tokens)". Claude Code does not know the server window is 65k, so it never compacts. The GPU holds 49.7 of 80 GB at 65k, so a 128k context fits.
|
| 233 |
+
3. **A fix that passes the agent's own checks but not the target tests:** django-11815 (1 of 2 target tests, the same at 50 and 100 turns), sphinx-10673 (0/1, patches of 164 and 175 lines), 11510 (0/2), 8265 (0/1), 9230 at 50 turns (0/1).
|
| 234 |
+
4. **Empty patch after long exploration:** django-11790 and sphinx-8265 and 9229 at 50 turns, sphinx-10435 in the rerun.
|
| 235 |
+
5. **A malformed tool call:** one WebFetch call in sphinx-10466 had template markup (`</function></tool_call><tool_call><function=WebFetch>`) inside its URL argument; one example seen, not counted across all runs.
|
| 236 |
+
6. **Environment friction:** in the first django-11790 transcript the agent spent turns finding a Python that works for the unprivileged user (one interpreter path returned permission denied) and imported Django through the system Python with a path hack.
|
| 237 |
+
7. **An oversized patch:** the resolved sphinx-9229 patch is 1,657 lines (the other resolved ones are 12 to 215); it passed with no regressions but would not survive code review. Contents not inspected.
|
| 238 |
+
|
| 239 |
+
### Setup caveats
|
| 240 |
+
- Thinking off (`enable_thinking` false), 65,536 context, sampling left to Claude Code and the server defaults.
|
| 241 |
+
- **Claude Code needs the rewriting proxy:** Qwen3.8's chat template raises "System message must be at the beginning" for the system-role entry Claude Code sends after the first user turn. The proxy folds it into the last user message; 1,594 requests went through, all 200 except the 5 context overflows.
|
| 242 |
+
- Docker-free environments, not the official images: uv venvs, `setuptools<70`, `Pygments==2.18.0`, Python 3.8 for django (the images use older versions), 37 of 50 instances reproduce.
|
| 243 |
+
- 20 instances: the interval is about +/-18-20 points, so 60% and 75% are not different from each other statistically.
|
| 244 |
+
- **Section 9's published agentic table (SWE-bench Pro, Multilingual, DeepSWE, NL2Repo, Toolathlon) is a different, harder set of benchmarks and is not comparable.** There is no published number for this exact setup.
|
| 245 |
+
|
| 246 |
+
### Verdict
|
| 247 |
+
k448 under Claude Code can do small, localized bug fixes: the 7 clean resolves are short patches (12 to 215 lines) at about 6 minutes each on the A100, and a "done" from the agent was right 8 times out of 9. It is not shown to be a daily coding agent. The no-help rate is between 35% and 75% on 20 instances, hard tasks hit the turn cap or the 65k context, and the agent does look up upstream fixes when it can, so its own skill cannot be separated from the lookups in this run. Speed on your PC is not measured (14 tokens/s on the L4 earlier would make 6 minutes into about 30).
|
| 248 |
+
|
| 249 |
+
**Next experiment, proposed and not run:** the same 20 instances offline (network blocked for the agent user, WebFetch and WebSearch disallowed, future git objects removed), a 128k context, the same turn caps, and a paired comparison with this table. About 2.5 to 3 hours of A100, roughly 17 to 20 units.
|
| 250 |
+
|
| 251 |
+
## 13. Overnight summary (2026-10-26, A100)
|
| 252 |
+
A100 time is from each run's own clock; units are time x 6.77 per hour, a rough figure that leaves out loading and idle time.
|
| 253 |
+
|
| 254 |
+
| # | Experiment | Result | Test | A100 time (about units) |
|
| 255 |
+
|---|---|---|---|---|
|
| 256 |
+
| 1 | Coding, 4k thinking budget (120 tasks) | 99/120 (LCB 41/60, CRUX 58/60) | baseline | 3,689 s (6.9) |
|
| 257 |
+
| 2 | Coding, no-think | 96/120 (LCB 38/60) | vs 4k: p = 0.508 | 2,888 s (5.4) |
|
| 258 |
+
| 3 | Redo of the 21 failures at 16k | 9 of 21 rescued | luck baseline about 17% | 4,516 s (8.5) |
|
| 259 |
+
| 4 | Two repair turns on the 10 still failing | 4 of 10 rescued (chained estimate 112/120) | estimate only | 3,411 s (6.4) |
|
| 260 |
+
| 5 | **Coding, clean rerun of all 120 at 16k** | **107/120 (89.2%), LCB 49/60** | vs 4k: p = 0.021 | 9,992 s (18.8) |
|
| 261 |
+
| 6 | 32k on the 11 still failing | 2 of 11 (likely luck) | none | 5,438 s (10.2) |
|
| 262 |
+
| 7 | Reasoning, no-think (60 tasks) | 50/60 | baseline | 468 s |
|
| 263 |
+
| 8 | Reasoning, 4k thinking on the 10 failures | 5 of 10 rescued | p about 0.016 vs luck baseline | 393 s |
|
| 264 |
+
| 9 | Reasoning, 16k thinking on the 10 failures | 3 of 10 rescued | p about 0.22 vs luck baseline | 1,315 s (rows 7 to 9: 4.1) |
|
| 265 |
+
| 10 | SWE-bench Verified Mini through Claude Code, 50 turns | 12/20 as run; 6/20 with no web lookup | none | 6,850 s (12.9) |
|
| 266 |
+
| 11 | Rerun of the 8 misses, 100 turns | +3 as run (+1 with no lookup) | none | 5,341 s (10.0) |
|
| 267 |
+
|
| 268 |
+
- **Coding:** a 16k thinking budget is the setting to use (107/120, significantly better than 4k); 32k adds nothing; repair turns on top rescue a few hard problems.
|
| 269 |
+
- **Reasoning:** thinking at 4k, not more; a bigger budget did not help.
|
| 270 |
+
- **Agentic:** 7 to 15 of 20, depending on whether web lookups count; not established until the offline rerun.
|
| 271 |
+
- **Units:** 84.10 at 06:20, 58.12 at 10:13, 51.37 at 11:13, **45.17 at 12:05**, burning 6.77 per hour while the runtime stays connected, idle or not.
|
| 272 |
+
- **A100 runtime:** disconnected and deleted at 12:10 on 2026-10-26 at your request, after the units reading of 45.17 at 12:05 (the balance cannot be read without a runtime, so the final figure is a little lower). The k448 and MTP files on that VM came from Hugging Face (download cache with the same commit hash), so they are re-downloadable; the raw SWE-bench transcripts, results JSONs and logs on the VM are gone (the compact CSVs and the report are saved locally). llama.cpp PR 30594 was not touched.
|
benchmarks/SPEED_PC.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# One-token routed-expert matvec on this PC (2026-10-26)
|
| 2 |
+
|
| 3 |
+
Tool: `bench.c` (build with `build.bat`, run with `run.bat <threads>`), CPU backend of `C:\Projects\llama.cpp-strata\build-clang`
|
| 4 |
+
(AVX2 + AVX-VNNI, no AVX-512), i7-13620H, DDR5-5200, 10 threads. 10 of 128 experts per op, ids rotated so the weights stream from RAM.
|
| 5 |
+
Shapes are k448-like guesses: gate/up k=2048 m=1024, down k=1024 m=2048. A 78 GB download was running in the background (light CPU use).
|
| 6 |
+
|
| 7 |
+
| type | gate/up Gweights/s (GB/s) | down Gweights/s (GB/s) | note |
|
| 8 |
+
|---|---|---|---|
|
| 9 |
+
| **iq2_s** (k448 gate/up) | 96.7 (31.0) | 90.4 (29.0) | compute-bound: about half of what RAM allows |
|
| 10 |
+
| **iq4_nl** (k448 down) | 93.4 (52.5) | 101.2 (57.0) | close to RAM speed |
|
| 11 |
+
| iq3_xxs | 61.4 (23.5) | 70.3 (26.9) | the slow one (Strata's model type) |
|
| 12 |
+
| q2_K | 183.1 (60.1) | 174.7 (57.3) | what a RAM-speed 2-bit kernel looks like |
|
| 13 |
+
| q4_K | 115.9 (65.2) | 118.8 (66.8) | RAM ceiling is about 65 GB/s |
|
| 14 |
+
| q4_0 | 112.7 (63.4) | 114.6 (64.5) | |
|
| 15 |
+
| q6_K | 71.7 (58.8) | 63.0 (51.7) | |
|
| 16 |
+
|
| 17 |
+
Reading: with k448's types the CPU expert work is about 95 Gweights/s. An IQ2_S kernel at RAM speed would be about 190 Gweights/s.
|
| 18 |
+
Estimate (not measured on the model): 2.36 B routed weights per token / 95 G = about 25 ms per token if every expert ran on the CPU.
|
| 19 |
+
|
| 20 |
+
## Server baseline on the model (Minecraft closed, Overwolf on)
|
| 21 |
+
no MTP 17.5 tok/s; MTP 1 draft 20.3-20.7; MTP 2 drafts 21-22 (acceptance 93%); GPU cache 645 MiB, hit rate about 14%. With Minecraft running: 11.7 no-MTP. Bigger cache + MTP draft fails to load (bug).
|
| 22 |
+
|
| 23 |
+
## All-VRAM test
|
| 24 |
+
no MTP, cache 3200 MiB, margin 250, ubatch 512: 20.1-22.5 tok/s, hit 52%, VRAM 7947/8188. MTP2 + cache 1800 (margin 700): 21.4-22.4, hit 29%. Cache 2400+ with MTP: draft fails to load (VRAM). They do not stack.
|
| 25 |
+
|
| 26 |
+
## Cache/draft, long prompts, kernel (2026-10-26)
|
| 27 |
+
Draft on CPU + cache 3000: 21.6 tok/s (no gain). Prefill: 5,198 tokens at 164 tok/s; repeat prompt 0.2 s. Decode on prose explanation 14-16 tok/s (draft acceptance 65% vs 93% for code). IQ2_S kernel already AVX2 with table gathers; est. upside under 10%, not written.
|
benchmarks/results/k448_code_nothink_a100_compact.csv
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,pass,tokens
|
| 2 |
+
lcb_hard_3744,1,2060
|
| 3 |
+
lcb_easy_3778,1,85
|
| 4 |
+
lcb_easy_abc392_a,1,177
|
| 5 |
+
lcb_medium_arc195_a,1,3119
|
| 6 |
+
lcb_hard_abc397_g,0,8192
|
| 7 |
+
lcb_hard_arc192_e,0,7505
|
| 8 |
+
lcb_hard_arc196_d,0,8192
|
| 9 |
+
lcb_hard_abc400_e,1,1019
|
| 10 |
+
lcb_hard_arc194_d,0,8192
|
| 11 |
+
lcb_medium_3779,0,8192
|
| 12 |
+
lcb_hard_abc392_f,0,818
|
| 13 |
+
lcb_easy_abc395_a,1,155
|
| 14 |
+
lcb_medium_3786,1,1317
|
| 15 |
+
lcb_hard_arc195_e,0,8192
|
| 16 |
+
lcb_hard_abc398_d,1,3789
|
| 17 |
+
lcb_hard_abc398_g,0,8192
|
| 18 |
+
lcb_medium_abc392_d,1,512
|
| 19 |
+
lcb_easy_abc393_a,1,518
|
| 20 |
+
lcb_hard_abc391_g,1,1557
|
| 21 |
+
lcb_hard_abc394_g,0,8192
|
| 22 |
+
lcb_medium_3805,1,8192
|
| 23 |
+
lcb_hard_abc396_g,1,754
|
| 24 |
+
lcb_easy_3817,1,100
|
| 25 |
+
lcb_easy_3832,1,1697
|
| 26 |
+
lcb_hard_3777,0,8192
|
| 27 |
+
lcb_hard_abc393_d,1,423
|
| 28 |
+
lcb_hard_abc388_g,0,2049
|
| 29 |
+
lcb_hard_abc394_f,0,6907
|
| 30 |
+
lcb_hard_abc389_f,1,3545
|
| 31 |
+
lcb_medium_3677,1,692
|
| 32 |
+
lcb_medium_3722,0,2127
|
| 33 |
+
lcb_hard_arc190_c,0,8165
|
| 34 |
+
lcb_hard_abc387_f,0,8192
|
| 35 |
+
lcb_hard_3783,1,5241
|
| 36 |
+
lcb_hard_arc192_d,0,8192
|
| 37 |
+
lcb_hard_abc393_e,1,748
|
| 38 |
+
lcb_medium_abc388_c,1,863
|
| 39 |
+
lcb_easy_3753,1,152
|
| 40 |
+
lcb_hard_3697,1,3650
|
| 41 |
+
lcb_hard_arc196_b,0,8192
|
| 42 |
+
lcb_easy_3736,1,109
|
| 43 |
+
lcb_hard_3789,1,4919
|
| 44 |
+
lcb_medium_arc192_a,0,8192
|
| 45 |
+
lcb_medium_abc392_c,1,978
|
| 46 |
+
lcb_medium_3785,1,1206
|
| 47 |
+
lcb_medium_3737,1,1899
|
| 48 |
+
lcb_medium_3748,1,1066
|
| 49 |
+
lcb_easy_3731,1,93
|
| 50 |
+
lcb_medium_abc398_b,1,676
|
| 51 |
+
lcb_easy_abc400_b,1,803
|
| 52 |
+
lcb_hard_arc193_b,0,8192
|
| 53 |
+
lcb_medium_abc399_d,0,8192
|
| 54 |
+
lcb_medium_abc400_d,1,3457
|
| 55 |
+
lcb_medium_abc399_c,1,520
|
| 56 |
+
lcb_medium_3760,1,1475
|
| 57 |
+
lcb_medium_3776,0,8192
|
| 58 |
+
lcb_medium_3743,1,2328
|
| 59 |
+
lcb_easy_abc396_b,1,177
|
| 60 |
+
lcb_easy_3799,1,298
|
| 61 |
+
lcb_hard_3674,0,8192
|
| 62 |
+
crux_o_sample_595,1,203
|
| 63 |
+
crux_i_sample_123,1,3696
|
| 64 |
+
crux_o_sample_32,1,209
|
| 65 |
+
crux_i_sample_198,1,1311
|
| 66 |
+
crux_o_sample_630,1,284
|
| 67 |
+
crux_i_sample_423,1,6083
|
| 68 |
+
crux_o_sample_388,1,217
|
| 69 |
+
crux_i_sample_379,1,663
|
| 70 |
+
crux_o_sample_64,1,555
|
| 71 |
+
crux_i_sample_506,1,593
|
| 72 |
+
crux_o_sample_560,1,142
|
| 73 |
+
crux_i_sample_204,1,624
|
| 74 |
+
crux_o_sample_760,1,547
|
| 75 |
+
crux_i_sample_308,1,594
|
| 76 |
+
crux_o_sample_379,1,224
|
| 77 |
+
crux_i_sample_223,1,656
|
| 78 |
+
crux_o_sample_184,1,237
|
| 79 |
+
crux_i_sample_374,1,804
|
| 80 |
+
crux_o_sample_385,1,509
|
| 81 |
+
crux_i_sample_11,1,431
|
| 82 |
+
crux_o_sample_155,0,1004
|
| 83 |
+
crux_i_sample_39,1,339
|
| 84 |
+
crux_o_sample_387,1,221
|
| 85 |
+
crux_i_sample_544,1,760
|
| 86 |
+
crux_o_sample_445,1,460
|
| 87 |
+
crux_i_sample_257,1,950
|
| 88 |
+
crux_o_sample_144,1,137
|
| 89 |
+
crux_i_sample_610,1,2444
|
| 90 |
+
crux_o_sample_728,1,176
|
| 91 |
+
crux_i_sample_490,1,421
|
| 92 |
+
crux_o_sample_670,1,345
|
| 93 |
+
crux_i_sample_20,1,385
|
| 94 |
+
crux_o_sample_694,1,252
|
| 95 |
+
crux_i_sample_551,1,772
|
| 96 |
+
crux_o_sample_747,1,315
|
| 97 |
+
crux_i_sample_260,1,910
|
| 98 |
+
crux_o_sample_286,1,397
|
| 99 |
+
crux_i_sample_549,1,880
|
| 100 |
+
crux_o_sample_650,1,166
|
| 101 |
+
crux_i_sample_783,1,860
|
| 102 |
+
crux_o_sample_114,1,1400
|
| 103 |
+
crux_i_sample_457,1,942
|
| 104 |
+
crux_o_sample_611,1,202
|
| 105 |
+
crux_i_sample_515,1,617
|
| 106 |
+
crux_o_sample_405,1,314
|
| 107 |
+
crux_i_sample_336,1,515
|
| 108 |
+
crux_o_sample_349,1,301
|
| 109 |
+
crux_i_sample_663,1,751
|
| 110 |
+
crux_o_sample_599,1,505
|
| 111 |
+
crux_i_sample_149,1,1256
|
| 112 |
+
crux_o_sample_669,1,291
|
| 113 |
+
crux_i_sample_703,1,1390
|
| 114 |
+
crux_o_sample_136,0,590
|
| 115 |
+
crux_i_sample_608,1,563
|
| 116 |
+
crux_o_sample_210,1,198
|
| 117 |
+
crux_i_sample_673,1,568
|
| 118 |
+
crux_o_sample_682,1,220
|
| 119 |
+
crux_i_sample_291,1,1010
|
| 120 |
+
crux_o_sample_561,1,202
|
| 121 |
+
crux_i_sample_557,1,635
|
benchmarks/results/k448_code_think16k_full_compact.csv
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,pass,tokens
|
| 2 |
+
lcb_hard_3744,1,13560
|
| 3 |
+
lcb_easy_3778,1,458
|
| 4 |
+
lcb_easy_abc392_a,1,919
|
| 5 |
+
lcb_medium_arc195_a,1,4474
|
| 6 |
+
lcb_hard_abc397_g,1,17532
|
| 7 |
+
lcb_hard_arc192_e,0,17527
|
| 8 |
+
lcb_hard_arc196_d,0,16399
|
| 9 |
+
lcb_hard_abc400_e,1,16663
|
| 10 |
+
lcb_hard_arc194_d,0,16934
|
| 11 |
+
lcb_medium_3779,1,16498
|
| 12 |
+
lcb_hard_abc392_f,0,16839
|
| 13 |
+
lcb_easy_abc395_a,1,370
|
| 14 |
+
lcb_medium_3786,1,16865
|
| 15 |
+
lcb_hard_arc195_e,1,17009
|
| 16 |
+
lcb_hard_abc398_d,1,9100
|
| 17 |
+
lcb_hard_abc398_g,0,16718
|
| 18 |
+
lcb_medium_abc392_d,1,16074
|
| 19 |
+
lcb_easy_abc393_a,1,779
|
| 20 |
+
lcb_hard_abc391_g,1,14693
|
| 21 |
+
lcb_hard_abc394_g,1,17640
|
| 22 |
+
lcb_medium_3805,1,16656
|
| 23 |
+
lcb_hard_abc396_g,1,17045
|
| 24 |
+
lcb_easy_3817,1,360
|
| 25 |
+
lcb_easy_3832,1,7308
|
| 26 |
+
lcb_hard_3777,1,17628
|
| 27 |
+
lcb_hard_abc393_d,1,4230
|
| 28 |
+
lcb_hard_abc388_g,1,17384
|
| 29 |
+
lcb_hard_abc394_f,1,16954
|
| 30 |
+
lcb_hard_abc389_f,1,17488
|
| 31 |
+
lcb_medium_3677,1,16896
|
| 32 |
+
lcb_medium_3722,1,12331
|
| 33 |
+
lcb_hard_arc190_c,0,17422
|
| 34 |
+
lcb_hard_abc387_f,0,17261
|
| 35 |
+
lcb_hard_3783,1,11649
|
| 36 |
+
lcb_hard_arc192_d,1,17481
|
| 37 |
+
lcb_hard_abc393_e,0,16979
|
| 38 |
+
lcb_medium_abc388_c,1,3173
|
| 39 |
+
lcb_easy_3753,1,448
|
| 40 |
+
lcb_hard_3697,1,16831
|
| 41 |
+
lcb_hard_arc196_b,1,17371
|
| 42 |
+
lcb_easy_3736,1,772
|
| 43 |
+
lcb_hard_3789,1,16774
|
| 44 |
+
lcb_medium_arc192_a,0,16900
|
| 45 |
+
lcb_medium_abc392_c,1,822
|
| 46 |
+
lcb_medium_3785,1,1293
|
| 47 |
+
lcb_medium_3737,1,6858
|
| 48 |
+
lcb_medium_3748,1,1953
|
| 49 |
+
lcb_easy_3731,1,1419
|
| 50 |
+
lcb_medium_abc398_b,1,562
|
| 51 |
+
lcb_easy_abc400_b,1,1476
|
| 52 |
+
lcb_hard_arc193_b,0,20480
|
| 53 |
+
lcb_medium_abc399_d,1,16745
|
| 54 |
+
lcb_medium_abc400_d,1,16900
|
| 55 |
+
lcb_medium_abc399_c,1,1324
|
| 56 |
+
lcb_medium_3760,1,6367
|
| 57 |
+
lcb_medium_3776,1,16989
|
| 58 |
+
lcb_medium_3743,1,16140
|
| 59 |
+
lcb_easy_abc396_b,1,510
|
| 60 |
+
lcb_easy_3799,1,3001
|
| 61 |
+
lcb_hard_3674,0,17132
|
| 62 |
+
crux_o_sample_595,1,564
|
| 63 |
+
crux_i_sample_123,1,2206
|
| 64 |
+
crux_o_sample_32,1,402
|
| 65 |
+
crux_i_sample_198,1,982
|
| 66 |
+
crux_o_sample_630,1,1180
|
| 67 |
+
crux_i_sample_423,1,4725
|
| 68 |
+
crux_o_sample_388,1,428
|
| 69 |
+
crux_i_sample_379,1,467
|
| 70 |
+
crux_o_sample_64,1,838
|
| 71 |
+
crux_i_sample_506,1,542
|
| 72 |
+
crux_o_sample_560,1,425
|
| 73 |
+
crux_i_sample_204,1,541
|
| 74 |
+
crux_o_sample_760,1,319
|
| 75 |
+
crux_i_sample_308,1,753
|
| 76 |
+
crux_o_sample_379,1,421
|
| 77 |
+
crux_i_sample_223,1,386
|
| 78 |
+
crux_o_sample_184,1,322
|
| 79 |
+
crux_i_sample_374,1,654
|
| 80 |
+
crux_o_sample_385,1,726
|
| 81 |
+
crux_i_sample_11,1,404
|
| 82 |
+
crux_o_sample_155,1,1422
|
| 83 |
+
crux_i_sample_39,1,346
|
| 84 |
+
crux_o_sample_387,1,195
|
| 85 |
+
crux_i_sample_544,1,2334
|
| 86 |
+
crux_o_sample_445,0,1312
|
| 87 |
+
crux_i_sample_257,1,999
|
| 88 |
+
crux_o_sample_144,1,164
|
| 89 |
+
crux_i_sample_610,1,2645
|
| 90 |
+
crux_o_sample_728,1,274
|
| 91 |
+
crux_i_sample_490,1,513
|
| 92 |
+
crux_o_sample_670,1,694
|
| 93 |
+
crux_i_sample_20,1,295
|
| 94 |
+
crux_o_sample_694,1,623
|
| 95 |
+
crux_i_sample_551,1,940
|
| 96 |
+
crux_o_sample_747,1,394
|
| 97 |
+
crux_i_sample_260,1,698
|
| 98 |
+
crux_o_sample_286,1,795
|
| 99 |
+
crux_i_sample_549,1,468
|
| 100 |
+
crux_o_sample_650,1,230
|
| 101 |
+
crux_i_sample_783,1,673
|
| 102 |
+
crux_o_sample_114,1,536
|
| 103 |
+
crux_i_sample_457,1,790
|
| 104 |
+
crux_o_sample_611,1,287
|
| 105 |
+
crux_i_sample_515,1,326
|
| 106 |
+
crux_o_sample_405,1,355
|
| 107 |
+
crux_i_sample_336,1,1078
|
| 108 |
+
crux_o_sample_349,1,867
|
| 109 |
+
crux_i_sample_663,1,302
|
| 110 |
+
crux_o_sample_599,1,999
|
| 111 |
+
crux_i_sample_149,1,1678
|
| 112 |
+
crux_o_sample_669,1,647
|
| 113 |
+
crux_i_sample_703,1,787
|
| 114 |
+
crux_o_sample_136,0,2757
|
| 115 |
+
crux_i_sample_608,1,633
|
| 116 |
+
crux_o_sample_210,1,379
|
| 117 |
+
crux_i_sample_673,1,792
|
| 118 |
+
crux_o_sample_682,1,505
|
| 119 |
+
crux_i_sample_291,1,1122
|
| 120 |
+
crux_o_sample_561,1,282
|
| 121 |
+
crux_i_sample_557,1,983
|
benchmarks/results/k448_code_think16k_redo_compact.csv
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,pass,tokens
|
| 2 |
+
lcb_hard_abc397_g,1,17629
|
| 3 |
+
lcb_hard_arc192_e,0,17677
|
| 4 |
+
lcb_hard_arc196_d,0,16399
|
| 5 |
+
lcb_hard_arc194_d,0,16936
|
| 6 |
+
lcb_hard_abc392_f,0,16895
|
| 7 |
+
lcb_hard_arc195_e,1,16935
|
| 8 |
+
lcb_hard_abc398_g,0,16691
|
| 9 |
+
lcb_hard_abc394_g,1,17923
|
| 10 |
+
lcb_medium_3805,1,16656
|
| 11 |
+
lcb_hard_abc394_f,1,16982
|
| 12 |
+
lcb_hard_arc190_c,0,17264
|
| 13 |
+
lcb_hard_abc387_f,0,17305
|
| 14 |
+
lcb_hard_arc196_b,0,17359
|
| 15 |
+
lcb_medium_arc192_a,1,17108
|
| 16 |
+
lcb_hard_arc193_b,0,20480
|
| 17 |
+
lcb_medium_abc399_d,1,16745
|
| 18 |
+
lcb_medium_abc400_d,1,16900
|
| 19 |
+
lcb_medium_3776,1,16989
|
| 20 |
+
lcb_hard_3674,0,18361
|
| 21 |
+
crux_o_sample_445,0,1312
|
| 22 |
+
crux_o_sample_136,0,3059
|
benchmarks/results/k448_code_think16k_retry_compact.csv
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,pass,tokens,retries
|
| 2 |
+
lcb_hard_arc192_e,1,35351,2
|
| 3 |
+
lcb_hard_arc196_d,0,32807,2
|
| 4 |
+
lcb_hard_arc194_d,1,16997,1
|
| 5 |
+
lcb_hard_abc392_f,0,0,0
|
| 6 |
+
lcb_hard_abc398_g,0,33498,2
|
| 7 |
+
lcb_hard_arc190_c,0,34698,2
|
| 8 |
+
lcb_hard_abc387_f,0,0,0
|
| 9 |
+
lcb_hard_arc196_b,1,34387,2
|
| 10 |
+
lcb_hard_arc193_b,0,35784,2
|
| 11 |
+
lcb_hard_3674,1,17212,1
|
benchmarks/results/k448_code_think32k_redo_compact.csv
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,pass,tokens
|
| 2 |
+
lcb_hard_arc192_e,0,34464
|
| 3 |
+
lcb_hard_arc196_d,0,34805
|
| 4 |
+
lcb_hard_arc194_d,0,33330
|
| 5 |
+
lcb_hard_abc392_f,0,33330
|
| 6 |
+
lcb_hard_abc398_g,0,33039
|
| 7 |
+
lcb_hard_arc190_c,0,35309
|
| 8 |
+
lcb_hard_abc387_f,0,34266
|
| 9 |
+
lcb_hard_abc393_e,1,33970
|
| 10 |
+
lcb_medium_arc192_a,1,33293
|
| 11 |
+
lcb_hard_arc193_b,0,33647
|
| 12 |
+
lcb_hard_3674,0,34103
|
benchmarks/results/k448_code_think_compact.csv
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,pass,tokens
|
| 2 |
+
lcb_hard_3744,1,4410
|
| 3 |
+
lcb_easy_3778,1,458
|
| 4 |
+
lcb_easy_abc392_a,1,919
|
| 5 |
+
lcb_medium_arc195_a,1,4448
|
| 6 |
+
lcb_hard_abc397_g,0,6412
|
| 7 |
+
lcb_hard_arc192_e,0,6590
|
| 8 |
+
lcb_hard_arc196_d,0,4268
|
| 9 |
+
lcb_hard_abc400_e,1,4389
|
| 10 |
+
lcb_hard_arc194_d,0,4900
|
| 11 |
+
lcb_medium_3779,1,4274
|
| 12 |
+
lcb_hard_abc392_f,0,4437
|
| 13 |
+
lcb_easy_abc395_a,1,370
|
| 14 |
+
lcb_medium_3786,1,4515
|
| 15 |
+
lcb_hard_arc195_e,0,4552
|
| 16 |
+
lcb_hard_abc398_d,1,4364
|
| 17 |
+
lcb_hard_abc398_g,0,4413
|
| 18 |
+
lcb_medium_abc392_d,1,4493
|
| 19 |
+
lcb_easy_abc393_a,1,779
|
| 20 |
+
lcb_hard_abc391_g,1,4675
|
| 21 |
+
lcb_hard_abc394_g,0,4923
|
| 22 |
+
lcb_medium_3805,0,4727
|
| 23 |
+
lcb_hard_abc396_g,1,4706
|
| 24 |
+
lcb_easy_3817,1,360
|
| 25 |
+
lcb_easy_3832,1,4169
|
| 26 |
+
lcb_hard_3777,1,4719
|
| 27 |
+
lcb_hard_abc393_d,1,4230
|
| 28 |
+
lcb_hard_abc388_g,1,4779
|
| 29 |
+
lcb_hard_abc394_f,0,4531
|
| 30 |
+
lcb_hard_abc389_f,1,5117
|
| 31 |
+
lcb_medium_3677,1,4521
|
| 32 |
+
lcb_medium_3722,1,4362
|
| 33 |
+
lcb_hard_arc190_c,0,8192
|
| 34 |
+
lcb_hard_abc387_f,0,5298
|
| 35 |
+
lcb_hard_3783,1,4697
|
| 36 |
+
lcb_hard_arc192_d,1,5087
|
| 37 |
+
lcb_hard_abc393_e,1,4479
|
| 38 |
+
lcb_medium_abc388_c,1,3173
|
| 39 |
+
lcb_easy_3753,1,448
|
| 40 |
+
lcb_hard_3697,1,4452
|
| 41 |
+
lcb_hard_arc196_b,0,5168
|
| 42 |
+
lcb_easy_3736,1,772
|
| 43 |
+
lcb_hard_3789,1,4593
|
| 44 |
+
lcb_medium_arc192_a,0,5127
|
| 45 |
+
lcb_medium_abc392_c,1,822
|
| 46 |
+
lcb_medium_3785,1,1293
|
| 47 |
+
lcb_medium_3737,1,4344
|
| 48 |
+
lcb_medium_3748,1,1953
|
| 49 |
+
lcb_easy_3731,1,1419
|
| 50 |
+
lcb_medium_abc398_b,1,562
|
| 51 |
+
lcb_easy_abc400_b,1,1476
|
| 52 |
+
lcb_hard_arc193_b,0,4545
|
| 53 |
+
lcb_medium_abc399_d,0,4540
|
| 54 |
+
lcb_medium_abc400_d,0,4633
|
| 55 |
+
lcb_medium_abc399_c,1,1324
|
| 56 |
+
lcb_medium_3760,1,4249
|
| 57 |
+
lcb_medium_3776,0,5012
|
| 58 |
+
lcb_medium_3743,1,4275
|
| 59 |
+
lcb_easy_abc396_b,1,510
|
| 60 |
+
lcb_easy_3799,1,3001
|
| 61 |
+
lcb_hard_3674,0,8192
|
| 62 |
+
crux_o_sample_595,1,564
|
| 63 |
+
crux_i_sample_123,1,2206
|
| 64 |
+
crux_o_sample_32,1,402
|
| 65 |
+
crux_i_sample_198,1,982
|
| 66 |
+
crux_o_sample_630,1,1180
|
| 67 |
+
crux_i_sample_423,1,4149
|
| 68 |
+
crux_o_sample_388,1,428
|
| 69 |
+
crux_i_sample_379,1,467
|
| 70 |
+
crux_o_sample_64,1,838
|
| 71 |
+
crux_i_sample_506,1,542
|
| 72 |
+
crux_o_sample_560,1,425
|
| 73 |
+
crux_i_sample_204,1,541
|
| 74 |
+
crux_o_sample_760,1,319
|
| 75 |
+
crux_i_sample_308,1,753
|
| 76 |
+
crux_o_sample_379,1,421
|
| 77 |
+
crux_i_sample_223,1,386
|
| 78 |
+
crux_o_sample_184,1,322
|
| 79 |
+
crux_i_sample_374,1,654
|
| 80 |
+
crux_o_sample_385,1,726
|
| 81 |
+
crux_i_sample_11,1,404
|
| 82 |
+
crux_o_sample_155,1,1422
|
| 83 |
+
crux_i_sample_39,1,346
|
| 84 |
+
crux_o_sample_387,1,195
|
| 85 |
+
crux_i_sample_544,1,2334
|
| 86 |
+
crux_o_sample_445,0,1312
|
| 87 |
+
crux_i_sample_257,1,999
|
| 88 |
+
crux_o_sample_144,1,164
|
| 89 |
+
crux_i_sample_610,1,2645
|
| 90 |
+
crux_o_sample_728,1,274
|
| 91 |
+
crux_i_sample_490,1,513
|
| 92 |
+
crux_o_sample_670,1,694
|
| 93 |
+
crux_i_sample_20,1,295
|
| 94 |
+
crux_o_sample_694,1,623
|
| 95 |
+
crux_i_sample_551,1,940
|
| 96 |
+
crux_o_sample_747,1,394
|
| 97 |
+
crux_i_sample_260,1,698
|
| 98 |
+
crux_o_sample_286,1,795
|
| 99 |
+
crux_i_sample_549,1,468
|
| 100 |
+
crux_o_sample_650,1,230
|
| 101 |
+
crux_i_sample_783,1,673
|
| 102 |
+
crux_o_sample_114,1,536
|
| 103 |
+
crux_i_sample_457,1,790
|
| 104 |
+
crux_o_sample_611,1,287
|
| 105 |
+
crux_i_sample_515,1,326
|
| 106 |
+
crux_o_sample_405,1,355
|
| 107 |
+
crux_i_sample_336,1,1078
|
| 108 |
+
crux_o_sample_349,1,867
|
| 109 |
+
crux_i_sample_663,1,302
|
| 110 |
+
crux_o_sample_599,1,999
|
| 111 |
+
crux_i_sample_149,1,1678
|
| 112 |
+
crux_o_sample_669,1,647
|
| 113 |
+
crux_i_sample_703,1,787
|
| 114 |
+
crux_o_sample_136,0,2757
|
| 115 |
+
crux_i_sample_608,1,633
|
| 116 |
+
crux_o_sample_210,1,379
|
| 117 |
+
crux_i_sample_673,1,792
|
| 118 |
+
crux_o_sample_682,1,505
|
| 119 |
+
crux_i_sample_291,1,1122
|
| 120 |
+
crux_o_sample_561,1,282
|
| 121 |
+
crux_i_sample_557,1,983
|
benchmarks/results/k448_reason_nothink_compact.csv
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,pass,tokens
|
| 2 |
+
reason_mmlu3028,1,719
|
| 3 |
+
reason_mmlu10879,1,271
|
| 4 |
+
reason_bbh_logical_deduction_five_objects_0,1,630
|
| 5 |
+
reason_mmlu11759,0,2048
|
| 6 |
+
reason_mmlu8693,1,302
|
| 7 |
+
reason_bbh_tracking_shuffled_objects_five_objects_0,1,494
|
| 8 |
+
reason_mmlu1760,1,742
|
| 9 |
+
reason_mmlu6359,1,603
|
| 10 |
+
reason_bbh_date_understanding_0,1,432
|
| 11 |
+
reason_mmlu4584,0,2048
|
| 12 |
+
reason_mmlu7301,1,685
|
| 13 |
+
reason_bbh_web_of_lies_0,1,263
|
| 14 |
+
reason_mmlu5893,1,259
|
| 15 |
+
reason_mmlu9408,1,739
|
| 16 |
+
reason_bbh_boolean_expressions_0,1,228
|
| 17 |
+
reason_mmlu4770,1,491
|
| 18 |
+
reason_mmlu2310,1,543
|
| 19 |
+
reason_bbh_navigate_0,1,128
|
| 20 |
+
reason_mmlu656,1,557
|
| 21 |
+
reason_mmlu10734,1,933
|
| 22 |
+
reason_bbh_formal_fallacies_0,1,1333
|
| 23 |
+
reason_mmlu4613,0,2048
|
| 24 |
+
reason_mmlu4984,1,733
|
| 25 |
+
reason_bbh_object_counting_0,1,191
|
| 26 |
+
reason_mmlu6184,0,2048
|
| 27 |
+
reason_mmlu3337,1,676
|
| 28 |
+
reason_bbh_logical_deduction_five_objects_1,1,512
|
| 29 |
+
reason_mmlu10806,1,168
|
| 30 |
+
reason_mmlu12187,0,2048
|
| 31 |
+
reason_bbh_tracking_shuffled_objects_five_objects_1,1,551
|
| 32 |
+
reason_mmlu2156,1,573
|
| 33 |
+
reason_mmlu527,0,282
|
| 34 |
+
reason_bbh_date_understanding_1,1,289
|
| 35 |
+
reason_mmlu10323,1,527
|
| 36 |
+
reason_mmlu5812,1,216
|
| 37 |
+
reason_bbh_web_of_lies_1,1,212
|
| 38 |
+
reason_mmlu962,1,714
|
| 39 |
+
reason_mmlu8463,1,445
|
| 40 |
+
reason_bbh_boolean_expressions_1,1,285
|
| 41 |
+
reason_mmlu10422,1,659
|
| 42 |
+
reason_mmlu7515,1,586
|
| 43 |
+
reason_bbh_navigate_1,1,158
|
| 44 |
+
reason_mmlu2640,1,446
|
| 45 |
+
reason_mmlu4987,0,567
|
| 46 |
+
reason_bbh_formal_fallacies_1,1,1616
|
| 47 |
+
reason_mmlu3166,1,552
|
| 48 |
+
reason_mmlu1366,0,830
|
| 49 |
+
reason_bbh_object_counting_1,1,263
|
| 50 |
+
reason_mmlu11789,0,2048
|
| 51 |
+
reason_mmlu5632,1,398
|
| 52 |
+
reason_bbh_logical_deduction_five_objects_2,1,673
|
| 53 |
+
reason_mmlu200,1,680
|
| 54 |
+
reason_mmlu8011,1,990
|
| 55 |
+
reason_bbh_tracking_shuffled_objects_five_objects_2,1,461
|
| 56 |
+
reason_mmlu6177,1,600
|
| 57 |
+
reason_mmlu10443,1,482
|
| 58 |
+
reason_bbh_date_understanding_2,1,244
|
| 59 |
+
reason_mmlu11236,0,454
|
| 60 |
+
reason_mmlu7172,1,680
|
| 61 |
+
reason_bbh_web_of_lies_2,1,279
|
benchmarks/results/k448_reason_think16k_compact.csv
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,pass,tokens
|
| 2 |
+
reason_mmlu11759,1,16721
|
| 3 |
+
reason_mmlu4584,0,12966
|
| 4 |
+
reason_mmlu4613,0,16697
|
| 5 |
+
reason_mmlu6184,0,16457
|
| 6 |
+
reason_mmlu12187,1,16565
|
| 7 |
+
reason_mmlu527,0,454
|
| 8 |
+
reason_mmlu4987,0,902
|
| 9 |
+
reason_mmlu1366,0,4612
|
| 10 |
+
reason_mmlu11789,0,20480
|
| 11 |
+
reason_mmlu11236,1,339
|
benchmarks/results/k448_reason_think4k_compact.csv
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,pass,tokens
|
| 2 |
+
reason_mmlu11759,1,4447
|
| 3 |
+
reason_mmlu4584,0,4199
|
| 4 |
+
reason_mmlu4613,1,4278
|
| 5 |
+
reason_mmlu6184,0,4159
|
| 6 |
+
reason_mmlu12187,1,4206
|
| 7 |
+
reason_mmlu527,0,454
|
| 8 |
+
reason_mmlu4987,0,902
|
| 9 |
+
reason_mmlu1366,0,4268
|
| 10 |
+
reason_mmlu11789,1,4240
|
| 11 |
+
reason_mmlu11236,1,339
|
benchmarks/results/k448_swe_compact.csv
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,resolved,turns,tool_calls,tool_errors,patch_lines,secs
|
| 2 |
+
django__django-11790,0,51,50,4,0,316
|
| 3 |
+
django__django-11815,0,51,50,9,18,360
|
| 4 |
+
django__django-11848,1,22,21,2,64,177
|
| 5 |
+
django__django-11880,1,39,38,4,12,257
|
| 6 |
+
django__django-11885,1,51,50,1,215,340
|
| 7 |
+
django__django-11951,1,49,48,1,14,334
|
| 8 |
+
django__django-11964,1,58,57,3,19,379
|
| 9 |
+
django__django-11999,1,47,46,3,17,293
|
| 10 |
+
django__django-12039,1,51,50,1,32,306
|
| 11 |
+
django__django-12050,1,42,41,9,16,266
|
| 12 |
+
sphinx-doc__sphinx-10323,1,32,31,1,29,230
|
| 13 |
+
sphinx-doc__sphinx-10435,0,51,52,1,27,380
|
| 14 |
+
sphinx-doc__sphinx-10466,1,51,50,2,27,366
|
| 15 |
+
sphinx-doc__sphinx-10673,0,51,57,1,164,370
|
| 16 |
+
sphinx-doc__sphinx-11510,0,51,54,3,75,325
|
| 17 |
+
sphinx-doc__sphinx-8265,0,51,50,2,0,920
|
| 18 |
+
sphinx-doc__sphinx-9229,0,51,51,5,0,314
|
| 19 |
+
sphinx-doc__sphinx-9230,0,51,53,4,41,365
|
| 20 |
+
sphinx-doc__sphinx-9320,1,51,50,4,57,448
|
| 21 |
+
sphinx-doc__sphinx-9367,1,14,13,2,15,104
|
benchmarks/results/k448_swe_t100_compact.csv
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
id,resolved,turns,tool_calls,tool_errors,patch_lines,secs
|
| 2 |
+
django__django-11790,1,51,50,5,16,319
|
| 3 |
+
django__django-11815,0,101,100,4,26,641
|
| 4 |
+
sphinx-doc__sphinx-10435,0,94,93,9,0,800
|
| 5 |
+
sphinx-doc__sphinx-10673,0,80,79,2,175,557
|
| 6 |
+
sphinx-doc__sphinx-11510,0,96,95,5,162,640
|
| 7 |
+
sphinx-doc__sphinx-8265,0,98,97,2,39,794
|
| 8 |
+
sphinx-doc__sphinx-9229,1,76,75,4,1657,561
|
| 9 |
+
sphinx-doc__sphinx-9230,1,101,105,5,13,1029
|
benchmarks/scripts/07_domain_eval.py
ADDED
|
@@ -0,0 +1,630 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
"""
|
| 4 |
+
07_domain_eval.py - does a quantized Tessera keep what matters (Turkish, English, code, math)? Everything is scored against a
|
| 5 |
+
reference model (the Q4), because the original checkpoint cannot be run on the test machines.
|
| 6 |
+
|
| 7 |
+
run 56 checkable prompts sent to a llama-server (OpenAI API): 11 Python functions with hidden unit tests (3 asked in Turkish),
|
| 8 |
+
16 math word problems (8 English + the same 8 in Turkish), 14 Turkish and 15 English language tasks (reading comprehension,
|
| 9 |
+
Turkish alphabet order, i/I casing, vowel-harmony plurals, instruction following, extraction, cross-language answers).
|
| 10 |
+
Problems with numbers are generated from a seed, so the answers are computed, not typed. Greedy decoding.
|
| 11 |
+
kld llama-perplexity per domain over the held-out text of 06_build_eval_set.py: mean KL divergence and same-top-token rate
|
| 12 |
+
against the reference model's saved logits (--save-base stores them for the reference)
|
| 13 |
+
compare table of result files; every task category as a % of the first file (the reference)
|
| 14 |
+
selftest the checkers accept the reference answers and reject garbage; no model needed
|
| 15 |
+
|
| 16 |
+
python 07_domain_eval.py run --bin <llama.cpp>/build/bin --model q4.gguf --ot '<-ot regex>' --name q4 --no-think (starts llama-server)
|
| 17 |
+
python 07_domain_eval.py run --bin <llama.cpp>/build/bin --model ours.gguf --ot '<-ot regex>' --name ours --no-think
|
| 18 |
+
python 07_domain_eval.py run --endpoint http://127.0.0.1:8080 --name x --no-think (a llama-server that is already running)
|
| 19 |
+
python 07_domain_eval.py compare results_q4.json results_ours.json
|
| 20 |
+
python 07_domain_eval.py kld --bin <llama.cpp>/build/bin --model q4.gguf --ot '<-ot regex>' --name q4 --save-base
|
| 21 |
+
python 07_domain_eval.py kld --bin <llama.cpp>/build/bin --model ours.gguf --ot '<-ot regex>' --name ours
|
| 22 |
+
|
| 23 |
+
`run` EXECUTES THE PYTHON THE MODEL WRITES (10 s limit, 2 GB, empty temp directory, nothing else isolated): use Colab or a throw-away
|
| 24 |
+
machine. 56 tasks are a smoke test: a difference of a few tasks is noise (one task is about 9 points of the 11 code tasks).
|
| 25 |
+
"""
|
| 26 |
+
from __future__ import annotations
|
| 27 |
+
|
| 28 |
+
import argparse
|
| 29 |
+
import json
|
| 30 |
+
import math
|
| 31 |
+
import os
|
| 32 |
+
import random
|
| 33 |
+
import re
|
| 34 |
+
import shlex
|
| 35 |
+
import subprocess
|
| 36 |
+
import sys
|
| 37 |
+
import tempfile
|
| 38 |
+
import time
|
| 39 |
+
import unicodedata
|
| 40 |
+
import urllib.request
|
| 41 |
+
from fractions import Fraction as Fr
|
| 42 |
+
from pathlib import Path
|
| 43 |
+
|
| 44 |
+
CATS = ("code", "math", "tr", "en", "reason", "lcb", "crux")
|
| 45 |
+
TR_ALPHA = "abcçdefgğhıijklmnoöprsştuüvyz"
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
# ---------------------------------------------------------------------------------------------------------------- checkers
|
| 49 |
+
def strip_think(r: str) -> str:
|
| 50 |
+
return re.sub(r"<think>.*", "", re.sub(r"<think>.*?</think>", "", r, flags=re.S), flags=re.S).strip()
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def numbers(text: str) -> list:
|
| 54 |
+
out = []
|
| 55 |
+
for tok in re.findall(r"-?\d[\d.,]*", text):
|
| 56 |
+
tok = tok.rstrip(".,")
|
| 57 |
+
tok = re.sub(r"[.,]", "", tok) if re.fullmatch(r"-?\d{1,3}([.,]\d{3})+", tok) else tok.replace(",", ".")
|
| 58 |
+
try:
|
| 59 |
+
out.append(Fr(tok))
|
| 60 |
+
except ValueError:
|
| 61 |
+
pass
|
| 62 |
+
return out
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def num(ans):
|
| 66 |
+
def f(r):
|
| 67 |
+
if "####" in r:
|
| 68 |
+
n = numbers(r.rsplit("####", 1)[1])
|
| 69 |
+
return bool(n) and n[0] == ans
|
| 70 |
+
n = numbers(r)
|
| 71 |
+
return bool(n) and n[-1] == ans
|
| 72 |
+
return f
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def has(*words): # every word present (case-insensitive)
|
| 76 |
+
return lambda r: all(w.lower() in r.lower() for w in words)
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def ordered(words): # the words appear in this order
|
| 80 |
+
def f(r):
|
| 81 |
+
pos = 0
|
| 82 |
+
for w in words:
|
| 83 |
+
i = r.lower().find(w.lower(), pos)
|
| 84 |
+
if i < 0:
|
| 85 |
+
return False
|
| 86 |
+
pos = i + len(w)
|
| 87 |
+
return True
|
| 88 |
+
return f
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def word(*ok): # the whole answer is one of these words
|
| 92 |
+
return lambda r: re.sub(r"[^\w]", "", r.casefold()) in ok
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def bullets(n):
|
| 96 |
+
def f(r):
|
| 97 |
+
lines = [l for l in r.splitlines() if l.strip()]
|
| 98 |
+
return len(lines) == n and all(l.startswith("- ") for l in lines)
|
| 99 |
+
return f
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def deaccent(s: str) -> str:
|
| 103 |
+
return "".join(c for c in unicodedata.normalize("NFD", s) if unicodedata.category(c) != "Mn").lower()
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def as_json(want: dict):
|
| 107 |
+
def f(r):
|
| 108 |
+
m = re.search(r"\{.*\}", r, flags=re.S)
|
| 109 |
+
try:
|
| 110 |
+
d = json.loads(m.group(0))
|
| 111 |
+
except Exception:
|
| 112 |
+
return False
|
| 113 |
+
return all(deaccent(str(d.get(k, ""))) == deaccent(v) for k, v in want.items())
|
| 114 |
+
return f
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def english_only(*words): # contains the words and no Turkish-specific letter
|
| 118 |
+
return lambda r: has(*words)(r) and not any(c in r for c in "çğıöşüÇĞİÖŞÜ")
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def code_of(r: str) -> str:
|
| 122 |
+
blocks = [b for b in re.findall(r"```(?:python|py)?[ \t]*\n(.*?)```", r, flags=re.S) if re.search(r"^\s*(def|class) ", b, re.M)]
|
| 123 |
+
return blocks[0] if blocks else r
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def run_code(code: str, tests: str, timeout: int = 10) -> bool:
|
| 127 |
+
pre = None
|
| 128 |
+
if os.name == "posix":
|
| 129 |
+
import resource
|
| 130 |
+
pre = lambda: resource.setrlimit(resource.RLIMIT_AS, (2 << 30, 2 << 30))
|
| 131 |
+
with tempfile.TemporaryDirectory() as d:
|
| 132 |
+
script = Path(d) / "task.py" # a file, not -c: the HumanEval+ tests are bigger than the 128 KiB limit of one argument
|
| 133 |
+
script.write_text(code + "\n\n" + tests, encoding="utf-8")
|
| 134 |
+
try:
|
| 135 |
+
return subprocess.run([sys.executable, "-I", str(script)], cwd=d, capture_output=True, timeout=timeout, preexec_fn=pre,
|
| 136 |
+
env={**os.environ, "OPENBLAS_NUM_THREADS": "1", "OMP_NUM_THREADS": "1"}).returncode == 0
|
| 137 |
+
except subprocess.TimeoutExpired:
|
| 138 |
+
return False
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
# ---------------------------------------------------------------------------------------------------------------- tasks
|
| 142 |
+
ONE_BLOCK_EN = " Reply with one Python code block only."
|
| 143 |
+
ONE_BLOCK_TR = " Yalnızca tek bir Python kod bloğu ile cevap ver."
|
| 144 |
+
CODE = [ # (id, prompt, tests, reference solution)
|
| 145 |
+
("roman", "Write a Python function `roman_to_int(s)` that converts a Roman numeral (I V X L C D M, with subtractive pairs such as "
|
| 146 |
+
"IV and IX) to an integer." + ONE_BLOCK_EN,
|
| 147 |
+
"assert roman_to_int('III')==3 and roman_to_int('IV')==4 and roman_to_int('XLII')==42 and roman_to_int('MCMXCIV')==1994",
|
| 148 |
+
"def roman_to_int(s):\n v = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}\n return sum(-v[c] if i + 1 < len(s) and "
|
| 149 |
+
"v[c] < v[s[i + 1]] else v[c] for i, c in enumerate(s))"),
|
| 150 |
+
("merge_tr", "Python'da `merge_intervals(intervals)` fonksiyonunu yaz: [başlangıç, bitiş] listelerinden oluşan bir listeyi alır, "
|
| 151 |
+
"kesişen veya uç uca değen aralıkları birleştirir ve başlangıca göre sıralı bir liste (iç içe listeler olarak) döndürür." + ONE_BLOCK_TR,
|
| 152 |
+
"assert merge_intervals([[1,3],[2,6],[8,10],[15,18]])==[[1,6],[8,10],[15,18]]\nassert merge_intervals([[1,4],[4,5]])==[[1,5]]\n"
|
| 153 |
+
"assert merge_intervals([])==[]\nassert merge_intervals([[5,6],[1,2]])==[[1,2],[5,6]]",
|
| 154 |
+
"def merge_intervals(iv):\n out = []\n for a, b in sorted(iv):\n if out and a <= out[-1][1]:\n"
|
| 155 |
+
" out[-1][1] = max(out[-1][1], b)\n else:\n out.append([a, b])\n return out"),
|
| 156 |
+
("balanced_tr", "Python'da `is_balanced(s)` fonksiyonunu yaz: s içindeki (), [] ve {} parantezleri doğru sırada kapatılmışsa True, "
|
| 157 |
+
"değilse False döndürsün (s yalnızca bu altı karakterden oluşur, boş dize True'dur)." + ONE_BLOCK_TR,
|
| 158 |
+
"assert is_balanced('([]{})') and not is_balanced('(]') and is_balanced('') and not is_balanced('((') and not is_balanced('())')"
|
| 159 |
+
" and not is_balanced('([)]')",
|
| 160 |
+
"def is_balanced(s):\n st, pair = [], {')': '(', ']': '[', '}': '{'}\n for c in s:\n if c in pair:\n"
|
| 161 |
+
" if not st or st.pop() != pair[c]:\n return False\n else:\n st.append(c)\n return not st"),
|
| 162 |
+
("flatten", "Write a Python function `flatten(x)` that turns an arbitrarily nested list into a flat list, keeping the order. "
|
| 163 |
+
"Strings are single items, not lists." + ONE_BLOCK_EN,
|
| 164 |
+
"assert flatten([1,[2,[3,[4]]],5])==[1,2,3,4,5] and flatten([])==[] and flatten([[],[[]]])==[] and flatten(['ab',[['c']]])==['ab','c']",
|
| 165 |
+
"def flatten(x):\n out = []\n for i in x:\n out += flatten(i) if isinstance(i, list) else [i]\n return out"),
|
| 166 |
+
("word_freq", "Write a Python function `word_freq(text)` that returns a dict mapping each lowercase word to its count; words are the "
|
| 167 |
+
"maximal runs of ASCII letters after lowercasing, everything else is a separator." + ONE_BLOCK_EN,
|
| 168 |
+
"assert word_freq('Hello, hello world!')=={'hello':2,'world':1} and word_freq('')=={} and word_freq(\"It's it\")=={'it':2,'s':1}",
|
| 169 |
+
"import re\nfrom collections import Counter\ndef word_freq(t):\n return dict(Counter(re.findall('[a-z]+', t.lower())))"),
|
| 170 |
+
("rle", "Write a Python function `rle_decode(s)` that decodes run-length encoding: each run is a decimal count (one or more digits) "
|
| 171 |
+
"followed by one non-digit character, e.g. '3a2b1c' -> 'aaabbc' and '12x' -> 'xxxxxxxxxxxx'." + ONE_BLOCK_EN,
|
| 172 |
+
"assert rle_decode('3a2b1c')=='aaabbc' and rle_decode('')=='' and rle_decode('12x')=='x'*12 and rle_decode('10a1b')=='a'*10+'b'",
|
| 173 |
+
"import re\ndef rle_decode(s):\n return ''.join(c * int(n) for n, c in re.findall(r'(\\d+)(\\D)', s))"),
|
| 174 |
+
("moving_avg", "This function should return the averages of every window of k consecutive items of xs (an empty list when k > len(xs)), "
|
| 175 |
+
"but it has a bug. Return the corrected function.\n\n```python\ndef moving_average(xs, k):\n out = []\n for i in range(len(xs) - k):\n"
|
| 176 |
+
" out.append(sum(xs[i:i + k]) / k)\n return out\n```" + ONE_BLOCK_EN,
|
| 177 |
+
"assert moving_average([1,2,3,4,5],2)==[1.5,2.5,3.5,4.5] and moving_average([1,2,3],3)==[2.0] and moving_average([1,2],3)==[]",
|
| 178 |
+
"def moving_average(xs, k):\n return [sum(xs[i:i + k]) / k for i in range(len(xs) - k + 1)]"),
|
| 179 |
+
("second_tr", "Python'da `ikinci_buyuk(xs)` fonksiyonunu yaz: sayı listesindeki en büyük ikinci FARKLI değeri döndürsün; böyle bir değer "
|
| 180 |
+
"yoksa None döndürsün." + ONE_BLOCK_TR,
|
| 181 |
+
"assert ikinci_buyuk([3,1,4,1,5])==4 and ikinci_buyuk([2,2]) is None and ikinci_buyuk([7]) is None and ikinci_buyuk([5,5,3])==3 "
|
| 182 |
+
"and ikinci_buyuk([]) is None",
|
| 183 |
+
"def ikinci_buyuk(xs):\n s = sorted(set(xs))\n return s[-2] if len(s) > 1 else None"),
|
| 184 |
+
("two_sum", "Write a Python function `two_sum(nums, target)` that returns a list [i, j] with i < j and nums[i] + nums[j] == target "
|
| 185 |
+
"(exactly one such pair exists)." + ONE_BLOCK_EN,
|
| 186 |
+
"assert two_sum([2,7,11,15],9)==[0,1] and two_sum([3,2,4],6)==[1,2] and two_sum([3,3],6)==[0,1]",
|
| 187 |
+
"def two_sum(nums, target):\n seen = {}\n for j, x in enumerate(nums):\n if target - x in seen:\n"
|
| 188 |
+
" return [seen[target - x], j]\n seen[x] = j"),
|
| 189 |
+
("ipv4", "Write a Python function `valid_ipv4(s)` that returns True only for a dotted-quad IPv4 address: exactly four decimal parts "
|
| 190 |
+
"separated by dots, digits only, each 0-255, no leading zeros (except the single digit '0')." + ONE_BLOCK_EN,
|
| 191 |
+
"assert valid_ipv4('192.168.1.1') and valid_ipv4('0.0.0.0') and not valid_ipv4('256.1.1.1') and not valid_ipv4('1.2.3') "
|
| 192 |
+
"and not valid_ipv4('01.2.3.4') and not valid_ipv4('1.2.3.4.5') and not valid_ipv4('a.b.c.d') and not valid_ipv4('1..2.3')",
|
| 193 |
+
"def valid_ipv4(s):\n p = s.split('.')\n return len(p) == 4 and all(x.isascii() and x.isdigit() and (x == '0' or x[0] != '0') "
|
| 194 |
+
"and int(x) <= 255 for x in p)"),
|
| 195 |
+
("lru", "Write a Python class `LRUCache(capacity)` with `get(key)` (returns the value, or -1 if absent) and `put(key, value)`. When "
|
| 196 |
+
"a put would exceed the capacity, evict the least recently used key; both get and put count as a use." + ONE_BLOCK_EN,
|
| 197 |
+
"c = LRUCache(2); c.put(1,1); c.put(2,2); assert c.get(1)==1; c.put(3,3); assert c.get(2)==-1; c.put(4,4); assert c.get(1)==-1\n"
|
| 198 |
+
"assert c.get(3)==3 and c.get(4)==4\nc = LRUCache(1); c.put(1,1); c.put(1,5); assert c.get(1)==5; c.put(2,2); assert c.get(1)==-1",
|
| 199 |
+
"from collections import OrderedDict\nclass LRUCache:\n def __init__(self, capacity):\n self.c, self.n = OrderedDict(), capacity\n"
|
| 200 |
+
" def get(self, k):\n if k not in self.c:\n return -1\n self.c.move_to_end(k)\n return self.c[k]\n"
|
| 201 |
+
" def put(self, k, v):\n self.c[k] = v\n self.c.move_to_end(k)\n if len(self.c) > self.n:\n"
|
| 202 |
+
" self.c.popitem(last=False)"),
|
| 203 |
+
]
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
# math: each template returns (English, Turkish, answer); the numbers are drawn so that the answers are whole and sensible
|
| 207 |
+
def m_shop(r):
|
| 208 |
+
p, n, a, b = r.randint(2, 9), r.randint(5, 15), r.randint(2, 9), r.randint(2, 6)
|
| 209 |
+
spend = a * p + b * n
|
| 210 |
+
m = (spend // 10 + 1) * 10 + r.choice([0, 10, 20])
|
| 211 |
+
return (f"A shop sells pencils for {p} dollars each and notebooks for {n} dollars each. Maria buys {a} pencils and {b} notebooks "
|
| 212 |
+
f"and pays with a {m}-dollar bill. How many dollars of change does she get?",
|
| 213 |
+
f"Bir kırtasiyede kalem tanesi {p} lira, defter tanesi {n} liradır. Maria {a} kalem ve {b} defter alıp {m} liralık "
|
| 214 |
+
f"banknotla ödeme yapıyor. Kaç lira para üstü alır?", m - spend)
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
def m_train(r):
|
| 218 |
+
v1, t1, v2, t2 = r.randint(40, 90), r.randint(2, 5), r.randint(60, 120), r.randint(1, 4)
|
| 219 |
+
return (f"A train travels at {v1} km/h for {t1} hours and then at {v2} km/h for {t2} hours. How many kilometers does it cover in total?",
|
| 220 |
+
f"Bir tren saatte {v1} km hızla {t1} saat, ardından saatte {v2} km hızla {t2} saat gidiyor. Toplam kaç km yol alır?",
|
| 221 |
+
v1 * t1 + v2 * t2)
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
def m_discount(r):
|
| 225 |
+
x, d, c = 20 * r.randint(5, 20), r.choice([10, 15, 20, 25, 30, 40]), r.randint(3, 15)
|
| 226 |
+
return (f"A jacket costs {x} dollars. It is discounted by {d}% and then a coupon takes another {c} dollars off the discounted price. "
|
| 227 |
+
f"What is the final price in dollars?",
|
| 228 |
+
f"Bir montun fiyatı {x} liradır. Önce %{d} indirim yapılıyor, sonra indirimli fiyattan {c} lira daha düşülüyor. "
|
| 229 |
+
f"Son fiyat kaç liradır?", Fr(x * (100 - d), 100) - c)
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
def m_age(r):
|
| 233 |
+
a, x, n = r.randint(8, 30), r.randint(2, 9), r.randint(2, 8)
|
| 234 |
+
s = 2 * a + x + 2 * n
|
| 235 |
+
return (f"Tom is {x} years older than Ann. In {n} years the sum of their ages will be {s}. How old is Ann now?",
|
| 236 |
+
f"Ali, Ayşe'den {x} yaş büyüktür. {n} yıl sonra ikisinin yaşları toplamı {s} olacaktır. Ayşe şimdi kaç yaşındadır?", a)
|
| 237 |
+
|
| 238 |
+
|
| 239 |
+
def m_work(r):
|
| 240 |
+
while True:
|
| 241 |
+
a, b = r.choice([2, 3, 4, 5, 6, 10, 12, 15]), r.choice([2, 3, 4, 5, 6, 10, 12, 15])
|
| 242 |
+
mins = Fr(60 * a * b, a + b)
|
| 243 |
+
if a != b and mins.denominator == 1:
|
| 244 |
+
return (f"Pipe A can fill a tank in {a} hours and pipe B can fill it in {b} hours. Working together, how many minutes do "
|
| 245 |
+
f"they need to fill the empty tank?",
|
| 246 |
+
f"A musluğu bir depoyu {a} saatte, B musluğu {b} saatte doldurabiliyor. İkisi birlikte çalışırsa boş depoyu kaç "
|
| 247 |
+
f"dakikada doldurur?", mins)
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
def m_rect(r):
|
| 251 |
+
w = r.randint(3, 20)
|
| 252 |
+
l, p = 2 * w + 3, 2 * (3 * w + 3)
|
| 253 |
+
return (f"The length of a rectangle is 3 more than twice its width. Its perimeter is {p} cm. What is its area in square cm?",
|
| 254 |
+
f"Bir dikdörtgenin uzun kenarı, kısa kenarının iki katından 3 cm fazladır. Çevresi {p} cm olduğuna göre alanı kaç cm²'dir?",
|
| 255 |
+
w * l)
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
def m_ratio(r):
|
| 259 |
+
a, b, c, k = r.randint(1, 4), r.randint(2, 6), r.randint(3, 8), r.randint(4, 15)
|
| 260 |
+
s = k * (a + b + c)
|
| 261 |
+
return (f"{s} dollars are shared among three friends in the ratio {a}:{b}:{c}. How many dollars does the friend with the largest "
|
| 262 |
+
f"share get?",
|
| 263 |
+
f"{s} lira, üç arkadaş arasında {a}:{b}:{c} oranında paylaştırılıyor. En büyük payı alan kaç lira alır?", k * max(a, b, c))
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
def m_codes(r):
|
| 267 |
+
n = r.randint(5, 9)
|
| 268 |
+
return (f"How many different 3-letter codes can be made from {n} distinct letters if no letter may be used twice in a code?",
|
| 269 |
+
f"{n} farklı harften, hiçbir harf bir şifrede iki kez kullanılmamak koşuluyla, kaç farklı 3 harfli şifre oluşturulabilir?",
|
| 270 |
+
n * (n - 1) * (n - 2))
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
MATH = [m_shop, m_train, m_discount, m_age, m_work, m_rect, m_ratio, m_codes]
|
| 274 |
+
HOW_EN = "\n\nThink step by step, then give the final answer on the last line as: #### <number>"
|
| 275 |
+
HOW_TR = "\n\nAdım adım düşün, sonra son satırda nihai cevabı şu biçimde yaz: #### <sayı>"
|
| 276 |
+
TR_PLURAL = [("kitap", "kitaplar"), ("göz", "gözler"), ("okul", "okullar"), ("kalem", "kalemler"), ("çiçek", "çiçekler"),
|
| 277 |
+
("araba", "arabalar"), ("kedi", "kediler"), ("ağaç", "ağaçlar"), ("öğretmen", "öğretmenler"), ("dağ", "dağlar"),
|
| 278 |
+
("deniz", "denizler"), ("masa", "masalar"), ("kuş", "kuşlar"), ("gül", "güller")]
|
| 279 |
+
TR_WORDS = ["cam", "çanta", "dağ", "ışık", "iyi", "orman", "ödev", "sandalye", "şeker", "uzay", "ümit", "zeytin", "gül", "hava", "kalem",
|
| 280 |
+
"lale", "yol", "yüz", "üzüm", "masa", "pencere", "çiçek", "şehir", "ılık", "ince", "öğle", "göl", "fırın", "tarla"]
|
| 281 |
+
MONTHS_EN = ["January", "March", "May", "July", "September", "November"]
|
| 282 |
+
MONTHS_TR = ["Ocak", "Mart", "Mayıs", "Temmuz", "Eylül", "Kasım"]
|
| 283 |
+
CITIES = ["Izmir", "Bursa", "Konya", "Trabzon", "Antalya", "Adana"]
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
def tr_key(w: str):
|
| 287 |
+
return [TR_ALPHA.index(c) for c in w]
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
def build(seed: int = 1) -> list:
|
| 291 |
+
"""[(id, category, prompt, check(response) -> bool, reference response)]"""
|
| 292 |
+
T = []
|
| 293 |
+
for tid, prompt, tests, ref in CODE:
|
| 294 |
+
T.append((f"code_{tid}", "code", prompt, (lambda t: lambda r: run_code(code_of(r), t))(tests), f"```python\n{ref}\n```"))
|
| 295 |
+
for i, f in enumerate(MATH):
|
| 296 |
+
en, tr, ans = f(random.Random(f"{seed}m{i}"))
|
| 297 |
+
T.append((f"math_{f.__name__[2:]}_en", "math", en + HOW_EN, num(ans), f"#### {ans}"))
|
| 298 |
+
T.append((f"math_{f.__name__[2:]}_tr", "math", tr + HOW_TR, num(ans), f"#### {ans}"))
|
| 299 |
+
# Turkish
|
| 300 |
+
for i in range(3):
|
| 301 |
+
r = random.Random(f"{seed}ta{i}")
|
| 302 |
+
a, b, c = r.randint(2, 7), r.randint(2, 6), r.randint(15, 40)
|
| 303 |
+
T.append((f"tr_age{i}", "tr", f"Zeynep, Ahmet'ten {a} yaş büyüktür. Ahmet, Deniz'den {b} yaş küçüktür. Deniz {c} yaşındadır. "
|
| 304 |
+
f"Zeynep kaç yaşındadır? Yalnızca sayıyı yaz.", num(c - b + a), str(c - b + a)))
|
| 305 |
+
for i in range(2):
|
| 306 |
+
ws = random.Random(f"{seed}ts{i}").sample(TR_WORDS, 6)
|
| 307 |
+
want = sorted(ws, key=tr_key)
|
| 308 |
+
T.append((f"tr_sort{i}", "tr", "Şu kelimeleri Türk alfabesine göre alfabetik sıraya diz ve aralarına virgül koyarak tek satırda yaz: "
|
| 309 |
+
+ ", ".join(ws), ordered(want), ", ".join(want)))
|
| 310 |
+
ph = random.Random(f"{seed}tu").choice(["istanbul ışığı", "ilkbahar ışıkları", "iğne ve ipek", "ılık süt içtim", "çiçekli bir bahçe"])
|
| 311 |
+
up = ph.replace("i", "İ").replace("ı", "I").upper()
|
| 312 |
+
T.append(("tr_upper", "tr", f"'{ph}' ifadesini Türkçe yazım kurallarına göre tamamen BÜYÜK harfe çevir. Yalnızca sonucu yaz.",
|
| 313 |
+
lambda r, up=up: up in r, up))
|
| 314 |
+
for i in range(2):
|
| 315 |
+
pairs = random.Random(f"{seed}tp{i}").sample(TR_PLURAL, 5)
|
| 316 |
+
T.append((f"tr_plural{i}", "tr", "Şu kelimelerin çoğul hâlini yaz (her biri için yalnızca çoğul biçimi, virgülle ayırarak): "
|
| 317 |
+
+ ", ".join(w for w, _ in pairs), has(*[p for _, p in pairs]), ", ".join(p for _, p in pairs)))
|
| 318 |
+
T.append(("tr_bullets", "tr", "Ankara hakkında tam olarak 3 madde yaz. Her madde satır başında '- ' ile başlasın, başka hiçbir şey yazma.",
|
| 319 |
+
bullets(3), "- Başkenttir.\n- İç Anadolu'dadır.\n- Kalabalıktır."))
|
| 320 |
+
T.append(("tr_yesno", "tr", "Yalnızca 'evet' veya 'hayır' yaz: Türkiye'nin başkenti İstanbul mu?", word("hayır", "hayir"), "hayır"))
|
| 321 |
+
T.append(("tr_translate", "tr", "Şu cümleyi İngilizceye çevir, yalnızca çeviriyi yaz: 'Yarın sabah erken kalkıp işe gideceğim.'",
|
| 322 |
+
lambda r: sum(bool(re.search(p, r.lower())) for p in (r"tomorrow", r"morning", r"early", r"\bwork|\bjob|office",
|
| 323 |
+
r"wake|get up|rise|getting up")) >= 4,
|
| 324 |
+
"Tomorrow morning I will get up early and go to work."))
|
| 325 |
+
for i in range(2):
|
| 326 |
+
r = random.Random(f"{seed}te{i}")
|
| 327 |
+
day, mon, hh, mm, city = r.randint(2, 28), r.choice(MONTHS_TR), r.randint(9, 17), r.choice(["00", "15", "30", "45"]), r.choice(CITIES)
|
| 328 |
+
txt = f"Toplantı {day} {mon} 2025 tarihinde, saat {hh}:{mm} olarak, {city} şubesinde yapılacaktır."
|
| 329 |
+
if i == 0:
|
| 330 |
+
T.append((f"tr_extract{i}", "tr", f"Metin: {txt}\nSoru: Toplantı saat kaçta? Yalnızca saati yaz.",
|
| 331 |
+
lambda r, a=f"{hh}:{mm}", b=f"{hh}.{mm}": a in r or b in r, f"{hh}:{mm}"))
|
| 332 |
+
else:
|
| 333 |
+
T.append((f"tr_extract{i}", "tr", f"Metin: {txt}\nSoru: Toplantı hangi şehirde yapılacak? Yalnızca şehir adını yaz.",
|
| 334 |
+
has(city), city))
|
| 335 |
+
T.append(("tr_cross", "tr", "İngilizce olarak cevap ver, tek cümle: Fransa'nın başkenti neresidir?", english_only("paris"),
|
| 336 |
+
"The capital of France is Paris."))
|
| 337 |
+
# English
|
| 338 |
+
for i in range(3):
|
| 339 |
+
r = random.Random(f"{seed}ea{i}")
|
| 340 |
+
a, b, c = r.randint(2, 7), r.randint(2, 6), r.randint(15, 40)
|
| 341 |
+
T.append((f"en_age{i}", "en", f"Emma is {a} years older than Noah. Noah is {b} years younger than Liam. Liam is {c} years old. "
|
| 342 |
+
f"How old is Emma? Answer with just the number.", num(c - b + a), str(c - b + a)))
|
| 343 |
+
T.append(("en_bullets", "en", "Write exactly 3 bullet points about Paris. Start each line with '- ' and write nothing else.",
|
| 344 |
+
bullets(3), "- Capital of France.\n- On the Seine.\n- Home of the Louvre."))
|
| 345 |
+
T.append(("en_yesno1", "en", "Answer with only 'yes' or 'no': Is the Pacific Ocean the largest ocean on Earth?", word("yes"), "yes"))
|
| 346 |
+
T.append(("en_yesno2", "en", "Answer with only 'yes' or 'no': Is 91 a prime number?", word("no"), "no"))
|
| 347 |
+
T.append(("en_reverse", "en", "Reverse the order of the words in this sentence and output only the result: 'the quick brown fox jumps'",
|
| 348 |
+
lambda r: "jumps fox brown quick the" in re.sub(r"[^\w ]", "", r.lower()), "jumps fox brown quick the"))
|
| 349 |
+
for i in range(2):
|
| 350 |
+
r = random.Random(f"{seed}ee{i}")
|
| 351 |
+
day, mon, hh, mm, city = r.randint(2, 28), r.choice(MONTHS_EN), r.randint(9, 17), r.choice(["00", "15", "30", "45"]), r.choice(CITIES)
|
| 352 |
+
txt = f"The meeting will take place on {mon} {day}, 2025 at {hh}:{mm} in the {city} office."
|
| 353 |
+
if i == 0:
|
| 354 |
+
T.append((f"en_extract{i}", "en", f"Text: {txt}\nQuestion: At what time is the meeting? Answer with the time only.",
|
| 355 |
+
has(f"{hh}:{mm}"), f"{hh}:{mm}"))
|
| 356 |
+
else:
|
| 357 |
+
T.append((f"en_extract{i}", "en", f"Text: {txt}\nQuestion: In which city is the meeting? Answer with the city only.", has(city), city))
|
| 358 |
+
T.append(("en_logic1", "en", "All bloops are razzies. All razzies are lazzies. Is every bloop a lazzie? Answer only yes or no.",
|
| 359 |
+
word("yes"), "yes"))
|
| 360 |
+
T.append(("en_logic2", "en", "All birds have feathers. Penguins have feathers. Does it follow that penguins are birds? Answer only yes or no.",
|
| 361 |
+
word("no"), "no"))
|
| 362 |
+
T.append(("en_json1", "en", "Give the capital of Japan as a JSON object with keys \"city\" and \"country\". Output only the JSON.",
|
| 363 |
+
as_json({"city": "Tokyo", "country": "Japan"}), '{"city": "Tokyo", "country": "Japan"}'))
|
| 364 |
+
T.append(("en_json2", "en", "Give the capital of Canada as a JSON object with keys \"city\" and \"country\". Output only the JSON.",
|
| 365 |
+
as_json({"city": "Ottawa", "country": "Canada"}), '{"city": "Ottawa", "country": "Canada"}'))
|
| 366 |
+
T.append(("en_cross", "en", "Answer in Turkish, in one sentence: What is the capital of Turkey?",
|
| 367 |
+
lambda r: "ankara" in r.lower() and ("başkent" in r.lower() or "baskent" in r.lower()), "Türkiye'nin başkenti Ankara'dır."))
|
| 368 |
+
T.append(("en_words", "en", "Summarize in at most 12 words: 'The city council voted on Tuesday to build a new bridge over the river, "
|
| 369 |
+
"after years of debate about the cost.'", lambda r: len(r.split()) <= 12 and "bridge" in r.lower(),
|
| 370 |
+
"Council votes to build new river bridge after years of debate."))
|
| 371 |
+
return T
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
# ---------------------------------------------------------------------------------------------------------------- commands
|
| 375 |
+
def table(rows, head):
|
| 376 |
+
w = [max(len(str(x)) for x in col) for col in zip(head, *rows)]
|
| 377 |
+
for r in [head] + rows:
|
| 378 |
+
print(" ".join(str(x).ljust(n) for x, n in zip(r, w)))
|
| 379 |
+
|
| 380 |
+
|
| 381 |
+
def serve(a):
|
| 382 |
+
"""starts llama-server on the model and returns once /health says ok"""
|
| 383 |
+
cmd = [str(Path(a.bin) / "llama-server"), "-m", a.model, "-ngl", "99", "-fa", "on", "-lzm", "on", "-t", str(a.threads), "-c", str(a.ctx),
|
| 384 |
+
"-np", "1", "--host", "127.0.0.1", "--port", str(a.port)] + (["-ot", a.ot] if a.ot else []) + shlex.split(a.extra)
|
| 385 |
+
log = open(f"server_{a.name}.log", "w")
|
| 386 |
+
p = subprocess.Popen(cmd, stdout=log, stderr=subprocess.STDOUT)
|
| 387 |
+
t0 = time.time()
|
| 388 |
+
while time.time() - t0 < a.load_timeout:
|
| 389 |
+
if p.poll() is not None:
|
| 390 |
+
sys.exit(f"llama-server exited early, see {log.name}")
|
| 391 |
+
try:
|
| 392 |
+
if urllib.request.urlopen(f"http://127.0.0.1:{a.port}/health", timeout=5).status == 200:
|
| 393 |
+
print(f"llama-server ready after {time.time() - t0:.0f} s", flush=True)
|
| 394 |
+
return p
|
| 395 |
+
except Exception:
|
| 396 |
+
time.sleep(5)
|
| 397 |
+
p.terminate()
|
| 398 |
+
sys.exit(f"llama-server not ready after {a.load_timeout} s, see {log.name}")
|
| 399 |
+
|
| 400 |
+
|
| 401 |
+
def cmd_run(a):
|
| 402 |
+
srv = serve(a) if a.model else None
|
| 403 |
+
if srv:
|
| 404 |
+
a.endpoint = f"http://127.0.0.1:{a.port}"
|
| 405 |
+
try:
|
| 406 |
+
run_tasks(a)
|
| 407 |
+
finally:
|
| 408 |
+
if srv:
|
| 409 |
+
srv.terminate()
|
| 410 |
+
srv.wait(60)
|
| 411 |
+
|
| 412 |
+
|
| 413 |
+
def run_tasks(a):
|
| 414 |
+
if a.suite != "basic": # public benchmarks from 08_hard_tasks.py / 09_big_suite.py / 10_code_hard.py; long answers need room
|
| 415 |
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
| 416 |
+
import importlib
|
| 417 |
+
mod, fn = {"hard": ("08_hard_tasks", "build_hard"), "big": ("09_big_suite", "build_big"), "codehard": ("10_code_hard", "build_codehard")}[a.suite]
|
| 418 |
+
tasks, a.max_tokens = getattr(importlib.import_module(mod), fn)(a.seed, a.hard_n, run_code, code_of, num), max(a.max_tokens, 2048)
|
| 419 |
+
else:
|
| 420 |
+
tasks = build(a.seed)
|
| 421 |
+
tasks = [t for t in tasks if t[1] in a.only.split(",")]
|
| 422 |
+
if a.redo: # only the tasks that file failed (math and reasoning first): does a setting rescue them?
|
| 423 |
+
prev = json.loads(Path(a.redo).read_text(encoding="utf-8"))["results"]
|
| 424 |
+
order = {"math": 0, "reason": 1, "code": 2}
|
| 425 |
+
tasks = sorted([t for t in tasks if t[0] in prev and not prev[t[0]]["pass"]], key=lambda t: order.get(t[1], 3))[:a.redo_max]
|
| 426 |
+
res, t0, toks = {}, time.time(), 0
|
| 427 |
+
out = a.out or f"results_{a.name}.json"
|
| 428 |
+
|
| 429 |
+
def save(): # after every task, so a dropped session keeps what is done
|
| 430 |
+
Path(out).write_text(json.dumps({"kind": "tasks", "name": a.name, "seed": a.seed, "tokens": toks, "seconds": round(time.time() - t0),
|
| 431 |
+
"results": res}, indent=1, ensure_ascii=False), encoding="utf-8")
|
| 432 |
+
def ask(messages, v): # one chat request -> (reply text, completion tokens)
|
| 433 |
+
body = {"model": a.name, "messages": messages, "max_tokens": a.max_tokens,
|
| 434 |
+
"temperature": a.temperature if a.temperature is not None else (a.temp if a.votes > 1 else 0), "seed": a.seed * 1000 + v}
|
| 435 |
+
for key, val in (("top_p", a.top_p), ("top_k", a.top_k)):
|
| 436 |
+
if val is not None:
|
| 437 |
+
body[key] = val
|
| 438 |
+
if a.no_think:
|
| 439 |
+
body["chat_template_kwargs"] = {"enable_thinking": False}
|
| 440 |
+
elif a.think:
|
| 441 |
+
body["chat_template_kwargs"] = {"enable_thinking": True}
|
| 442 |
+
req = urllib.request.Request(a.endpoint.rstrip("/") + "/v1/chat/completions", json.dumps(body).encode(),
|
| 443 |
+
{"Content-Type": "application/json"})
|
| 444 |
+
try:
|
| 445 |
+
with urllib.request.urlopen(req, timeout=a.timeout) as f:
|
| 446 |
+
d = json.load(f)
|
| 447 |
+
return d["choices"][0]["message"].get("content") or "", d.get("usage", {}).get("completion_tokens", 0)
|
| 448 |
+
except Exception as e:
|
| 449 |
+
return f"[request failed: {e}]", 0
|
| 450 |
+
|
| 451 |
+
first = {k: v["resp"] for k, v in json.loads(Path(a.first_from).read_text(encoding="utf-8"))["results"].items()} if a.first_from else {}
|
| 452 |
+
for k, (tid, cat, prompt, check, _) in enumerate(tasks, 1):
|
| 453 |
+
resps, tt, tries = [], 0, 0
|
| 454 |
+
for v in range(a.votes):
|
| 455 |
+
text, n = (first[tid], 0) if tid in first else ask([{"role": "user", "content": prompt}], v) # --first-from: reuse the stored first answer
|
| 456 |
+
resps.append(text)
|
| 457 |
+
tt += n
|
| 458 |
+
oks = [bool(check(strip_think(r))) for r in resps]
|
| 459 |
+
if a.retry and a.votes == 1 and not oks[0] and hasattr(check, "feedback"): # repair loop: only visible sample tests are shown to the model
|
| 460 |
+
msgs = [{"role": "user", "content": prompt}]
|
| 461 |
+
for _try in range(a.retry):
|
| 462 |
+
fb = check.feedback(strip_think(resps[0]))
|
| 463 |
+
if fb is None: # the visible tests pass: nothing more to tell it
|
| 464 |
+
break
|
| 465 |
+
msgs += [{"role": "assistant", "content": strip_think(resps[0])}, {"role": "user", "content": fb}]
|
| 466 |
+
resps[0], n = ask(msgs, 0)
|
| 467 |
+
tt += n
|
| 468 |
+
tries += 1
|
| 469 |
+
oks = [bool(check(strip_think(resps[0])))]
|
| 470 |
+
if oks[0]:
|
| 471 |
+
break
|
| 472 |
+
if a.votes > 1 and cat == "math": # self-consistency: the most common final number wins, ties go to the first sample
|
| 473 |
+
ans = [(numbers(strip_think(r)) or [None])[-1] for r in resps]
|
| 474 |
+
best = max(ans, key=lambda x: (ans.count(x), -ans.index(x)))
|
| 475 |
+
ok = oks[ans.index(best)]
|
| 476 |
+
else: # no canonical answer to vote on: the majority of the samples must pass
|
| 477 |
+
ok = sum(oks) * 2 > len(oks)
|
| 478 |
+
toks += tt
|
| 479 |
+
res[tid] = {"cat": cat, "pass": ok, "frac": sum(oks) / len(oks), "toks": tt, "resp": resps[0], **({"retries": tries} if a.retry else {})}
|
| 480 |
+
print(f"{k:3d}/{len(tasks)} {tid:22s} {'PASS' if ok else 'fail'} {sum(oks)}/{len(oks)} {time.time() - t0:5.0f} s" + (f" retries {tries}" if a.retry else ""), flush=True)
|
| 481 |
+
save()
|
| 482 |
+
print(f"{toks} tokens in {time.time() - t0:.0f} s -> {out}")
|
| 483 |
+
cmd_compare(argparse.Namespace(files=[out]))
|
| 484 |
+
|
| 485 |
+
|
| 486 |
+
def cmd_compare(a):
|
| 487 |
+
docs = [json.loads(Path(f).read_text(encoding="utf-8")) for f in a.files]
|
| 488 |
+
tasks = [d for d in docs if d["kind"] == "tasks"]
|
| 489 |
+
if tasks:
|
| 490 |
+
def rate(d, c):
|
| 491 |
+
r = [v["pass"] for v in d["results"].values() if c is None or v["cat"] == c]
|
| 492 |
+
return sum(r), len(r)
|
| 493 |
+
ref = tasks[0]
|
| 494 |
+
rows = []
|
| 495 |
+
for c in list(CATS) + [None]:
|
| 496 |
+
if c and not rate(ref, c)[1]:
|
| 497 |
+
continue
|
| 498 |
+
row = [c or "ALL"]
|
| 499 |
+
for d in tasks:
|
| 500 |
+
k, n = rate(d, c)
|
| 501 |
+
rk, rn = rate(ref, c)
|
| 502 |
+
pct = f"{100 * (k / n) / (rk / rn):.0f}%" if n and rk else "-"
|
| 503 |
+
row.append(f"{k}/{n}" + ("" if d is ref else f" ({pct} of ref)"))
|
| 504 |
+
rows.append(row)
|
| 505 |
+
rows.append(["time / tokens"] + [f"{d.get('seconds', 0)} s / {d.get('tokens', 0)} tok ({d.get('tokens', 0) / max(d.get('seconds', 1), 1):.1f} t/s)" for d in tasks])
|
| 506 |
+
table(rows, ["tasks"] + [d["name"] + (" (ref)" if d is ref else "") for d in tasks])
|
| 507 |
+
for d in tasks[1:]: # paired sign test on the tasks only one of the two passes ("beats" needs p < 0.05 in its favour)
|
| 508 |
+
ids = [i for i in ref["results"] if i in d["results"]]
|
| 509 |
+
b = sum(ref["results"][i]["pass"] and not d["results"][i]["pass"] for i in ids)
|
| 510 |
+
c = sum(d["results"][i]["pass"] and not ref["results"][i]["pass"] for i in ids)
|
| 511 |
+
p = min(1.0, 2 * sum(math.comb(b + c, i) for i in range(min(b, c) + 1)) / 2 ** (b + c)) if b + c else 1.0
|
| 512 |
+
print(f"paired {d['name']} vs {ref['name']}: only {ref['name']} passes {b}, only {d['name']} passes {c}, sign test p = {p:.3f}")
|
| 513 |
+
klds = [d for d in docs if d["kind"] == "kld"]
|
| 514 |
+
if klds:
|
| 515 |
+
print()
|
| 516 |
+
rows = [[dom] + [f"KLD {d['domains'][dom]['kld']:.3f} top {d['domains'][dom]['top']:.1f}% pplx {d['domains'][dom]['ppl_ratio']:.3f}"
|
| 517 |
+
if dom in d["domains"] else "-" for d in klds] for dom in ("tr", "en", "code", "math")]
|
| 518 |
+
table(rows, ["domain"] + [d["name"] for d in klds])
|
| 519 |
+
|
| 520 |
+
|
| 521 |
+
def parse_kld(text: str) -> dict:
|
| 522 |
+
g = lambda p: float(re.search(p, text).group(1))
|
| 523 |
+
return {"kld": g(r"Mean\s+KLD:\s+([\d.]+)"), "top": g(r"Same top p:\s+([\d.]+)"),
|
| 524 |
+
"ppl_ratio": g(r"Mean PPL\(Q\)/PPL\(base\)\s*:\s+([\d.]+)"), "ppl": g(r"Mean PPL\(Q\)\s*:\s+([\d.]+)")}
|
| 525 |
+
|
| 526 |
+
|
| 527 |
+
def cmd_kld(a):
|
| 528 |
+
ev = Path(a.eval_dir)
|
| 529 |
+
res = {}
|
| 530 |
+
for dom in ("tr", "en", "code", "math"):
|
| 531 |
+
base = ev / f"base_{dom}.kld"
|
| 532 |
+
cmd = [str(Path(a.bin) / "llama-perplexity"), "-m", a.model, "-f", str(ev / f"eval_{dom}.txt"), "-c", "512", "-b", "512", "-ub", "512",
|
| 533 |
+
"--chunks", str(a.chunks), "-ngl", "99", "-fa", "on", "-lzm", "on", "-t", str(a.threads)]
|
| 534 |
+
cmd += (["-ot", a.ot] if a.ot else []) + shlex.split(a.extra) + ["--kl-divergence-base", str(base)]
|
| 535 |
+
cmd += [] if a.save_base else ["--kl-divergence"]
|
| 536 |
+
t0 = time.time()
|
| 537 |
+
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
| 538 |
+
if p.returncode != 0:
|
| 539 |
+
sys.exit(f"{dom}: llama-perplexity failed ({p.returncode}):\n{p.stdout[-1500:]}")
|
| 540 |
+
if a.save_base:
|
| 541 |
+
m = re.search(r"Final estimate: PPL = ([\d.]+)", p.stdout)
|
| 542 |
+
res[dom] = {"ppl": float(m.group(1)) if m else None}
|
| 543 |
+
print(f"{dom:5s} base saved {base} ({time.time() - t0:.0f} s) PPL {res[dom]['ppl']}", flush=True)
|
| 544 |
+
continue
|
| 545 |
+
try:
|
| 546 |
+
res[dom] = parse_kld(p.stdout)
|
| 547 |
+
except AttributeError:
|
| 548 |
+
sys.exit(f"{dom}: no statistics in the output:\n{p.stdout[-1500:]}")
|
| 549 |
+
r = res[dom]
|
| 550 |
+
print(f"{dom:5s} KLD {r['kld']:.3f} same top {r['top']:.1f}% PPL ratio {r['ppl_ratio']:.3f} ({time.time() - t0:.0f} s)", flush=True)
|
| 551 |
+
if not a.save_base:
|
| 552 |
+
out = a.out or f"kld_{a.name}.json"
|
| 553 |
+
Path(out).write_text(json.dumps({"kind": "kld", "name": a.name, "domains": res}, indent=1), encoding="utf-8")
|
| 554 |
+
print("->", out)
|
| 555 |
+
|
| 556 |
+
|
| 557 |
+
def cmd_selftest(a):
|
| 558 |
+
T = build(a.seed)
|
| 559 |
+
bad = [t[0] for t in T if not t[3](t[4])]
|
| 560 |
+
junk = [t[0] for t in T if t[3]("zzz 0")]
|
| 561 |
+
code_wrong = run_code("def roman_to_int(s):\n return 0", CODE[0][2])
|
| 562 |
+
sample = "Mean PPL(Q) : 3.059708 ± 0.061630\nMean PPL(Q)/PPL(base) : 1.131630 ± 0.011859\n" \
|
| 563 |
+
"Mean KLD: 0.350462 ± 0.007497\nSame top p: 82.255 ± 0.378 %\n"
|
| 564 |
+
k = parse_kld(sample)
|
| 565 |
+
ids = [t[0] for t in T]
|
| 566 |
+
assert len(set(ids)) == len(ids), "duplicate task ids"
|
| 567 |
+
assert numbers("1.250 ve 3,5 ve 12") == [1250, Fr(7, 2), 12] and strip_think("<think>x</think>ok") == "ok" and strip_think("<think>x") == ""
|
| 568 |
+
assert not bad and not junk and not code_wrong, (bad, junk, code_wrong)
|
| 569 |
+
assert k == {"kld": 0.350462, "top": 82.255, "ppl_ratio": 1.13163, "ppl": 3.059708}, k
|
| 570 |
+
n = {c: sum(t[1] == c for t in T) for c in CATS}
|
| 571 |
+
print(f"selftest OK: {len(T)} tasks {n}; reference answers pass, garbage fails, kld parser reads the sample")
|
| 572 |
+
|
| 573 |
+
|
| 574 |
+
def main():
|
| 575 |
+
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
| 576 |
+
sub = ap.add_subparsers(dest="cmd", required=True)
|
| 577 |
+
r = sub.add_parser("run")
|
| 578 |
+
r.add_argument("--endpoint", default="http://127.0.0.1:8080")
|
| 579 |
+
r.add_argument("--name", required=True)
|
| 580 |
+
r.add_argument("--out")
|
| 581 |
+
r.add_argument("--seed", type=int, default=1)
|
| 582 |
+
r.add_argument("--only", default=",".join(CATS), help="categories, comma separated")
|
| 583 |
+
r.add_argument("--suite", choices=("basic", "hard", "big", "codehard"), default="basic", help="hard: HumanEval+, MATH-500, MMLU-Pro (08_hard_tasks.py); big: four domains, nested pools (09_big_suite.py); codehard: LiveCodeBench + CRUXEval (10_code_hard.py, use --max-tokens 4096 --ctx 8192); use --out")
|
| 584 |
+
r.add_argument("--hard-n", type=int, default=100, help="tasks per category in the hard / big suite (big: 60 = quick prefix, 300 = full)")
|
| 585 |
+
r.add_argument("--max-tokens", type=int, default=768)
|
| 586 |
+
r.add_argument("--think", action="store_true", help="send chat_template_kwargs enable_thinking=true")
|
| 587 |
+
r.add_argument("--redo", help="results file: run only the tasks it failed (same --suite/--seed/--hard-n)")
|
| 588 |
+
r.add_argument("--redo-max", type=int, default=1000)
|
| 589 |
+
r.add_argument("--first-from", help="with --retry: take each task's first answer from this results file (its 'resp') instead of generating it again")
|
| 590 |
+
r.add_argument("--retry", type=int, default=0, help="lcb tasks: after a failed answer, show the model its first failing VISIBLE sample test and ask again, up to N times (needs --ctx big enough for the extra turns)")
|
| 591 |
+
r.add_argument("--temperature", type=float, help="sampling temperature (default: 0, or --temp when --votes > 1)")
|
| 592 |
+
r.add_argument("--top-p", type=float)
|
| 593 |
+
r.add_argument("--top-k", type=int)
|
| 594 |
+
r.add_argument("--timeout", type=int, default=1200)
|
| 595 |
+
r.add_argument("--no-think", action="store_true", help="send chat_template_kwargs enable_thinking=false")
|
| 596 |
+
r.add_argument("--votes", type=int, default=1, help="samples per task; math: the most common final number wins, other categories: majority must pass")
|
| 597 |
+
r.add_argument("--temp", type=float, default=0.7, help="sampling temperature when --votes > 1 ")
|
| 598 |
+
r.add_argument("--model", help="start llama-server on this GGUF (needs --bin) instead of using --endpoint")
|
| 599 |
+
r.add_argument("--bin", help="directory with llama-server")
|
| 600 |
+
r.add_argument("--ot", default="", help="-ot overrides for the server")
|
| 601 |
+
r.add_argument("--extra", default="", help="more llama-server flags, one string: --extra='--flag value'")
|
| 602 |
+
r.add_argument("--threads", type=int, default=8)
|
| 603 |
+
r.add_argument("--ctx", type=int, default=4096)
|
| 604 |
+
r.add_argument("--port", type=int, default=18080) # 8080 is taken on Colab
|
| 605 |
+
r.add_argument("--load-timeout", type=int, default=1800)
|
| 606 |
+
r.set_defaults(f=cmd_run)
|
| 607 |
+
c = sub.add_parser("compare")
|
| 608 |
+
c.add_argument("files", nargs="+", help="result files; the first task file is the reference")
|
| 609 |
+
c.set_defaults(f=cmd_compare)
|
| 610 |
+
k = sub.add_parser("kld")
|
| 611 |
+
k.add_argument("--bin", required=True, help="directory with llama-perplexity")
|
| 612 |
+
k.add_argument("--model", required=True)
|
| 613 |
+
k.add_argument("--name", required=True)
|
| 614 |
+
k.add_argument("--eval-dir", default="evalset")
|
| 615 |
+
k.add_argument("--chunks", type=int, default=16)
|
| 616 |
+
k.add_argument("--ot", default="", help="-ot overrides (which tensors stay on the CPU)")
|
| 617 |
+
k.add_argument("--extra", default="", help="more llama-perplexity flags, one string: --extra='--flag value'")
|
| 618 |
+
k.add_argument("--threads", type=int, default=8)
|
| 619 |
+
k.add_argument("--save-base", action="store_true", help="this is the reference: store its logits")
|
| 620 |
+
k.add_argument("--out")
|
| 621 |
+
k.set_defaults(f=cmd_kld)
|
| 622 |
+
s = sub.add_parser("selftest")
|
| 623 |
+
s.add_argument("--seed", type=int, default=1)
|
| 624 |
+
s.set_defaults(f=cmd_selftest)
|
| 625 |
+
a = ap.parse_args()
|
| 626 |
+
a.f(a)
|
| 627 |
+
|
| 628 |
+
|
| 629 |
+
if __name__ == "__main__":
|
| 630 |
+
main()
|
benchmarks/scripts/09_big_suite.py
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
"""
|
| 4 |
+
09_big_suite.py - the large four-domain task set behind `07_domain_eval.py run --suite big --hard-n N` (N tasks per domain, up to the pool size).
|
| 5 |
+
Public benchmarks, English only, every answer checked by code; the tasks of a smaller N are the FIRST N of a bigger one (nested), so a quick run
|
| 6 |
+
(--hard-n 60) is a prefix of the full run (--hard-n 300) and the two can be pooled:
|
| 7 |
+
code HumanEval+ (164) and MBPP sanitized test (257), 2:3 mix; the model writes the function, the unit tests run on it
|
| 8 |
+
math MATH-500 integer answers of level 2-5 (278) and AIME (90, AI-MO/aimo-validation-aime), 3:1 mix; final line "#### <integer>"
|
| 9 |
+
reason MMLU-Pro (240, 14 subjects round-robin, 10 options) and BIG-Bench Hard (120, 8 tasks), 2:1 mix; final line "Answer: <x>"
|
| 10 |
+
en RACE-high reading comprehension (120), CoLA grammar acceptability (120, half acceptable), and 120 writing prompts with machine-checked
|
| 11 |
+
constraints (word counts, paragraphs, bullets, case, keywords, start/end text, quotes, title, commas, P.S.), 1:1:1 mix
|
| 12 |
+
Needs `pip install datasets` and network access; the model-written code is EXECUTED (see 07). Selftest (same needs):
|
| 13 |
+
python 09_big_suite.py selftest reference answers pass, garbage fails, every constraint checker passes its own good/bad example
|
| 14 |
+
python 09_big_suite.py validate runs EVERY reference solution (421 code tasks) and prints the ids to put in BAD_CODE
|
| 15 |
+
"""
|
| 16 |
+
import random
|
| 17 |
+
import re
|
| 18 |
+
import sys
|
| 19 |
+
from fractions import Fraction as Fr
|
| 20 |
+
|
| 21 |
+
HOW = "\n\nThink step by step, then give the final answer on the last line as: #### <integer>"
|
| 22 |
+
LETTERS = "ABCDEFGHIJ"
|
| 23 |
+
BAD_CODE = {"code_he32"} # code task ids whose own reference solution fails its tests (`validate`: HumanEval/32 find_zero is float-sensitive)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def mix(pools, pattern):
|
| 27 |
+
"""The pools interleaved by the digits of `pattern` ("00101" = two from pool 0, one from pool 1, ...) until every pool is used up."""
|
| 28 |
+
pos, out, i = [0] * len(pools), [], 0
|
| 29 |
+
while any(pos[k] < len(pools[k]) for k in range(len(pools))) and i < 10 ** 6:
|
| 30 |
+
k = int(pattern[i % len(pattern)])
|
| 31 |
+
i += 1
|
| 32 |
+
if pos[k] < len(pools[k]):
|
| 33 |
+
out.append(pools[k][pos[k]])
|
| 34 |
+
pos[k] += 1
|
| 35 |
+
return out
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def letter(L, k):
|
| 39 |
+
"""check: the last 'Answer: X' of the response is the letter L (X among the first k letters)."""
|
| 40 |
+
pat = rf"Answer:[\s*(]*([{LETTERS[:k]}])\b"
|
| 41 |
+
return lambda resp: (re.findall(pat, resp) or [None])[-1] == L
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def token(target):
|
| 45 |
+
"""check: the last 'Answer: X' of the response has the single word/number X equal to the target (case-insensitive, '(A)' = 'a')."""
|
| 46 |
+
want = re.sub(r"[^a-z0-9\-]", "", target.casefold())
|
| 47 |
+
return lambda resp: bool((got := re.findall(r"Answer:[\s*(\[]*([A-Za-z0-9\-]+)", resp))) and got[-1].casefold() == want
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
# ---------------------------------------------------------------------------------------------------------------------------------- code
|
| 51 |
+
def pool_code(rnd, run_code, code_of):
|
| 52 |
+
from datasets import load_dataset
|
| 53 |
+
he, mb = [], []
|
| 54 |
+
for r in load_dataset("evalplus/humanevalplus", split="test"):
|
| 55 |
+
tests = r["test"] + f"\n\ncheck({r['entry_point']})"
|
| 56 |
+
he.append((f"code_he{r['task_id'].split('/')[-1]}", "code",
|
| 57 |
+
"Complete this Python function. Reply with one Python code block containing the whole function (and any imports it needs).\n\n"
|
| 58 |
+
f"```python\n{r['prompt']}```",
|
| 59 |
+
(lambda t: lambda resp: run_code(code_of(resp), t, 20))(tests), f"```python\n{r['prompt']}{r['canonical_solution']}\n```"))
|
| 60 |
+
for r in load_dataset("google-research-datasets/mbpp", "sanitized", split="test"):
|
| 61 |
+
tests = "\n".join(r["test_imports"]) + "\n" + "\n".join(r["test_list"])
|
| 62 |
+
mb.append((f"code_mbpp{r['task_id']}", "code",
|
| 63 |
+
"Write a Python function for the task below. Reply with one Python code block containing the whole function (and any imports it "
|
| 64 |
+
f"needs).\n\nTask: {r['prompt']}\n\nYour function must pass these tests (they fix its name and signature):\n" + "\n".join(r["test_list"]),
|
| 65 |
+
(lambda t: lambda resp: run_code(code_of(resp), t, 20))(tests), f"```python\n{r['code']}\n```"))
|
| 66 |
+
he, mb = [t for t in he if t[0] not in BAD_CODE], [t for t in mb if t[0] not in BAD_CODE]
|
| 67 |
+
rnd.shuffle(he)
|
| 68 |
+
rnd.shuffle(mb)
|
| 69 |
+
return mix([he, mb], "00111") # 2 HumanEval+ : 3 MBPP per cycle of five
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
# ---------------------------------------------------------------------------------------------------------------------------------- math
|
| 73 |
+
def pool_math(rnd, num):
|
| 74 |
+
from datasets import load_dataset
|
| 75 |
+
ma, ai = [], []
|
| 76 |
+
for r in load_dataset("HuggingFaceH4/MATH-500", split="test"):
|
| 77 |
+
if re.fullmatch(r"-?\d+", str(r["answer"]).strip()) and int(r["level"]) >= 2:
|
| 78 |
+
ans = Fr(str(r["answer"]).strip())
|
| 79 |
+
ma.append((f"math_{r['unique_id'].replace('/', '_').removesuffix('.json')}", "math", r["problem"] + HOW, num(ans), f"#### {ans}"))
|
| 80 |
+
for r in load_dataset("AI-MO/aimo-validation-aime", split="train"):
|
| 81 |
+
if re.fullmatch(r"-?\d+", str(r["answer"]).strip()):
|
| 82 |
+
ans = Fr(str(r["answer"]).strip())
|
| 83 |
+
ai.append((f"math_aime{r['id']}", "math", r["problem"] + HOW, num(ans), f"#### {ans}"))
|
| 84 |
+
rnd.shuffle(ma)
|
| 85 |
+
rnd.shuffle(ai)
|
| 86 |
+
return mix([ma, ai], "0001") # 3 MATH-500 : 1 AIME
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
# ---------------------------------------------------------------------------------------------------------------------------------- reasoning
|
| 90 |
+
BBH = { # task -> the closing instruction that names the answer format
|
| 91 |
+
"logical_deduction_five_objects": "Answer: <option letter>", "tracking_shuffled_objects_five_objects": "Answer: <option letter>",
|
| 92 |
+
"date_understanding": "Answer: <option letter>", "web_of_lies": "Answer: Yes or Answer: No", "boolean_expressions": "Answer: True or Answer: False",
|
| 93 |
+
"navigate": "Answer: Yes or Answer: No", "formal_fallacies": "Answer: valid or Answer: invalid", "object_counting": "Answer: <integer>"}
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def pool_reason(rnd):
|
| 97 |
+
from datasets import load_dataset
|
| 98 |
+
by = {}
|
| 99 |
+
for r in load_dataset("TIGER-Lab/MMLU-Pro", split="test"):
|
| 100 |
+
by.setdefault(r["category"], []).append(r)
|
| 101 |
+
cats = sorted(by)
|
| 102 |
+
for c in cats:
|
| 103 |
+
rnd.shuffle(by[c])
|
| 104 |
+
mm = []
|
| 105 |
+
for i in range(18): # round-robin over the 14 subjects, the subject order shuffled each round
|
| 106 |
+
order = cats[:]
|
| 107 |
+
rnd.shuffle(order)
|
| 108 |
+
for c in order:
|
| 109 |
+
r = by[c][i]
|
| 110 |
+
opts = "\n".join(f"{LETTERS[j]}. {o}" for j, o in enumerate(r["options"]))
|
| 111 |
+
mm.append((f"reason_mmlu{r['question_id']}", "reason", f"{r['question']}\n\n{opts}\n\nThink step by step, then end with exactly: Answer: <letter>",
|
| 112 |
+
letter(r["answer"], 10), f"Answer: {r['answer']}"))
|
| 113 |
+
mm = mm[:240]
|
| 114 |
+
bb = []
|
| 115 |
+
for task, fmt in BBH.items():
|
| 116 |
+
rows = list(load_dataset("lukaemon/bbh", task, split="test"))
|
| 117 |
+
rnd.shuffle(rows)
|
| 118 |
+
bb.append([(f"reason_bbh_{task}_{k}", "reason", f"{r['input']}\n\nThink step by step, then end with exactly: {fmt}", token(r["target"]),
|
| 119 |
+
f"Answer: {r['target'].strip('()')}") for k, r in enumerate(rows[:15])])
|
| 120 |
+
return mix([mm, mix(bb, "01234567")], "001") # 2 MMLU-Pro : 1 BBH
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
# ---------------------------------------------------------------------------------------------------------------------------------- English
|
| 124 |
+
def _words(r):
|
| 125 |
+
return len(re.findall(r"\w+", r))
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
C = {} # constraint name -> (tag, make); make(rnd) -> (rule sentence, check, a response that passes, a response that fails)
|
| 129 |
+
CLASH = [("lowercase", "end_phrase"), ("lowercase", "start_word"), ("lowercase", "postscript"), ("uppercase", "end_phrase"),
|
| 130 |
+
("uppercase", "start_word"), ("wrap_quotes", "end_phrase"), ("wrap_quotes", "start_word"), ("wrap_quotes", "postscript"),
|
| 131 |
+
("end_phrase", "postscript"), ("title", "start_word")]
|
| 132 |
+
KEYS = ("river", "lantern", "courage", "market", "silver", "window", "winter", "bridge")
|
| 133 |
+
BANNED = ("very", "really", "good", "nice", "thing")
|
| 134 |
+
ENDS = ("Is there anything else I can help with?", "That is all for now.", "Thank you for reading.")
|
| 135 |
+
STARTS = ("Today", "Imagine", "Remember", "Consider")
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def cons(tag):
|
| 139 |
+
def deco(f):
|
| 140 |
+
C[f.__name__] = (tag, f)
|
| 141 |
+
return f
|
| 142 |
+
return deco
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
@cons("len")
|
| 146 |
+
def words_min(rnd):
|
| 147 |
+
n = rnd.choice((80, 120, 150, 200))
|
| 148 |
+
return f"Your response must contain at least {n} words.", lambda r: _words(r) >= n, "word " * n, "word " * (n - 1)
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
@cons("len")
|
| 152 |
+
def words_max(rnd):
|
| 153 |
+
n = rnd.choice((60, 80, 100, 120))
|
| 154 |
+
return f"Your response must contain fewer than {n} words.", lambda r: _words(r) < n, "word " * (n - 1), "word " * n
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
@cons("struct")
|
| 158 |
+
def paragraphs(rnd):
|
| 159 |
+
n = rnd.choice((2, 3, 4))
|
| 160 |
+
return (f"Write exactly {n} paragraphs, separated from each other by a line containing only ***.",
|
| 161 |
+
lambda r: len(p := re.split(r"(?m)^[ \t]*\*\*\*[ \t]*$", r.strip())) == n and all(x.strip() for x in p),
|
| 162 |
+
"\n***\n".join(["para"] * n), "\n***\n".join(["para"] * (n + 1)))
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
@cons("struct")
|
| 166 |
+
def bullets(rnd):
|
| 167 |
+
n = rnd.choice((3, 4, 5))
|
| 168 |
+
return (f"Use exactly {n} bullet points in markdown format, each line starting with \"* \", and no other bullets.",
|
| 169 |
+
lambda r: sum(1 for l in r.splitlines() if re.match(r"\s*\* ", l)) == n, "\n".join(["* item"] * n), "\n".join(["* item"] * (n + 1)))
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
@cons("kw")
|
| 173 |
+
def keywords(rnd):
|
| 174 |
+
a, b = rnd.sample(KEYS, 2)
|
| 175 |
+
return (f"Include the words \"{a}\" and \"{b}\".", lambda r: all(re.search(rf"\b{k}\b", r, re.I) for k in (a, b)), f"{a} and {b}", f"only {a}")
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
@cons("forbid")
|
| 179 |
+
def forbid(rnd):
|
| 180 |
+
w = rnd.choice(BANNED)
|
| 181 |
+
return f"Do not use the word \"{w}\" anywhere.", lambda r: not re.search(rf"\b{w}\b", r, re.I), "fine text", f"a {w} text"
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
@cons("case")
|
| 185 |
+
def lowercase(rnd):
|
| 186 |
+
return "Your entire response must be in lowercase letters, with no capital letters at all.", lambda r: r == r.lower(), "all lower", "Not lower"
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
@cons("case")
|
| 190 |
+
def uppercase(rnd):
|
| 191 |
+
return "Your entire response must be in ALL CAPITAL LETTERS.", lambda r: r == r.upper(), "ALL UPPER", "Not upper"
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
@cons("end")
|
| 195 |
+
def end_phrase(rnd):
|
| 196 |
+
p = rnd.choice(ENDS)
|
| 197 |
+
return f"Finish your response with the exact phrase \"{p}\" and add nothing after it.", lambda r: r.strip().endswith(p), f"text {p}", f"{p} text"
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
@cons("start")
|
| 201 |
+
def start_word(rnd):
|
| 202 |
+
w = rnd.choice(STARTS)
|
| 203 |
+
return f"Begin your response with the word \"{w}\".", lambda r: bool(re.match(rf"\W*{w}\b", r.strip())), f"{w} is a day", f"Then {w}"
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
@cons("wrap")
|
| 207 |
+
def wrap_quotes(rnd):
|
| 208 |
+
return ("Wrap your entire response in double quotation marks.", lambda r: len(r.strip()) > 1 and r.strip()[0] == '"' and r.strip()[-1] == '"',
|
| 209 |
+
'"text"', "text")
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
@cons("title")
|
| 213 |
+
def title(rnd):
|
| 214 |
+
return "Include a title wrapped in double angular brackets, like <<title>>.", lambda r: bool(re.search(r"<<[^<>\n]+>>", r)), "<<A title>> body", "A title body"
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
@cons("punct")
|
| 218 |
+
def no_commas(rnd):
|
| 219 |
+
return "Do not use any commas in your response.", lambda r: "," not in r, "no comma", "a, b"
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
@cons("ps")
|
| 223 |
+
def postscript(rnd):
|
| 224 |
+
return "At the end, add a postscript that starts with P.S.", lambda r: bool(re.search(r"(?m)^\s*P\.S\.", r)), "text\nP.S. more", "text"
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
@cons("letter")
|
| 228 |
+
def letter_z(rnd):
|
| 229 |
+
n = rnd.choice((3, 5))
|
| 230 |
+
return f"The letter \"z\" must appear at least {n} times.", lambda r: r.lower().count("z") >= n, "z" * n, "z" * (n - 1)
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
TOPICS = ("a rainy morning in a small town", "why sleep matters", "the history of tea", "a lost umbrella", "learning to swim as an adult", "a city without cars",
|
| 234 |
+
"the first day at a new job", "a village market", "the smell of fresh bread", "an old lighthouse", "a long train journey", "keeping a diary",
|
| 235 |
+
"a robot that learns to paint", "the quiet of a library", "planting a vegetable garden", "a broken clock", "moving to another country",
|
| 236 |
+
"the last bus home", "a mountain hike", "a neighbour who plays the violin", "saving money as a student", "a power cut at night",
|
| 237 |
+
"the invention of the bicycle", "a street musician", "cooking for a big family", "an unexpected letter", "the sound of the sea",
|
| 238 |
+
"a school sports day", "a very small apartment", "the first snow of winter")
|
| 239 |
+
FORMS = ("short story", "product description", "email to a colleague", "blog post", "poem", "short speech", "review", "letter to a friend",
|
| 240 |
+
"news summary", "explanation for a ten-year-old")
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
def pool_en(rnd):
|
| 244 |
+
from datasets import load_dataset
|
| 245 |
+
race = list(load_dataset("ehovy/race", "high", split="test"))
|
| 246 |
+
rnd.shuffle(race)
|
| 247 |
+
ra = []
|
| 248 |
+
for k, r in enumerate(race[:120]): # several questions share one passage id, so the position is part of the task id
|
| 249 |
+
opts = "\n".join(f"{LETTERS[j]}. {o}" for j, o in enumerate(r["options"]))
|
| 250 |
+
ra.append((f"en_race_{k:03d}_{r['example_id'].replace('/', '_').replace('.txt', '')}", "en",
|
| 251 |
+
f"Read the passage, then answer the question.\n\nPassage:\n{r['article']}\n\nQuestion: {r['question']}\n\n{opts}\n\n"
|
| 252 |
+
"Think briefly, then end with exactly: Answer: <letter>", letter(r["answer"], 4), f"Answer: {r['answer']}"))
|
| 253 |
+
cola = list(load_dataset("nyu-mll/glue", "cola", split="validation"))
|
| 254 |
+
yes, no = [r for r in cola if r["label"] == 1], [r for r in cola if r["label"] == 0]
|
| 255 |
+
rnd.shuffle(yes)
|
| 256 |
+
rnd.shuffle(no)
|
| 257 |
+
co = []
|
| 258 |
+
for r in mix([yes[:60], no[:60]], "01"):
|
| 259 |
+
co.append((f"en_cola_{r['idx']}", "en", "Is this sentence grammatically acceptable English, as a careful native speaker would judge it?\n\n"
|
| 260 |
+
f"Sentence: {r['sentence']}\n\nGive at most two sentences of reasoning, then end with exactly: Answer: Yes or Answer: No",
|
| 261 |
+
token("Yes" if r["label"] == 1 else "No"), f"Answer: {'Yes' if r['label'] == 1 else 'No'}"))
|
| 262 |
+
wr, names = [], sorted(C)
|
| 263 |
+
for i in range(120):
|
| 264 |
+
for _ in range(200):
|
| 265 |
+
pick = rnd.sample(names, 2 if rnd.random() < 0.7 else 3)
|
| 266 |
+
if len({C[n][0] for n in pick}) == len(pick) and not any(a in pick and b in pick for a, b in CLASH):
|
| 267 |
+
break
|
| 268 |
+
parts = [C[n][1](rnd) for n in pick]
|
| 269 |
+
wr.append((f"en_if{i:03d}", "en", f"Write a {rnd.choice(FORMS)} about {rnd.choice(TOPICS)}. Follow every rule below.\n" + "\n".join(f"- {p[0]}" for p in parts),
|
| 270 |
+
(lambda cs: lambda resp: all(c(resp) for c in cs))([p[1] for p in parts]), None))
|
| 271 |
+
return mix([ra, co, wr], "012")
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
# ---------------------------------------------------------------------------------------------------------------------------------- the suite
|
| 275 |
+
def build_big(seed, n, run_code, code_of, num):
|
| 276 |
+
"""[(id, category, prompt, check(response) -> bool, reference response or None)]: the first n tasks of each pool (nested for any n)."""
|
| 277 |
+
T = []
|
| 278 |
+
for name, pool in (("code", lambda r: pool_code(r, run_code, code_of)), ("math", lambda r: pool_math(r, num)), ("reason", pool_reason), ("en", pool_en)):
|
| 279 |
+
T += pool(random.Random(f"{seed}big{name}"))[:n]
|
| 280 |
+
assert len({t[0] for t in T}) == len(T), "duplicate task ids"
|
| 281 |
+
return T
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
def constraint_unit_tests():
|
| 285 |
+
bad = []
|
| 286 |
+
for name, (tag, make) in C.items():
|
| 287 |
+
for s in range(8):
|
| 288 |
+
_, chk, good, worse = make(random.Random(s))
|
| 289 |
+
if not chk(good) or chk(worse):
|
| 290 |
+
bad.append((name, s))
|
| 291 |
+
return bad
|
| 292 |
+
|
| 293 |
+
|
| 294 |
+
if __name__ == "__main__" and sys.argv[1:] in (["selftest"], ["validate"]):
|
| 295 |
+
import importlib
|
| 296 |
+
sys.path.insert(0, __import__("pathlib").Path(__file__).resolve().parent.as_posix())
|
| 297 |
+
m = importlib.import_module("07_domain_eval")
|
| 298 |
+
if sys.argv[1] == "selftest":
|
| 299 |
+
assert not constraint_unit_tests(), constraint_unit_tests()
|
| 300 |
+
T = build_big(1, 12, m.run_code, m.code_of, m.num)
|
| 301 |
+
ref = [t for t in T if t[4] is not None]
|
| 302 |
+
bad = [t[0] for t in ref if not t[3](t[4])]
|
| 303 |
+
junk = [t[0] for t in T if t[4] is not None and t[3]("zzz 987654321")] # the constraint tasks have no reference and garbage may satisfy a rule
|
| 304 |
+
per = {c: sum(t[1] == c for t in T) for c in ("code", "math", "reason", "en")}
|
| 305 |
+
assert not bad and not junk and per == {c: 12 for c in per} and len({t[0] for t in T}) == len(T), (bad, junk, per)
|
| 306 |
+
print(f"selftest OK: {len(T)} tasks {per}, {len(ref)} references pass, garbage fails, {len(C)} constraint checkers pass their own examples")
|
| 307 |
+
else:
|
| 308 |
+
bad = [t[0] for t in pool_code(random.Random("v"), m.run_code, m.code_of) if not t[3](t[4])]
|
| 309 |
+
print(f"{len(bad)} reference solutions fail: BAD_CODE = {set(bad)!r}")
|
benchmarks/scripts/10_code_hard.py
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
"""
|
| 4 |
+
10_code_hard.py - harder coding benchmarks behind `07_domain_eval.py run --suite codehard --hard-n N` (N tasks per benchmark, nested prefixes):
|
| 5 |
+
lcb LiveCodeBench code_generation_lite, release 6: 175 AtCoder and LeetCode contest problems from 2025-01 to 2025-04 (newer than most training
|
| 6 |
+
data), about 40 hidden tests each; the model writes a whole program (stdin/stdout) or a LeetCode class, every test must pass.
|
| 7 |
+
The task id carries the difficulty: lcb_easy_..., lcb_medium_..., lcb_hard_...
|
| 8 |
+
crux CRUXEval (800 short Python functions), half output prediction (CRUXEval-O) and half input prediction (CRUXEval-I): code understanding,
|
| 9 |
+
checked by running `assert f(...) == ...` on the model's answer.
|
| 10 |
+
Public data, no token. Needs `pip install datasets` and network (the LiveCodeBench file is about 1 GB). THE MODEL-WRITTEN CODE IS EXECUTED (see 07).
|
| 11 |
+
Use `--max-tokens 4096 --ctx 8192` for the lcb tasks (long answers). Checks:
|
| 12 |
+
python 10_code_hard.py selftest lookup-table solutions pass every test of a few lcb problems, wrong ones fail; crux references pass
|
| 13 |
+
python 10_code_hard.py validate runs all 800 crux references and prints the ids to put in BAD_CRUX
|
| 14 |
+
"""
|
| 15 |
+
import base64
|
| 16 |
+
import io
|
| 17 |
+
import json
|
| 18 |
+
import os
|
| 19 |
+
import pickle
|
| 20 |
+
import random
|
| 21 |
+
import re
|
| 22 |
+
import subprocess
|
| 23 |
+
import sys
|
| 24 |
+
import tempfile
|
| 25 |
+
import time
|
| 26 |
+
import zlib
|
| 27 |
+
from pathlib import Path
|
| 28 |
+
|
| 29 |
+
LCB_FILES = ("test6",) # release 6 (2025-01 .. 2025-04); add "test5" (2024-09 .. 2025-01) for a bigger pool
|
| 30 |
+
BAD_CRUX = set() # crux ids whose own reference fails (filled by `validate`)
|
| 31 |
+
HEADER = ("from string import *\nfrom re import *\nfrom datetime import *\nfrom collections import *\nfrom heapq import *\nfrom bisect import *\n"
|
| 32 |
+
"from copy import deepcopy\nfrom math import *\nfrom typing import *\nfrom functools import *\nfrom itertools import *\nfrom operator import *\n"
|
| 33 |
+
"from random import *\nfrom statistics import *\nimport sys, heapq, bisect, math, collections, itertools, functools, random, string, re, json, copy\n")
|
| 34 |
+
FUNC_RUNNER = '''import json, sys
|
| 35 |
+
ns = {}
|
| 36 |
+
exec(compile(open("sol.py", encoding="utf-8").read(), "sol.py", "exec"), ns)
|
| 37 |
+
f = getattr(ns["Solution"](), sys.argv[1])
|
| 38 |
+
for inp, out in json.load(open("tests.json", encoding="utf-8")):
|
| 39 |
+
got = f(*[json.loads(l) for l in inp.split("\\n") if l.strip()])
|
| 40 |
+
if json.loads(json.dumps(got)) != json.loads(out):
|
| 41 |
+
print("FAIL")
|
| 42 |
+
sys.exit(1)
|
| 43 |
+
print("OK")
|
| 44 |
+
'''
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# ---------------------------------------------------------------------------------------------------------------------------------- LiveCodeBench
|
| 48 |
+
class _Plain(pickle.Unpickler):
|
| 49 |
+
"""The private tests are a pickled JSON string; a string needs no globals, so refuse every one (a dataset must not run code while loading)."""
|
| 50 |
+
def find_class(self, module, name):
|
| 51 |
+
raise pickle.UnpicklingError(f"global {module}.{name} refused")
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def decode_private(s):
|
| 55 |
+
return json.loads(_Plain(io.BytesIO(zlib.decompress(base64.b64decode(s)))).load())
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def lcb_tests(row):
|
| 59 |
+
return json.loads(row["public_test_cases"]) + decode_private(row["private_test_cases"])
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def _same(got, want):
|
| 63 |
+
g, w = [l.rstrip() for l in got.strip().splitlines()], [l.rstrip() for l in want.strip().splitlines()]
|
| 64 |
+
if len(g) != len(w):
|
| 65 |
+
return False
|
| 66 |
+
for a, b in zip(g, w):
|
| 67 |
+
if a == b:
|
| 68 |
+
continue
|
| 69 |
+
ta, tb = a.split(), b.split()
|
| 70 |
+
if len(ta) != len(tb):
|
| 71 |
+
return False
|
| 72 |
+
for x, y in zip(ta, tb):
|
| 73 |
+
if x == y:
|
| 74 |
+
continue
|
| 75 |
+
if re.fullmatch(r"-?\d+", x) and re.fullmatch(r"-?\d+", y): # integers are exact
|
| 76 |
+
return False
|
| 77 |
+
try:
|
| 78 |
+
if abs(float(x) - float(y)) > 1e-6 * max(1.0, abs(float(y))):
|
| 79 |
+
return False
|
| 80 |
+
except ValueError:
|
| 81 |
+
return False
|
| 82 |
+
return True
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def _limits():
|
| 86 |
+
if os.name != "posix":
|
| 87 |
+
return None
|
| 88 |
+
import resource
|
| 89 |
+
return lambda: resource.setrlimit(resource.RLIMIT_AS, (2 << 30, 2 << 30))
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def run_lcb(code, tests, func, total=90, per=8):
|
| 93 |
+
"""True when `code` passes every test: func None = a stdin/stdout program (one process per test), else a LeetCode Solution method."""
|
| 94 |
+
env = {**os.environ, "OPENBLAS_NUM_THREADS": "1", "OMP_NUM_THREADS": "1"}
|
| 95 |
+
with tempfile.TemporaryDirectory() as d:
|
| 96 |
+
d = Path(d)
|
| 97 |
+
(d / "sol.py").write_text(HEADER + code, encoding="utf-8")
|
| 98 |
+
t0 = time.time()
|
| 99 |
+
if func is None:
|
| 100 |
+
for t in tests:
|
| 101 |
+
if time.time() - t0 > total:
|
| 102 |
+
return False
|
| 103 |
+
try:
|
| 104 |
+
r = subprocess.run([sys.executable, "-I", "sol.py"], input=t["input"], capture_output=True, text=True, timeout=per, cwd=d, env=env,
|
| 105 |
+
preexec_fn=_limits())
|
| 106 |
+
except (subprocess.TimeoutExpired, UnicodeDecodeError):
|
| 107 |
+
return False
|
| 108 |
+
if r.returncode != 0 or not _same(r.stdout, t["output"]):
|
| 109 |
+
return False
|
| 110 |
+
return True
|
| 111 |
+
(d / "tests.json").write_text(json.dumps([[t["input"], t["output"]] for t in tests]), encoding="utf-8")
|
| 112 |
+
(d / "run.py").write_text(FUNC_RUNNER, encoding="utf-8")
|
| 113 |
+
try:
|
| 114 |
+
r = subprocess.run([sys.executable, "-I", "run.py", func], capture_output=True, text=True, timeout=total, cwd=d, env=env, preexec_fn=_limits())
|
| 115 |
+
except (subprocess.TimeoutExpired, UnicodeDecodeError):
|
| 116 |
+
return False
|
| 117 |
+
return r.returncode == 0 and r.stdout.strip().endswith("OK")
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
FUNC_DEBUG = '''import json, sys, traceback
|
| 121 |
+
ns = {}
|
| 122 |
+
exec(compile(open("sol.py", encoding="utf-8").read(), "sol.py", "exec"), ns)
|
| 123 |
+
f = getattr(ns["Solution"](), sys.argv[1])
|
| 124 |
+
for inp, out in json.load(open("tests.json", encoding="utf-8")):
|
| 125 |
+
try:
|
| 126 |
+
got = f(*[json.loads(l) for l in inp.split("\\n") if l.strip()])
|
| 127 |
+
except Exception:
|
| 128 |
+
print("Input:\\n" + inp.strip()[:300] + "\\nRuntime error:\\n" + traceback.format_exc()[-600:])
|
| 129 |
+
sys.exit(1)
|
| 130 |
+
if json.loads(json.dumps(got)) != json.loads(out):
|
| 131 |
+
print("Input:\\n" + inp.strip()[:300] + "\\nExpected output:\\n" + out.strip()[:300] + "\\nYour output:\\n" + json.dumps(got)[:300])
|
| 132 |
+
sys.exit(1)
|
| 133 |
+
print("OK")
|
| 134 |
+
'''
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def first_failure(code, tests, func, per=8):
|
| 138 |
+
"""None when `code` passes every test in `tests` (the VISIBLE sample tests), else a short text on the first failure, for a repair prompt."""
|
| 139 |
+
env = {**os.environ, "OPENBLAS_NUM_THREADS": "1", "OMP_NUM_THREADS": "1"}
|
| 140 |
+
with tempfile.TemporaryDirectory() as d:
|
| 141 |
+
d = Path(d)
|
| 142 |
+
(d / "sol.py").write_text(HEADER + code, encoding="utf-8")
|
| 143 |
+
if func is None:
|
| 144 |
+
for t in tests:
|
| 145 |
+
shown = "Input:\n" + t["input"].strip()[:300]
|
| 146 |
+
try:
|
| 147 |
+
r = subprocess.run([sys.executable, "-I", "sol.py"], input=t["input"], capture_output=True, text=True, timeout=per, cwd=d, env=env,
|
| 148 |
+
preexec_fn=_limits())
|
| 149 |
+
except subprocess.TimeoutExpired:
|
| 150 |
+
return f"{shown}\nThe program did not finish within {per} seconds."
|
| 151 |
+
except UnicodeDecodeError:
|
| 152 |
+
return f"{shown}\nThe program printed bytes that are not valid text."
|
| 153 |
+
if r.returncode != 0:
|
| 154 |
+
return f"{shown}\nRuntime error:\n{r.stderr[-600:]}"
|
| 155 |
+
if not _same(r.stdout, t["output"]):
|
| 156 |
+
return f"{shown}\nExpected output:\n{t['output'].strip()[:300]}\nYour output:\n{r.stdout.strip()[:300]}"
|
| 157 |
+
return None
|
| 158 |
+
(d / "tests.json").write_text(json.dumps([[t["input"], t["output"]] for t in tests]), encoding="utf-8")
|
| 159 |
+
(d / "run.py").write_text(FUNC_DEBUG, encoding="utf-8")
|
| 160 |
+
try:
|
| 161 |
+
r = subprocess.run([sys.executable, "-I", "run.py", func], capture_output=True, text=True, timeout=per * 4, cwd=d, env=env, preexec_fn=_limits())
|
| 162 |
+
except subprocess.TimeoutExpired:
|
| 163 |
+
return "The code did not finish in time on the sample tests."
|
| 164 |
+
except UnicodeDecodeError:
|
| 165 |
+
return "The code printed bytes that are not valid text."
|
| 166 |
+
if r.returncode == 0 and r.stdout.strip().endswith("OK"):
|
| 167 |
+
return None
|
| 168 |
+
return (r.stdout or r.stderr).strip()[-800:] or "The code crashed."
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
def lcb_feedback(resp, row, func):
|
| 172 |
+
"""What to tell the model after a failed attempt: only the visible sample tests are used (never the hidden ones); None = no new information."""
|
| 173 |
+
code = last_block(resp)
|
| 174 |
+
if not code.strip():
|
| 175 |
+
return "I could not find a ```python code block in your answer. Give the complete solution in one ```python block."
|
| 176 |
+
bad = first_failure(code, json.loads(row["public_test_cases"]), func)
|
| 177 |
+
if bad is None:
|
| 178 |
+
return None
|
| 179 |
+
return "Your code fails this sample test.\n\n" + bad + "\n\nFix the code. Reply with the complete corrected solution in one ```python block."
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
def last_block(resp):
|
| 183 |
+
blocks = re.findall(r"```(?:python|py|Python)?[ \t]*\n(.*?)```", resp, flags=re.S)
|
| 184 |
+
return blocks[-1] if blocks else ""
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
def lcb_prompt(row):
|
| 188 |
+
if row["starter_code"]:
|
| 189 |
+
fmt = "You will use the following starter code to write the solution to the problem and enclose your code within delimiters."
|
| 190 |
+
block = row["starter_code"]
|
| 191 |
+
else:
|
| 192 |
+
fmt = ("Read the inputs from stdin solve the problem and write the answer to stdout (do not directly test on the sample inputs). Enclose your "
|
| 193 |
+
"code within delimiters as follows. Ensure that when the python program runs, it reads the inputs, runs the algorithm and writes output "
|
| 194 |
+
"to STDOUT.")
|
| 195 |
+
block = "# YOUR CODE HERE"
|
| 196 |
+
return f"### Question:\n{row['question_content']}\n\n### Format: {fmt}\n```python\n{block}\n```\n\n### Answer: (use the provided format with backticks)\n"
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
def lcb_rows():
|
| 200 |
+
from datasets import load_dataset
|
| 201 |
+
rows = []
|
| 202 |
+
for f in LCB_FILES:
|
| 203 |
+
rows += list(load_dataset("json", data_files=f"hf://datasets/livecodebench/code_generation_lite/{f}.jsonl", split="train"))
|
| 204 |
+
return rows
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
def pool_lcb(rnd):
|
| 208 |
+
rows = lcb_rows()
|
| 209 |
+
rnd.shuffle(rows)
|
| 210 |
+
T = []
|
| 211 |
+
for r in rows:
|
| 212 |
+
func = json.loads(r["metadata"] or "{}").get("func_name") if r["starter_code"] else None
|
| 213 |
+
|
| 214 |
+
def check(resp, r=r, func=func, cache={}):
|
| 215 |
+
code = last_block(resp)
|
| 216 |
+
if not code.strip():
|
| 217 |
+
return False
|
| 218 |
+
if r["question_id"] not in cache:
|
| 219 |
+
cache.clear()
|
| 220 |
+
cache[r["question_id"]] = lcb_tests(r)
|
| 221 |
+
return run_lcb(code, cache[r["question_id"]], func)
|
| 222 |
+
check.feedback = lambda resp, r=r, func=func: lcb_feedback(resp, r, func) # used by `07 run --retry N`
|
| 223 |
+
T.append((f"lcb_{r['difficulty']}_{r['question_id']}", "lcb", lcb_prompt(r), check, None))
|
| 224 |
+
return T
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
# ---------------------------------------------------------------------------------------------------------------------------------- CRUXEval
|
| 228 |
+
def pool_crux(rnd, run_code):
|
| 229 |
+
from datasets import load_dataset
|
| 230 |
+
rows = [r for r in load_dataset("cruxeval-org/cruxeval", split="test")]
|
| 231 |
+
ro, ri = rows[:], rows[:]
|
| 232 |
+
rnd.shuffle(ro)
|
| 233 |
+
rnd.shuffle(ri)
|
| 234 |
+
O, I = [], []
|
| 235 |
+
for r in ro:
|
| 236 |
+
if f"crux_o_{r['id']}" in BAD_CRUX:
|
| 237 |
+
continue
|
| 238 |
+
pro = ("You are given a Python function and an assertion containing an input to the function. Complete the assertion with a literal (no "
|
| 239 |
+
"unsimplified expressions, no function calls) containing the output when executing the provided code on the given input, even if the "
|
| 240 |
+
"function is incorrect or incomplete. Think step by step, then end with exactly one line in this form: [ANSWER] assert f(...) == <literal> "
|
| 241 |
+
f"[/ANSWER]\n\n```python\n{r['code']}\nassert f({r['input']}) == ??\n```")
|
| 242 |
+
|
| 243 |
+
def check_o(resp, r=r):
|
| 244 |
+
m = re.findall(r"\[ANSWER\]\s*assert\s+f\(.*?\)\s*==\s*(.*?)\s*\[/ANSWER\]", resp, flags=re.S)
|
| 245 |
+
return bool(m) and run_code(r["code"], f"assert f({r['input']}) == ({m[-1]})", 10)
|
| 246 |
+
O.append((f"crux_o_{r['id']}", "crux", pro, check_o, f"[ANSWER] assert f({r['input']}) == {r['output']} [/ANSWER]"))
|
| 247 |
+
for r in ri:
|
| 248 |
+
if f"crux_i_{r['id']}" in BAD_CRUX:
|
| 249 |
+
continue
|
| 250 |
+
pri = ("You are given a Python function and an assertion containing an output of the function. Find any input such that executing the function "
|
| 251 |
+
"on the input leads to the given output. There may be several answers, give only one. Think step by step, then end with exactly one line "
|
| 252 |
+
f"in this form: [ANSWER] assert f(<your input>) == {r['output']} [/ANSWER]\n\n```python\n{r['code']}\nassert f(??) == {r['output']}\n```")
|
| 253 |
+
|
| 254 |
+
def check_i(resp, r=r):
|
| 255 |
+
m = re.findall(r"\[ANSWER\]\s*assert\s+f\((.*)\)\s*==", resp, flags=re.S)
|
| 256 |
+
return bool(m) and run_code(r["code"], f"assert f({m[-1]}) == {r['output']}", 10)
|
| 257 |
+
I.append((f"crux_i_{r['id']}", "crux", pri, check_i, f"[ANSWER] assert f({r['input']}) == {r['output']} [/ANSWER]"))
|
| 258 |
+
mixed, i = [], 0
|
| 259 |
+
while i < min(len(O), len(I)):
|
| 260 |
+
mixed += [O[i], I[i]]
|
| 261 |
+
i += 1
|
| 262 |
+
return mixed
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
# ---------------------------------------------------------------------------------------------------------------------------------- the suite
|
| 266 |
+
def build_codehard(seed, n, run_code, code_of, num):
|
| 267 |
+
"""[(id, category, prompt, check(response) -> bool, reference response or None)]: the first n lcb problems and the first n crux tasks."""
|
| 268 |
+
T = pool_lcb(random.Random(f"{seed}lcb"))[:n] + pool_crux(random.Random(f"{seed}crux"), run_code)[:n]
|
| 269 |
+
assert len({t[0] for t in T}) == len(T), "duplicate task ids"
|
| 270 |
+
return T
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
def _lookup_solution(row, tests):
|
| 274 |
+
"""A 'solution' that only looks the answers up: it passes iff the runner, the decoding and the comparison are right."""
|
| 275 |
+
if not row["starter_code"]:
|
| 276 |
+
return "import sys\nD = " + repr({t["input"]: t["output"] for t in tests}) + "\nprint(D[sys.stdin.read()], end='')\n", None
|
| 277 |
+
func = json.loads(row["metadata"])["func_name"]
|
| 278 |
+
D = {json.dumps([json.loads(l) for l in t["input"].split("\n") if l.strip()]): t["output"] for t in tests}
|
| 279 |
+
return f"import json\nD = {D!r}\nclass Solution:\n def {func}(self, *a):\n return json.loads(D[json.dumps(list(a))])\n", func
|
| 280 |
+
|
| 281 |
+
|
| 282 |
+
if __name__ == "__main__" and sys.argv[1:] in (["selftest"], ["validate"]):
|
| 283 |
+
import importlib
|
| 284 |
+
sys.path.insert(0, Path(__file__).resolve().parent.as_posix())
|
| 285 |
+
m = importlib.import_module("07_domain_eval")
|
| 286 |
+
if sys.argv[1] == "selftest":
|
| 287 |
+
rows = lcb_rows()
|
| 288 |
+
stdin, func = [r for r in rows if not r["starter_code"]][:4], [r for r in rows if r["starter_code"]][:4]
|
| 289 |
+
for r in stdin + func:
|
| 290 |
+
tests = lcb_tests(r)
|
| 291 |
+
code, fn = _lookup_solution(r, tests)
|
| 292 |
+
assert run_lcb(code, tests, fn), ("lookup solution failed", r["question_id"])
|
| 293 |
+
wrong = "print(0)\n" if fn is None else f"class Solution:\n def {fn}(self, *a):\n return None\n"
|
| 294 |
+
assert not run_lcb(wrong, tests, fn), ("wrong solution passed", r["question_id"])
|
| 295 |
+
assert last_block("text\n```python\nA\n```\nmore\n```python\nB\n```") == "B\n"
|
| 296 |
+
for r in stdin + func: # the repair feedback: a correct answer needs none, wrong / crashing / empty answers get a message
|
| 297 |
+
tests = json.loads(r["public_test_cases"])
|
| 298 |
+
good, fn = _lookup_solution(r, tests)
|
| 299 |
+
assert lcb_feedback("```python\n" + good + "```", r, fn) is None, ("feedback for a correct solution", r["question_id"])
|
| 300 |
+
bad_code = "print(0)\n" if fn is None else f"class Solution:\n def {fn}(self, *a):\n return None\n"
|
| 301 |
+
crash = "raise ValueError('boom')\n" if fn is None else f"class Solution:\n def {fn}(self, *a):\n raise ValueError('boom')\n"
|
| 302 |
+
assert "sample test" in (lcb_feedback("```python\n" + bad_code + "```", r, fn) or ""), ("no feedback for a wrong answer", r["question_id"])
|
| 303 |
+
assert "boom" in (lcb_feedback("```python\n" + crash + "```", r, fn) or ""), ("no error text for a crash", r["question_id"])
|
| 304 |
+
assert "could not find" in lcb_feedback("no code here", r, fn)
|
| 305 |
+
T = build_codehard(1, 10, m.run_code, m.code_of, m.num)
|
| 306 |
+
crux = [t for t in T if t[1] == "crux"]
|
| 307 |
+
bad = [t[0] for t in crux if not t[3](t[4])]
|
| 308 |
+
junk = [t[0] for t in T if t[1] == "crux" and t[3]("zzz 987654321")] + [t[0] for t in T if t[1] == "lcb" and t[3]("zzz 987654321")]
|
| 309 |
+
per = {c: sum(t[1] == c for t in T) for c in ("lcb", "crux")}
|
| 310 |
+
assert not bad and not junk and per == {"lcb": 10, "crux": 10}, (bad, junk, per)
|
| 311 |
+
print(f"selftest OK: {len(T)} tasks {per}; {len(stdin)} stdin + {len(func)} functional lcb problems pass their lookup solution and fail a wrong one; "
|
| 312 |
+
f"crux references pass, garbage fails")
|
| 313 |
+
else:
|
| 314 |
+
from datasets import load_dataset
|
| 315 |
+
bad = []
|
| 316 |
+
for r in load_dataset("cruxeval-org/cruxeval", split="test"):
|
| 317 |
+
if not m.run_code(r["code"], f"assert f({r['input']}) == ({r['output']})", 10):
|
| 318 |
+
bad += [f"crux_o_{r['id']}", f"crux_i_{r['id']}"]
|
| 319 |
+
print(f"{len(bad) // 2} crux references fail: BAD_CRUX = {set(bad)!r}")
|
| 320 |
+
n_ok = sum(1 for r in lcb_rows() if lcb_tests(r))
|
| 321 |
+
print(f"lcb: {n_ok} problems decode their tests")
|
benchmarks/scripts/13_swe_native.py
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
"""
|
| 4 |
+
13_swe_native.py - SWE-bench Verified (Mini) WITHOUT Docker or conda, on a plain Linux VM, driving the real Claude Code CLI.
|
| 5 |
+
|
| 6 |
+
It reuses swebench 4.0.4's own per-repo specs, setup/eval scripts and log parsers (pip install --no-deps --target /content/sb4 swebench==4.0.4),
|
| 7 |
+
translating the conda lines to `uv venv` environments, one /testbed checkout at a time.
|
| 8 |
+
|
| 9 |
+
python 13_swe_native.py list the instances of SWE-bench Verified Mini with their repo / version
|
| 10 |
+
python 13_swe_native.py gold INSTANCE_ID build the environment and check that the GOLD patch resolves the instance
|
| 11 |
+
python 13_swe_native.py agent --ids a,b,c --out results_swe_k448.json --endpoint http://127.0.0.1:18080 --model k448 --user agent
|
| 12 |
+
[--max-turns 60] [--timeout 2700] Claude Code solves each instance, the patch is graded by the official parsers
|
| 13 |
+
|
| 14 |
+
A resolved instance = every FAIL_TO_PASS test passes and no PASS_TO_PASS test breaks (the official SWE-bench definition). THE MODEL'S COMMANDS
|
| 15 |
+
AND THE REPOSITORIES' TESTS ARE EXECUTED: use a disposable VM; the agent runs as a separate unix user.
|
| 16 |
+
"""
|
| 17 |
+
import argparse
|
| 18 |
+
import json
|
| 19 |
+
import os
|
| 20 |
+
import re
|
| 21 |
+
import shlex
|
| 22 |
+
import shutil
|
| 23 |
+
import subprocess
|
| 24 |
+
import sys
|
| 25 |
+
import time
|
| 26 |
+
from pathlib import Path
|
| 27 |
+
|
| 28 |
+
sys.path.insert(0, "/content/sb4")
|
| 29 |
+
ENVS, TESTBED, WORK = Path("/content/sb_envs"), Path("/testbed"), Path("/content/sb_work")
|
| 30 |
+
CONSTRAINTS = Path("/content/sb_constraints.txt")
|
| 31 |
+
PY_MAP = {"3.5": "3.8", "3.6": "3.8", "3.7": "3.8"} # uv offers CPython 3.8+ ; these old pins run fine on 3.8
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def rows():
|
| 35 |
+
from datasets import load_dataset
|
| 36 |
+
return [dict(r) for r in load_dataset("MariusHobbhahn/swe-bench-verified-mini", split="test")]
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def get(iid):
|
| 40 |
+
for r in rows():
|
| 41 |
+
if r["instance_id"] == iid:
|
| 42 |
+
return r
|
| 43 |
+
sys.exit(f"unknown instance {iid}")
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def test_spec(inst):
|
| 47 |
+
from swebench.harness.test_spec.test_spec import make_test_spec
|
| 48 |
+
return make_test_spec(inst)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def env_dir(inst):
|
| 52 |
+
return ENVS / f"{inst['repo'].replace('/', '__')}__{inst['version']}__v4"
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def adapt(script, venv, py):
|
| 56 |
+
"""conda lines -> uv venv lines (the scripts are plain bash otherwise)."""
|
| 57 |
+
s = script.replace("source /opt/miniconda3/bin/activate\n", "")
|
| 58 |
+
s = re.sub(r"conda create -n testbed python=([\d.]+)\s+-y", lambda m: f"uv venv --seed --python {PY_MAP.get(m.group(1), m.group(1))} {venv} && {venv}/bin/python -m pip install 'setuptools<70'", s)
|
| 59 |
+
s = s.replace("conda activate testbed", f"source {venv}/bin/activate")
|
| 60 |
+
s = s.replace('echo "Current environment: $CONDA_DEFAULT_ENV"', "true")
|
| 61 |
+
# sphinx: tox would build its own interpreter without pytest here; run what its tox.ini runs, directly in the venv
|
| 62 |
+
s = re.sub(r"tox --current-env -e\S+ -v -- ", "PYTHONWARNINGS=all python -X dev -m pytest --durations 25 -rA ", s)
|
| 63 |
+
return s
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def bash(script, log, timeout, env=None):
|
| 67 |
+
Path(log).parent.mkdir(parents=True, exist_ok=True)
|
| 68 |
+
f = Path(log).with_suffix(".sh")
|
| 69 |
+
f.write_text(script, encoding="utf-8")
|
| 70 |
+
try:
|
| 71 |
+
r = subprocess.run(["bash", str(f)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, timeout=timeout, errors="replace",
|
| 72 |
+
env={**os.environ, "PIP_CONSTRAINT": str(CONSTRAINTS), **(env or {})}) # one stream, in order: the grader reads the output between the START/END markers
|
| 73 |
+
out = r.stdout
|
| 74 |
+
code = r.returncode
|
| 75 |
+
except subprocess.TimeoutExpired as e:
|
| 76 |
+
out = ((e.stdout or b"").decode("utf-8", "replace") if isinstance(e.stdout, bytes) else (e.stdout or "")) + "\n[timeout]"
|
| 77 |
+
code = 124
|
| 78 |
+
Path(log).write_text(out, encoding="utf-8")
|
| 79 |
+
return code, out
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def prepare(inst):
|
| 83 |
+
"""Environment (cached per repo+version) and a fresh /testbed at the base commit with the repo installed."""
|
| 84 |
+
ts = test_spec(inst)
|
| 85 |
+
venv = env_dir(inst)
|
| 86 |
+
py = re.search(r"python=([\d.]+)", ts.setup_env_script)
|
| 87 |
+
py = PY_MAP.get(py.group(1), py.group(1)) if py else "3.9"
|
| 88 |
+
if not (venv / ".done").exists():
|
| 89 |
+
shutil.rmtree(venv, ignore_errors=True)
|
| 90 |
+
ENVS.mkdir(parents=True, exist_ok=True)
|
| 91 |
+
code, out = bash(adapt(ts.setup_env_script, venv, py), WORK / "logs" / f"{venv.name}_env.log", 3000)
|
| 92 |
+
if code != 0 or not (venv / "bin" / "python").exists():
|
| 93 |
+
raise RuntimeError(f"environment build failed (exit {code}): {out[-600:]}")
|
| 94 |
+
(venv / ".done").write_text("ok")
|
| 95 |
+
shutil.rmtree(TESTBED, ignore_errors=True)
|
| 96 |
+
code, out = bash(adapt(ts.install_repo_script, venv, py), WORK / "logs" / f"{inst['instance_id']}_repo.log", 2400)
|
| 97 |
+
if code != 0 or not (TESTBED / ".git").exists():
|
| 98 |
+
raise RuntimeError(f"repo install failed (exit {code}): {out[-600:]}")
|
| 99 |
+
return ts, venv
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def alias_docstring_lines(out):
|
| 103 |
+
"""Python 3.8 prints `test_x (mod.Class)` and the docstring line separately; add the one-line form that the dataset's test names use."""
|
| 104 |
+
res, prev = [], None
|
| 105 |
+
for line in out.split("\n"):
|
| 106 |
+
res.append(line)
|
| 107 |
+
t = line.strip()
|
| 108 |
+
m = re.match(r"^(test\S* \([\w.]+\))$", t)
|
| 109 |
+
if m:
|
| 110 |
+
prev = m.group(1)
|
| 111 |
+
elif prev and " ... " in t:
|
| 112 |
+
res.append(f"{prev} ... {t.rsplit(' ... ', 1)[1]}")
|
| 113 |
+
prev = None
|
| 114 |
+
else:
|
| 115 |
+
prev = None
|
| 116 |
+
return "\n".join(res)
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def evaluate(inst, ts, venv, patch):
|
| 120 |
+
"""Fresh checkout, apply the model patch, run the official eval script, grade with the official parser. -> (resolved, note)"""
|
| 121 |
+
from swebench.harness.grading import get_eval_report
|
| 122 |
+
py = re.search(r"python=([\d.]+)", ts.setup_env_script)
|
| 123 |
+
py = PY_MAP.get(py.group(1), py.group(1)) if py else "3.9"
|
| 124 |
+
subprocess.run("git reset --hard -q && git clean -fdq", shell=True, cwd=TESTBED)
|
| 125 |
+
if not patch.strip():
|
| 126 |
+
return False, "empty patch"
|
| 127 |
+
pf = WORK / f"{inst['instance_id']}.patch"
|
| 128 |
+
pf.write_text(patch if patch.endswith("\n") else patch + "\n", encoding="utf-8")
|
| 129 |
+
r = subprocess.run(["git", "apply", "-v", str(pf)], cwd=TESTBED, capture_output=True, text=True)
|
| 130 |
+
if r.returncode != 0:
|
| 131 |
+
return False, "patch does not apply: " + (r.stdout + r.stderr)[-200:]
|
| 132 |
+
code, out = bash(adapt(ts.eval_script, venv, py), WORK / "logs" / f"{inst['instance_id']}_eval.log", 2700)
|
| 133 |
+
logp = WORK / "logs" / f"{inst['instance_id']}_report.log"
|
| 134 |
+
logp.write_text(">>>>> Applied Patch\n" + alias_docstring_lines(out), encoding="utf-8")
|
| 135 |
+
try:
|
| 136 |
+
rep = get_eval_report(test_spec=ts, prediction={"instance_id": inst["instance_id"], "model_name_or_path": "k448", "model_patch": patch},
|
| 137 |
+
test_log_path=str(logp), include_tests_status=True)[inst["instance_id"]]
|
| 138 |
+
except Exception as e:
|
| 139 |
+
return False, f"grading error: {e!r}"
|
| 140 |
+
ts_ = rep.get("tests_status", {})
|
| 141 |
+
f2p, p2p = ts_.get("FAIL_TO_PASS", {}), ts_.get("PASS_TO_PASS", {})
|
| 142 |
+
note = f"F2P {len(f2p.get('success', []))}/{len(f2p.get('success', [])) + len(f2p.get('failure', []))}, P2P ok {len(p2p.get('success', []))} broken {len(p2p.get('failure', []))}"
|
| 143 |
+
return bool(rep.get("resolved")), note
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def cmd_goldall(a):
|
| 147 |
+
"""Gold-patch check of every instance: the ones that resolve are the runnable benchmark."""
|
| 148 |
+
out = Path(a.out)
|
| 149 |
+
res = json.loads(out.read_text(encoding="utf-8")) if out.exists() else {}
|
| 150 |
+
for inst in rows():
|
| 151 |
+
iid = inst["instance_id"]
|
| 152 |
+
if iid in res:
|
| 153 |
+
continue
|
| 154 |
+
t0 = time.time()
|
| 155 |
+
try:
|
| 156 |
+
ts, venv = prepare(inst)
|
| 157 |
+
ok, note = evaluate(inst, ts, venv, inst["patch"])
|
| 158 |
+
except Exception as e:
|
| 159 |
+
ok, note = False, f"error: {e!r}"[:300]
|
| 160 |
+
res[iid] = {"ok": ok, "note": note, "secs": round(time.time() - t0)}
|
| 161 |
+
out.write_text(json.dumps(res, indent=1), encoding="utf-8")
|
| 162 |
+
print(f"{iid:36s} gold_resolved={ok} {note[:100]} ({time.time() - t0:.0f} s)", flush=True)
|
| 163 |
+
print(f"runnable {sum(v['ok'] for v in res.values())}/{len(res)}")
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
def cmd_list(a):
|
| 167 |
+
for r in rows():
|
| 168 |
+
print(f"{r['instance_id']:36s} {r['repo']:20s} {r['version']:5s} F2P={len(json.loads(r['FAIL_TO_PASS']) if isinstance(r['FAIL_TO_PASS'], str) else r['FAIL_TO_PASS'])}")
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
def cmd_gold(a):
|
| 172 |
+
inst = get(a.instance)
|
| 173 |
+
t0 = time.time()
|
| 174 |
+
ts, venv = prepare(inst)
|
| 175 |
+
print(f"prepared in {time.time() - t0:.0f} s", flush=True)
|
| 176 |
+
ok, note = evaluate(inst, ts, venv, inst["patch"])
|
| 177 |
+
print(f"GOLD {inst['instance_id']}: resolved={ok} {note} ({time.time() - t0:.0f} s)")
|
| 178 |
+
return 0 if ok else 1
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
def agent_prompt(inst):
|
| 182 |
+
return (f"<uploaded_files>\n/testbed\n</uploaded_files>\nI've uploaded a python code repository in the directory /testbed. Consider the following issue "
|
| 183 |
+
f"description:\n\n<issue>\n{inst['problem_statement']}\n</issue>\n\nCan you help me implement the necessary changes to the repository so that the "
|
| 184 |
+
"requirements specified in the issue are met? I've already taken care of all changes to any of the test files described in the issue, so you do NOT "
|
| 185 |
+
"need to modify the testing logic or any of the tests in any way. Make the minimal changes to non-test files in /testbed so that the issue is resolved. "
|
| 186 |
+
"You can run the existing tests to check your work. When you are done, stop.")
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
def parse_stream(text):
|
| 190 |
+
calls = errs = 0
|
| 191 |
+
last, final = "", {}
|
| 192 |
+
for line in text.splitlines():
|
| 193 |
+
if not line.startswith("{"):
|
| 194 |
+
continue
|
| 195 |
+
try:
|
| 196 |
+
ev = json.loads(line)
|
| 197 |
+
except ValueError:
|
| 198 |
+
continue
|
| 199 |
+
t = ev.get("type")
|
| 200 |
+
if t == "assistant":
|
| 201 |
+
for b in (ev.get("message", {}).get("content") or []):
|
| 202 |
+
if b.get("type") == "tool_use":
|
| 203 |
+
calls += 1
|
| 204 |
+
elif b.get("type") == "text" and b.get("text", "").strip():
|
| 205 |
+
last = b["text"].strip()
|
| 206 |
+
elif t == "user":
|
| 207 |
+
c = ev.get("message", {}).get("content")
|
| 208 |
+
if isinstance(c, list):
|
| 209 |
+
errs += sum(1 for b in c if isinstance(b, dict) and b.get("type") == "tool_result" and b.get("is_error"))
|
| 210 |
+
elif t == "result":
|
| 211 |
+
final = ev
|
| 212 |
+
u = final.get("usage") or {}
|
| 213 |
+
return {"turns": final.get("num_turns", 0), "tool_calls": calls, "tool_errors": errs, "out_tok": u.get("output_tokens", 0),
|
| 214 |
+
"in_tok": u.get("input_tokens", 0) + u.get("cache_read_input_tokens", 0) + u.get("cache_creation_input_tokens", 0),
|
| 215 |
+
"stop": final.get("subtype") or ("no_result" if not final else "?"), "last": last[-300:]}
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
def cmd_agent(a):
|
| 219 |
+
ids = a.ids.split(",") if a.ids else [r["instance_id"] for r in rows()]
|
| 220 |
+
out = Path(a.out)
|
| 221 |
+
res = json.loads(out.read_text(encoding="utf-8")).get("results", {}) if out.exists() else {}
|
| 222 |
+
logs = Path(str(out.with_suffix("")) + "_logs")
|
| 223 |
+
logs.mkdir(parents=True, exist_ok=True)
|
| 224 |
+
home = WORK / "_home"
|
| 225 |
+
home.mkdir(parents=True, exist_ok=True)
|
| 226 |
+
t0 = time.time()
|
| 227 |
+
for k, iid in enumerate(ids, 1):
|
| 228 |
+
if iid in res:
|
| 229 |
+
continue
|
| 230 |
+
inst = get(iid)
|
| 231 |
+
s0 = time.time()
|
| 232 |
+
info = {"repo": inst["repo"], "version": inst["version"]}
|
| 233 |
+
try:
|
| 234 |
+
ts, venv = prepare(inst)
|
| 235 |
+
subprocess.run(["chown", "-R", f"{a.user}:{a.user}", str(TESTBED), str(home)], check=True)
|
| 236 |
+
env = {"PATH": f"{venv}/bin:" + os.environ.get("PATH", ""), "VIRTUAL_ENV": str(venv), "HOME": str(home), "LANG": "C.UTF-8",
|
| 237 |
+
"ANTHROPIC_BASE_URL": a.endpoint, "ANTHROPIC_AUTH_TOKEN": "local", "ANTHROPIC_API_KEY": "local", "ANTHROPIC_MODEL": a.model,
|
| 238 |
+
"ANTHROPIC_SMALL_FAST_MODEL": a.model, "ANTHROPIC_DEFAULT_HAIKU_MODEL": a.model, "ANTHROPIC_DEFAULT_SONNET_MODEL": a.model,
|
| 239 |
+
"ANTHROPIC_DEFAULT_OPUS_MODEL": a.model, "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", "DISABLE_TELEMETRY": "1",
|
| 240 |
+
"DISABLE_AUTOUPDATER": "1", "DISABLE_ERROR_REPORTING": "1", "IS_SANDBOX": "1"}
|
| 241 |
+
cmd = ["runuser", "-u", a.user, "--", "env"] + [f"{kk}={vv}" for kk, vv in env.items()] + shlex.split(a.claude) + [
|
| 242 |
+
"-p", agent_prompt(inst), "--output-format", "stream-json", "--verbose", "--dangerously-skip-permissions",
|
| 243 |
+
"--max-turns", str(a.max_turns), "--model", a.model]
|
| 244 |
+
try:
|
| 245 |
+
r = subprocess.run(cmd, cwd=TESTBED, capture_output=True, text=True, timeout=a.timeout, errors="replace", stdin=subprocess.DEVNULL)
|
| 246 |
+
text, err, timed_out = r.stdout, r.stderr, False
|
| 247 |
+
except subprocess.TimeoutExpired as e:
|
| 248 |
+
text = ((e.stdout or b"").decode("utf-8", "replace") if isinstance(e.stdout, bytes) else (e.stdout or ""))
|
| 249 |
+
err, timed_out = "timeout", True
|
| 250 |
+
(logs / f"{iid}.jsonl").write_text(text + ("\n[stderr]\n" + err[-2000:] if err else ""), encoding="utf-8")
|
| 251 |
+
info.update(parse_stream(text))
|
| 252 |
+
info["timed_out"] = timed_out
|
| 253 |
+
subprocess.run("git add -A && git diff --cached HEAD > /tmp/model.patch", shell=True, cwd=TESTBED)
|
| 254 |
+
patch = Path("/tmp/model.patch").read_text(encoding="utf-8", errors="replace")
|
| 255 |
+
info["patch_lines"] = patch.count("\n")
|
| 256 |
+
info["pass"], info["note"] = evaluate(inst, ts, venv, patch)
|
| 257 |
+
except Exception as e:
|
| 258 |
+
info.update({"pass": False, "note": f"harness error: {e!r}"[:300]})
|
| 259 |
+
info["secs"] = round(time.time() - s0)
|
| 260 |
+
res[iid] = info
|
| 261 |
+
out.write_text(json.dumps({"kind": "swe", "name": a.model, "seconds": round(time.time() - t0), "results": res}, indent=1), encoding="utf-8")
|
| 262 |
+
print(f"{k:3d}/{len(ids)} {iid:34s} {'RESOLVED' if info['pass'] else 'no':8s} turns={info.get('turns', 0):3d} calls={info.get('tool_calls', 0):3d} "
|
| 263 |
+
f"tool_errors={info.get('tool_errors', 0):2d} patch={info.get('patch_lines', 0):3d} lines {info['secs']:5d} s {info.get('note', '')[:80]}", flush=True)
|
| 264 |
+
n = len(res)
|
| 265 |
+
print(f"\nresolved {sum(v['pass'] for v in res.values())}/{n}")
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
if __name__ == "__main__":
|
| 269 |
+
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
| 270 |
+
sub = ap.add_subparsers(dest="cmd", required=True)
|
| 271 |
+
sub.add_parser("list")
|
| 272 |
+
ga = sub.add_parser("goldall")
|
| 273 |
+
ga.add_argument("--out", default="/content/gold_all.json")
|
| 274 |
+
g = sub.add_parser("gold")
|
| 275 |
+
g.add_argument("instance")
|
| 276 |
+
ag = sub.add_parser("agent")
|
| 277 |
+
ag.add_argument("--ids")
|
| 278 |
+
ag.add_argument("--out", default="results_swe.json")
|
| 279 |
+
ag.add_argument("--endpoint", default="http://127.0.0.1:18080")
|
| 280 |
+
ag.add_argument("--model", default="k448")
|
| 281 |
+
ag.add_argument("--user", default="agent")
|
| 282 |
+
ag.add_argument("--claude", default="claude")
|
| 283 |
+
ag.add_argument("--max-turns", type=int, default=60)
|
| 284 |
+
ag.add_argument("--timeout", type=int, default=2700)
|
| 285 |
+
a = ap.parse_args()
|
| 286 |
+
WORK.mkdir(parents=True, exist_ok=True)
|
| 287 |
+
CONSTRAINTS.write_text("Pygments==2.18.0\n", encoding="utf-8") # the version current when the official images were built
|
| 288 |
+
{"list": cmd_list, "gold": cmd_gold, "goldall": cmd_goldall, "agent": cmd_agent}[a.cmd](a)
|
benchmarks/scripts/14_msg_proxy.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# -*- coding: utf-8 -*-
|
| 3 |
+
"""
|
| 4 |
+
14_msg_proxy.py - a small logging / rewriting proxy between Claude Code and llama-server's /v1/messages endpoint.
|
| 5 |
+
|
| 6 |
+
python 14_msg_proxy.py listens on 127.0.0.1:18082, forwards to 127.0.0.1:18080, streams the answer back, and appends every
|
| 7 |
+
/v1/messages request body to /content/proxy_log.jsonl. fix() is the hook for rewriting a request
|
| 8 |
+
(the chat template of Qwen3.8 rejects some shapes that Claude Code sends).
|
| 9 |
+
"""
|
| 10 |
+
import http.client
|
| 11 |
+
import http.server
|
| 12 |
+
import json
|
| 13 |
+
import time
|
| 14 |
+
|
| 15 |
+
UP = ("127.0.0.1", 18080)
|
| 16 |
+
CRLF = bytes([13, 10])
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def fix(d):
|
| 20 |
+
"""Qwen3.8's chat template raises 'System message must be at the beginning' for a system-role entry in `messages`, which Claude Code sends
|
| 21 |
+
after the user turn. Fold every such entry into the last user message as an extra text block (nothing is dropped)."""
|
| 22 |
+
msgs = d.get("messages") or []
|
| 23 |
+
keep, extra = [], []
|
| 24 |
+
for m in msgs:
|
| 25 |
+
if m.get("role") == "system":
|
| 26 |
+
c = m.get("content")
|
| 27 |
+
text = c if isinstance(c, str) else chr(10).join(b.get("text", "") for b in c if isinstance(b, dict) and b.get("type") == "text")
|
| 28 |
+
if text.strip():
|
| 29 |
+
extra.append(text)
|
| 30 |
+
else:
|
| 31 |
+
keep.append(m)
|
| 32 |
+
if len(keep) != len(msgs):
|
| 33 |
+
block = dict(type="text", text=(chr(10) * 2).join(extra) if extra else "(no content)")
|
| 34 |
+
for m in reversed(keep):
|
| 35 |
+
if m.get("role") == "user":
|
| 36 |
+
c = m.get("content")
|
| 37 |
+
m["content"] = ([dict(type="text", text=c)] if isinstance(c, str) else list(c)) + [block]
|
| 38 |
+
break
|
| 39 |
+
else:
|
| 40 |
+
keep.append(dict(role="user", content=[block]))
|
| 41 |
+
d["messages"] = keep
|
| 42 |
+
return d
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class H(http.server.BaseHTTPRequestHandler):
|
| 46 |
+
protocol_version = "HTTP/1.1"
|
| 47 |
+
|
| 48 |
+
def log_message(self, *a):
|
| 49 |
+
pass
|
| 50 |
+
|
| 51 |
+
def handle_any(self):
|
| 52 |
+
n = int(self.headers.get("Content-Length") or 0)
|
| 53 |
+
body = self.rfile.read(n) if n else b""
|
| 54 |
+
if self.path.startswith("/v1/messages") and body:
|
| 55 |
+
try:
|
| 56 |
+
d = json.loads(body)
|
| 57 |
+
with open("/content/proxy_log.jsonl", "a") as f:
|
| 58 |
+
f.write(json.dumps(dict(t=time.time(), path=self.path, req=d))[:600000] + "\n")
|
| 59 |
+
body = json.dumps(fix(d)).encode()
|
| 60 |
+
except Exception as e:
|
| 61 |
+
open("/content/proxy_err.log", "a").write(repr(e) + "\n")
|
| 62 |
+
c = http.client.HTTPConnection(*UP, timeout=7200)
|
| 63 |
+
hdr = dict((k, v) for k, v in self.headers.items() if k.lower() not in ("host", "content-length", "connection", "accept-encoding", "transfer-encoding"))
|
| 64 |
+
c.request(self.command, self.path, body, hdr)
|
| 65 |
+
r = c.getresponse()
|
| 66 |
+
with open("/content/proxy_status.log", "a") as f:
|
| 67 |
+
f.write(f"{time.time():.0f} {self.command} {self.path} {r.status}\n")
|
| 68 |
+
self.send_response(r.status)
|
| 69 |
+
for k, v in r.getheaders():
|
| 70 |
+
if k.lower() not in ("transfer-encoding", "connection", "content-length"):
|
| 71 |
+
self.send_header(k, v)
|
| 72 |
+
self.send_header("Transfer-Encoding", "chunked")
|
| 73 |
+
self.end_headers()
|
| 74 |
+
while True:
|
| 75 |
+
chunk = r.read1(65536)
|
| 76 |
+
if not chunk:
|
| 77 |
+
break
|
| 78 |
+
self.wfile.write(b"%x" % len(chunk) + CRLF + chunk + CRLF)
|
| 79 |
+
self.wfile.flush()
|
| 80 |
+
self.wfile.write(b"0" + CRLF + CRLF)
|
| 81 |
+
self.wfile.flush()
|
| 82 |
+
|
| 83 |
+
do_GET = do_POST = do_PUT = do_DELETE = handle_any
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
if __name__ == "__main__":
|
| 87 |
+
http.server.ThreadingHTTPServer(("127.0.0.1", 18082), H).serve_forever()
|