MRSL Motion Primitive Library  1.2
A motion primitive library for generating trajectory for mobile robots
graph_search.h
Go to the documentation of this file.
1 
6 #ifndef MPL_GRAPH_SEARCH_H
7 #define MPL_GRAPH_SEARCH_H
8 
9 #include <mpl_basis/trajectory.h>
11 
12 namespace MPL {
13 
19 template <int Dim, typename Coord>
20 class GraphSearch {
21  public:
27  GraphSearch(bool verbose = false) : verbose_(verbose){};
28 
39  decimal_t Astar(const Coord &start_coord,
40  const std::shared_ptr<env_base<Dim>> &ENV,
41  std::shared_ptr<StateSpace<Dim, Coord>> &ss_ptr,
42  Trajectory<Dim> &traj, int max_expand = -1) {
43  // Check if done
44  if (ENV->is_goal(start_coord)) return 0;
45 
46  // Initialize start node
47  StatePtr<Coord> currNode_ptr = ss_ptr->hm_[start_coord];
48  if (ss_ptr->pq_.empty()) {
49  if (verbose_)
50  printf(ANSI_COLOR_GREEN "Start from new node!\n" ANSI_COLOR_RESET);
51  currNode_ptr = std::make_shared<State<Coord>>(start_coord);
52  currNode_ptr->g = 0;
53  currNode_ptr->h = ss_ptr->eps_ == 0 ? 0 : ENV->get_heur(start_coord);
54  decimal_t fval = currNode_ptr->g + ss_ptr->eps_ * currNode_ptr->h;
55  currNode_ptr->heapkey =
56  ss_ptr->pq_.push(std::make_pair(fval, currNode_ptr));
57  currNode_ptr->iterationopened = true;
58  currNode_ptr->iterationclosed = false;
59  ss_ptr->hm_[start_coord] = currNode_ptr;
60  }
61 
62  int expand_iteration = 0;
63  while (true) {
64  expand_iteration++;
65  // get element with smallest cost
66  currNode_ptr = ss_ptr->pq_.top().second;
67  ss_ptr->pq_.pop();
68  currNode_ptr->iterationclosed = true; // Add to closed list
69 
70  // Get successors
71  vec_E<Coord> succ_coord;
72  std::vector<decimal_t> succ_cost;
73  std::vector<int> succ_act_id;
74 
75  ENV->get_succ(currNode_ptr->coord, succ_coord, succ_cost, succ_act_id);
76 
77  // Process successors (satisfy dynamic constraints but might hit
78  // obstacles)
79  for (unsigned s = 0; s < succ_coord.size(); ++s) {
80  // If the primitive is occupied, skip
81  if (std::isinf(succ_cost[s])) continue;
82 
83  // Get child
84  StatePtr<Coord> &succNode_ptr = ss_ptr->hm_[succ_coord[s]];
85  if (!succNode_ptr) {
86  succNode_ptr = std::make_shared<State<Coord>>(succ_coord[s]);
87  succNode_ptr->h =
88  ss_ptr->eps_ == 0 ? 0 : ENV->get_heur(succNode_ptr->coord);
89  /*
90  * Comment this block if build multiple connected graph
91  succNode_ptr->pred_coord.push_back(currNode_ptr->coord);
92  succNode_ptr->pred_action_id.push_back(succ_act_id[s]);
93  succNode_ptr->pred_action_cost.push_back(succ_cost[s]);
94  */
95  }
96 
100  succNode_ptr->pred_coord.push_back(currNode_ptr->coord);
101  succNode_ptr->pred_action_cost.push_back(succ_cost[s]);
102  succNode_ptr->pred_action_id.push_back(succ_act_id[s]);
103  //*/
104 
105  // see if we can improve the value of successor
106  // taking into account the cost of action
107  decimal_t tentative_gval = currNode_ptr->g + succ_cost[s];
108 
109  if (tentative_gval < succNode_ptr->g) {
117  succNode_ptr->g = tentative_gval; // Update gval
118 
119  decimal_t fval = succNode_ptr->g + (ss_ptr->eps_) * succNode_ptr->h;
120 
121  // if currently in OPEN, update
122  if (succNode_ptr->iterationopened && !succNode_ptr->iterationclosed) {
123  if (verbose_) {
124  if ((*succNode_ptr->heapkey).first < fval) {
125  std::cout << "UPDATE fval(old) = "
126  << (*succNode_ptr->heapkey).first << std::endl;
127  std::cout << "UPDATE fval = " << fval << std::endl;
128  }
129  }
130 
131  (*succNode_ptr->heapkey).first = fval; // update heap element
132  // ss_ptr->pq.update(succNode_ptr->heapkey);
133  ss_ptr->pq_.increase(succNode_ptr->heapkey); // update heap
134  // printf(ANSI_COLOR_RED "ASTAR ERROR!\n" ANSI_COLOR_RESET);
135  } else // new node, add to heap
136  {
137  // std::cout << "ADD fval = " << fval << std::endl;
138  succNode_ptr->heapkey =
139  ss_ptr->pq_.push(std::make_pair(fval, succNode_ptr));
140  succNode_ptr->iterationopened = true;
141  }
142  }
143  }
144 
145  // If goal reached, abort!
146  if (ENV->is_goal(currNode_ptr->coord)) break;
147 
148  // If maximum expansion reached, abort!
149  if (max_expand > 0 && expand_iteration >= max_expand) {
150  printf(ANSI_COLOR_RED
151  "MaxExpandStep [%d] Reached!!!!!!\n\n" ANSI_COLOR_RESET,
152  max_expand);
153  return std::numeric_limits<decimal_t>::infinity();
154  }
155 
156  // If pq is empty, abort!
157  if (ss_ptr->pq_.empty()) {
158  printf(ANSI_COLOR_RED
159  "Priority queue is empty!!!!!!\n\n" ANSI_COLOR_RESET);
160  return std::numeric_limits<decimal_t>::infinity();
161  }
162  }
163 
164  if (verbose_) {
165  decimal_t fval = ss_ptr->calculateKey(currNode_ptr);
166  printf(ANSI_COLOR_GREEN "goalNode fval: %f, g: %f!\n" ANSI_COLOR_RESET,
167  fval, currNode_ptr->g);
168  printf(ANSI_COLOR_GREEN "Expand [%d] nodes!\n" ANSI_COLOR_RESET,
169  expand_iteration);
170  }
171 
172  if (ENV->is_goal(currNode_ptr->coord)) {
173  if (verbose_)
174  printf(ANSI_COLOR_GREEN "Reached Goal !!!!!!\n\n" ANSI_COLOR_RESET);
175  }
176 
177  ss_ptr->expand_iteration_ = expand_iteration;
178  if (recoverTraj(currNode_ptr, ss_ptr, ENV, start_coord, traj))
179  return currNode_ptr->g;
180  else
181  return std::numeric_limits<decimal_t>::infinity();
182  }
183 
194  decimal_t LPAstar(const Coord &start_coord,
195  const std::shared_ptr<env_base<Dim>> &ENV,
196  std::shared_ptr<StateSpace<Dim, Coord>> &ss_ptr,
197  Trajectory<Dim> &traj, int max_expand = -1) {
198  // Check if done
199  if (ENV->is_goal(start_coord)) {
200  if (verbose_)
201  printf(ANSI_COLOR_GREEN
202  "Start is inside goal region!\n" ANSI_COLOR_RESET);
203  return 0;
204  }
205 
206  // Initialize start node
207  StatePtr<Coord> currNode_ptr = ss_ptr->hm_[start_coord];
208  if (!currNode_ptr) {
209  if (verbose_)
210  printf(ANSI_COLOR_GREEN "Start from new node!\n" ANSI_COLOR_RESET);
211  currNode_ptr = std::make_shared<State<Coord>>(start_coord);
212  currNode_ptr->g = std::numeric_limits<decimal_t>::infinity();
213  currNode_ptr->rhs = 0;
214  currNode_ptr->h = ss_ptr->eps_ == 0 ? 0 : ENV->get_heur(start_coord);
215  currNode_ptr->heapkey = ss_ptr->pq_.push(
216  std::make_pair(ss_ptr->calculateKey(currNode_ptr), currNode_ptr));
217  currNode_ptr->iterationopened = true;
218  currNode_ptr->iterationclosed = false;
219  ss_ptr->hm_[start_coord] = currNode_ptr;
220  }
221 
222  // Initialize goal node
223  StatePtr<Coord> goalNode_ptr = std::make_shared<State<Coord>>(Coord());
224  if (!ss_ptr->best_child_.empty() &&
225  ENV->is_goal(ss_ptr->best_child_.back()->coord)) {
226  goalNode_ptr = ss_ptr->best_child_.back();
227  if (verbose_) {
228  printf(ANSI_COLOR_GREEN "Use existing goal!\n" ANSI_COLOR_RESET);
229  printf(ANSI_COLOR_GREEN
230  "goalNode fval: %f, g: %f, rhs: %f!\n" ANSI_COLOR_RESET,
231  ss_ptr->calculateKey(goalNode_ptr), goalNode_ptr->g,
232  goalNode_ptr->rhs);
233  }
234  } else {
235  goalNode_ptr->g = std::numeric_limits<decimal_t>::infinity();
236  goalNode_ptr->rhs = std::numeric_limits<decimal_t>::infinity();
237  goalNode_ptr->h = 0;
238  if (verbose_)
239  printf("goalNode key: %f\n", ss_ptr->calculateKey(goalNode_ptr));
240  }
241 
242  int expand_iteration = 0;
243  while (ss_ptr->pq_.top().first < ss_ptr->calculateKey(goalNode_ptr) ||
244  goalNode_ptr->rhs != goalNode_ptr->g) {
245  expand_iteration++;
246  // Get element with smallest cost
247  currNode_ptr = ss_ptr->pq_.top().second;
248  ss_ptr->pq_.pop();
249  currNode_ptr->iterationclosed = true; // Add to closed list
250 
251  if (currNode_ptr->g > currNode_ptr->rhs)
252  currNode_ptr->g = currNode_ptr->rhs;
253  else {
254  currNode_ptr->g = std::numeric_limits<decimal_t>::infinity();
255  ss_ptr->updateNode(currNode_ptr);
256  }
257 
258 #if 1
259  // Get successors
260  vec_E<Coord> succ_coord = currNode_ptr->succ_coord;
261  std::vector<decimal_t> succ_cost = currNode_ptr->succ_action_cost;
262  std::vector<int> succ_act_id = currNode_ptr->succ_action_id;
263 
264  bool explored = !currNode_ptr->succ_coord.empty();
265  if (!explored) {
266  ENV->get_succ(currNode_ptr->coord, succ_coord, succ_cost, succ_act_id);
267  currNode_ptr->succ_coord.resize(succ_coord.size());
268  currNode_ptr->succ_action_id.resize(succ_coord.size());
269  currNode_ptr->succ_action_cost.resize(succ_coord.size());
270  }
271 
272 #else
273  vec_E<Coord> succ_coord; // = currNode_ptr->succ_coord;
274  std::vector<decimal_t> succ_cost; // = currNode_ptr->succ_action_cost;
275  std::vector<int> succ_act_id; // = currNode_ptr->succ_action_id;
276 
277  ENV->get_succ(currNode_ptr->coord, succ_coord, succ_cost, succ_act_id);
278  currNode_ptr->succ_coord.resize(succ_coord.size());
279  currNode_ptr->succ_action_id.resize(succ_coord.size());
280  currNode_ptr->succ_action_cost.resize(succ_coord.size());
281 #endif
282 
283  // Process successors
284  for (size_t s = 0; s < succ_coord.size(); ++s) {
285  // Get child
286  StatePtr<Coord> &succNode_ptr = ss_ptr->hm_[succ_coord[s]];
287  if (!succNode_ptr) {
288  succNode_ptr = std::make_shared<State<Coord>>(succ_coord[s]);
289  succNode_ptr->h =
290  ss_ptr->eps_ == 0 ? 0 : ENV->get_heur(succNode_ptr->coord);
291  }
292 
293  // Store the hashkey
294  currNode_ptr->succ_coord[s] = succ_coord[s];
295  currNode_ptr->succ_action_id[s] = succ_act_id[s];
296  currNode_ptr->succ_action_cost[s] = succ_cost[s];
297 
298  int id = -1;
299  for (unsigned int i = 0; i < succNode_ptr->pred_coord.size(); i++) {
300  if (succNode_ptr->pred_coord[i] == currNode_ptr->coord) {
301  id = i;
302  break;
303  }
304  }
305  if (id == -1) {
306  succNode_ptr->pred_coord.push_back(currNode_ptr->coord);
307  succNode_ptr->pred_action_cost.push_back(succ_cost[s]);
308  succNode_ptr->pred_action_id.push_back(succ_act_id[s]);
309  }
310 
311  ss_ptr->updateNode(succNode_ptr);
312  }
313 
314  // If goal reached, terminate!
315  if (ENV->is_goal(currNode_ptr->coord)) goalNode_ptr = currNode_ptr;
316 
317  // If maximum expansion reached, abort!
318  if (max_expand > 0 && expand_iteration >= max_expand) {
319  if (verbose_)
320  printf(ANSI_COLOR_RED
321  "MaxExpandStep [%d] Reached!!!!!!\n\n" ANSI_COLOR_RESET,
322  max_expand);
323  return std::numeric_limits<decimal_t>::infinity();
324  }
325 
326  // If pq is empty, abort!
327  if (ss_ptr->pq_.empty()) {
328  if (verbose_)
329  printf(ANSI_COLOR_RED
330  "Priority queue is empty!!!!!!\n\n" ANSI_COLOR_RESET);
331  return std::numeric_limits<decimal_t>::infinity();
332  }
333  }
334 
335  //***** Report value of goal
336  if (verbose_) {
337  printf(ANSI_COLOR_GREEN
338  "goalNode fval: %f, g: %f, rhs: %f!\n" ANSI_COLOR_RESET,
339  ss_ptr->calculateKey(goalNode_ptr), goalNode_ptr->g,
340  goalNode_ptr->rhs);
341  // printf(ANSI_COLOR_GREEN "currNode fval: %f, g: %f, rhs: %f!\n"
342  // ANSI_COLOR_RESET,
343  // ss_ptr->calculateKey(currNode_ptr), currNode_ptr->g,
344  // currNode_ptr->rhs);
345  printf(ANSI_COLOR_GREEN "Expand [%d] nodes!\n" ANSI_COLOR_RESET,
346  expand_iteration);
347  }
348 
349  //****** Check if the goal is reached, if reached, set the flag to be True
350  if (verbose_) {
351  if (ENV->is_goal(goalNode_ptr->coord))
352  printf(ANSI_COLOR_GREEN "Reached Goal !!!!!!\n\n" ANSI_COLOR_RESET);
353  else
354  printf(ANSI_COLOR_RED
355  "Terminated for unknown reason!!!!!!\n\n" ANSI_COLOR_RESET);
356  }
357 
358  ss_ptr->expand_iteration_ = expand_iteration;
359  // auto start = std::chrono::high_resolution_clock::now();
360  //****** Recover trajectory
361  if (recoverTraj(goalNode_ptr, ss_ptr, ENV, start_coord, traj))
362  return goalNode_ptr->g - ss_ptr->start_g_;
363  else
364  return std::numeric_limits<decimal_t>::infinity();
365  }
366 
367  private:
369  bool recoverTraj(StatePtr<Coord> currNode_ptr,
370  std::shared_ptr<StateSpace<Dim, Coord>> ss_ptr,
371  const std::shared_ptr<env_base<Dim>> &ENV,
372  const Coord &start_key, Trajectory<Dim> &traj) {
373  // Recover trajectory
374  ss_ptr->best_child_.clear();
375  bool find_traj = false;
376 
378  while (!currNode_ptr->pred_coord.empty()) {
379  if (verbose_) {
380  std::cout << "t: " << currNode_ptr->coord.t
381  << " pos: " << currNode_ptr->coord.pos.transpose()
382  << " vel: " << currNode_ptr->coord.vel.transpose()
383  << std::endl;
384  printf("g: %f, rhs: %f, h: %f\n", currNode_ptr->g, currNode_ptr->rhs,
385  currNode_ptr->h);
386  }
387  ss_ptr->best_child_.push_back(currNode_ptr);
388  int min_id = -1;
389  decimal_t min_rhs = std::numeric_limits<decimal_t>::infinity();
390  decimal_t min_g = std::numeric_limits<decimal_t>::infinity();
391  for (unsigned int i = 0; i < currNode_ptr->pred_coord.size(); i++) {
392  Coord key = currNode_ptr->pred_coord[i];
393  if (min_rhs > ss_ptr->hm_[key]->g + currNode_ptr->pred_action_cost[i]) {
394  min_rhs = ss_ptr->hm_[key]->g + currNode_ptr->pred_action_cost[i];
395  min_g = ss_ptr->hm_[key]->g;
396  min_id = i;
397  } else if (!std::isinf(currNode_ptr->pred_action_cost[i]) &&
398  min_rhs == ss_ptr->hm_[key]->g +
399  currNode_ptr->pred_action_cost[i]) {
400  if (min_g < ss_ptr->hm_[key]->g) {
401  min_g = ss_ptr->hm_[key]->g;
402  min_id = i;
403  }
404  }
405  }
406 
407  if (min_id >= 0) {
408  Coord key = currNode_ptr->pred_coord[min_id];
409  int action_idx = currNode_ptr->pred_action_id[min_id];
410  currNode_ptr = ss_ptr->hm_[key];
411  Primitive<Dim> pr;
412  ENV->forward_action(currNode_ptr->coord, action_idx, pr);
413  prs.push_back(pr);
414  } else {
415  if (verbose_) {
416  printf(ANSI_COLOR_RED
417  "Trace back failure, the number of "
418  "predecessors is %zu: \n" ANSI_COLOR_RESET,
419  currNode_ptr->pred_coord.size());
420  for (size_t i = 0; i < currNode_ptr->pred_coord.size(); i++) {
421  Coord key = currNode_ptr->pred_coord[i];
422  printf(
423  "i: %zu, t: %f, g: %f, rhs: %f, action cost: "
424  "%f\n" ANSI_COLOR_RESET,
425  i, key.t, ss_ptr->hm_[key]->g, ss_ptr->hm_[key]->rhs,
426  currNode_ptr->pred_action_cost[i]);
427  }
428  }
429 
430  break;
431  }
432 
433  if (currNode_ptr->coord == start_key) {
434  ss_ptr->best_child_.push_back(currNode_ptr);
435  find_traj = true;
436  if (verbose_) {
437  std::cout << "t: " << currNode_ptr->coord.t
438  << " pos: " << currNode_ptr->coord.pos.transpose()
439  << std::endl;
440  printf("g: %f, rhs: %f, h: %f\n", currNode_ptr->g, currNode_ptr->rhs,
441  currNode_ptr->h);
442  }
443 
444  break;
445  }
446  }
447 
448  std::reverse(prs.begin(), prs.end());
449  std::reverse(ss_ptr->best_child_.begin(), ss_ptr->best_child_.end());
450  if (find_traj)
451  traj = Trajectory<Dim>(prs);
452  else
453  traj = Trajectory<Dim>();
454  return find_traj;
455  }
457  bool verbose_ = false;
458 };
459 } // namespace MPL
460 #endif
Definition: map_util.h:12
Trajectory class.
#define ANSI_COLOR_RED
Set red font in printf funtion.
Definition: data_type.h:16
#define ANSI_COLOR_GREEN
Set green font in printf funtion.
Definition: data_type.h:20
GraphSearch class.
Definition: graph_search.h:20
Trajectory class.
Definition: trajectory.h:43
bool verbose_
Verbose flag.
Definition: graph_search.h:457
std::vector< T, Eigen::aligned_allocator< T > > vec_E
Pre-allocated std::vector for Eigen using vec_E.
Definition: data_type.h:53
decimal_t Astar(const Coord &start_coord, const std::shared_ptr< env_base< Dim >> &ENV, std::shared_ptr< StateSpace< Dim, Coord >> &ss_ptr, Trajectory< Dim > &traj, int max_expand=-1)
Astar graph search.
Definition: graph_search.h:39
GraphSearch(bool verbose=false)
Simple empty constructor.
Definition: graph_search.h:27
State space.
Definition: state_space.h:83
double decimal_t
Rename the float type used in lib.
Definition: data_type.h:49
bool recoverTraj(StatePtr< Coord > currNode_ptr, std::shared_ptr< StateSpace< Dim, Coord >> ss_ptr, const std::shared_ptr< env_base< Dim >> &ENV, const Coord &start_key, Trajectory< Dim > &traj)
Recover trajectory.
Definition: graph_search.h:369
decimal_t LPAstar(const Coord &start_coord, const std::shared_ptr< env_base< Dim >> &ENV, std::shared_ptr< StateSpace< Dim, Coord >> &ss_ptr, Trajectory< Dim > &traj, int max_expand=-1)
Lifelong Planning Astar graph search.
Definition: graph_search.h:194
state space class for graph search
#define ANSI_COLOR_RESET
Reset font color in printf funtion.
Definition: data_type.h:40
Base environment class.
Definition: env_base.h:17
std::shared_ptr< State< Coord > > StatePtr
Declare StatePtr.
Definition: state_space.h:74
Primitive class.
Definition: primitive.h:206