00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifndef PLANNER_CSPACE_GRID_ASTAR_H
00031 #define PLANNER_CSPACE_GRID_ASTAR_H
00032
00033 #include <memory>
00034 #define _USE_MATH_DEFINES
00035 #include <cmath>
00036 #include <cfloat>
00037 #include <list>
00038 #include <map>
00039 #include <unordered_map>
00040 #include <vector>
00041
00042 #include <boost/chrono.hpp>
00043
00044 #include <planner_cspace/reservable_priority_queue.h>
00045 #include <planner_cspace/cyclic_vec.h>
00046 #include <planner_cspace/blockmem_gridmap.h>
00047
00048 #include <omp.h>
00049
00050 template <int DIM = 3, int NONCYCLIC = 2>
00051 class GridAstar
00052 {
00053 public:
00054 using Vec = CyclicVecInt<DIM, NONCYCLIC>;
00055 using Vecf = CyclicVecFloat<DIM, NONCYCLIC>;
00056
00057 template <class T, int block_width = 0x20>
00058 class Gridmap : public BlockMemGridmap<T, DIM, NONCYCLIC, block_width>
00059 {
00060 using BlockMemGridmap<T, DIM, NONCYCLIC, block_width>::BlockMemGridmap;
00061 };
00062
00063 class PriorityVec
00064 {
00065 public:
00066 float p_;
00067 float p_raw_;
00068 Vec v_;
00069
00070 PriorityVec()
00071 {
00072 p_ = 0;
00073 }
00074 PriorityVec(const float& p, const float& p_raw, const Vec& v)
00075 {
00076 p_ = p;
00077 p_raw_ = p_raw;
00078 v_ = v;
00079 }
00080 bool operator<(const PriorityVec& b) const
00081 {
00082
00083 return p_ > b.p_;
00084 }
00085 };
00086
00087 protected:
00088 Gridmap<float> g_;
00089 std::unordered_map<Vec, Vec, Vec> parents_;
00090 reservable_priority_queue<PriorityVec> open_;
00091 size_t queue_size_limit_;
00092 size_t search_task_num_;
00093
00094 public:
00095 constexpr int getDim() const
00096 {
00097 return DIM;
00098 }
00099 constexpr int getNoncyclic() const
00100 {
00101 return NONCYCLIC;
00102 }
00103 void setSearchTaskNum(const size_t& search_task_num)
00104 {
00105 search_task_num_ = search_task_num;
00106 }
00107
00108 void reset(const Vec size)
00109 {
00110 g_.reset(size);
00111 g_.clear(FLT_MAX);
00112 parents_.reserve(g_.ser_size() / 16);
00113 open_.reserve(g_.ser_size() / 16);
00114 }
00115 GridAstar()
00116 : queue_size_limit_(0)
00117 , search_task_num_(1)
00118 {
00119 }
00120 explicit GridAstar(const Vec size)
00121 {
00122 reset(size);
00123 queue_size_limit_ = 0;
00124 }
00125 void setQueueSizeLimit(const size_t size)
00126 {
00127 queue_size_limit_ = size;
00128 }
00129
00130 bool search(
00131 const Vec& s, const Vec& e,
00132 std::list<Vec>& path,
00133 std::function<float(const Vec&, Vec&, const Vec&, const Vec&)> cb_cost,
00134 std::function<float(const Vec&, const Vec&)> cb_cost_estim,
00135 std::function<std::vector<Vec>&(const Vec&, const Vec&, const Vec&)> cb_search,
00136 std::function<bool(const std::list<Vec>&)> cb_progress,
00137 const float cost_leave,
00138 const float progress_interval,
00139 const bool return_best = false)
00140 {
00141 return searchImpl(g_, s, e, path,
00142 cb_cost, cb_cost_estim, cb_search, cb_progress,
00143 cost_leave, progress_interval, return_best);
00144 }
00145 bool searchImpl(
00146 Gridmap<float>& g,
00147 const Vec& st, const Vec& en,
00148 std::list<Vec>& path,
00149 std::function<float(const Vec&, Vec&, const Vec&, const Vec&)> cb_cost,
00150 std::function<float(const Vec&, const Vec&)> cb_cost_estim,
00151 std::function<std::vector<Vec>&(const Vec&, const Vec&, const Vec&)> cb_search,
00152 std::function<bool(const std::list<Vec>&)> cb_progress,
00153 const float cost_leave,
00154 const float progress_interval,
00155 const bool return_best = false)
00156 {
00157 if (st == en)
00158 {
00159 return false;
00160 }
00161 Vec s = st;
00162 Vec e = en;
00163 for (int i = NONCYCLIC; i < DIM; i++)
00164 {
00165 s.cycleUnsigned(g.size());
00166 e.cycleUnsigned(g.size());
00167 }
00168 g.clear(FLT_MAX);
00169 open_.clear();
00170 parents_.clear();
00171
00172 g[s] = 0;
00173 open_.push(PriorityVec(cb_cost_estim(s, e), 0, s));
00174
00175 auto ts = boost::chrono::high_resolution_clock::now();
00176
00177 Vec better = s;
00178 int cost_estim_min = cb_cost_estim(s, e);
00179
00180 while (true)
00181 {
00182
00183 if (open_.size() < 1)
00184 {
00185
00186 if (return_best)
00187 {
00188 findPath(s, better, path);
00189 }
00190 return false;
00191 }
00192 bool found(false);
00193 std::vector<PriorityVec> centers;
00194 for (size_t i = 0; i < search_task_num_; ++i)
00195 {
00196 if (open_.size() == 0)
00197 break;
00198 PriorityVec center = open_.top();
00199 open_.pop();
00200 if (center.v_ == e || center.p_ - center.p_raw_ <= cost_leave)
00201 {
00202 e = center.v_;
00203 found = true;
00204 break;
00205 }
00206 centers.push_back(center);
00207 }
00208 if (found)
00209 break;
00210 auto tnow = boost::chrono::high_resolution_clock::now();
00211 if (boost::chrono::duration<float>(tnow - ts).count() >= progress_interval)
00212 {
00213 std::list<Vec> path_tmp;
00214 ts = tnow;
00215 findPath(s, better, path_tmp);
00216 cb_progress(path_tmp);
00217 }
00218
00219 #pragma omp parallel for schedule(static)
00220 for (auto it = centers.begin(); it < centers.end(); ++it)
00221 {
00222 const Vec p = it->v_;
00223 const float c = it->p_raw_;
00224 const float c_estim = it->p_;
00225 float& gp = g[p];
00226 if (c > gp)
00227 continue;
00228
00229 if (c_estim - c < cost_estim_min)
00230 {
00231 cost_estim_min = c_estim - c;
00232 better = p;
00233 }
00234
00235 const std::vector<Vec> search_list = cb_search(p, s, e);
00236 int updates = 0;
00237
00238 for (auto it = search_list.begin(); it < search_list.end(); ++it)
00239 {
00240 while (1)
00241 {
00242 Vec next = p + *it;
00243 for (int i = NONCYCLIC; i < DIM; i++)
00244 {
00245 next.cycleUnsigned(g.size());
00246 }
00247 if ((unsigned int)next[0] >= (unsigned int)g.size()[0] ||
00248 (unsigned int)next[1] >= (unsigned int)g.size()[1])
00249 break;
00250 if (g[next] < 0)
00251 break;
00252
00253 const float cost_estim = cb_cost_estim(next, e);
00254 if (cost_estim < 0 || cost_estim == FLT_MAX)
00255 break;
00256
00257 const float cost = cb_cost(p, next, s, e);
00258 if (cost < 0 || cost == FLT_MAX)
00259 break;
00260
00261 float& gnext = g[next];
00262 if (gnext > c + cost)
00263 {
00264 gnext = c + cost;
00265 #pragma omp critical
00266 {
00267 parents_[next] = p;
00268 open_.push(PriorityVec(c + cost + cost_estim, c + cost, next));
00269 if (queue_size_limit_ > 0 &&
00270 open_.size() > queue_size_limit_)
00271 open_.pop_back();
00272 }
00273 updates++;
00274 }
00275 break;
00276 }
00277 }
00278 if (updates == 0)
00279 {
00280 gp = -1;
00281 }
00282 }
00283
00284 }
00285
00286
00287 return findPath(s, e, path);
00288 }
00289 bool findPath(const Vec& s, const Vec& e, std::list<Vec>& path)
00290 {
00291 Vec n = e;
00292 while (true)
00293 {
00294 path.push_front(n);
00295
00296 if (n == s)
00297 break;
00298 if (parents_.find(n) == parents_.end())
00299 {
00300 n = parents_[n];
00301
00302 return false;
00303 }
00304 n = parents_[n];
00305 }
00306 return true;
00307 }
00308 };
00309
00310 #endif // PLANNER_CSPACE_GRID_ASTAR_H