File size: 2,982 Bytes
a115eaf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | """
Regression pin for the redundant-full-grid-build bug: /v1/plan used to call
builder.build() with no BFS-reduced window active (_active_cells still None)
right before solver.solve(), which immediately rebuilds it properly anyway —
free on tiny synthetic maps, but apply_one_hot()'s O(cells²) constraint loop
made it dominate wall time on real-sized maps (see builder/base_qubo.py's
_warn_if_unrestricted_build(), added alongside the fix).
This needs a map above _warn_if_unrestricted_build()'s 200-cell threshold —
no_obs50x50 (2,500 cells) — even though the robot's own path only needs a
tiny window: the bug was building the *whole grid* regardless of how short
the requested path was, so a small map would never actually exercise it.
The fast classical solver keeps this quick with no GPU/real hardware needed.
"""
from fastapi.testclient import TestClient
from api import app
def test_plan_does_not_trigger_unrestricted_build(capsys):
with TestClient(app) as client:
response = client.post(
"/v1/plan",
json={
"map_id": "no_obs50x50",
"solver": "dwave.fast",
"format": "grid",
"robots": [{"start": [2, 0], "goal": [0, 2]}],
"penalty_set": "crash",
},
)
assert response.status_code == 200, response.text
# The actual regression pin: this warning only fires when build() ran
# over the full grid instead of a BFS-reduced window — i.e. a
# builder.build() call snuck back in before solver.solve() again.
captured = capsys.readouterr()
assert "unrestricted QUBO" not in captured.out
def test_cbs_profile_plans_on_grid_and_graph():
"""classic.cbs must route to the CBS builders in both /v1/plan formats —
the endpoints used to branch ilp-vs-QUBO only, so a CBS profile fell
through to a QUBOBuilder the CBSSolver can't consume."""
with TestClient(app) as client:
assert "classic.cbs" in client.get("/solvers").json()
grid = client.post(
"/v1/plan",
json={
"map_id": "obs5x5_hard",
"solver": "classic.cbs",
"format": "grid",
"robots": [
{"id": "r0", "start": [0, 0], "goal": [4, 4]},
{"id": "r1", "start": [4, 0], "goal": [0, 4]},
],
},
)
assert grid.status_code == 200, grid.text
body = grid.json()
assert body["solver_used"] == "classic.cbs"
assert len(body["paths"]) == 2
assert body["cost"] == body["cost"] # finite, not NaN/inf
graph = client.post(
"/v1/plan",
json={
"map_id": "obs5x5_hard",
"solver": "classic.cbs",
"format": "graph",
"robots": [{"start": [0, 0], "goal": [4, 4]}],
},
)
assert graph.status_code == 200, graph.text
|