symbolic
breadth_first_search.h
1 
10 #ifndef SYMBOLIC_PLANNING_BREADTH_FIRST_SEARCH_H_
11 #define SYMBOLIC_PLANNING_BREADTH_FIRST_SEARCH_H_
12 
13 #include <chrono> // std::chrono
14 #include <cstddef> // ptrdiff_t
15 #include <iostream> // std::cout
16 #include <iterator> // std::input_iterator_tag
17 #include <memory> // std::shared_ptr
18 #include <queue> // std::queue
19 #include <utility> // std::pair
20 #include <vector> // std::vector
21 
22 namespace symbolic {
23 
24 template <typename NodeT>
26  public:
27  class iterator;
28 
30  const NodeT& root, size_t max_depth, bool verbose = false,
31  std::chrono::microseconds us_timeout = std::chrono::microseconds(0))
32  : max_depth_(max_depth),
33  verbose_(verbose),
34  root_(root),
35  timeout_(us_timeout) {}
36 
37  iterator begin() const {
38  iterator it(this);
39  return ++it;
40  }
41  iterator end() const { return iterator(); }
42 
43  private:
44  const size_t max_depth_;
45  const bool verbose_;
46  const std::chrono::microseconds timeout_;
47 
48  const NodeT& root_;
49 };
50 
51 template <typename NodeT>
53  public:
54  using iterator_category = std::input_iterator_tag;
55  using value_type = std::vector<NodeT>;
56  using difference_type = ptrdiff_t;
57  using pointer = const value_type*;
58  using reference = const value_type&;
59 
60  iterator() = default;
61  explicit iterator(const BreadthFirstSearch<NodeT>* bfs)
62  : bfs_(bfs),
63  queue_({{bfs_->root_, std::make_shared<std::vector<NodeT>>()}}) {}
64 
65  iterator& operator++();
66 
67  bool operator==(const iterator& other) const {
68  return IsFinished() && other.IsFinished();
69  }
70 
71  bool operator!=(const iterator& other) const { return !(*this == other); }
72 
73  reference operator*() const { return *ancestors_; }
74 
75  private:
76  const BreadthFirstSearch<NodeT>* bfs_ = nullptr;
77  bool IsFinished() const { return queue_.empty() && !ancestors_; }
78 
79  std::queue<std::pair<NodeT, std::shared_ptr<std::vector<NodeT>>>> queue_;
80  std::shared_ptr<std::vector<NodeT>> ancestors_;
81 };
82 
83 template <typename NodeT>
86  const auto t_start = std::chrono::high_resolution_clock::now();
87  size_t depth = 0;
88  while (!queue_.empty()) {
89  // Abort on timeout.
90  if (bfs_->timeout_.count() > 0 &&
91  std::chrono::high_resolution_clock::now() - t_start > bfs_->timeout_) {
92  std::queue<std::pair<NodeT, std::shared_ptr<std::vector<NodeT>>>> empty;
93  std::swap(queue_, empty);
94  break;
95  }
96 
97  std::pair<NodeT, std::shared_ptr<std::vector<NodeT>>>& front =
98  queue_.front();
99 
100  // Take ancestors list and append current node
101  ancestors_ = std::make_shared<std::vector<NodeT>>(*front.second);
102  ancestors_->push_back(std::move(front.first));
103  queue_.pop();
104  const NodeT& node = ancestors_->back();
105 
106  // Print search depth
107  if (bfs_->verbose_ && ancestors_->size() > depth) {
108  depth = ancestors_->size();
109  std::cout << "BFS depth: " << depth - 1 << std::endl;
110  }
111 
112  // Return if node evaluates to true
113  if (node) {
114  if (bfs_->verbose_) {
115  std::cout << "Goal state reached: " << node << std::endl;
116  }
117  return *this;
118  }
119 
120  // Skip children if max depth has been reached
121  if (ancestors_->size() > bfs_->max_depth_) continue;
122 
123  // Add node's children to queue
124  if (bfs_->verbose_) {
125  for (const NodeT& node : *ancestors_) {
126  std::cout << node << std::endl;
127  }
128  std::cout << "====================" << std::endl;
129  }
130  for (const NodeT& child : node) {
131  // Print node
132  if (bfs_->verbose_) {
133  std::cout << child << std::endl << std::endl;
134  }
135 
136  queue_.emplace(child, ancestors_);
137  }
138  }
139  ancestors_.reset();
140  return *this;
141 }
142 
143 } // namespace symbolic
144 
145 #endif // SYMBOLIC_PLANNING_BREADTH_FIRST_SEARCH_H_
symbolic
Definition: action.cc:329
symbolic::BreadthFirstSearch
Definition: breadth_first_search.h:25
symbolic::BreadthFirstSearch::iterator
Definition: breadth_first_search.h:52