{"data":{"kind":"file","path":"README.md","version_id":"lwlpj6dd2zhku0vj63bk1i5c","entry":{"name":"README.md","path":"README.md","is_directory":false,"size":3932,"modified_at":"2026-09-18T21:05:35.034000","content_hash":"b21fefebe77adf161bd28d245f35a28772b045f203aa17838d7674cb6a4fc5ca"},"entries":[],"content":"# geo-distance\n\n### Overview\n- **Environment ID**: `geo-distance`\n- **Short description**: Given two latitude/longitude points on a sphere, answer the great-circle distance in kilometres. Single turn, no tools, graded on relative error.\n- **Tags**: geometry, math, train, eval\n\n### Datasets\nGenerated, not downloaded — `random.Random(seed)` makes a run reproducible and\n`seed` is the only thing separating a train split from an eval split.\n\nPoint B is *placed* at a log-uniform distance from point A along a random bearing, so\nseparations span 10 km to ~19,500 km evenly in log space. That matters: two points\nsampled independently on a sphere are ~10,000 km apart on average, which would let a\npolicy score by always answering \"10000\". Here no constant does better than 0.16\n(see `test_not_farmable`).\n\nEvery row belongs to one of four tiers, round-robined so any prefix (`-n 8`) stays\ndifficulty-balanced:\n\n| Tier | What it is | Why |\n| --- | --- | --- |\n| `axis` | Both points share a meridian, or both sit on the equator | Distance is one multiplication — the rung a weak policy can reach |\n| `near` | Separation below `near_km` (200 km) | The flat-earth approximation is still exact enough to score 1.0 |\n| `general` | Arbitrary pair, `near_km` to `max_km` | Needs real haversine; flat-earth scores 0.67 |\n| `parallel` | Both points share a latitude | Trap: the arc *along* the parallel is not the great-circle distance, and answering it scores 0.49 |\n\n### Task\n- **Type**: single-turn\n- **Output format**: a single number in kilometres inside `\\boxed{}`. An unboxed reply\n  falls back to the last number in the text — a format miss is reward noise, not\n  signal, and the number still has to be right.\n- **Rubric**: one reward, `accuracy`.\n\nThe package exports `NullHarness`, which makes the default harness a single plain\nmodel turn. Without it the loader falls back to `bash`, which both provisions a billed\ncontainer and hands the model a shell it could just compute the answer in.\n\n### Quickstart\n\n```bash\nuv pip install -e environments/geo_distance\nuv run python environments/geo_distance/test_geo_distance.py   # self-check, no network\nuv run eval @ configs/eval/geo-distance.toml\n```\n\nThe config pins `env.agent.runtime.type = \"subprocess\"`. The default (`prime`)\nprovisions a sandbox per task, which this environment has no use for.\n\n### Taskset Config\n\n| Field | Type | Default | Description |\n| --- | --- | --- | --- |\n| `num_tasks` | int | `400` | How many rows to build |\n| `seed` | int | `0` | Generator seed; use a different one for eval than for train |\n| `min_km` | float | `10.0` | Shortest separation generated |\n| `near_km` | float | `200.0` | Boundary between the `near` and `general` tiers |\n| `max_km` | float | `19500.0` | Longest separation generated |\n| `task.full_credit_err` | float | `0.01` | Relative error at or below which the answer scores 1.0 |\n| `task.zero_credit_err` | float | `0.5` | Relative error at or above which it scores 0.0 |\n\nBetween the two thresholds the score is log-linear, so a group of all-wrong rollouts\nstill ranks \"off by 3%\" above \"off by 300%\" and produces a usable advantage. Widening\n`zero_credit_err` gives a denser gradient; narrowing it toward `full_credit_err`\napproaches pass/fail.\n\n### Metrics\n\n| Metric | Meaning |\n| ------ | ------- |\n| `reward` | The weighted sum — here just `accuracy` |\n| `accuracy` | 1.0 within `full_credit_err`, 0.0 beyond `zero_credit_err`, log-linear between |\n| `solved` | Fraction scoring exactly 1.0 — the strict accuracy to report |\n| `rel_error` | Relative error, clipped at 10 so one wild guess cannot dominate the mean |\n| `answered` | Whether a number could be parsed at all |\n| `truncated` | Whether the reply hit the token limit (a low `answered` with a high `truncated` means raise `max_tokens`, not that the policy failed) |\n\n`trace.info` also carries `tier` and `guess_km`, so scores can be broken down per tier.\n","encoding":"utf-8","truncated":false,"total_bytes":3932},"status":null}