Skip to content

Commit d4b11a8

Browse files
committed
found real dumb bug in SIPP
1 parent 06899f2 commit d4b11a8

File tree

4 files changed

+48
-34
lines changed

4 files changed

+48
-34
lines changed

PathPlanning/TimeBasedPathPlanning/ConflictBasedSearch.py

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
3838
path = single_agent_planner_class.plan(grid, start_and_goal.start, start_and_goal.goal, start_and_goal.index, verbose)
3939
initial_solution[AgentId(start_and_goal.index)] = path
4040

41-
for (agent_idx, path) in initial_solution.items():
42-
print(f"\nAgent {agent_idx} path:\n {path}")
41+
if verbose:
42+
print("Initial solution:")
43+
for (agent_idx, path) in initial_solution.items():
44+
print(f"\nAgent {agent_idx} path:\n {path}")
4345

4446
constraint_tree = ConstraintTree(initial_solution)
4547

@@ -49,8 +51,8 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
4951
constraint_tree_node = constraint_tree.get_next_node_to_expand()
5052
ancestor_constraints = constraint_tree.get_ancestor_constraints(constraint_tree_node.parent_idx)
5153

52-
print(f"Expanded node: {constraint_tree_node.constraint} with parent: {constraint_tree_node.parent_idx}")
53-
print(f"\tAncestor constraints: {ancestor_constraints}")
54+
# print(f"Expanded node: {constraint_tree_node.constraint} with parent: {constraint_tree_node.parent_idx}")
55+
# print(f"\tAncestor constraints: {ancestor_constraints}")
5456

5557
if verbose:
5658
print(f"Expanding node with constraint {constraint_tree_node.constraint} and parent {constraint_tree_node.parent_idx}")
@@ -66,6 +68,9 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
6668

6769
# TODO: contents of this loop should probably be in a helper?
6870
for constrained_agent in constraint_tree_node.constraint.constrained_agents:
71+
num_expansions = constraint_tree.expanded_node_count()
72+
if num_expansions % 50 == 0:
73+
print(f"Expanded {num_expansions} nodes so far...")
6974
if verbose:
7075
print(f"\nOuter loop step for agent {constrained_agent}")
7176

@@ -78,40 +83,41 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
7883
# Skip if we have already tried this set of constraints
7984
constraint_hash = hash(frozenset(all_constraints))
8085
if constraint_hash in attempted_constraint_combos:
81-
print(f"\tSkipping already attempted constraint combination: {all_constraints}")
86+
if verbose:
87+
print(f"\tSkipping already attempted constraint combination: {all_constraints}")
8288
continue
8389
else:
8490
attempted_constraint_combos.add(constraint_hash)
8591

8692
if verbose:
8793
print(f"\tall constraints: {all_constraints}")
88-
print(f"\tall constraints: {all_constraints}")
8994

9095
grid.clear_constraint_points()
9196
grid.apply_constraint_points(all_constraints)
9297

9398
# Just plan for agent with new constraint
9499
start_and_goal = ConflictBasedSearch.find_by_index(start_and_goals, constrained_agent.agent)
95100
try:
96-
print("\tplanning for: {}", start_and_goal)
101+
if verbose:
102+
print("\tplanning for: {}", start_and_goal)
97103
new_path = single_agent_planner_class.plan(grid, start_and_goal.start, start_and_goal.goal, start_and_goal.index, verbose)
98104
except Exception as e:
99105
continue
100106

101107
applied_constraint_parent = deepcopy(constraint_tree_node) #TODO: not sure if deepcopy is actually needed
102-
paths: dict[AgentId, NodePath] = deepcopy(applied_constraint_parent.paths) # TODO: not sure if deepcopy is actually needed
108+
paths: dict[AgentId, NodePath] = deepcopy(constraint_tree_node.paths) # TODO: not sure if deepcopy is actually needed
103109
paths[constrained_agent.agent] = new_path
104110

105-
for (agent_idx, path) in paths.items():
106-
print(f"\nAgent {agent_idx} path:\n {path}")
111+
# for (agent_idx, path) in paths.items():
112+
# print(f"\nAgent {agent_idx} path:\n {path}")
107113

108114
applied_constraint_parent.constraint = applied_constraint
109115
parent_idx = constraint_tree.add_expanded_node(applied_constraint_parent)
110116

