-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathICBSSingleAgentLLSearch.cpp
341 lines (308 loc) · 12.2 KB
/
ICBSSingleAgentLLSearch.cpp
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
#include "ICBSSingleAgentLLSearch.h"
#include "conflict_avoidance_table.h"
// Put the path to the given goal node in the <path> vector
void ICBSSingleAgentLLSearch::updatePath(const ICBSSingleAgentLLNode* goal, Path &path)
{
const ICBSSingleAgentLLNode* curr = goal;
int old_length = (int)path.size();
if (goal->timestep >= old_length)
path.resize(goal->timestep + 1);
// The start and goal are singletons:
path[goal->timestep].builtMDD = true;
path[goal->timestep].single = true;
path[goal->timestep].numMDDNodes = 1;
path[0].builtMDD = true;
path[0].single = true;
path[0].numMDDNodes = 1;
for(int t = goal->timestep; curr != nullptr; t--)
{
path[t].location = curr->loc;
path[t].builtMDD = false;
curr = curr->parent;
}
if (path.size() > old_length)
{
int i = old_length;
while (path[i].location == -1)
{
path[i] = path[old_length - 1];
i++;
}
}
}
int ICBSSingleAgentLLSearch::getDifferentialHeuristic(int loc1, int loc2) const
{
if (loc2 == goal_location)
return my_heuristic[loc1];
int h = 0, sub;
for (int i = 0; i < differential_h.size(); i++)
{
sub = abs(differential_h[i][loc1] - differential_h[i][loc2]);
if (sub > h)
h = sub;
}
return h;
}
// iterate over the constraints ( cons[t] is a list of all constraints for timestep t) and return the latest
// timestep which has a constraint involving the goal location
// which is the minimal plan length for the agent
int ICBSSingleAgentLLSearch::extractLastGoalTimestep(int goal_location, const vector<list<ConstraintForKnownTimestep>>* cons)
{
if (cons != NULL)
{
for (int t = static_cast<int>(cons->size()) - 1; t > 0; t--)
{
for (list<ConstraintForKnownTimestep>::const_iterator it = cons->at(t).begin(); it != cons->at(t).end(); ++it)
{
auto [loc1, loc2, positive_constraint] = *it;
if (loc1 == goal_location && loc2 < 0 && !positive_constraint) {
return t;
}
}
}
}
return -1;
}
// Checks if a move into next_id at next_timestepfrom direction is valid (wrt my_map and constraints)
// input: direction (into next_id) ; next_id (location at time next_timestep); next_timestep
// cons[timestep] is a list of <loc1,loc2, bool> of (vertex/edge) constraints for that timestep. (loc2=-1 for vertex constraint).
bool ICBSSingleAgentLLSearch::isConstrained(int direction, int next_id, int next_timestep,
const XytHolder<ConstraintState>& cons_table) const
{
if (my_map[next_id]) // obstacles
return true;
int loc_id = next_id - moves_offset[direction];
auto [found_curr, state_curr] = cons_table.get(loc_id, next_timestep - 1);
if (found_curr && state_curr->vertex)
return true;
auto [found_next, state_next] = cons_table.get(next_id, next_timestep);
if (!found_next)
return false;
// Check if there's a vertex constraint on next_id in the source and next timestep
if (state_next->vertex)
return true;
// Check if there's an edge constraint on entering next_id in next_timestep
return state_next->edge[direction];
}
// find a path from location start.first at timestep start.second to location goal.first at timestep goal.second
// that satisfies all constraints in cons_table
// while minimizing conflicts with paths in cat
// return true if a path found (and updates path) or false if no path exists
// Since we don't have to find the SHORTEST path, we only use FOCAL (without OPEN) here and prune all nodes
// that cannot reach the goal at the given timestep
// This is used to re-plan a (sub-)path between two positive constraints.
bool ICBSSingleAgentLLSearch::findPath(Path &path,
const XytHolder<ConstraintState>& cons_table,
ConflictAvoidanceTable& cat,
const pair<int, int> &start, const pair<int, int>&goal, lowlevel_heuristic h_type)
{
num_expanded = 0;
num_generated = 0;
hashtable_t::iterator it; // will be used for find()
// generate root and add it to the FOCAL list
ICBSSingleAgentLLNode* root = new ICBSSingleAgentLLNode(start.first, 0,
getDifferentialHeuristic(start.first, goal.first), NULL, start.second, 0, false);
num_generated++;
root->focal_handle = focal_list.push(root);
allNodes_table[root] = root;
while (!focal_list.empty())
{
ICBSSingleAgentLLNode* curr = focal_list.top(); focal_list.pop();
// check if the popped node is a goal
if (curr->timestep == goal.second)
{
if (curr->loc != goal.first)
continue;
updatePath(curr, path);
focal_list.clear();
releaseClosedListNodes(allNodes_table);
return true;
}
num_expanded++;
for (int i = 0; i < 5; i++)
{
int next_id = curr->loc + moves_offset[i];
int next_timestep = curr->timestep + 1;
if (0 <= next_id && next_id < map_size &&
abs(next_id % num_col - curr->loc % num_col) < 2 &&
!isConstrained(i, next_id, next_timestep, cons_table))
{
// compute cost to next_id via curr node
int next_g_val = curr->g_val + 1;
int next_h_val;
if (h_type == lowlevel_heuristic::DEFAULT)
next_h_val = abs(my_heuristic[goal.first] - my_heuristic[next_id]);
else //h_type == lowlevel_heuristic::DH
next_h_val = getDifferentialHeuristic(next_id, goal.first);
if (next_timestep + next_h_val > goal.second) // the node cannot reach the goal node at time goal.second
continue;
int next_internal_conflicts = curr->num_internal_conf +
cat.num_conflicts_for_step(curr->loc, next_id, next_timestep);
// generate (maybe temporary) node
auto next = new ICBSSingleAgentLLNode(next_id, next_g_val, next_h_val, curr,
next_timestep, next_internal_conflicts, false);
it = allNodes_table.find(next);// try to retrieve it from the hash table
if (it == allNodes_table.end())
{
num_generated++;
next->focal_handle = focal_list.push(next);
allNodes_table[next] = next;
}
else
{ // update existing node's if needed
delete(next); // not needed anymore -- we already generated it before
ICBSSingleAgentLLNode* existing_next = (*it).second;
if (existing_next->num_internal_conf > next_internal_conflicts) // if there's fewer internal conflicts
{
// update existing node
existing_next->parent = curr;
existing_next->num_internal_conf = next_internal_conflicts;
}
}
}
} // end for loop that generates successors
} // end while loop
// no path found
focal_list.clear();
releaseClosedListNodes(allNodes_table);
return false;
}
// find the shortest path from location start.first at timestep start.second to location goal.first
// (no earlier than timestep max{earliestGoalTimestep, lastGoalConsTime + 1} and no later than timestep goal.second)
// that satisfies all constraints in cons_table
// while minimizing conflicts with paths in cat and put it in the given <path> vector
// return true if a path was found (and update path) or false if no path exists
bool ICBSSingleAgentLLSearch::findShortestPath(Path &path,
const XytHolder<ConstraintState>& cons_table,
ConflictAvoidanceTable& cat,
const pair<int, int> &start, const pair<int, int>&goal, int earliestGoalTimestep, int lastGoalConsTime)
{
num_expanded = 0;
num_generated = 0;
hashtable_t::iterator it; // will be used for find()
// generate start and add it to the OPEN list
auto root = new ICBSSingleAgentLLNode(start.first, 0, my_heuristic[start.first], nullptr, start.second, 0, false);
num_generated++;
root->open_handle = open_list.push(root);
root->focal_handle = focal_list.push(root);
root->in_openlist = true;
allNodes_table[root] = root;
min_f_val = root->getFVal();
lower_bound = max(min_f_val,
(max(earliestGoalTimestep, lastGoalConsTime + 1) - start.second));
while (!focal_list.empty())
{
ICBSSingleAgentLLNode* curr = focal_list.top(); focal_list.pop();
open_list.erase(curr->open_handle);
curr->in_openlist = false;
// check if the popped node is a goal
if (curr->loc == goal.first && curr->timestep > lastGoalConsTime)
{
updatePath(curr, path);
open_list.clear();
focal_list.clear();
releaseClosedListNodes(allNodes_table);
return true;
}
else if (curr->timestep > goal.second) // did not reach the goal location before the required timestep
continue;
num_expanded++;
for (int i = 0; i < 5; i++)
{
int next_id = curr->loc + moves_offset[i];
int next_timestep = curr->timestep + 1;
if (0 <= next_id && next_id < map_size &&
abs(next_id % num_col - curr->loc % num_col) < 2 &&
!isConstrained(i, next_id, next_timestep, cons_table))
{
// compute cost to next_id via curr node
int next_g_val = curr->g_val + 1;
int next_h_val = my_heuristic[next_id];
int next_internal_conflicts = curr->num_internal_conf +
cat.num_conflicts_for_step(curr->loc, next_id, next_timestep);
// generate (maybe temporary) node
ICBSSingleAgentLLNode* next = new ICBSSingleAgentLLNode(next_id, next_g_val, next_h_val, curr, next_timestep, next_internal_conflicts, false);
it = allNodes_table.find(next); // try to retrieve it from the hash table
if (it == allNodes_table.end())
{
next->open_handle = open_list.push(next);
next->in_openlist = true;
num_generated++;
if (next->getFVal() <= lower_bound)
next->focal_handle = focal_list.push(next);
allNodes_table[next] = next;
}
else
{ // update existing node's if needed (only in the open_list)
delete next; // not needed anymore -- we already generated it before
ICBSSingleAgentLLNode* existing_next = (*it).second;
if (existing_next->in_openlist == true) // if its in the open list
{
if (existing_next->num_internal_conf > next_internal_conflicts)// if there's less internal conflicts
{
// update existing node
existing_next->parent = curr;
existing_next->num_internal_conf = next_internal_conflicts;
if (existing_next->getFVal() <= lower_bound) // the existing node is in FOCAL
{
focal_list.update(existing_next->focal_handle);
}
}
}
} // end update an existing node
}
} // end for loop that generates successors
if (open_list.empty()) // in case OPEN is empty, no path found...
break;
// update FOCAL if min f-val increased
ICBSSingleAgentLLNode* open_head = open_list.top();
if (open_head->getFVal() > min_f_val)
{
int new_min_f_val = open_head->getFVal();
int new_lower_bound = max(lower_bound, new_min_f_val);
for (ICBSSingleAgentLLNode* n : open_list)
{
if (n->getFVal() > lower_bound && n->getFVal() <= new_lower_bound)
{
n->focal_handle = focal_list.push(n);
}
}
min_f_val = new_min_f_val;
lower_bound = new_lower_bound;
}
} // end while loop
// no path found
open_list.clear();
focal_list.clear();
releaseClosedListNodes(allNodes_table);
return false;
}
inline void ICBSSingleAgentLLSearch::releaseClosedListNodes(hashtable_t& allNodes_table)
{
for (const auto& pair: allNodes_table)
{
const auto& [node_k, node] = pair;
delete node;
}
allNodes_table.clear();
}
ICBSSingleAgentLLSearch::ICBSSingleAgentLLSearch(int start_location, int goal_location,
const bool* my_map, int num_row, int num_col, const int* moves_offset, int* my_heuristic):
my_map(my_map), moves_offset(moves_offset), start_location(start_location), goal_location(goal_location),
num_col(num_col), my_heuristic(my_heuristic)
{
this->map_size = num_row * num_col;
// initialize allNodes_table (hash table)
empty_node = new ICBSSingleAgentLLNode();
empty_node->loc = -1;
deleted_node = new ICBSSingleAgentLLNode();
deleted_node->loc = -2;
allNodes_table.set_empty_key(empty_node);
allNodes_table.set_deleted_key(deleted_node);
}
ICBSSingleAgentLLSearch::~ICBSSingleAgentLLSearch()
{
delete empty_node;
delete deleted_node;
delete [] my_heuristic;
}