CL-CBS
hybrid_astar.hpp
Go to the documentation of this file.
1 
10 #pragma once
11 #include <algorithm>
12 #include <cmath>
13 #include <iostream>
14 #include <unordered_map>
15 #include <unordered_set>
16 
17 #define USE_FIBONACCI_HEAP
18 #include <boost/heap/d_ary_heap.hpp>
19 #include <boost/heap/fibonacci_heap.hpp>
20 #include <boost/program_options.hpp>
21 
22 #include "neighbor.hpp"
23 #include "planresult.hpp"
24 
25 namespace libMultiRobotPlanning {
78 template <typename State, typename Action, typename Cost, typename Environment,
79  typename StateHasher = std::hash<State>>
80 class HybridAStar {
81  public:
82  HybridAStar(Environment& environment) : m_env(environment) {}
84 
85  bool search(const State& startState,
86  PlanResult<State, Action, Cost>& solution, Cost initialCost = 0) {
87  solution.states.clear();
88  solution.actions.clear();
89  solution.cost = 0;
90 
91  openSet_t openSet;
92  std::unordered_map<uint64_t, heapHandle_t, std::hash<uint64_t>> stateToHeap;
93  std::unordered_set<uint64_t, std::hash<uint64_t>> closedSet;
94  std::unordered_map<State, std::tuple<State, Action, Cost, Cost>,
95  StateHasher>
96  cameFrom;
97 
98  auto handle =
99  openSet.push(Node(startState, Action(),
100  m_env.admissibleHeuristic(startState), initialCost));
101  stateToHeap.insert(std::make_pair<>(m_env.calcIndex(startState), handle));
102  (*handle).handle = handle;
103 
104  std::vector<Neighbor<State, Action, Cost>> neighbors;
105  neighbors.reserve(10);
106 
107  while (!openSet.empty()) {
108  Node current = openSet.top();
109  m_env.onExpandNode(current.state, current.fScore, current.gScore);
110  if (m_env.isSolution(current.state, current.gScore, cameFrom)) {
111  solution.states.clear();
112  solution.actions.clear();
113  auto iter = cameFrom.find(m_env.getGoal());
114  solution.cost = std::get<3>(iter->second);
115  solution.fmin =
116  std::get<3>(iter->second) +
117  m_env.admissibleHeuristic(iter->first); // current.fScore;
118  while (iter != cameFrom.end()) {
119  // std::cout << " From " << std::get<0>(iter->second)
120  // << " to Node:" << iter->first
121  // << " with ACTION: " << std::get<1>(iter->second) << "
122  // cost "
123  // << std::get<2>(iter->second) << " g_score "
124  // << std::get<3>(iter->second) << std::endl;
125  solution.states.push_back(
126  std::make_pair<>(iter->first, std::get<3>(iter->second)));
127  solution.actions.push_back(std::make_pair<>(
128  std::get<1>(iter->second), std::get<2>(iter->second)));
129  iter = cameFrom.find(std::get<0>(iter->second));
130  }
131  solution.states.push_back(std::make_pair<>(startState, initialCost));
132  std::reverse(solution.states.begin(), solution.states.end());
133  std::reverse(solution.actions.begin(), solution.actions.end());
134 
135  openSet.clear();
136  return true;
137  }
138 
139  openSet.pop();
140  stateToHeap.erase(m_env.calcIndex(current.state));
141  closedSet.insert(m_env.calcIndex(current.state));
142  // traverse neighbors
143  neighbors.clear();
144  m_env.getNeighbors(current.state, current.action, neighbors);
145  for (const Neighbor<State, Action, Cost>& neighbor : neighbors) {
146  if (closedSet.find(m_env.calcIndex(neighbor.state)) ==
147  closedSet.end()) { // not in closed set
148  Cost tentative_gScore = current.gScore + neighbor.cost;
149  auto iter = stateToHeap.find(m_env.calcIndex(neighbor.state));
150  if (iter == stateToHeap.end()) { // Discover a new node
151  Cost fScore =
152  tentative_gScore + m_env.admissibleHeuristic(neighbor.state);
153  auto handle = openSet.push(Node(neighbor.state, neighbor.action,
154  fScore, tentative_gScore));
155  (*handle).handle = handle;
156  stateToHeap.insert(
157 
158  std::make_pair<>(m_env.calcIndex(neighbor.state), handle));
159  m_env.onDiscover(neighbor.state, fScore, tentative_gScore);
160  // std::cout << " this is a new node " << fScore << "," <<
161  // tentative_gScore << std::endl;
162  } else {
163  auto handle = iter->second;
164  // std::cout << " this is an old node: " << tentative_gScore << ","
165  // << (*handle).gScore << std::endl;
166  // We found this node before with a better path
167  if (tentative_gScore >= (*handle).gScore) {
168  continue;
169  }
170 
171  // update f and gScore
172  Cost delta = (*handle).gScore - tentative_gScore;
173  (*handle).gScore = tentative_gScore;
174  (*handle).fScore -= delta;
175  (*handle).state = neighbor.state;
176  openSet.increase(handle);
177  m_env.onDiscover(neighbor.state, (*handle).fScore,
178  (*handle).gScore);
179  }
180 
181  // Best path for this node so far
182  // TODO: this is not the best way to update "cameFrom", but otherwise
183  // default c'tors of State and Action are required
184  cameFrom.erase(neighbor.state);
185  cameFrom.insert(std::make_pair<>(
186  neighbor.state,
187  std::make_tuple<>(current.state, neighbor.action, neighbor.cost,
188  tentative_gScore)));
189  }
190  }
191  }
192  openSet.clear();
193  return false;
194  }
195 
196  private:
197  struct Node {
198  Node(const State& state, Action action, Cost fScore, Cost gScore)
199  : state(state), action(action), fScore(fScore), gScore(gScore) {}
200 
201  bool operator<(const Node& other) const {
202  // Sort order
203  // 1. lowest fScore
204  // 2. highest gScore
205 
206  // Our heap is a maximum heap, so we invert the comperator function here
207  if (fScore != other.fScore) {
208  return fScore > other.fScore;
209  } else {
210  return gScore < other.gScore;
211  }
212  }
213 
214  friend std::ostream& operator<<(std::ostream& os, const Node& node) {
215  os << "state: " << node.state << " fScore: " << node.fScore
216  << " gScore: " << node.gScore;
217  return os;
218  }
219 
220  State state;
221  Action action;
222  Cost fScore;
223  Cost gScore;
224 
225 #ifdef USE_FIBONACCI_HEAP
226  typename boost::heap::fibonacci_heap<Node>::handle_type handle;
227 #else
228  typename boost::heap::d_ary_heap<Node, boost::heap::arity<2>,
229  boost::heap::mutable_<true>>::handle_type
230  handle;
231 #endif
232  };
233 
234 #ifdef USE_FIBONACCI_HEAP
235  typedef typename boost::heap::fibonacci_heap<Node> openSet_t;
236  typedef typename openSet_t::handle_type heapHandle_t;
237 #else
238  typedef typename boost::heap::d_ary_heap<Node, boost::heap::arity<2>,
239  boost::heap::mutable_<true>>
240  openSet_t;
241  typedef typename openSet_t::handle_type heapHandle_t;
242 #endif
243 
244  private:
245  Environment& m_env;
246 };
247 
248 } // namespace libMultiRobotPlanning
bool search(const State &startState, PlanResult< State, Action, Cost > &solution, Cost initialCost=0)
Definition: hybrid_astar.hpp:85
std::vector< std::pair< Action, Cost > > actions
actions and their cost
Definition: planresult.hpp:32
Spatiotemporal Hybrid A* Algorithm.
Definition: hybrid_astar.hpp:80
HybridAStar(Environment &environment)
Definition: hybrid_astar.hpp:82
uint64_t calcIndex(const State &s)
Definition: environment.hpp:367
std::vector< std::pair< State, Cost > > states
states and their gScore
Definition: planresult.hpp:30
Represents state transations.
Definition: neighbor.hpp:24
Definition: cl_cbs.hpp:19
Cost cost
actual cost of the result
Definition: planresult.hpp:34
int admissibleHeuristic(const State &s)
Definition: environment.hpp:199
Neighbor header.
State getGoal()
Definition: environment.hpp:366
Represents the path for an agent.
Definition: planresult.hpp:28
PlanResult header.
~HybridAStar()
Definition: hybrid_astar.hpp:83
bool isSolution(const State &state, double gscore, std::unordered_map< State, std::tuple< State, Action, double, double >, std::hash< State >> &_camefrom)
Definition: environment.hpp:232
void getNeighbors(const State &s, Action action, std::vector< Neighbor< State, Action, double >> &neighbors)
Definition: environment.hpp:323
Cost fmin
lower bound of the cost (for suboptimal solvers)
Definition: planresult.hpp:36