111-
new_constraint_tree_node = ConstraintTreeNode(deepcopy(paths), parent_idx, all_constraints)
117+
new_constraint_tree_node = ConstraintTreeNode(paths, parent_idx, all_constraints)
112118
if new_constraint_tree_node.constraint is None:
113119
# This means we found a solution!
114-
print("Found a path with constraints:")
120+
print(f"Found a path with constraints after {num_expansions} expansions:")
115121
for constraint in all_constraints:
116122
print(f"\t{constraint}")
117123
# return (start_and_goals, [paths[AgentId(i)] for i in range(len(start_and_goals))])
@@ -131,25 +137,24 @@ def find_by_index(start_and_goal_list: list[StartAndGoal], target_index: AgentId
131137
raise RuntimeError(f"Could not find agent with index {target_index} in {start_and_goal_list}")
132138

133139
# TODO
134-
# * get SIPP working w CBS
135-
# * add checks for duplicate expansions
140+
# * still discrepancies between sipp and A*
136141
# * fan out across multiple threads
137-
# * sipp intervals seem much larger than needed?
138-
142+
# * somehow test/check that high level tree is doing what you want
143+
# * SIPP stinks at 3 robots in the hallway case
139144
verbose = False
140145
show_animation = True
141146
def main():
142147
grid_side_length = 21
143148

144149
# TODO: bug somewhere where it expects agent ids to match indices
145150
# start_and_goals = [StartAndGoal(i, Position(1, i), Position(19, 19-i)) for i in range(1, 12)]
146-
# start_and_goals = [StartAndGoal(i, Position(1, 8+i), Position(19, 19-i)) for i in range(6)]
151+
start_and_goals = [StartAndGoal(i, Position(1, 8+i), Position(19, 19-i)) for i in range(6)]
147152
# start_and_goals = [StartAndGoal(i, Position(1, 2*i), Position(19, 19-i)) for i in range(4)]
148153

149154
# hallway cross
150-
start_and_goals = [StartAndGoal(0, Position(6, 10), Position(13, 10)),
151-
StartAndGoal(1, Position(11, 10), Position(6, 10)),
152-
StartAndGoal(2, Position(13, 10), Position(7, 10))]
155+
# start_and_goals = [StartAndGoal(0, Position(6, 10), Position(13, 10)),
156+
# StartAndGoal(1, Position(11, 10), Position(6, 10)),
157+
# StartAndGoal(2, Position(13, 10), Position(7, 10))]
153158

154159
# temporary obstacle
155160
# start_and_goals = [StartAndGoal(0, Position(15, 14), Position(15, 16))]
@@ -163,8 +168,8 @@ def main():
163168
num_obstacles=250,
164169
obstacle_avoid_points=obstacle_avoid_points,
165170
# obstacle_arrangement=ObstacleArrangement.TEMPORARY_OBSTACLE,
166-
obstacle_arrangement=ObstacleArrangement.HALLWAY,
167-
# obstacle_arrangement=ObstacleArrangement.NARROW_CORRIDOR,
171+
# obstacle_arrangement=ObstacleArrangement.HALLWAY,
172+
obstacle_arrangement=ObstacleArrangement.NARROW_CORRIDOR,
168173
# obstacle_arrangement=ObstacleArrangement.ARRANGEMENT1,
169174
# obstacle_arrangement=ObstacleArrangement.RANDOM,
170175
)

PathPlanning/TimeBasedPathPlanning/ConstraintTree.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ def get_constraint_point(self, verbose = False) -> Optional[ForkingConstraint]:
7575
conflicting_agent_id2 = positions_at_time[old_position_at_new_time]
7676

7777
if conflicting_agent_id1 == conflicting_agent_id2 and conflicting_agent_id1 != agent_id:
78-
print(f"Found edge constraint between with agent {conflicting_agent_id1} for {agent_id}")
79-
print(f"\tpositions old: {old_position_at_new_time}, new: {position_at_time}")
78+
# print(f"Found edge constraint between with agent {conflicting_agent_id1} for {agent_id}")
79+
# print(f"\tpositions old: {old_position_at_new_time}, new: {position_at_time}")
8080
new_constraint = ForkingConstraint((
8181
ConstrainedAgent(agent_id, position_at_time),
8282
ConstrainedAgent(conflicting_agent_id1, Constraint(position=last_position, time=t))
@@ -94,14 +94,17 @@ def get_constraint_point(self, verbose = False) -> Optional[ForkingConstraint]:
9494
)))
9595
continue
9696
if possible_constraints:
97-
print(f"choosing best constraint of {possible_constraints}")
97+
if verbose:
98+
print(f"Choosing best constraint of {possible_constraints}")
9899
# first check for edge constraints
99100
for constraint in possible_constraints:
100101
if constraint.constrained_agents[0].constraint.position != constraint.constrained_agents[1].constraint.position:
101-
print(f"\tfound edge conflict constraint: {constraint}")
102+
if verbose:
103+
print(f"\tFound edge conflict constraint: {constraint}")
102104
return constraint
103105
# if none, then return first normal constraint
104-
print("\treturning normal constraint")
106+
if verbose:
107+
print(f"\tReturning normal constraint: {possible_constraints[0]}")
105108
return possible_constraints[0]
106109

