File size: 3,446 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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | """
Coverage for PathfindingProblem's construction-time feasibility guards: a
robot's start/goal that is out of bounds, on an obstacle, or an unknown
graph node, or a start_time that leaves no time to plan within an explicit
horizon, must be rejected at construction time (InfeasibleProblemError),
not discovered later as a cryptic var_limit crash, a silently-unsatisfiable
QUBO, or a failed benchmark run.
"""
import pytest
from quantum.map import Grid, Graph
from quantum.robotConfiguration import RobotConfig
from quantum.pathFormulation import PathfindingProblem, InfeasibleProblemError
def _grid():
return Grid(3, 3, obstacles=[(1, 1)])
def test_valid_start_and_goal_construct_without_error():
robot = RobotConfig("a", start=(0, 0), goal=(2, 2))
problem = PathfindingProblem(robot, grid=_grid())
assert problem.robots["a"].start == (0, 0)
def test_start_on_obstacle_raises():
robot = RobotConfig("a", start=(1, 1), goal=(2, 2))
with pytest.raises(InfeasibleProblemError, match="obstacle"):
PathfindingProblem(robot, grid=_grid())
def test_goal_on_obstacle_raises():
robot = RobotConfig("a", start=(0, 0), goal=(1, 1))
with pytest.raises(InfeasibleProblemError, match="obstacle"):
PathfindingProblem(robot, grid=_grid())
@pytest.mark.parametrize("start", [(-1, 0), (3, 0), (0, -1), (0, 3)])
def test_out_of_bounds_start_raises(start):
robot = RobotConfig("a", start=start, goal=(2, 2))
with pytest.raises(InfeasibleProblemError, match="out of bounds"):
PathfindingProblem(robot, grid=_grid())
def test_out_of_bounds_goal_raises():
robot = RobotConfig("a", start=(0, 0), goal=(5, 5))
with pytest.raises(InfeasibleProblemError, match="out of bounds"):
PathfindingProblem(robot, grid=_grid())
def test_one_bad_robot_among_several_still_raises():
robots = [
RobotConfig("good", start=(0, 0), goal=(0, 2)),
RobotConfig("bad", start=(1, 1), goal=(2, 0)),
]
with pytest.raises(InfeasibleProblemError, match="'bad'"):
PathfindingProblem(robots, grid=_grid())
def _graph():
return Graph(nodes=[(0, 0), (0, 1), (1, 1)], edges=[(0, 1), (1, 2)])
def test_valid_graph_node_ids_construct_without_error():
robot = RobotConfig("a", start=0, goal=2)
problem = PathfindingProblem(robot, graph=_graph())
assert problem.robots["a"].goal == 2
@pytest.mark.parametrize("goal", [-1, 3, 999])
def test_out_of_range_graph_node_id_raises(goal):
robot = RobotConfig("a", start=0, goal=goal)
with pytest.raises(InfeasibleProblemError, match="does not exist"):
PathfindingProblem(robot, graph=_graph())
def test_start_time_beyond_horizon_raises():
robot = RobotConfig("a", start=(0, 0), goal=(2, 2), start_time=5)
with pytest.raises(InfeasibleProblemError, match="leaves no time"):
PathfindingProblem(robot, grid=_grid(), T=5)
def test_start_time_at_horizon_raises():
"""start_time == T leaves a zero-length window -- also infeasible, not
just start_time > T."""
robot = RobotConfig("a", start=(0, 0), goal=(2, 2), start_time=4)
with pytest.raises(InfeasibleProblemError, match="leaves no time"):
PathfindingProblem(robot, grid=_grid(), T=4)
def test_start_time_within_horizon_is_fine():
robot = RobotConfig("a", start=(0, 0), goal=(2, 2), start_time=2)
problem = PathfindingProblem(robot, grid=_grid(), T=6)
assert problem.robots["a"].T == 4
|