Skip to content

Repository files navigation

eecbs-benchmark

Bounded-suboptimal CBS with Explicit Estimation Search, benchmarked against optimal CBS.

ci python coverage licence

Third repository in the femi-mapf series. Builds on astar-grid and cbs-from-scratch.


The question this answers

cbs-from-scratch established that optimal CBS collapses under congestion: on 10×10 grids at 10% obstacle density, success fell from 100% at 8 agents to 5% at 20. The cost of that failure is not path quality — it is the exponential price of proving a cost optimal.

EECBS asks what happens if you stop insisting on proof. Accept any solution within a factor w of optimal, and spend the search effort chasing conflict-free plans rather than certifying lower bounds.

The answer, measured here: at 20 agents, optimal CBS solves 1 instance in 20. EECBS at w = 1.5 solves 20 in 20, and pays 2.5% extra cost to do it.


Results

All numbers from eecbs benchmark. 10×10 grids, 10% obstacles, 20 seeds per agent count, 5 s limit.

CBS vs EECBS

solver agents success median ms median ratio cost vs optimal
CBS (optimal) 8 20/20 6.8 1.000 1.000
CBS (optimal) 12 16/20 37.7 1.000 1.000
CBS (optimal) 16 5/20 441.2 1.000 1.000
CBS (optimal) 20 1/20 246.7 1.000 1.000
EECBS w=1.1 16 17/20 100.9 1.059 1.011
EECBS w=1.1 20 15/20 493.6 1.085 1.016
EECBS w=1.5 16 20/20 42.6 1.075 1.017
EECBS w=1.5 20 20/20 124.0 1.142 1.025
EECBS w=2.0 20 20/20 91.8 1.159 1.025

Read the last two columns together. Median ratio is cost divided by the solver's own proven lower bound — what EECBS can certify without knowing the optimum. Cost vs optimal is the real penalty, computed only over instances both solvers finished, so it compares like with like.

At 20 agents, w = 1.5 turns a 5% success rate into 100% for 2.5% extra cost. At 16 agents it is 25% → 100% for 1.7%.

The bound is a worst case, not a forecast

bound slack

w worst ratio observed slack unused
1.1 1.099 0.1%
1.5 1.426 5%
2.0 1.419 29%

Permitting 2× degradation does not produce 2× worse paths. The worst instance across the whole sweep came in at 1.419, and the median at 1.159. w is a ceiling the search rarely approaches — it functions as permission to stop proving, not as a quality target.

Note that w = 2.0's worst case (1.419) is marginally better than w = 1.5's (1.426). Once the bound is loose enough to stop constraining the search, further loosening changes little; the two explore almost identically.


Two honest negative results

Both are reported because a benchmark that only publishes wins is not a benchmark.

The CG heuristic costs more than it saves at this scale

The CG heuristic builds MDDs to identify cardinal conflicts and computes a minimum vertex cover over them, producing a provably admissible bonus to the lower bound. It works — the bound tightens — but it does not pay for itself here:

w heuristic solved median ms median LB
1.1 CG 15/15 78.1 103
1.1 none 14/15 53.1 100
1.5 CG 15/15 29.6 102
1.5 none 15/15 19.7 102

The bound genuinely sharpens (103 vs 100 at w = 1.1, which is a stronger guarantee for the same w), and it converts one timeout into a solve. But MDD construction is two breadth-first sweeps per agent per node, and on instances this small that dominates. It would be dishonest to report the heuristic as a speed-up.

It is on by default because the tighter bound is the more defensible artefact; --no-heuristic turns it off, and both settings are tested for bound compliance.

The EES fallback lists barely fire when the bound is loose

EECBS's node selection maintains three lists. Counting which one each expansion came from:

w FOCAL OPEN CLEANUP
1.00 643 4 22
1.10 82 0 0
1.50 35 0 0
2.00 30 0 0

At w = 1.0 the machinery matters: FOCAL is restricted to lower-bound nodes, so OPEN and CLEANUP fire to advance the bound. Loosen the bound and FOCAL is always populated and always within it, so the other two never win — at w ≥ 1.1 on these instances, this behaves as ECBS with an explicit lower bound rather than as full EES.

That is not a defect; it is what the selection rule should do. But it means the "explicit estimation" contribution is not what produces the speed-up in the table above. The focal-search low level is.


Correctness

The guarantee is cost <= w * optimal, and it is checked against the optimal solver from cbs-from-scratch — an independent implementation, not a self-consistency check.

Cross-validated across w ∈ {1.0, 1.1, 1.5, 2.0} × {3, 5} agents × 8 seeds — 64 instances, zero violations, with three separate properties asserted on each:

  1. cost <= w * optimal_cost — the bound itself.
  2. lower_bound <= optimal_cost — admissibility of the reported bound. Without this the guarantee would be vacuous: a solver could inflate its own lower bound and satisfy cost <= w * lb while badly exceeding w * optimal.
  3. The plan validates under cbs.validate — legal moves, no conflicts, correct endpoints.

