A small, reproducible EDA routing challenge for a simplified hybrid-bonded 3D integration stack. Two dies sit face to face with a shared vertical stack of routing layers between them. Participants connect cell pins across a 3D grid graph while minimizing total routing delay under a simple additive delay model.
Everything here is self-contained and pure standard library (only the
visualization needs matplotlib). The repository ships a deterministic
benchmark generator, six benchmark tiers (five generated, one built from real
circuits) whose every case has a verified legal reference solution, an
independent legality checker and scorer, a baseline router, a visualization
tool, an example participant router, and tests.
Sweeping the routing stack of one case (reference solution). Edge delay is lowest on the middle layers and highest next to the dies (see the strip at the bottom), so long connections dive to the cheap middle of the stack. Cells are shaded on the die layers; pins are dots colored by die; vias are open squares; nets are colored; the faint grey is the whole routing for context.
The intro 20-case size ladder (each case's reference solution, flattened top-down), growing grid, cell, pin and net counts from case_01 to case_20.
Ranked per tier (each tier is normalized to its own baseline, so a
higher aggregate is better and the baseline itself scores 1.0000).
✓ marks submissions on the runtime-vs-total-delay Pareto frontier;
† marks derivative entries that start from another entry's routes.
runtime (s) is the summed wall-clock time of one run per case, as
reported in runtime.json (hardware and threads are in meta.json).
It is required: entries still missing it on 2026-10-15 become unranked.
verified is set by the maintainers once they have re-run an entry's
router and reproduced its routes (verification.json); — means not yet.
Submit by pull request; see CONTRIBUTING.md. Also in LEADERBOARD.md.
| rank | submission | author | aggregate | legal | total delay | runtime (s) | Pareto | verified |
|---|---|---|---|---|---|---|---|---|
| 1 | coordinated_refinement † | jay-tau | 1.1566 | 20/20 | 339328 | missing | — | |
| 2 | leonid-popryho | Leonid Popryho | 1.1563 | 20/20 | 339406 | missing | — | |
| 3 | cuda-have-been-shorter | YJ Kim | 1.1562 | 20/20 | 339546 | missing | — | |
| 4 | pathfinder_lns | Tazeem Mahashin | 1.1514 | 20/20 | 341746 | 46476.76 | ✓ | — |
| 5 | warm_lns_refinement † | kesudh | 1.1509 | 20/20 | 342006 | missing | — | |
| 6 | spt_lns | James (IrwinJam) | 1.1444 | 20/20 | 345066 | missing | — | |
| 7 | iamparv7043 | Parv (iamparv7043) | 1.1254 | 20/20 | 353836 | 2213.60 | ✓ | — |
| 8 | anvesh | anvesh | 1.1069 | 20/20 | 360172 | missing | — | |
| 9 | synapse-surge | Sameer-Deepak | 1.1004 | 20/20 | 368374 | missing | — | |
| 10 | lns_negotiated | adityuhkapoor | 1.0937 | 20/20 | 367388 | missing | — | |
| 11 | negotiated_delay | Mantej Singh Gill | 1.0906 | 20/20 | 368046 | 752.29 | ✓ | — |
| 12 | gavinoh-spt-lns | Gavin Oh | 1.0632 | 20/20 | 382210 | 1826.80 | — | |
| 13 | dw_metric_lns | OpenCode (DeepSeek V4.1 Flash) | 1.0584 | 20/20 | 393668 | 25289.93 | — | |
| 14 | shivaahir158 | Shiva Ahir (PhD Candidate, Stony Brook University) | 1.0274 | 20/20 | 388638 | 440.56 | ✓ | — |
† derivative entry (refines another entry's routes): coordinated_refinement builds on drama3d-portfolio; leonid-popryho; pathfinder_lns; warm_lns_refinement (Leonid Popryho; Taz33m; Tazeem Mahashin; YJ Kim; kesudh); warm_lns_refinement builds on pathfinder_lns (Taz33m).
| rank | submission | author | aggregate | legal | total delay | runtime (s) | Pareto | verified |
|---|---|---|---|---|---|---|---|---|
| 1 | coordinated_refinement † | jay-tau | 1.4136 | 9/9 | 142321 | missing | — | |
| 2 | leonid-popryho | Leonid Popryho | 1.4123 | 9/9 | 142413 | missing | — | |
| 3 | cuda-have-been-shorter | YJ Kim | 1.4085 | 9/9 | 142989 | missing | — | |
| 4 | spt_lns | James (IrwinJam) | 1.3971 | 9/9 | 144153 | missing | — | |
| 5 | pathfinder_lns | Tazeem Mahashin | 1.3884 | 9/9 | 144991 | missing | — | |
| 6 | warm_lns_refinement † | kesudh | 1.3874 | 9/9 | 145095 | missing | — | |
| 7 | reubalink | reubalink | 1.3622 | 9/9 | 147825 | missing | — | |
| 8 | iamparv7043 | Parv (iamparv7043) | 1.3019 | 9/9 | 155125 | 7333.40 | ✓ | — |
| 9 | erikqu_root_aware_portfolio | erikqu | 1.2745 | 9/9 | 158455 | missing | — | |
| 10 | synapse-surge | Sameer-Deepak | 1.2569 | 9/9 | 161183 | missing | — | |
| 11 | lns_negotiated | adityuhkapoor | 1.2267 | 9/9 | 165367 | missing | — | |
| 12 | anvesh | anvesh | 1.1863 | 9/9 | 169737 | missing | reproduced | |
| 13 | ly | ly | 1.1500 | 9/9 | 175329 | 822.57 | ✓ | — |
| 14 | negotiated_delay | Mantej Singh Gill | 1.1499 | 9/9 | 175879 | 105.39 | ✓ | — |
| 15 | shivaahir158 | Shiva Ahir (PhD Candidate, Stony Brook University) | 1.0508 | 9/9 | 192507 | 787.30 | — | |
| 16 | negotiated_x2 | Anthropic (reference) | 1.0168 | 9/9 | 198763 | 177.01 | — | |
| 17 | negotiated | Anthropic (reference) | 1.0000 | 9/9 | 201863 | 85.20 | ✓ | — |
| 18 | negotiated_fast | Anthropic (reference) | — | 8/9 | — | 61.74 | — |
† derivative entry (refines another entry's routes): coordinated_refinement builds on drama3d-portfolio; leonid-popryho (Leonid Popryho; YJ Kim); warm_lns_refinement builds on pathfinder_lns (Taz33m).
| rank | submission | author | aggregate | legal | total delay | runtime (s) | Pareto | verified |
|---|---|---|---|---|---|---|---|---|
| 1 | coordinated_refinement † | jay-tau | 1.1399 | 8/8 | 531688 | missing | — | |
| 2 | leonid-popryho | Leonid Popryho | 1.1397 | 8/8 | 531766 | missing | — | |
| 3 | cuda-have-been-shorter | YJ Kim | 1.1391 | 8/8 | 532016 | missing | — | |
| 4 | pathfinder_lns | Tazeem Mahashin | 1.1277 | 8/8 | 537468 | 62411.00 | ✓ | — |
| 5 | warm_lns_refinement † | kesudh | 1.1274 | 8/8 | 537576 | 7543.00 | ✓ | — |
| 6 | spt_lns | James (IrwinJam) | 1.1188 | 8/8 | 541966 | missing | — | |
| 7 | iamparv7043 | Parv (iamparv7043) | 1.1010 | 8/8 | 550828 | 3094.50 | ✓ | — |
| 8 | anvesh | anvesh | 1.0821 | 8/8 | 559460 | missing | — | |
| 9 | lns_negotiated | adityuhkapoor | 1.0682 | 8/8 | 567094 | missing | — | |
| 10 | synapse-surge | Sameer-Deepak | 1.0496 | 8/8 | 579306 | missing | — | |
| 11 | shivaahir158 | Shiva Ahir (PhD Candidate, Stony Brook University) | 1.0108 | 8/8 | 598244 | 2196.48 | ✓ | — |
† derivative entry (refines another entry's routes): coordinated_refinement builds on leonid-popryho (Leonid Popryho); warm_lns_refinement builds on pathfinder_lns (Taz33m).
| rank | submission | author | aggregate | legal | total delay | runtime (s) | Pareto | verified |
|---|---|---|---|---|---|---|---|---|
| 1 | coordinated_refinement † | jay-tau | 1.0984 | 1/1 | 1042314 | missing | — | |
| 2 | leonid-popryho | Leonid Popryho | 1.0984 | 1/1 | 1042322 | missing | — | |
| 3 | cuda-have-been-shorter | YJ Kim | 1.0978 | 1/1 | 1042926 | missing | — | |
| 4 | pathfinder_lns | Tazeem Mahashin | 1.0914 | 1/1 | 1048990 | 43262.89 | ✓ | — |
| 5 | warm_lns_refinement † | kesudh | 1.0911 | 1/1 | 1049332 | 2070.00 | ✓ | — |
| 6 | spt_lns | James (IrwinJam) | 1.0779 | 1/1 | 1062208 | missing | — | |
| 7 | lns_negotiated | adityuhkapoor | 1.0669 | 1/1 | 1073124 | missing | — | |
| 8 | synapse-surge | Sameer-Deepak | 1.0008 | 1/1 | 1143964 | missing | — |
† derivative entry (refines another entry's routes): coordinated_refinement builds on leonid-popryho (Leonid Popryho); warm_lns_refinement builds on pathfinder_lns (Taz33m).
| rank | submission | author | aggregate | legal | total delay | runtime (s) | Pareto | verified |
|---|---|---|---|---|---|---|---|---|
| 1 | coordinated_refinement † | jay-tau | 1.3508 | 4/4 | 476231 | missing | — | |
| 2 | leonid-popryho | Leonid Popryho | 1.3505 | 4/4 | 476333 | missing | — | |
| 3 | cuda-have-been-shorter | YJ Kim | 1.3392 | 4/4 | 479359 | missing | — | |
| 4 | spt_lns | James (IrwinJam) | 1.3156 | 4/4 | 489177 | missing | — | |
| 5 | pathfinder_lns | Tazeem Mahashin | 1.3111 | 4/4 | 490499 | 61369.30 | ✓ | — |
| 6 | warm_lns_refinement † | kesudh | 1.3085 | 4/4 | 491467 | 3621.00 | ✓ | — |
| 7 | iamparv7043 | Parv (iamparv7043) | 1.1252 | 4/4 | 591707 | 4593.60 | — | |
| 8 | lns_negotiated | adityuhkapoor | 1.0981 | 4/4 | 590513 | missing | — | |
| 9 | shivaahir158 | Shiva Ahir (PhD Candidate, Stony Brook University) | 1.0549 | 4/4 | 608243 | 8756.73 | — | |
| 10 | synapse-surge | Sameer-Deepak | 1.0518 | 4/4 | 616017 | missing | — |
† derivative entry (refines another entry's routes): coordinated_refinement builds on leonid-popryho (Leonid Popryho); warm_lns_refinement builds on pathfinder_lns (Taz33m).
| rank | submission | author | aggregate | legal | total delay | runtime (s) | Pareto | verified |
|---|---|---|---|---|---|---|---|---|
| 1 | coordinated_refinement † | jay-tau | 1.4673 | 3/3 | 204497 | missing | — | |
| 2 | leonid-popryho | Leonid Popryho | 1.4667 | 3/3 | 204581 | missing | — | |
| 3 | cuda-have-been-shorter | YJ Kim | 1.4634 | 3/3 | 204963 | missing | — | |
| 4 | pathfinder_lns | Tazeem Mahashin | 1.4354 | 3/3 | 209175 | 47267.61 | ✓ | — |
| 5 | spt_lns | James (IrwinJam) | 1.4347 | 3/3 | 209415 | missing | — | |
| 6 | warm_lns_refinement † | kesudh | 1.4331 | 3/3 | 209509 | 3615.00 | ✓ | — |
| 7 | iamparv7043 | Parv (iamparv7043) | 1.3276 | 3/3 | 226581 | 1309.30 | ✓ | — |
| 8 | lns_negotiated | adityuhkapoor | 1.2533 | 3/3 | 240751 | missing | — | |
| 9 | anvesh | anvesh | 1.2520 | 3/3 | 240501 | missing | — | |
| 10 | negotiated_delay | Mantej Singh Gill | 1.1947 | 3/3 | 252901 | 636.11 | ✓ | — |
| 11 | synapse-surge | Sameer-Deepak | 1.1456 | 3/3 | 264847 | missing | — | |
| 12 | shivaahir158 | Shiva Ahir (PhD Candidate, Stony Brook University) | 1.0593 | 3/3 | 288347 | 3728.39 | — |
† derivative entry (refines another entry's routes): coordinated_refinement builds on leonid-popryho (Leonid Popryho); warm_lns_refinement builds on pathfinder_lns (Taz33m).
The challenge ships several tiers, from an easy on-ramp to genuinely hard, plus a tier built from real open-source circuits. Each is its own directory with its own manifest; each case is normalized against its own tier's baseline.
| Tier | Dir | Cases | Largest case | Baseline (to beat) | What makes it hard |
|---|---|---|---|---|---|
| intro | benchmarks/ |
20 | 92×92×6, 139 nets, 514 pins | simple rip-up router | On-ramp. Sparse (~6% of edges used); the simple baseline routes every case with 0 rip-ups, so it is easy and conventional — good for getting a submission working. |
| hard | benchmarks_hard/ |
9 | 40×40×6, 104 nets, 323 pins | negotiated-congestion router | Contended. Pins and nets crowd the cheap middle layers, so the delay-vs-detour tradeoff is the crux and legality itself needs a real router: the simple rip-up baseline fails or thrashes on most cases (thousands of rip-ups), while the negotiated router certifies a legal solution. Beating that baseline is the real contest. |
| scale | benchmarks_scale/ |
8 | 156×156×6, 265 nets, 766 pins | simple router | Large. Big enough that runtime is a first-class axis (the baseline itself takes ~10–70 s/case), which is what the runtime-vs-delay Pareto below measures. |
| stress | benchmarks_stress/ |
1 | 530×530×6, 901 nets, 2,612 pins | simple router | ~30-minute baseline (sparse). One giant sparse case for stress-testing router runtime and scaling; the reference (simple) baseline routes it in ~33 min. Baseline route time fits ≈ 7e-6 · nets · side², so you can dial any target wall time in m3d/suite.py. |
| congested | benchmarks_congested/ |
4 | 116×116×6, ~302 nets, ~950 pins | negotiated router | Large + contended stress. The congested counterpart of stress: net density and locality hold the cheap middle layers at ~35% utilization at every size, so the simple baseline is hopeless and even the negotiated router ramps ~80 s → ~9 min across the four cases (64/88/112/116). |
| designs | benchmarks_designs/ |
3 | 105×105×6, 344 nets, 888 pins | negotiated router | Real open-source circuits. Instances built from real gate-level netlists — the MIT-licensed EPFL combinational benchmark suite. Every gate, input and output becomes a cell and every signal a net, so fanout and connectivity are those of a real design; cells are placed by connectivity clustering (reverse Cuthill-McKee) and folded across the two dies. The negotiated router certifies each reference. Bring your own with m3d.cli import-design. |
Is the intro tier "too easy / conventional"? Yes, deliberately — it is the
on-ramp. The hard tier is where the 3D structure bites: the
delay-graded layer stack is only interesting when the cheap layers are scarce and
contended, and there the problem stops being a clean maze and becomes a real
congestion-plus-delay optimization that a naive router cannot even legalize. The
scale tier adds the runtime dimension. The designs tier grounds all of
this in real silicon: the same model, checker and scorer applied to actual
open-source netlists, where the fanout and connectivity are not synthetic.
Everything is parametric (m3d/suite.py, m3d/generator.py::GenConfig,
m3d/designs.py::DesignConfig), so you can push grids, nets, fanout, contention,
layer count — and add more real designs — further.
The designs tier is built from real gate-level netlists, not the random
generator. The sources are vendored under designs/blif/ from the MIT-licensed
EPFL combinational benchmark suite (see
designs/PROVENANCE.md). The mapping is direct:
- every logic gate, primary input and primary output becomes a cell (footprint sized to its pin count);
- every signal with a driver and ≥1 sink becomes a net — the driving terminal is the driver pin, the reading terminals are the sinks — so the fanout and connectivity are exactly the design's;
- cells are ordered by reverse Cuthill-McKee (connectivity clustering) and spread on a lattice with a routing channel around each, then split across the two dies at a low-connectivity cut, so signals crossing the fold use vias;
- the negotiated router certifies a legal reference, widening the channel until it succeeds — the same verified-feasible guarantee as every other tier.
Only the connectivity is used; the logic (the BLIF truth tables) is irrelevant to
routing and is ignored. Build the tier with make generate-designs (resumable —
re-run to finish if interrupted), or turn any BLIF into an instance:
python -m m3d.cli import-design --blif designs/blif/cavlc.blif --name cavlc \
--out cavlc.json --reference cavlc.sol.json
- Two dies — bottom = die 0, top = die 1 — share one rectangular,
grid-aligned XY coordinate system of size
width x height. - Between them is a stack of
layersrouting layers,z = 0 .. layers-1. The number of layers is configurable (default 6). - Rectangular, grid-aligned cells are placed without overlap on each die. Cells on opposite dies may overlap in XY. Each cell carries one or more grid-aligned pins.
- Bottom-die pins live on layer
z = 0; top-die pins live on layerz = layers-1. - Routing is a 3D grid graph. A vertex is
(x, y, z). Legal moves:- one grid step in X or Y on the same layer, or
- a via to an adjacent layer at the same XY. No diagonal moves, no skipped layers.
- In this first model, cell footprints do not obstruct the routing layers. The only routing obstacles are other nets' pins (see legality).
This is an abstract additive delay objective, not electrical timing analysis. There is no capacitance, slew, buffering, loading, or congestion-dependent delay.
- Each routing layer has a constant positive integer delay per grid edge.
The default profile is symmetric about the middle of the stack, lowest
in the middle and highest next to either die:
layer_delay[z] = center_delay + slope * |2z - (layers-1)|. - Each via between adjacent layers has a constant positive integer delay.
- All delay values are stored explicitly in every instance (
layer_delay,via_delay), and delays are integers so scoring is exact and deterministic.
- Nets connect cell pins; a net may be same-die or cross-die (spanning both dies), two-pin or multi-pin. Proportions and fanout are configurable.
- Each net has exactly one driver and one or more sinks. Every pin belongs to exactly one net.
- A submitted route for a net must be a connected, acyclic tree that spans all of the net's pins, so every driver→sink path is unambiguous.
- Total routing delay = the sum, over all sinks of all nets, of the delay of the driver→sink path through that net's tree. A shared segment contributes to each sink path that traverses it.
- Objective: minimize total routing delay while routing every net legally.
- Each routing-grid vertex and edge may belong to at most one net.
- Branches of the same net may share vertices and edges (a tree already does).
- Different nets may cross in XY on different layers, as long as they share no 3D vertex or edge.
- A via occupies its two endpoint vertices and the edge between them.
- A route may not pass through another net's pin.
- All routes must stay within the grid and layer bounds and use only legal moves.
A submission is rejected (illegal, non-competitive) if it has any disconnected pin, missing net, short, resource conflict, cycle, invalid coordinate, or illegal layer transition. Partial routing does not earn a competitive score.
m3d/ the toolkit (pure stdlib)
model.py data model, delay profile, JSON I/O
grid.py 3D grid moves used by the router
generator.py deterministic, verified-feasible benchmark generator
checker.py independent legality checker + delay recomputation
scorer.py per-case scoring + normalized leaderboard
baseline.py baseline router (Dijkstra trees + rip-up-and-reroute)
negotiated.py negotiated-congestion router (PathFinder-style; hard tier)
designs.py BLIF netlist -> routing instance (the 'designs' tier)
suite.py the generated tiers (intro/hard/scale/stress/congested)
scorer.py per-case scoring, leaderboard, Pareto frontier
viz.py matplotlib visualization + Pareto plot
anim.py animated GIF renderers
cli.py command-line entry point
designs/ vendored open-source netlists (blif/) + license + provenance
benchmarks/ intro tier: 20 cases + suite.json + reference/
benchmarks_hard/ hard (contended) tier: 9 cases + suite.json + reference/
benchmarks_scale/ scale (large) tier: 8 cases + suite.json + reference/
benchmarks_stress/ stress tier: 1 giant sparse case + suite.json + reference/
benchmarks_congested/ congested tier: 4 large contended cases + reference/
benchmarks_designs/ designs tier: 3 real EPFL circuits + suite.json + reference/
submissions/ PR-based leaderboard entries: submissions/<tier>/<name>/
LEADERBOARD.md generated leaderboard (python -m m3d.cli leaderboard-all)
CONTRIBUTING.md how to submit results by pull request
scripts/ verify_submissions.py (the check CI runs on every PR)
.github/workflows/ CI: verify submissions + keep LEADERBOARD.md current
examples/ example participant router + example submissions
tests/ unit + end-to-end tests
docs/ images, the Pareto plot, and the format reference (FORMATS.md)
Requires Python 3.9+ and nothing else — the toolkit is pure standard library,
so it runs on macOS, Linux and Windows with no install. CI tests macOS and Linux
on Python 3.9 and 3.12. Only the optional visualization needs matplotlib
(pip install -r requirements.txt). Run all commands from the repository root.
Any language, any hardware. A submission is just JSON route files (see
docs/FORMATS.md), so you can write your router in any
language and run it on anything — CPU, GPU, a cluster, a Mac laptop. The toolkit
only reads and scores your output; it never runs your solver. Scoring is
deterministic across platforms: it recomputes delay with exact integer arithmetic
on the committed benchmark instances, so your local score matches CI's exactly.
# regenerate a tier deterministically (intro -> benchmarks/, hard -> benchmarks_hard/,
# scale -> benchmarks_scale/, ...; `all` builds all six tiers, including the
# ~30-minute stress tier)
python -m m3d.cli generate --tier intro
python -m m3d.cli generate --tier all
# run the baseline router on one case
python -m m3d.cli baseline --case benchmarks/case_01.json --out my.sol.json
# evaluate a submission (legality + delay + ratio vs baseline)
python -m m3d.cli evaluate --case benchmarks/case_01.json --sol my.sol.json --suite benchmarks
# score a full submission for one tier (leaderboard; here the 20-case intro tier)
python -m m3d.cli score-suite --suite benchmarks --submission-dir examples/submissions
# visualize a case (all layers, or one layer with --layer N)
python -m m3d.cli visualize --case benchmarks/case_01.json --sol benchmarks/reference/case_01.sol.json --out case_01.png
# animate: sweep the stack of one case, or sweep the whole suite
python -m m3d.cli animate --mode layers --case benchmarks/case_12.json --sol benchmarks/reference/case_12.sol.json --out layer_sweep.gif
python -m m3d.cli animate --mode suite --suite benchmarks --out suite_sweep.gif
# print a case summary
python -m m3d.cli info --case benchmarks/case_10.json
# run the tests
python -m unittest discover -s tests -t .A Makefile wraps the common commands: make generate, make baseline,
make score-example, make visualize, make test.
- Read each instance (
benchmarks/case_NN.json): grid, layers, delays, cells, pins, and nets. - For each net, produce a tree of routing edges connecting the driver to all sinks, obeying the legality rules above.
- Write a submission JSON per case (
case_NN.sol.json) in the submission format (below). Put one per case (all 20 for the intro tier) in one directory. - Score locally:
python -m m3d.cli score-suite --suite benchmarks --submission-dir <your_dir>.
A complete ranked submission must be legal on every case in the tier. See
examples/example_submission.py for a minimal, self-contained router you can
copy and replace with your own algorithm — it demonstrates loading, routing on
the shared grid, self-checking, and writing a submission.
- To appear on the live leaderboard, open a pull request adding your results
under
submissions/<tier>/<name>/— seeCONTRIBUTING.mdand section 5b below.
Instance (case_NN.json, format: m3d-instance): grid {width,height,layers},
delay {layer_delay:[...], via_delay}, cells, pins (id, cell, die, x, y, z),
nets (id, driver, sinks:[...]), plus generation params and seed.
Submission (format: m3d-submission): instance name and routes, a list of
{net, edges} where each edge is a pair of vertices [[x1,y1,z1],[x2,y2,z2]].
Result (format: m3d-result): legal, total_delay, per-net {legal, delay, reasons}, global reasons, and conflict_vertices / conflict_edges for
visualization of invalid submissions.
The evaluator independently reconstructs and validates every route and recomputes the delay from the instance; it never trusts participant-reported metrics.
-
Per case the checker reports the raw total delay it recomputes.
-
The aggregate leaderboard normalizes each case against the baseline so the largest case cannot dominate by size. For a legal case with total
s_cand baseline totalb_c, the per-case ratio isb_c / s_c(a ratio above 1 beats the baseline). The aggregate is the geometric mean of the ratios:aggregate = ( product over cases of (baseline_total / submission_total) ) ** (1 / N)Higher is better; the baseline scores exactly 1.0. A submission must be legal on every case of the tier to be complete and ranked — otherwise it is marked incomplete with aggregate
0.0. -
Runtime is recorded separately (pass a
{case: seconds}JSON via--runtimes) and never affects the delay score. Leaderboard entries must report it:runtime.jsonholds the wall-clock seconds of the run that produced each case, withhardwareandthreadsinmeta.json(see CONTRIBUTING.md).
The baseline itself is the normalization reference; its per-case totals are in
each tier's suite.json (e.g. benchmarks/suite.json).
To compare several routers on a tier, put each one's solutions (plus an optional
runtime.json of {case: seconds}) in its own subdirectory and rank them:
# produce a few submissions for the hard tier (each writes runtime.json)
python -m m3d.cli run-suite --suite benchmarks_hard --router negotiated_fast --out-dir subs/fast
python -m m3d.cli run-suite --suite benchmarks_hard --router negotiated --out-dir subs/negotiated
python -m m3d.cli run-suite --suite benchmarks_hard --router negotiated2 --out-dir subs/negotiated_x2
# rank them (aggregate score; complete submissions first) and mark the Pareto set
python -m m3d.cli leaderboard --suite benchmarks_hard --submissions-root subs --md board.md
# plot total runtime vs total raw delay, with the Pareto frontier
python -m m3d.cli pareto --suite benchmarks_hard --submissions-root subs --out pareto.pngThe ranked leaderboard sorts complete submissions by aggregate score (then by total delay); a submission that is not legal on every case is listed but not ranked. The Pareto plot shows one point per submission — total runtime vs total raw routing delay — and highlights the frontier (you cannot lower delay without spending more time).
Hard tier: negotiated (faster, higher delay) and negotiated_x2 (best-of-two
orders — ~2× the runtime for ~1.5% lower delay) are both Pareto-optimal;
negotiated_fast is faster still but illegal on one case, so it is not ranked.
The project leaderboard is at the top of this README and in
LEADERBOARD.md; both are built
from real, checker-verified entries under submissions/<tier>/<name>/. You get
on it by opening a pull request that adds your results — see
CONTRIBUTING.md for the step-by-step.
Scores are always recomputed from the submitted route files by the independent
checker, so the board cannot be gamed by editing numbers — you rank higher only by
submitting better legal routes. CI on every PR re-checks each solution, confirms
LEADERBOARD.md and the README block are current (leaderboard-all --check), and
blocks submission PRs that touch anything outside submissions/, LEADERBOARD.md
and the README's generated leaderboard block. Entries that start from another
entry's routes declare derived_from in meta.json and are marked †.
# self-check your submission, then regenerate the board before you commit
python -m m3d.cli score-suite --suite benchmarks_hard --submission-dir submissions/hard/<name>
python -m m3d.cli leaderboard-all # writes LEADERBOARD.md + README block
make verify-submissions # CI's submission checks (CI also runs the tests)The seed entries under submissions/hard/ are the three negotiated variants shown
in the Pareto plot above.
m3d/baseline.py is a deliberately simple, deterministic reference: it routes
nets one at a time (largest bounding box first), grows each net as a shortest
(minimum-delay) tree with multi-source Dijkstra, enforces hard capacity, and
uses rip-up-and-reroute when a net is blocked. It is not state of the art;
it exists to establish a usable reference score and to certify that generated
instances are routable. Beating it is the point.
For the contended hard tier, that simple router is not strong enough (it
fails or thrashes), so a second reference — m3d/negotiated.py, a PathFinder-style
negotiated-congestion router — certifies feasibility and provides the hard
tier's baseline. It routes every net each round allowing temporary overuse, then
raises a per-resource history cost on anything overused so nets negotiate away
from contention, and (after the first pass) only reroutes the nets touching an
overused resource. When uncongested it reduces to per-net shortest paths, so it
preserves the delay objective on sparse instances. Both routers are deterministic.
- Determinism. The suite uses a fixed master seed (
20260923) and a reproducible per-case seed schedule (m3d/suite.py). Generation uses Python'srandom.Random(Mersenne Twister), stable across CPython versions for a given seed and call sequence. Delays are integers, so scoring is exact. - Cross-platform and hardware-agnostic. The toolkit is pure standard library (Python 3.9+); CI runs the tests and submission checks on macOS and Linux across Python 3.9 and 3.12. Because scoring recomputes integer delay on the committed benchmark instances, a submission scores identically on every OS and on any hardware — so participants are free to use GPUs, other languages, or a cluster to produce their route files. (Regenerate benchmarks only if you intend to fork the suite; the released cases and baselines are what everyone is scored against.)
- Verified feasibility. Every released instance is generated and then routed
by the baseline and validated by the independent checker; candidates without a
checker-verified legal solution are discarded and regenerated. The verified
reference solution lives in
benchmarks/reference/, separate from the participant inputs, and doubles as the scoring baseline. (A router's failure is not treated as proof of infeasibility — we only accept an instance once a legal solution is in hand.) - Documented simplifications. Cell footprints do not obstruct routing (only other nets' pins do); the delay model is abstract and additive (no electrical effects); capacity is a simple one-net-per-resource model. These keep the challenge correct and reproducible end to end; richer models are natural future extensions.
- Configurable. Grid size, layer count, cell counts/sizes, pins per cell,
net count, fanout distribution, cross-die fraction, locality, and all delays
are configurable (
m3d/generator.py::GenConfig,m3d/suite.py). The routing layer count and benchmark sizes are intentionally easy to change.
Found a bug, a broken case, unclear docs, or a rough edge? Please fix it and open a pull request. Improvements to the toolkit, generator, docs, tests, or tooling are all welcome — no need to ask first for small fixes.
- Toolkit / bug-fix PRs may touch any file; please keep the tests green
(
make test) and add a test when you fix a bug. - Leaderboard-submission PRs only add your results under
submissions/— seeCONTRIBUTING.md. CI keeps those two kinds of PR separate.
If you would rather just report something, open a GitHub issue describing the problem and, if you can, the case or command that triggers it.
MIT — see LICENSE.


