MRSL Motion Primitive Library  1.2
A motion primitive library for generating trajectory for mobile robots
state_space.h
Go to the documentation of this file.
1 
5 #ifndef MPL_STATE_SPACE_H
6 #define MPL_STATE_SPACE_H
7 
9 
10 #include <boost/heap/d_ary_heap.hpp> // boost::heap::d_ary_heap
11 #include <boost/unordered_map.hpp> // std::unordered_map
12 
13 namespace MPL {
15 template <typename state>
16 struct compare_pair {
17  bool operator()(
18  const std::pair<decimal_t, std::shared_ptr<state>> &p1,
19  const std::pair<decimal_t, std::shared_ptr<state>> &p2) const {
20  if (p1.first == p2.first) {
21  // if equal compare gvals
22  return std::min(p1.second->g, p1.second->rhs) >
23  std::min(p2.second->g, p2.second->rhs);
24  }
25  return p1.first > p2.first;
26  }
27 };
28 
30 template <typename state>
31 using priorityQueue =
32  boost::heap::d_ary_heap<std::pair<decimal_t, std::shared_ptr<state>>,
33  boost::heap::mutable_<true>, boost::heap::arity<2>,
34  boost::heap::compare<compare_pair<state>>>;
36 template <typename Coord>
37 struct State {
39  Coord coord;
43  std::vector<int> succ_action_id;
45  std::vector<decimal_t> succ_action_cost;
49  std::vector<int> pred_action_id;
51  std::vector<decimal_t> pred_action_cost;
52 
54  typename priorityQueue<State<Coord>>::handle_type heapkey;
55 
56  // plan data
58  decimal_t g = std::numeric_limits<decimal_t>::infinity();
60  decimal_t rhs = std::numeric_limits<decimal_t>::infinity();
62  decimal_t h = std::numeric_limits<decimal_t>::infinity();
64  bool iterationopened = false;
66  bool iterationclosed = false;
67 
69  State(const Coord &coord) : coord(coord) {}
70 };
71 
73 template <typename Coord>
74 using StatePtr = std::shared_ptr<State<Coord>>;
75 
77 template <typename Coord>
78 using hashMap =
79  boost::unordered_map<Coord, StatePtr<Coord>, boost::hash<Coord>>;
80 
82 template <int Dim, typename Coord>
83 struct StateSpace {
95  int expand_iteration_ = 0;
97  decimal_t start_t_{0};
99  decimal_t start_g_{0};
101  decimal_t start_rhs_{0};
102 
104  StateSpace(decimal_t eps = 1) : eps_(eps) {}
105 
106  decimal_t getInitTime() const {
107  if (best_child_.empty())
108  return 0;
109  else
110  return best_child_.front()->coord.t;
111  }
116  void getSubStateSpace(int time_step) {
117  if (best_child_.empty()) return;
118 
119  StatePtr<Coord> currNode_ptr = best_child_[time_step];
120  start_g_ = currNode_ptr->g;
121  start_rhs_ = currNode_ptr->rhs;
122  start_t_ = currNode_ptr->coord.t;
123 
124  currNode_ptr->pred_action_cost.clear();
125  currNode_ptr->pred_action_id.clear();
126  currNode_ptr->pred_coord.clear();
127 
128  for (auto &it : hm_) {
129  it.second->g = std::numeric_limits<decimal_t>::infinity();
130  it.second->rhs = std::numeric_limits<decimal_t>::infinity();
131  it.second->pred_action_cost.clear();
132  it.second->pred_action_id.clear();
133  it.second->pred_coord.clear();
134  }
135 
136  // printf("getSubstatespace hm: %zu\n", hm_.size());
137 
138  currNode_ptr->g = start_g_;
139  currNode_ptr->rhs = start_rhs_;
140 
141  hashMap<Coord> new_hm;
143  currNode_ptr->heapkey =
144  epq.push(std::make_pair(currNode_ptr->rhs, currNode_ptr));
145  new_hm[currNode_ptr->coord] = currNode_ptr;
146 
147  while (!epq.empty()) {
148  currNode_ptr = epq.top().second;
149  epq.pop();
150 
151  for (size_t i = 0; i < currNode_ptr->succ_coord.size(); i++) {
152  Coord succ_coord = currNode_ptr->succ_coord[i];
153 
154  StatePtr<Coord> &succNode_ptr = new_hm[succ_coord];
155  if (!succNode_ptr) succNode_ptr = hm_[succ_coord];
156  if (!succNode_ptr) {
157  printf("critical bug!!!!\n\n");
158  succ_coord.print("Does not exist!");
159  }
160 
161  int id = -1;
162  for (size_t i = 0; i < succNode_ptr->pred_coord.size(); i++) {
163  if (succNode_ptr->pred_coord[i] == currNode_ptr->coord) {
164  id = i;
165  break;
166  }
167  }
168  if (id == -1) {
169  succNode_ptr->pred_coord.push_back(currNode_ptr->coord);
170  succNode_ptr->pred_action_cost.push_back(
171  currNode_ptr->succ_action_cost[i]);
172  succNode_ptr->pred_action_id.push_back(
173  currNode_ptr->succ_action_id[i]);
174  }
175 
176  decimal_t tentative_rhs =
177  currNode_ptr->rhs + currNode_ptr->succ_action_cost[i];
178 
179  if (tentative_rhs < succNode_ptr->rhs) {
180  succNode_ptr->rhs = tentative_rhs;
181  if (succNode_ptr->iterationclosed) {
182  succNode_ptr->g = succNode_ptr->rhs; // set g == rhs
183  succNode_ptr->heapkey =
184  epq.push(std::make_pair(succNode_ptr->rhs, succNode_ptr));
185  }
186  }
187  }
188  }
189 
190  hm_ = new_hm;
191  pq_.clear();
192  for (auto &it : new_hm) {
193  if (it.second->iterationopened && !it.second->iterationclosed) {
194  // state->succ_coord.clear();
195  // state->succ_action_cost.clear();
196  // state->succ_action_id.clear();
197  it.second->heapkey =
198  pq_.push(std::make_pair(calculateKey(it.second), it.second));
199  }
200  }
201 
202  // printf("getSubstatespace new_hm: %zu, hm_: %zu\n", new_hm.size(),
203  // hm_.size());
204  }
205 
207  void increaseCost(std::vector<std::pair<Coord, int>> states) {
208  for (const auto &affected_node : states) {
209  // update edge
210  StatePtr<Coord> &succNode_ptr = hm_[affected_node.first];
211  const int i = affected_node.second; // i-th pred
212  if (!std::isinf(succNode_ptr->pred_action_cost[i])) {
213  succNode_ptr->pred_action_cost[i] =
214  std::numeric_limits<decimal_t>::infinity();
215  updateNode(succNode_ptr);
216 
217  Coord parent_key = succNode_ptr->pred_coord[i];
218  int succ_act_id = succNode_ptr->pred_action_id[i];
219  for (size_t j = 0; j < hm_[parent_key]->succ_action_id.size(); j++) {
220  if (succ_act_id == hm_[parent_key]->succ_action_id[j]) {
221  hm_[parent_key]->succ_action_cost[j] =
222  std::numeric_limits<decimal_t>::infinity();
223  break;
224  }
225  }
226  }
227  }
228  }
230  void decreaseCost(std::vector<std::pair<Coord, int>> states,
231  const std::shared_ptr<env_base<Dim>> &ENV) {
232  for (const auto &affected_node : states) {
233  StatePtr<Coord> &succNode_ptr = hm_[affected_node.first];
234  const int i = affected_node.second;
235  if (std::isinf(succNode_ptr->pred_action_cost[i])) {
236  Coord parent_key = succNode_ptr->pred_coord[i];
237  Primitive<Dim> pr;
238  ENV->forward_action(parent_key, succNode_ptr->pred_action_id[i], pr);
239  if (ENV->is_free(pr)) {
240  succNode_ptr->pred_action_cost[i] = ENV->calculate_intrinsic_cost(pr);
241  updateNode(succNode_ptr);
242  int succ_act_id = succNode_ptr->pred_action_id[i];
243  for (size_t j = 0; j < hm_[parent_key]->succ_action_id.size(); j++) {
244  if (succ_act_id == hm_[parent_key]->succ_action_id[j]) {
245  hm_[parent_key]->succ_action_cost[j] =
246  succNode_ptr->pred_action_cost[i];
247  break;
248  }
249  }
250  }
251  }
252  }
253  }
255  void updateNode(StatePtr<Coord> &currNode_ptr) {
256  // if currNode is not start, update its rhs
257  // start rhs is assumed to be 0
258  if (currNode_ptr->rhs != start_rhs_) {
259  currNode_ptr->rhs = std::numeric_limits<decimal_t>::infinity();
260  for (size_t i = 0; i < currNode_ptr->pred_coord.size(); i++) {
261  Coord pred_key = currNode_ptr->pred_coord[i];
262  if (currNode_ptr->rhs >
263  hm_[pred_key]->g + currNode_ptr->pred_action_cost[i])
264  currNode_ptr->rhs =
265  hm_[pred_key]->g + currNode_ptr->pred_action_cost[i];
266  }
267  }
268 
269  // if currNode is in openset, remove it
270  if (currNode_ptr->iterationopened && !currNode_ptr->iterationclosed) {
271  pq_.erase(currNode_ptr->heapkey);
272  currNode_ptr->iterationclosed = true;
273  }
274 
275  // if currNode's g value is not equal to its rhs, put it into openset
276  if (currNode_ptr->g != currNode_ptr->rhs) {
277  decimal_t fval = calculateKey(currNode_ptr);
278  currNode_ptr->heapkey = pq_.push(std::make_pair(fval, currNode_ptr));
279  currNode_ptr->iterationopened = true;
280  currNode_ptr->iterationclosed = false;
281  }
282  }
283 
286  return std::min(node->g, node->rhs) + eps_ * node->h;
287  }
288 
291  //****** Check if there is null element in succ graph
292  for (const auto &it : hm) {
293  if (!it.second) {
294  std::cout << "error!!! detect null element!" << std::endl;
295  it.first.print("Not exist!");
296  } else {
297  bool null_succ = false;
298  for (size_t i = 0; i < it.second->succ_coord.size(); i++) {
299  if (hm.find(it.second->succ_coord[i]) == hm.end()) {
300  std::cout << "error!!! detect null succ !" << std::endl;
301  // it.second->succ_coord[i].print("Not exist!");
302  null_succ = true;
303  }
304  }
305  if (null_succ) {
306  it.first.print("From this pred:");
307  printf("rhs: %f, g: %f, open: %d, closed: %d\n\n\n", it.second->rhs,
308  it.second->g, it.second->iterationopened,
309  it.second->iterationclosed);
310  }
311  }
312  }
313  return;
314 
315  //****** Check rhs and g value of close set
316  printf("Check rhs and g value of closeset\n");
317  int close_cnt = 0;
318  for (const auto &it : hm_) {
319  if (it.second->iterationopened && it.second->iterationclosed) {
320  printf("g: %f, rhs: %f\n", it.second->g, it.second->rhs);
321  close_cnt++;
322  }
323  }
324 
325  // Check rhs and g value of open set
326  printf("Check rhs and g value of openset\n");
327  int open_cnt = 0;
328  for (const auto &it : hm_) {
329  if (it.second->iterationopened && !it.second->iterationclosed) {
330  printf("g: %f, rhs: %f\n", it.second->g, it.second->rhs);
331  open_cnt++;
332  }
333  }
334 
335  // Check rhs and g value of null set
336  printf("Check rhs and g value of nullset\n");
337  int null_cnt = 0;
338  for (const auto &it : hm_) {
339  if (!it.second->iterationopened) {
340  printf("g: %f, rhs: %f\n", it.second->g, it.second->rhs);
341  null_cnt++;
342  }
343  }
344 
345  printf("hm: [%zu], open: [%d], closed: [%d], null: [%d]\n", hm_.size(),
346  open_cnt, close_cnt, null_cnt);
347  }
348 };
349 
350 } // namespace MPL
351 
352 #endif
std::vector< int > succ_action_id
action id of successors
Definition: state_space.h:43
Lattice of the graph in graph search.
Definition: state_space.h:37
std::vector< decimal_t > pred_action_cost
action cost of predecessors
Definition: state_space.h:51
State(const Coord &coord)
Simple constructor.
Definition: state_space.h:69
Definition: map_util.h:12
StateSpace(decimal_t eps=1)
Simple constructor.
Definition: state_space.h:104
vec_E< Coord > pred_coord
coordinates of predecessors
Definition: state_space.h:47
environment base class
void increaseCost(std::vector< std::pair< Coord, int >> states)
Increase the cost of actions.
Definition: state_space.h:207
std::vector< T, Eigen::aligned_allocator< T > > vec_E
Pre-allocated std::vector for Eigen using vec_E.
Definition: data_type.h:53
vec_E< Coord > succ_coord
coordinates of successors
Definition: state_space.h:41
std::vector< int > pred_action_id
action id of predecessors
Definition: state_space.h:49
State space.
Definition: state_space.h:83
decimal_t eps_
Heuristic weight, default as 1.
Definition: state_space.h:89
hashMap< Coord > hm_
Hashmap, stores all the nodes.
Definition: state_space.h:87
double decimal_t
Rename the float type used in lib.
Definition: data_type.h:49
boost::unordered_map< Coord, StatePtr< Coord >, boost::hash< Coord > > hashMap
Define hashmap type.
Definition: state_space.h:79
void decreaseCost(std::vector< std::pair< Coord, int >> states, const std::shared_ptr< env_base< Dim >> &ENV)
Decrease the cost of actions.
Definition: state_space.h:230
vec_E< StatePtr< Coord > > best_child_
The best trajectory from previous plan.
Definition: state_space.h:93
priorityQueue< State< Coord > > pq_
Priority queue, open set.
Definition: state_space.h:85
void checkValidation(const hashMap< Coord > hm)
Internal function to check if the graph is valid.
Definition: state_space.h:290
Base environment class.
Definition: env_base.h:17
std::shared_ptr< State< Coord > > StatePtr
Declare StatePtr.
Definition: state_space.h:74
Heap element comparison.
Definition: state_space.h:16
void updateNode(StatePtr< Coord > &currNode_ptr)
Update the node in the graph.
Definition: state_space.h:255
std::vector< decimal_t > succ_action_cost
action cost of successors
Definition: state_space.h:45
void getSubStateSpace(int time_step)
Get the subtree.
Definition: state_space.h:116
Primitive class.
Definition: primitive.h:206
Coord coord
state
Definition: state_space.h:39
priorityQueue< State< Coord > >::handle_type heapkey
pointer to heap location
Definition: state_space.h:54
decimal_t dt_
Execution time for each primitive.
Definition: state_space.h:91
boost::heap::d_ary_heap< std::pair< decimal_t, std::shared_ptr< state > >, boost::heap::mutable_< true >, boost::heap::arity< 2 >, boost::heap::compare< compare_pair< state > >> priorityQueue
Define priority queue.
Definition: state_space.h:34
decimal_t calculateKey(const StatePtr< Coord > &node)
Calculate the fval as min(rhs, g) + h.
Definition: state_space.h:285