searchable_set.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018, The Regents of the University of California (Regents).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer in the documentation and/or other materials provided
15  * with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Please contact the author(s) of this library if you have any questions.
34  * Authors: David Fridovich-Keil ( dfk@eecs.berkeley.edu )
35  */
36 
38 //
39 // Defines SearchableSet class, which is a wrapper around the FLANN library's
40 // fast kdtree index. SearchableSets store a collection of nodes (N) which are
41 // themselves templated on the state type (S) and allow for nearest neighbor
42 // and radius searches.
43 //
45 
46 #ifndef FASTRACK_UTILS_SEARCHABLE_SET_H
47 #define FASTRACK_UTILS_SEARCHABLE_SET_H
48 
49 #include <fastrack/utils/types.h>
51 
52 #include <flann/flann.h>
53 #include <ros/ros.h>
54 
55 namespace fastrack {
56 
57 template <typename N, typename S>
58 class SearchableSet : private Uncopyable {
59  public:
61  explicit SearchableSet(const typename N::Ptr& node);
62 
63  // Access the initial node.
64  inline typename N::Ptr InitialNode() const { return registry_.front(); }
65 
66  // Insert a new node into the set.
67  bool Insert(const typename N::Ptr& node);
68 
69  // Nearest neighbor search.
70  std::vector<typename N::Ptr> KnnSearch(const S& query, size_t k) const;
71 
72  // Radius search.
73  std::vector<typename N::Ptr> RadiusSearch(const S& query, double r) const;
74 
75  private:
76  // A Flann kdtree. Searches in this index return indices, which are then
77  // mapped to node pointers in an array.
78  // TODO: fix the distance metric to be something more intelligent.
79  std::unique_ptr<flann::KDTreeIndex<flann::L2<double> > > index_;
80  std::vector<typename N::Ptr> registry_;
81 };
82 
83 // ------------------------------ IMPLEMENTATION -----------------------------
84 // //
85 
86 // Destructor. Must free all memory in the index.
87 template <typename N, typename S>
89  // Free memory from points in the kdtree.
90  if (index_ != nullptr) {
91  for (size_t ii = 0; ii < index_->size(); ++ii) {
92  double* point = index_->getPoint(ii);
93  delete[] point;
94  }
95  }
96 }
97 
98 // Construct from a single node.
99 template <typename N, typename S>
100 SearchableSet<N, S>::SearchableSet(const typename N::Ptr& node) {
101  if (!node.get()) {
102  ROS_WARN("SearchableSet: Constructing without initial node.");
103  } else {
104  Insert(node);
105  }
106 }
107 
108 // Insert a new node into the set.
109 template <typename N, typename S>
110 bool SearchableSet<N, S>::Insert(const typename N::Ptr& node) {
111  if (!node.get()) {
112  ROS_WARN("SearchableSet: Tried to insert a null node.");
113  return false;
114  }
115 
116  // Copy the input point into FLANN's Matrix type.
117  const VectorXd x = node->state.ToVector();
118  flann::Matrix<double> flann_point(new double[x.size()], 1, x.size());
119 
120  for (size_t ii = 0; ii < x.size(); ii++) flann_point[0][ii] = x(ii);
121 
122  // If this is the first point in the index, create the index and exit.
123  if (index_ == nullptr) {
124  // Single kd-tree.
125  const int kNumTrees = 1;
126  index_.reset(new flann::KDTreeIndex<flann::L2<double> >(
127  flann_point, flann::KDTreeIndexParams(kNumTrees)));
128 
129  index_->buildIndex();
130  } else {
131  // If the index is already created, add the data point to the index.
132  // Rebuild every time the index floats in size to occasionally rebalance
133  // the kdtree.
134  const double kRebuildThreshold = 2.0;
135  index_->addPoints(flann_point, kRebuildThreshold);
136  }
137 
138  // Add point to registry.
139  registry_.push_back(node);
140 
141  return true;
142 }
143 
144 // Nearest neighbor search.
145 template <typename N, typename S>
146 std::vector<typename N::Ptr> SearchableSet<N, S>::KnnSearch(const S& query,
147  size_t k) const {
148  if (index_ == nullptr) {
149  ROS_WARN("SearchableSet: Cannot search empty index.");
150  return std::vector<typename N::Ptr>();
151  }
152 
153  // Convert the input point to the FLANN format.
154  VectorXd x = query.ToVector();
155  const flann::Matrix<double> flann_query(x.data(), 1, x.size());
156 
157  // Search the kd tree for the nearest neighbor to the query.
158  std::vector<std::vector<int> > query_match_indices;
159  std::vector<std::vector<double> > query_squared_distances;
160 
161  const int num_neighbors_found = index_->knnSearch(
162  flann_query, query_match_indices, query_squared_distances,
163  static_cast<int>(k), flann::SearchParams(-1, 0.0, false));
164 
165  // Assign output.
166  std::vector<typename N::Ptr> neighbors;
167  for (size_t ii = 0; ii < num_neighbors_found; ii++)
168  neighbors.push_back(registry_[query_match_indices[0][ii]]);
169 
170  return neighbors;
171 }
172 
173 // Radius search.
174 template <typename N, typename S>
175 std::vector<typename N::Ptr> SearchableSet<N, S>::RadiusSearch(const S& query,
176  double r) const {
177  if (index_ == nullptr) {
178  ROS_WARN("SearchableSet: cannot search empty index.");
179  return std::vector<typename N::Ptr>();
180  }
181 
182  // Convert the input point to the FLANN format.
183  VectorXd x = query.ToVector();
184  const flann::Matrix<double> flann_query(x.data(), 1, x.size());
185 
186  // Search the kd tree for the nearest neighbor to the query.
187  std::vector<std::vector<int> > query_match_indices;
188  std::vector<std::vector<double> > query_squared_distances;
189 
190  // FLANN checks Euclidean distance squared, so we pass in r * r.
191  int num_neighbors_found = index_->radiusSearch(
192  flann_query, query_match_indices, query_squared_distances, r * r,
193  flann::SearchParams(-1, 0.0, false));
194  // Assign output.
195  std::vector<typename N::Ptr> neighbors;
196  for (size_t ii = 0; ii < num_neighbors_found; ii++)
197  neighbors.push_back(registry_[query_match_indices[0][ii]]);
198 
199  return neighbors;
200 }
201 
202 } //\namespace fastrack
203 
204 #endif
Definition: box.h:53
SearchableSet(const typename N::Ptr &node)
N::Ptr InitialNode() const
std::unique_ptr< flann::KDTreeIndex< flann::L2< double > > > index_
std::vector< typename N::Ptr > RadiusSearch(const S &query, double r) const
bool Insert(const typename N::Ptr &node)
std::vector< typename N::Ptr > registry_
std::vector< typename N::Ptr > KnnSearch(const S &query, size_t k) const


fastrack
Author(s): David Fridovich-Keil
autogenerated on Mon Aug 3 2020 21:28:37