107110
return None
@@ -150,3 +153,6 @@ def add_expanded_node(self, node: ConstraintTreeNode) -> int:
150153
parent_idx = len(self.expanded_nodes)
151154
self.expanded_nodes[parent_idx] = node
152155
return parent_idx
156+
157+
def expanded_node_count(self) -> int:
158+
return len(self.expanded_nodes)

PathPlanning/TimeBasedPathPlanning/GridWithDynamicObstacles.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class Grid:
5555

5656
# TODO: do i want this as part of grid?
5757
constraint_points: np.ndarray
58+
applied_constraints: list[AppliedConstraint] = []
5859

5960
# Number of time steps in the simulation
6061
time_limit: int
@@ -272,6 +273,7 @@ def generate_temporary_obstacle(self, hallway_length: int = 3) -> list[list[Posi
272273
return [obstacle_path]
273274

274275
def apply_constraint_points(self, constraints: list[AppliedConstraint], verbose = False):
276+
self.applied_constraints.extend(constraints)
275277
for constraint in constraints:
276278
if verbose:
277279
print(f"Applying {constraint=}")
@@ -282,7 +284,10 @@ def apply_constraint_points(self, constraints: list[AppliedConstraint], verbose
282284
print(f"\tExisting constraints: {self.constraint_points[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time]}")
283285

284286
def clear_constraint_points(self):
285-
self.constraint_points = empty_3d_array_of_sets(self.grid_size[0], self.grid_size[1], self.time_limit)
287+
for constraint in self.applied_constraints:
288+
if constraint in self.constraint_points[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time]:
289+
self.constraint_points[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time].remove(constraint)
290+
self.applied_constraints.clear()
286291

287292
"""
288293
Check if the given position is valid at time t
@@ -304,9 +309,6 @@ def valid_position(self, position: Position, t: int, agent_idx: int) -> bool:
304309
if constraint.constrained_agent == agent_idx:
305310
return False
306311

307-
# if any([constraint.constrained_agent == agent_idx for constraint in constraints]):
308-
# return False
309-
310312
# Check if position is not occupied at time t
311313
return self.reservation_matrix[position.x, position.y, t] == 0
312314

PathPlanning/TimeBasedPathPlanning/SafeInterval.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ class SafeIntervalPathPlanner(SingleAgentPlanner):
6363
"""
6464
@staticmethod
6565
def plan(grid: Grid, start: Position, goal: Position, agent_idx: int, verbose: bool = False) -> NodePath:
66-
6766
# TODO: hacky
6867
grid.reset()
6968
safe_intervals = grid.get_safe_intervals(agent_idx)
@@ -134,8 +133,8 @@ def generate_successors(
134133
continue
135134

136135
current_interval = parent_node.interval
137-
138136
new_cell_intervals: list[Interval] = intervals[new_pos.x, new_pos.y]
137+
139138
for interval in new_cell_intervals:
140139
# if interval starts after current ends, break
141140
# assumption: intervals are sorted by start time, so all future intervals will hit this condition as well
@@ -157,7 +156,9 @@ def generate_successors(
157156

158157
# We know there is a node worth expanding. Generate successor at the earliest possible time the
159158
# new interval can be entered
160-
for possible_t in range(max(parent_node.time + 1, interval.start_time), min(current_interval.end_time, interval.end_time)):
159+
minimum_entry_time = max(parent_node.time + 1, interval.start_time)
160+
maximum_entry_time = min(current_interval.end_time, interval.end_time)
161+
for possible_t in range(minimum_entry_time, maximum_entry_time + 1):
161162
if grid.valid_position(new_pos, possible_t, agent_idx):
162163
new_nodes.append(SIPPNode(
163164
new_pos,

0 commit comments

Comments
 (0)