Separately, w = 1.0 returns exactly the optimal cost on every instance tested (30 checked, zero mismatches). That is the property that says focal search degenerates correctly: at w = 1.0 FOCAL admits only lower-bound nodes and the algorithm is CBS.

The benchmark harness re-checks every run as it goes and refuses to report a sweep containing any invalid plan or any bound violation.


What is and is not implemented

From Li, Ruml and Koenig (2021):

Implemented. Explicit Estimation Search node selection over three lists; bounded-suboptimal focal search at the low level with a conflict-avoidance tie-break; the CG heuristic via exact minimum vertex cover on the cardinal conflict graph, with MDDs built to classify cardinality.

Not implemented. The WDG heuristic, symmetry reasoning (rectangle, target, corridor), and bypassing. These are further speed-ups; their absence costs runtime, never correctness or the bound.

One deliberate weakening: only vertex conflicts are classified as cardinal. Edge conflicts can be cardinal too, but establishing that requires MDD edge sets rather than levels. Omitting them makes the heuristic weaker, never inadmissible — the safe direction.


Install

git clone https://github.com/femi-mapf/eecbs-benchmark.git
cd eecbs-benchmark

python -m venv .venv
source .venv/Scripts/activate      # Git Bash on Windows

pip install -e ".[dev]"

astar-grid and cbs-from-scratch install automatically from GitHub. Both must be public.


Usage

# Solve at a bound and compare against optimal CBS on the same instance
eecbs solve --size 16 --agents 12 --seed 3 -w 1.5 --compare-optimal

# Turn the CG heuristic off
eecbs solve --size 16 --agents 12 -w 1.5 --no-heuristic

# Reproduce every table and figure above
eecbs benchmark --size 10 --agents 8 12 16 20 --bounds 1.1 1.5 2.0 --seeds 20

Exit codes: 0 solved and within bound, 1 no solution, 2 bad arguments, 3 validation failed, 4 bound violated.

from cbs import random_instance, validate
from eecbs import eecbs

instance = random_instance(size=16, num_agents=12, density=0.15, seed=3)
result = eecbs(instance, suboptimality=1.5)

print(result.summary())
# cost=  152 lb=  141 ratio=1.078 (w=1.50) ct=     4   0.031s

assert validate(instance, result.paths)
assert result.ratio <= 1.5

Design notes

Focal search is where the speed-up comes from. OPEN is ordered by f and its minimum is a valid lower bound; FOCAL holds nodes with f <= w * f_min, ordered by how many conflicts the partial path already has. Expanding from FOCAL steers toward paths that get in everyone's way least, while the admission rule caps how much detour that steering may cost.

The lower bound is returned, not inferred. The low level reports the true optimal cost under its constraints alongside the path it chose. The high level sums those, and the guarantee is stated against that sum. A solver that reported the returned path's own cost as the bound would satisfy cost <= w * lb trivially and guarantee nothing.

Lower bounds never regress. A child inherits max(child.lb, parent.lb). Constraints only ever make paths longer, so a child's true bound cannot be below its parent's; taking the max recovers precision lost when one agent's replan happens to report a looser figure.

The MVC fallback stays admissible. Minimum vertex cover is NP-hard. If branch-and-bound exhausts its budget the code returns a matching size — a lower bound on the cover — rather than the truncated search value, which could overestimate and silently break the guarantee. Tested directly.

A finished agent still occupies space. Occupancy reserves each agent's goal cell from its arrival time onward, not merely for the length of its path. Same class of bug as in cbs-from-scratch, same fix.


Tests

pytest                    # full suite with coverage gate
ruff check src tests
mypy

122 tests, 95.7% coverage. The build fails below 95%.

Highlights: the bound checked against true optimal CBS at four values of w; w = 1.0 proven to recover optimality; lower-bound admissibility asserted separately from the bound itself; minimum vertex cover checked exactly against brute-force enumeration on six graph topologies; the MVC budget fallback proven not to overestimate; MDD levels verified singleton in corridors and wide in open terrain; cardinal, semi-cardinal and non-cardinal conflicts each classified; and the harness's own violation detectors tested by feeding them sabotaged runs.


Roadmap

repository status role
astar-grid complete single-agent A*, instrumentation, benchmark I/O
cbs-from-scratch complete constraint tree, optimal baseline
eecbs-benchmark complete focal search, bounded suboptimality, EES
lacam-python next configuration-space DFS with PIBT, anytime refinement
inspection-mapf planned 30-node pipeline benchmark, heterogeneous UAV battery, two-mode inspection

The next repository takes the other branch of Sturtevant's framing. CBS and EECBS both prove a lower bound and work upward. LaCAM finds a solution immediately and improves it — a different answer to the same congestion problem, and the one better suited to reactive inspection.


Licence

MIT. See LICENSE.

About

Bounded-suboptimal CBS with Explicit Estimation Search, benchmarked against optimal CBS.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages