grid_astar.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2020, the neonavigation authors
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef PLANNER_CSPACE_GRID_ASTAR_H
31 #define PLANNER_CSPACE_GRID_ASTAR_H
32 
33 #define _USE_MATH_DEFINES
34 #include <cfloat>
35 #include <cmath>
36 #include <limits>
37 #include <list>
38 #include <map>
39 #include <memory>
40 #include <unordered_map>
41 #include <utility>
42 #include <vector>
43 
44 #include <boost/chrono.hpp>
45 
50 
51 #include <omp.h>
52 
53 namespace planner_cspace
54 {
56 {
57  size_t num_loop;
61 };
62 
63 template <int DIM = 3, int NONCYCLIC = 2>
64 class GridAstar
65 {
66 public:
70  using ProgressCallback = std::function<bool(const std::list<Vec>&, const SearchStats&)>;
71 
72  template <class T, int block_width = 0x20>
73  class Gridmap : public BlockMemGridmap<T, DIM, NONCYCLIC, block_width>
74  {
76  };
77 
79  {
80  public:
81  float p_;
82  float p_raw_;
84 
85  PriorityVec(const float p, const float p_raw, const Vec& v)
86  : p_(p)
87  , p_raw_(p_raw)
88  , v_(v)
89  {
90  }
91  bool operator<(const PriorityVec& b) const
92  {
93  // smaller first
94  return p_ > b.p_;
95  }
96  };
98  {
99  private:
100  const Vec p0_;
101  const Vec p1_;
102  const float cost_estim_;
103  const float cost_;
104 
105  public:
107  const Vec& p0, const Vec& p1,
108  const float cost_estim, const float cost)
109  : p0_(p0)
110  , p1_(p1)
111  , cost_estim_(cost_estim)
112  , cost_(cost)
113  {
114  }
115  const Vec& getParentPos() const
116  {
117  return p0_;
118  }
119  const Vec& getPos() const
120  {
121  return p1_;
122  }
123  const float getCost() const
124  {
125  return cost_;
126  }
128  {
129  return PriorityVec(cost_estim_, cost_, p1_);
130  }
131  };
132 
133 public:
134  constexpr int getDim() const
135  {
136  return DIM;
137  }
138  constexpr int getNoncyclic() const
139  {
140  return NONCYCLIC;
141  }
142  void setSearchTaskNum(const size_t& search_task_num)
143  {
144  search_task_num_ = search_task_num;
145  }
146 
147  void reset(const Vec size)
148  {
149  g_.reset(size);
150  g_.clear(std::numeric_limits<float>::max());
151  parents_.reserve(g_.ser_size() / 16);
152  open_.reserve(g_.ser_size() / 16);
153  }
155  : queue_size_limit_(0)
156  , search_task_num_(1)
157  {
158  }
159  explicit GridAstar(const Vec size)
160  {
161  reset(size);
162  queue_size_limit_ = 0;
163  }
164  void setQueueSizeLimit(const size_t size)
165  {
166  queue_size_limit_ = size;
167  }
168 
169  bool search(
170  const std::vector<VecWithCost>& ss, const Vec& e,
171  std::list<Vec>& path,
172  const typename GridAstarModelBase<DIM, NONCYCLIC>::Ptr& model,
173  ProgressCallback cb_progress,
174  const float cost_leave,
175  const float progress_interval,
176  const bool return_best = false)
177  {
178  return searchImpl(
179  g_, ss, e, path,
180  model, cb_progress,
181  cost_leave, progress_interval, return_best);
182  }
183 
184 protected:
186  Gridmap<float>& g,
187  const std::vector<VecWithCost>& sts, const Vec& en,
188  std::list<Vec>& path,
189  const typename GridAstarModelBase<DIM, NONCYCLIC>::Ptr& model,
190  ProgressCallback cb_progress,
191  const float cost_leave,
192  const float progress_interval,
193  const bool return_best = false)
194  {
195  if (sts.size() == 0)
196  return false;
197 
198  auto ts = boost::chrono::high_resolution_clock::now();
199 
200  Vec e = en;
201  e.cycleUnsigned(g.size());
202  g.clear(std::numeric_limits<float>::max());
203  open_.clear();
204  parents_.clear();
205 
206  std::vector<VecWithCost> ss_normalized;
207  Vec better;
208  int cost_estim_min = std::numeric_limits<int>::max();
209  for (const VecWithCost& st : sts)
210  {
211  if (st.v_ == en)
212  return false;
213 
214  Vec s = st.v_;
215  s.cycleUnsigned(g.size());
216  ss_normalized.emplace_back(s, st.c_);
217  g[s] = st.c_;
218 
219  const int cost_estim = model->costEstim(s, e);
220  open_.emplace(cost_estim + st.c_, st.c_, s);
221  if (cost_estim_min > cost_estim)
222  {
223  cost_estim_min = cost_estim;
224  better = s;
225  }
226  }
227 
228  std::vector<PriorityVec> centers;
229  centers.reserve(search_task_num_);
230 
231  size_t num_updates(0);
232  size_t num_total_updates(0);
233  size_t num_loop(0);
234 
235  bool found(false);
236  bool abort(false);
237 #pragma omp parallel
238  {
239  std::vector<GridmapUpdate> updates;
240  // Reserve buffer using example search diff list
241  updates.reserve(
242  search_task_num_ *
243  model->searchGrids(ss_normalized[0].v_, ss_normalized, e).size() /
244  omp_get_num_threads());
245  std::vector<Vec> dont;
246  dont.reserve(search_task_num_);
247 
248  while (true)
249  {
250 #pragma omp barrier
251 #pragma omp single
252  {
253  const size_t num_search_queue = open_.size();
254  num_loop++;
255 
256  // Fetch tasks to be paralellized
257  centers.clear();
258  for (size_t i = 0; i < search_task_num_;)
259  {
260  if (open_.size() == 0)
261  break;
262  PriorityVec center(open_.top());
263  open_.pop();
264  if (center.v_ == e || center.p_ - center.p_raw_ < cost_leave)
265  {
266  e = center.v_;
267  found = true;
268  break;
269  }
270  centers.emplace_back(std::move(center));
271  ++i;
272  }
273  const auto tnow = boost::chrono::high_resolution_clock::now();
274  if (boost::chrono::duration<float>(tnow - ts).count() >= progress_interval)
275  {
276  std::list<Vec> path_tmp;
277  ts = tnow;
278  findPath(ss_normalized, better, path_tmp);
279  const SearchStats stats =
280  {
281  .num_loop = num_loop,
282  .num_search_queue = num_search_queue,
283  .num_prev_updates = num_updates,
284  .num_total_updates = num_total_updates,
285  };
286  if (!cb_progress(path_tmp, stats))
287  {
288  abort = true;
289  }
290  }
291  num_updates = 0;
292  }
293 
294  if (centers.size() < 1 || found || abort)
295  break;
296  updates.clear();
297  dont.clear();
298 
299 #pragma omp for schedule(static)
300  for (auto it = centers.cbegin(); it < centers.cend(); ++it)
301  {
302  const Vec p = it->v_;
303  const float c = it->p_raw_;
304  const float c_estim = it->p_;
305  const float gp = g[p];
306  if (c > gp)
307  continue;
308 
309  if (c_estim - c < cost_estim_min)
310  {
311  cost_estim_min = c_estim - c;
312  better = p;
313  }
314 
315  const std::vector<Vec> search_list = model->searchGrids(p, ss_normalized, e);
316 
317  bool updated(false);
318  for (auto it = search_list.cbegin(); it < search_list.cend(); ++it)
319  {
320  Vec next = p + *it;
321  next.cycleUnsigned(g.size());
322  if (next.isExceeded(g.size()))
323  continue;
324 
325  if (g[next] < gp)
326  {
327  // Skip as this search task has no chance to find better way.
328  continue;
329  }
330 
331  const float cost_estim = model->costEstim(next, e);
332  if (cost_estim < 0 || cost_estim == std::numeric_limits<float>::max())
333  continue;
334 
335  const float cost = model->cost(p, next, ss_normalized, e);
336  if (cost < 0 || cost == std::numeric_limits<float>::max())
337  continue;
338 
339  const float cost_next = c + cost;
340  if (g[next] > cost_next)
341  {
342  updated = true;
343  updates.emplace_back(p, next, cost_next + cost_estim, cost_next);
344  }
345  }
346  if (!updated)
347  dont.push_back(p);
348  }
349 #pragma omp barrier
350 #pragma omp critical
351  {
352  for (const GridmapUpdate& u : updates)
353  {
354  if (g[u.getPos()] > u.getCost())
355  {
356  g[u.getPos()] = u.getCost();
357  parents_[u.getPos()] = u.getParentPos();
358  open_.push(std::move(u.getPriorityVec()));
359  if (queue_size_limit_ > 0 && open_.size() > queue_size_limit_)
360  open_.pop_back();
361  }
362  }
363  for (const Vec& p : dont)
364  {
365  g[p] = -1;
366  }
367  const size_t n = updates.size();
368  num_updates += n;
369  num_total_updates += n;
370  } // omp critical
371  }
372  } // omp parallel
373 
374  if (!found)
375  {
376  // No fesible path
377  if (return_best)
378  {
379  findPath(ss_normalized, better, path);
380  }
381  return false;
382  }
383  return findPath(ss_normalized, e, path);
384  }
385  bool findPath(const std::vector<VecWithCost>& ss, const Vec& e, std::list<Vec>& path) const
386  {
387  std::unordered_map<Vec, Vec, Vec> parents = parents_;
388  Vec n = e;
389  while (true)
390  {
391  path.push_front(n);
392 
393  bool found(false);
394  for (const VecWithCost& s : ss)
395  {
396  if (n == s.v_)
397  {
398  found = true;
399  break;
400  }
401  }
402  if (found)
403  break;
404  if (parents.find(n) == parents.end())
405  return false;
406 
407  const Vec child = n;
408  n = parents[child];
409  parents.erase(child);
410  }
411  return true;
412  }
413 
414  Gridmap<float> g_;
415  std::unordered_map<Vec, Vec, Vec> parents_;
419 };
420 } // namespace planner_cspace
421 
422 #endif // PLANNER_CSPACE_GRID_ASTAR_H
constexpr int getNoncyclic() const
Definition: grid_astar.h:138
void setSearchTaskNum(const size_t &search_task_num)
Definition: grid_astar.h:142
bool search(const std::vector< VecWithCost > &ss, const Vec &e, std::list< Vec > &path, const typename GridAstarModelBase< DIM, NONCYCLIC >::Ptr &model, ProgressCallback cb_progress, const float cost_leave, const float progress_interval, const bool return_best=false)
Definition: grid_astar.h:169
bool searchImpl(Gridmap< float > &g, const std::vector< VecWithCost > &sts, const Vec &en, std::list< Vec > &path, const typename GridAstarModelBase< DIM, NONCYCLIC >::Ptr &model, ProgressCallback cb_progress, const float cost_leave, const float progress_interval, const bool return_best=false)
Definition: grid_astar.h:185
bool operator<(const PriorityVec &b) const
Definition: grid_astar.h:91
XmlRpcServer s
std::function< bool(const std::list< Vec > &, const SearchStats &)> ProgressCallback
Definition: grid_astar.h:70
void cycleUnsigned(const int res, const ArgList &...rest)
Definition: cyclic_vec.h:289
void setQueueSizeLimit(const size_t size)
Definition: grid_astar.h:164
PriorityVec(const float p, const float p_raw, const Vec &v)
Definition: grid_astar.h:85
virtual const std::vector< Vec > & searchGrids(const Vec &cur, const std::vector< VecWithCost > &start, const Vec &goal) const =0
constexpr int getDim() const
Definition: grid_astar.h:134
virtual float costEstim(const Vec &cur, const Vec &next) const =0
typename std::shared_ptr< GridAstarModelBase< DIM, NONCYCLIC >> Ptr
std::unordered_map< Vec, Vec, Vec > parents_
Definition: grid_astar.h:415
GridmapUpdate(const Vec &p0, const Vec &p1, const float cost_estim, const float cost)
Definition: grid_astar.h:106
void reset(const Vec size)
Definition: grid_astar.h:147
virtual float cost(const Vec &cur, const Vec &next, const std::vector< VecWithCost > &start, const Vec &goal) const =0
Gridmap< float > g_
Definition: grid_astar.h:414
GridAstar(const Vec size)
Definition: grid_astar.h:159
typename GridAstarModelBase< DIM, NONCYCLIC >::VecWithCost VecWithCost
Definition: grid_astar.h:69
bool isExceeded(const CyclicVecBase< DIM, NONCYCLIC, int > &v) const
Definition: cyclic_vec.h:323
const PriorityVec getPriorityVec() const
Definition: grid_astar.h:127
reservable_priority_queue< PriorityVec > open_
Definition: grid_astar.h:416
bool findPath(const std::vector< VecWithCost > &ss, const Vec &e, std::list< Vec > &path) const
Definition: grid_astar.h:385


planner_cspace
Author(s): Atsushi Watanabe
autogenerated on Wed May 12 2021 02:20:42