CL-CBS
cl_cbs.hpp
Go to the documentation of this file.
1 
10 #pragma once
11 
12 #include <chrono>
13 #include <map>
14 
15 #include "hybrid_astar.hpp"
16 
17 #define MAX_RUNTIME 120
18 
86 template <typename State, typename Action, typename Cost, typename Conflict,
87  typename Constraints, typename Environment>
88 class CL_CBS {
89  public:
90  CL_CBS(Environment& environment) : m_env(environment) {}
91  ~CL_CBS() {}
92 
93  bool search(const std::vector<State>& initialStates,
94  std::vector<PlanResult<State, Action, Cost>>& solution) {
95  HighLevelNode start;
96  start.solution.resize(initialStates.size());
97  start.constraints.resize(initialStates.size());
98  start.cost = 0;
99  start.id = 0;
100 
101  for (size_t i = 0; i < initialStates.size(); ++i) {
102  // if (i < solution.size() && solution[i].states.size() > 1) {
103  // start.solution[i] = solution[i];
104  // std::cout << "use existing solution for agent: " << i << std::endl;
105  // } else {
106  LowLevelEnvironment llenv(m_env, i, start.constraints[i]);
107  LowLevelSearch_t lowLevel(llenv);
108  bool success = lowLevel.search(initialStates[i], start.solution[i]);
109  if (!success) {
110  return false;
111  }
112  // }
113  start.cost += start.solution[i].cost;
114  }
115 
116  // std::priority_queue<HighLevelNode> open;
117  typename boost::heap::d_ary_heap<HighLevelNode, boost::heap::arity<2>,
118  boost::heap::mutable_<true>>
119  open;
120 
121  auto handle = open.push(start);
122  (*handle).handle = handle;
123 
124  std::chrono::high_resolution_clock::time_point
125  startTime = std::chrono::high_resolution_clock::now(),
126  endTime;
127  solution.clear();
128  int id = 1;
129  while (!open.empty()) {
130  endTime = std::chrono::high_resolution_clock::now();
131  if (std::chrono::duration_cast<std::chrono::duration<double>>(endTime -
132  startTime)
133  .count() > MAX_RUNTIME) {
134  open.clear();
135  std::cout << "\033[1m\033[31m Plan out of runtime time! \033[0m\n";
136  return false;
137  }
138 
139  HighLevelNode P = open.top();
140  m_env.onExpandHighLevelNode(P.cost);
141  // std::cout << "expand: " << P << std::endl;
142 
143  open.pop();
144 
145  Conflict conflict;
146  if (!m_env.getFirstConflict(P.solution, conflict)) {
147  // std::cout << "done; cost: " << P.cost << std::endl;
148  solution = P.solution;
149  return true;
150  }
151 
152  // create additional nodes to resolve conflict
153  // std::cout << "Found conflict: " << conflict << std::endl;
154 
155  std::map<size_t, Constraints> constraints;
156  m_env.createConstraintsFromConflict(conflict, constraints);
157  for (const auto& c : constraints) {
158  // std::cout << "Add HL node for " << c.first << std::endl;
159  size_t i = c.first;
160  // std::cout << "create child with id " << id << std::endl;
161  HighLevelNode newNode = P;
162  newNode.id = id;
163  // (optional) check that this constraint was not included already
164  // std::cout << newNode.constraints[i] << std::endl;
165  // std::cout << c.second << std::endl;
166  assert(!newNode.constraints[i].overlap(c.second));
167 
168  newNode.constraints[i].add(c.second);
169 
170  newNode.cost -= newNode.solution[i].cost;
171 
172  LowLevelEnvironment llenv(m_env, i, newNode.constraints[i]);
173  LowLevelSearch_t lowLevel(llenv);
174  bool success = lowLevel.search(initialStates[i], newNode.solution[i]);
175 
176  newNode.cost += newNode.solution[i].cost;
177 
178  if (success) {
179  // std::cout << " success. cost: " << newNode.cost << std::endl;
180  auto handle = open.push(newNode);
181  (*handle).handle = handle;
182  }
183 
184  ++id;
185  }
186  }
187 
188  return false;
189  }
190 
191  private:
192  struct HighLevelNode {
193  std::vector<PlanResult<State, Action, Cost>> solution;
194  std::vector<Constraints> constraints;
195 
196  Cost cost;
197 
198  int id;
199 
200  typename boost::heap::d_ary_heap<HighLevelNode, boost::heap::arity<2>,
201  boost::heap::mutable_<true>>::handle_type
202  handle;
203 
204  bool operator<(const HighLevelNode& n) const {
205  // if (cost != n.cost)
206  return cost > n.cost;
207  // return id > n.id;
208  }
209 
210  friend std::ostream& operator<<(std::ostream& os, const HighLevelNode& c) {
211  os << "id: " << c.id << " cost: " << c.cost << std::endl;
212  for (size_t i = 0; i < c.solution.size(); ++i) {
213  os << "Agent: " << i << std::endl;
214  os << " States:" << std::endl;
215  for (size_t t = 0; t < c.solution[i].states.size(); ++t) {
216  os << " " << c.solution[i].states[t].first << std::endl;
217  }
218  os << " Constraints:" << std::endl;
219  os << c.constraints[i];
220  os << " cost: " << c.solution[i].cost << std::endl;
221  }
222  return os;
223  }
224  };
225 
226  struct LowLevelEnvironment {
227  LowLevelEnvironment(Environment& env, size_t agentIdx,
228  const Constraints& constraints)
229  : m_env(env)
230  // , m_agentIdx(agentIdx)
231  // , m_constraints(constraints)
232  {
233  m_env.setLowLevelContext(agentIdx, &constraints);
234  }
235 
236  Cost admissibleHeuristic(const State& s) {
237  return m_env.admissibleHeuristic(s);
238  }
239 
240  bool isSolution(
241  const State& s, Cost g,
242  std::unordered_map<State, std::tuple<State, Action, Cost, Cost>,
243  std::hash<State>>& camefrom) {
244  return m_env.isSolution(s, g, camefrom);
245  }
246 
247  void getNeighbors(const State& s, Action act,
248  std::vector<Neighbor<State, Action, Cost>>& neighbors) {
249  m_env.getNeighbors(s, act, neighbors);
250  }
251 
252  State getGoal() { return m_env.getGoal(); }
253 
254  int calcIndex(const State& s) { return m_env.calcIndex(s); }
255 
256  void onExpandNode(const State& s, Cost fScore, Cost gScore) {
257  // std::cout << "LL expand: " << s << std::endl;
258  m_env.onExpandLowLevelNode(s, fScore, gScore);
259  }
260 
261  void onDiscover(const State& /*s*/, Cost /*fScore*/, Cost /*gScore*/) {
262  // std::cout << "LL discover: " << s << std::endl;
263  // m_env.onDiscoverLowLevel(s, m_agentIdx, m_constraints);
264  }
265 
266  private:
267  Environment& m_env;
268  };
269 
270  private:
271  Environment& m_env;
274 };
275 
276 } // namespace libMultiRobotPlanning
bool search(const State &startState, PlanResult< State, Action, Cost > &solution, Cost initialCost=0)
Definition: hybrid_astar.hpp:85
hybrid Astar header
void onExpandHighLevelNode(int)
Definition: environment.hpp:172
bool getFirstConflict(const std::vector< PlanResult< State, Action, double >> &solution, Conflict &result)
High Level Environment functions.
Definition: environment.hpp:133
Spatiotemporal Hybrid A* Algorithm.
Definition: hybrid_astar.hpp:80
bool search(const std::vector< State > &initialStates, std::vector< PlanResult< State, Action, Cost >> &solution)
Definition: cl_cbs.hpp:93
~CL_CBS()
Definition: cl_cbs.hpp:91
Environment class.
Definition: environment.hpp:97
Represents state transations.
Definition: neighbor.hpp:24
Definition: cl_cbs.hpp:19
void createConstraintsFromConflict(const Conflict &conflict, std::map< size_t, Constraints > &constraints)
Definition: environment.hpp:160
Represents the path for an agent.
Definition: planresult.hpp:28
Car-Like Conflict-Based Search(CL-CBS) algorithm to solve the Multi-Agent Path Finding for Car-Like r...
Definition: cl_cbs.hpp:88
CL_CBS(Environment &environment)
Definition: cl_cbs.hpp:90
#define MAX_RUNTIME
Definition: cl_cbs.hpp:17