提交 3a6b932e 编写于 作者: M Marius Muja

Replaced TBB with OpenMP. Fixed the const-ness of search functions

上级 2ba14aeb
......@@ -42,8 +42,7 @@ set(TEST_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/test)
option(BUILD_C_BINDINGS "Build C bindings" ON)
option(BUILD_PYTHON_BINDINGS "Build Python bindings" ON)
option(BUILD_MATLAB_BINDINGS "Build Matlab bindings" ON)
option(BUILD_CUDA_LIB "Build CUDA library" ON)
option(USE_TBB "Use TBB" OFF)
option(BUILD_CUDA_LIB "Build CUDA library" OFF)
option(USE_MPI "Use MPI" OFF)
set(NVCC_COMPILER_BINDIR "" CACHE PATH "Directory where nvcc should look for C++ compiler. This is passed to nvcc through the --compiler-bindir option.")
......@@ -90,12 +89,22 @@ if (USE_MPI)
endif(USE_MPI)
find_package(GTest)
if (NOT GTEST_FOUND)
message(WARNING "gtest library not found, some tests will not be run")
endif()
find_package(OpenMP)
if(OPENMP_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
else()
message(WARNING "OpenMP NOT found")
endif()
# CUDA support
if (BUILD_CUDA_LIB)
find_package(CUDA)
......@@ -108,31 +117,6 @@ if (BUILD_CUDA_LIB)
endif(CUDA_FOUND)
endif(BUILD_CUDA_LIB)
if (USE_TBB)
# find Intel TBB
find_package(TBB)
if(TBB_FOUND AND TBB_DEBUG_FOUND)
message(STATUS "Intel TBB include dir: " ${TBB_INCLUDE_DIRS})
message(STATUS "Intel TBB libs: " ${TBB_LIBRARIES})
message(STATUS "Intel TBB libs (debug): " ${TBB_DEBUG_LIBRARIES})
include_directories(${TBB_INCLUDE_DIRS})
endif(TBB_FOUND AND TBB_DEBUG_FOUND)
# print additional info
if(TBB_FOUND AND NOT TBB_DEBUG_FOUND)
message(STATUS "Only the Intel TBB (release) libraries were found")
endif()
if(TBB_DEBUG_FOUND AND NOT TBB_FOUND)
message(STATUS "Only the Intel TBB (debug) libraries were found")
endif()
if(NOT TBB_FOUND AND NOT TBB_DEBUG_FOUND)
message(STATUS "No intel TBB libraries were found")
endif()
endif(USE_TBB)
#set the C/C++ include path to the "include" directory
include_directories(${PROJECT_SOURCE_DIR}/src/cpp)
......
###############################################################################
# Find Intel Threading Building Blocks
#
# This sets the following variables:
#
# TBB_INCLUDE_DIRS - Directories containing the TBB include files.
# TBB_LIBRARY_DIRS - Directories containing the TBB libs.
#
# (release libs)
# TBB_FOUND - True if TBB was found.
# TBB_LIBRARIES - Libraries needed to use TBB.
#
# (debug libs)
# TBB_DEBUG_FOUND - True if TBB was found.
# TBB_DEBUG_LIBRARIES - Libraries needed to use TBB.
find_package(PkgConfig)
pkg_check_modules(PC_TBB tbb)
# Find include directory
find_path(TBB_INCLUDE_DIR tbb/task_scheduler_init.h
HINTS ${PC_TBB_INCLUDEDIR} ${PC_TBB_INCLUDE_DIRS})
# Find libraries
find_library(TBB_LIBRARY tbb
HINTS ${PC_TBB_LIBDIR} ${PC_TBB_LIBRARY_DIRS})
find_library(TBB_DEBUG_LIBRARY tbb_debug
HINTS ${PC_TBB_LIBDIR} ${PC_TBB_LIBRARY_DIRS})
#find_library(TBB_MALLOC_LIBRARY tbbmalloc
# HINTS ${PC_TBB_LIBDIR} ${PC_TBB_LIBRARY_DIRS})
#find_library(TBB_MALLOC_LIBRARY tbbmalloc_debug
# HINTS ${PC_TBB_LIBDIR} ${PC_TBB_LIBRARY_DIRS})
#find_library(TBB_MALLOC_PROXY_LIBRARY tbbmalloc_proxy
# HINTS ${PC_TBB_LIBDIR} ${PC_TBB_LIBRARY_DIRS})
#find_library(TBB_MALLOC_PROXY_LIBRARY tbbmalloc_proxy_debug
# HINTS ${PC_TBB_LIBDIR} ${PC_TBB_LIBRARY_DIRS})
# Set the appropriate CMake variables and mark them as advanced
set(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR})
set(TBB_LIBRARY_DIRS ${PC_TBB_LIBRARY_DIRS})
#set(TBB_LIBRARIES ${TBB_LIBRARY};${TBB_MALLOC_LIBRARY};${TBB_MALLOC_PROXY_LIBRARY})
set(TBB_LIBRARIES ${TBB_LIBRARY})
#set(TBB_DEBUG_LIBRARIES ${TBB_DEBUG_LIBRARY};${TBB_MALLOC_DEBUG_LIBRARY};${TBB_MALLOC_PROXY_DEBUG_LIBRARY})
set(TBB_DEBUG_LIBRARIES ${TBB_DEBUG_LIBRARY})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(tbb DEFAULT_MSG TBB_LIBRARIES TBB_INCLUDE_DIRS)
find_package_handle_standard_args(tbb_debug DEFAULT_MSG TBB_DEBUG_LIBRARIES TBB_INCLUDE_DIRS)
mark_as_advanced(TBB_LIBRARY TBB_DEBUG_LIBRARY TBB_INCLUDE_DIR)
#mark_as_advanced(TBB_LIBRARY TBB_DEBUG_LIBRARY TBB_MALLOC_LIBRARY TBB_DEBUG_MALLOC_LIBRARY TBB_MALLOC_PROXY_LIBRARY TBB_MALLOC_PROXY_DEBUG_LIBRARY TBB_INCLUDE_DIR)
......@@ -272,12 +272,11 @@ to obtain the pointer to the memory buffer.
\subsection{Compiling FLANN with multithreading support}
To make use of FLANN multithreading support, it is required that Intel Threading Building Blocks is installed correctly
on your system. You can either get it from your package manager or from: \texttt{http://threadingbuildingblocks.org/}
You also need a pkgconfig file (tbb.pc) in one of the directories in your \texttt{PKG\_CONFIG\_PATH} and need to define
the \texttt{TBB} macro on compilation of your project (for example by adding \texttt{-DTBB} to the compiler options or
if using cmake by adding \texttt{add\_definitions(-DTBB)} to your \texttt{CMakeLists.txt}).
For taking advantage of multithreaded search, the project that uses FLANN needs to be compiled with a compiler that
supports the OpenMP standard and the OpenMP support must be enabled. The number of cores to be used can be selected with
the \texttt{cores} field in the \texttt{SearchParams} structure. By default a single core will be used.
Setting the \texttt{cores} field to zero will automatically use as many threads as cores available on the machine.
\section{Using FLANN}
......
......@@ -289,7 +289,7 @@ public:
/**
* Method that searches for nearest-neighbors
*/
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams)
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) const
{
// should not get here
assert(false);
......
......@@ -202,7 +202,7 @@ public:
/**
* \brief Method that searches for nearest-neighbours
*/
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams)
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) const
{
kmeans_index_->findNeighbors(result, vec, searchParams);
kdtree_index_->findNeighbors(result, vec, searchParams);
......
......@@ -303,13 +303,13 @@ public:
* searchParams = parameters that influence the search algorithm (checks)
*/
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams)
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) const
{
if (removed_) {
findNeighbors<true>(result, vec, searchParams);
findNeighborsWithRemoved<true>(result, vec, searchParams);
}
else {
findNeighbors<false>(result, vec, searchParams);
findNeighborsWithRemoved<false>(result, vec, searchParams);
}
}
......@@ -527,7 +527,7 @@ private:
template<bool with_removed>
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams)
void findNeighborsWithRemoved(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) const
{
int maxChecks = searchParams.checks;
......@@ -564,7 +564,7 @@ private:
template<bool with_removed>
void findNN(NodePtr node, ResultSet<DistanceType>& result, const ElementType* vec, int& checks, int maxChecks,
Heap<BranchSt>* heap, DynamicBitset& checked)
Heap<BranchSt>* heap, DynamicBitset& checked) const
{
if (node->childs.empty()) {
if (checks>=maxChecks) {
......
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved.
* Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef INDEX_ABSTRACTIONS_H
#define INDEX_ABSTRACTIONS_H
#include "flann/util/matrix.h"
#include "flann/util/params.h"
#include "flann/algorithms/dist.h"
namespace flann {
class IndexBase
{
public:
virtual ~IndexBase() {};
virtual size_t veclen() const = 0;
virtual size_t size() const = 0;
virtual flann_algorithm_t getType() const = 0;
virtual int usedMemory() const = 0;
virtual IndexParams getParameters() const = 0;
virtual void loadIndex(FILE* stream) = 0;
virtual void saveIndex(FILE* stream) = 0;
};
template<typename ElementType_, typename DistanceType_ = typename Accumulator<ElementType_>::Type>
class TypedIndexBase : public IndexBase
{
public:
typedef ElementType_ ElementType;
typedef DistanceType_ DistanceType;
virtual void buildIndex() = 0;
virtual void buildIndex(const Matrix<ElementType>& points) = 0;
virtual void addPoints(const Matrix<ElementType>& points, float rebuild_threshold) = 0;
virtual void removePoint(size_t index) = 0;
virtual int knnSearch(const Matrix<ElementType>& queries,
Matrix<size_t>& indices,
Matrix<DistanceType>& dists,
size_t knn,
const SearchParams& params) = 0;
virtual int knnSearch(const Matrix<ElementType>& queries,
std::vector< std::vector<size_t> >& indices,
std::vector<std::vector<DistanceType> >& dists,
size_t knn,
const SearchParams& params) = 0;
virtual int radiusSearch(const Matrix<ElementType>& queries,
Matrix<size_t>& indices,
Matrix<DistanceType>& dists,
DistanceType radius,
const SearchParams& params) = 0;
virtual int radiusSearch(const Matrix<ElementType>& queries,
std::vector< std::vector<size_t> >& indices,
std::vector<std::vector<DistanceType> >& dists,
DistanceType radius,
const SearchParams& params) = 0;
};
/**
* Class that wraps an index and makes it a polymorphic object.
*/
template<typename Index>
class IndexWrapper : public TypedIndexBase<typename Index::ElementType, typename Index::DistanceType>
{
public:
typedef typename Index::ElementType ElementType;
typedef typename Index::DistanceType DistanceType;
IndexWrapper(Index* index) : index_(index)
{
};
virtual ~IndexWrapper()
{
delete index_;
}
void buildIndex()
{
index_->buildIndex();
}
void buildIndex(const Matrix<ElementType>& points)
{
index_->buildIndex(points);
}
void addPoints(const Matrix<ElementType>& points, float rebuild_threshold = 2)
{
index_->addPoints(points, rebuild_threshold);
}
void removePoint(size_t index)
{
index_->removePoint(index);
}
size_t veclen() const
{
return index_->veclen();
}
size_t size() const
{
return index_->size();
}
flann_algorithm_t getType() const
{
return index_->getType();
}
int usedMemory() const
{
return index_->usedMemory();
}
IndexParams getParameters() const
{
return index_->getParameters();
}
void loadIndex(FILE* stream)
{
index_->loadIndex(stream);
}
void saveIndex(FILE* stream)
{
index_->saveIndex(stream);
}
Index* getIndex() const
{
return index_;
}
int knnSearch(const Matrix<ElementType>& queries,
Matrix<size_t>& indices,
Matrix<DistanceType>& dists,
size_t knn,
const SearchParams& params)
{
return index_->knnSearch(queries, indices,dists, knn, params);
}
int knnSearch(const Matrix<ElementType>& queries,
std::vector< std::vector<size_t> >& indices,
std::vector<std::vector<DistanceType> >& dists,
size_t knn,
const SearchParams& params)
{
return index_->knnSearch(queries, indices,dists, knn, params);
}
int radiusSearch(const Matrix<ElementType>& queries,
Matrix<size_t>& indices,
Matrix<DistanceType>& dists,
DistanceType radius,
const SearchParams& params)
{
return index_->radiusSearch(queries, indices, dists, radius, params);
}
int radiusSearch(const Matrix<ElementType>& queries,
std::vector< std::vector<size_t> >& indices,
std::vector<std::vector<DistanceType> >& dists,
DistanceType radius,
const SearchParams& params)
{
return index_->radiusSearch(queries, indices, dists, radius, params);
}
private:
Index* index_;
};
}
#endif
......@@ -197,7 +197,7 @@ public:
* \param[in] knn Number of nearest neighbors to return
* \param[in] params Search parameters
*/
int knnSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, size_t knn, const SearchParams& params)
int knnSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, size_t knn, const SearchParams& params) const
{
knnSearchGpu(queries,indices, dists, knn, params);
return knn*queries.rows; // hack...
......@@ -215,7 +215,7 @@ public:
std::vector< std::vector<int> >& indices,
std::vector<std::vector<DistanceType> >& dists,
size_t knn,
const SearchParams& params)
const SearchParams& params) const
{
knnSearchGpu(queries,indices, dists, knn, params);
return knn*queries.rows; // hack...
......@@ -229,13 +229,13 @@ public:
* \param[in] knn Number of nearest neighbors to return
* \param[in] params Search parameters
*/
void knnSearchGpu(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, size_t knn, const SearchParams& params);
void knnSearchGpu(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, size_t knn, const SearchParams& params) const;
int knnSearchGpu(const Matrix<ElementType>& queries,
std::vector< std::vector<int> >& indices,
std::vector<std::vector<DistanceType> >& dists,
size_t knn,
const SearchParams& params)
const SearchParams& params) const
{
flann::Matrix<int> ind( new int[knn*queries.rows], queries.rows,knn);
flann::Matrix<DistanceType> dist( new DistanceType[knn*queries.rows], queries.rows,knn);
......@@ -254,22 +254,22 @@ public:
}
int radiusSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists,
float radius, const SearchParams& params)
float radius, const SearchParams& params) const
{
return radiusSearchGpu(queries,indices, dists, radius, params);
}
int radiusSearch(const Matrix<ElementType>& queries, std::vector< std::vector<int> >& indices,
std::vector<std::vector<DistanceType> >& dists, float radius, const SearchParams& params)
std::vector<std::vector<DistanceType> >& dists, float radius, const SearchParams& params) const
{
return radiusSearchGpu(queries,indices, dists, radius, params);
}
int radiusSearchGpu(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists,
float radius, const SearchParams& params);
float radius, const SearchParams& params) const;
int radiusSearchGpu(const Matrix<ElementType>& queries, std::vector< std::vector<int> >& indices,
std::vector<std::vector<DistanceType> >& dists, float radius, const SearchParams& params);
std::vector<std::vector<DistanceType> >& dists, float radius, const SearchParams& params) const;
private:
......
......@@ -253,7 +253,7 @@ public:
* vec = the vector for which to search the nearest neighbors
* maxCheck = the maximum number of restarts (in a best-bin-first manner)
*/
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams)
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) const
{
int maxChecks = searchParams.checks;
float epsError = 1+searchParams.eps;
......@@ -524,7 +524,7 @@ private:
* traversal of the tree.
*/
template<bool with_removed>
void getExactNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, float epsError)
void getExactNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, float epsError) const
{
// checkID -= 1; /* Set a different unique ID for each search. */
......@@ -542,7 +542,7 @@ private:
* the tree.
*/
template<bool with_removed>
void getNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, int maxCheck, float epsError)
void getNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, int maxCheck, float epsError) const
{
int i;
BranchSt branch;
......@@ -572,7 +572,7 @@ private:
*/
template<bool with_removed>
void searchLevel(ResultSet<DistanceType>& result_set, const ElementType* vec, NodePtr node, DistanceType mindist, int& checkCount, int maxCheck,
float epsError, Heap<BranchSt>* heap, DynamicBitset& checked)
float epsError, Heap<BranchSt>* heap, DynamicBitset& checked) const
{
if (result_set.worstDist()<mindist) {
// printf("Ignoring branch, too far\n");
......@@ -623,7 +623,7 @@ private:
* Performs an exact search in the tree starting from a node.
*/
template<bool with_removed>
void searchLevelExact(ResultSet<DistanceType>& result_set, const ElementType* vec, const NodePtr node, DistanceType mindist, const float epsError)
void searchLevelExact(ResultSet<DistanceType>& result_set, const ElementType* vec, const NodePtr node, DistanceType mindist, const float epsError) const
{
/* If this is a leaf node, then do check and return. */
if ((node->child1 == NULL)&&(node->child2 == NULL)) {
......
......@@ -242,7 +242,7 @@ public:
* vec = the vector for which to search the nearest neighbors
* maxCheck = the maximum number of restarts (in a best-bin-first manner)
*/
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams)
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) const
{
float epsError = 1+searchParams.eps;
......@@ -569,7 +569,7 @@ private:
lim2 = left;
}
DistanceType computeInitialDistances(const ElementType* vec, std::vector<DistanceType>& dists)
DistanceType computeInitialDistances(const ElementType* vec, std::vector<DistanceType>& dists) const
{
DistanceType distsq = 0.0;
......@@ -592,7 +592,7 @@ private:
*/
template <bool with_removed>
void searchLevel(ResultSet<DistanceType>& result_set, const ElementType* vec, const NodePtr node, DistanceType mindistsq,
std::vector<DistanceType>& dists, const float epsError)
std::vector<DistanceType>& dists, const float epsError) const
{
/* If this is a leaf node, then do check and return. */
if ((node->child1 == NULL)&&(node->child2 == NULL)) {
......
......@@ -308,13 +308,13 @@ public:
* searchParams = parameters that influence the search algorithm (checks, cb_index)
*/
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams)
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) const
{
if (removed_) {
findNeighbors<true>(result, vec, searchParams);
findNeighborsWithRemoved<true>(result, vec, searchParams);
}
else {
findNeighbors<false>(result, vec, searchParams);
findNeighborsWithRemoved<false>(result, vec, searchParams);
}
}
......@@ -718,7 +718,7 @@ private:
template<bool with_removed>
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams)
void findNeighborsWithRemoved(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) const
{
int maxChecks = searchParams.checks;
......@@ -759,7 +759,7 @@ private:
template<bool with_removed>
void findNN(NodePtr node, ResultSet<DistanceType>& result, const ElementType* vec, int& checks, int maxChecks,
Heap<BranchSt>* heap)
Heap<BranchSt>* heap) const
{
// Ignore those clusters that are too far away
{
......@@ -805,7 +805,7 @@ private:
* distances = array with the distances to each child node.
* Returns:
*/
int exploreNodeBranches(NodePtr node, const ElementType* q, Heap<BranchSt>* heap)
int exploreNodeBranches(NodePtr node, const ElementType* q, Heap<BranchSt>* heap) const
{
std::vector<DistanceType> domain_distances(branching_);
int best_index = 0;
......@@ -838,7 +838,7 @@ private:
* Function the performs exact nearest neighbor search by traversing the entire tree.
*/
template<bool with_removed>
void findExactNN(NodePtr node, ResultSet<DistanceType>& result, const ElementType* vec)
void findExactNN(NodePtr node, ResultSet<DistanceType>& result, const ElementType* vec) const
{
// Ignore those clusters that are too far away
{
......@@ -883,7 +883,7 @@ private:
*
* I computes the order in which to traverse the child nodes of a particular node.
*/
void getCenterOrdering(NodePtr node, const ElementType* q, std::vector<int>& sort_indices)
void getCenterOrdering(NodePtr node, const ElementType* q, std::vector<int>& sort_indices) const
{
std::vector<DistanceType> domain_distances(branching_);
for (int i=0; i<branching_; ++i) {
......@@ -905,7 +905,7 @@ private:
* from inside region with center c to the border between this
* region and the region with center p
*/
DistanceType getDistanceToBorder(DistanceType* p, DistanceType* c, DistanceType* q)
DistanceType getDistanceToBorder(DistanceType* p, DistanceType* c, DistanceType* q) const
{
DistanceType sum = 0;
DistanceType sum2 = 0;
......@@ -929,7 +929,7 @@ private:
* varianceValue = variance of the clustering (return value)
* Returns:
*/
int getMinVarianceClusters(NodePtr root, std::vector<NodePtr>& clusters, int clusters_length, DistanceType& varianceValue)
int getMinVarianceClusters(NodePtr root, std::vector<NodePtr>& clusters, int clusters_length, DistanceType& varianceValue) const
{
int clusterCount = 1;
clusters[0] = root;
......
......@@ -133,7 +133,7 @@ public:
la & *this;
}
void findNeighbors(ResultSet<DistanceType>& resultSet, const ElementType* vec, const SearchParams& /*searchParams*/)
void findNeighbors(ResultSet<DistanceType>& resultSet, const ElementType* vec, const SearchParams& /*searchParams*/) const
{
if (removed_) {
for (size_t i = 0; i < points_.size(); ++i) {
......
......@@ -251,7 +251,7 @@ public:
Matrix<size_t>& indices,
Matrix<DistanceType>& dists,
size_t knn,
const SearchParams& params)
const SearchParams& params) const
{
assert(queries.cols == veclen_);
assert(indices.rows >= queries.rows);
......@@ -298,7 +298,7 @@ public:
std::vector< std::vector<size_t> >& indices,
std::vector<std::vector<DistanceType> >& dists,
size_t knn,
const SearchParams& params)
const SearchParams& params) const
{
assert(queries.cols == veclen_);
if (indices.size() < queries.rows ) indices.resize(queries.rows);
......@@ -348,7 +348,7 @@ public:
* vec = the vector for which to search the nearest neighbors
* maxCheck = the maximum number of restarts (in a best-bin-first manner)
*/
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& /*searchParams*/)
void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& /*searchParams*/) const
{
getNeighbors(vec, result);
}
......@@ -469,7 +469,7 @@ private:
* This is a slower version than the above as it uses the ResultSet
* @param vec the feature to analyze
*/
void getNeighbors(const ElementType* vec, ResultSet<DistanceType>& result)
void getNeighbors(const ElementType* vec, ResultSet<DistanceType>& result) const
{
typename std::vector<lsh::LshTable<ElementType> >::const_iterator table = tables_.begin();
typename std::vector<lsh::LshTable<ElementType> >::const_iterator table_end = tables_.end();
......
此差异已折叠。
......@@ -336,11 +336,6 @@ FLANN_EXPORT int flann_find_nearest_neighbors_index_int(flann_index_t index_id,
* (the same way as for the KNN search). A lower value for checks will give
* a higher search speedup at the cost of potentially not returning all the
* neighbours in the specified radius.
*
* The cores parameter in the FLANNParameters below sets the number of cores
* that will be used for the radius search, in case Intel TBB is present on
* the system and FLANN is built with multicore support on. Auto core selection
* can be achieved by setting the number of cores to -1.
*/
FLANN_EXPORT int flann_radius_search(flann_index_t index_ptr, /* the index */
float* query, /* query point */
......
......@@ -206,7 +206,7 @@ public:
Matrix<size_t>& indices,
Matrix<DistanceType>& dists,
size_t knn,
const SearchParams& params)
const SearchParams& params) const
{
return nnIndex_->knnSearch(queries, indices, dists, knn, params);
}
......@@ -224,7 +224,7 @@ public:
Matrix<int>& indices,
Matrix<DistanceType>& dists,
size_t knn,
const SearchParams& params)
const SearchParams& params) const
{
return nnIndex_->knnSearch(queries, indices, dists, knn, params);
}
......@@ -259,7 +259,7 @@ public:
std::vector< std::vector<int> >& indices,
std::vector<std::vector<DistanceType> >& dists,
size_t knn,
const SearchParams& params)
const SearchParams& params) const
{
return nnIndex_->knnSearch(queries, indices, dists, knn, params);
}
......@@ -277,7 +277,7 @@ public:
Matrix<size_t>& indices,
Matrix<DistanceType>& dists,
float radius,
const SearchParams& params)
const SearchParams& params) const
{
return nnIndex_->radiusSearch(queries, indices, dists, radius, params);
}
......@@ -295,7 +295,7 @@ public:
Matrix<int>& indices,
Matrix<DistanceType>& dists,
float radius,
const SearchParams& params)
const SearchParams& params) const
{
return nnIndex_->radiusSearch(queries, indices, dists, radius, params);
}
......@@ -313,7 +313,7 @@ public:
std::vector< std::vector<size_t> >& indices,
std::vector<std::vector<DistanceType> >& dists,
float radius,
const SearchParams& params)
const SearchParams& params) const
{
return nnIndex_->radiusSearch(queries, indices, dists, radius, params);
}
......@@ -331,7 +331,7 @@ public:
std::vector< std::vector<int> >& indices,
std::vector<std::vector<DistanceType> >& dists,
float radius,
const SearchParams& params)
const SearchParams& params) const
{
return nnIndex_->radiusSearch(queries, indices, dists, radius, params);
}
......
/***********************************************************************
* Software License Agreement (BSD License)
*
* Copyright 2010-2011 Nick Vanbaelen (nickon@acm.org). All rights reserved.
*
* THE BSD LICENSE
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*************************************************************************/
#ifndef FLANN_TBB_BODIES_H
#define FLANN_TBB_BODIES_H
#include <tbb/blocked_range.h>
#include <tbb/atomic.h>
#include "flann/util/matrix.h"
#include "flann/util/params.h"
#include "flann/util/result_set.h"
namespace flann
{
template <typename Distance> class NNIndex;
template<typename Distance>
class parallel_knnSearch
{
public:
typedef typename Distance::ElementType ElementType;
typedef typename Distance::ResultType DistanceType;
parallel_knnSearch(const Matrix<ElementType>& queries,
Matrix<size_t>& indices,
Matrix<DistanceType>& distances,
size_t knn,
const SearchParams& params,
NNIndex<Distance>* index,
tbb::atomic<int>& count)
: queries_(queries),
indices_(indices),
distances_(distances),
knn_(knn),
params_(params),
index_(index),
count_(count)
{}
/* default destructor will do */
/* default copy constructor will do,
parallel for will use this to create a separate parallel_knnSearch object
for each worker thread (pointers will be copied, which is OK) */
/**
* Perform knnSearch for the query points assigned to this worker thread
* \param r query point range assigned for this worker thread to operate on
*/
void operator()( const tbb::blocked_range<size_t>& r ) const
{
if (params_.use_heap==FLANN_True)
{
KNNResultSet2<DistanceType> resultSet(knn_);
for (size_t i=r.begin(); i!=r.end(); ++i)
{
resultSet.clear();
index_->findNeighbors(resultSet, queries_[i], params_);
resultSet.copy(indices_[i], distances_[i], knn_, params_.sorted);
count_ += resultSet.size();
}
}
else
{
KNNSimpleResultSet<DistanceType> resultSet(knn_);
for (size_t i=r.begin(); i!=r.end(); ++i)
{
resultSet.clear();
index_->findNeighbors(resultSet, queries_[i], params_);
resultSet.copy(indices_[i], distances_[i], knn_, params_.sorted);
count_ += resultSet.size();
}
}
}
private:
//! All query points to perform search on
//! \note each worker thread only operates on a specified range
const Matrix<ElementType>& queries_;
//! Matrix for storing the indices of the nearest neighbors
//! \note no need for this to be a parallel container, each worker thread
//! solely operates on its specified range!
Matrix<size_t>& indices_;
//! Matrix for storing the distances to the nearest neighbors
//! \note no need for this to be a parallel container, each worker thread
//! solely operates on its specified range!
Matrix<DistanceType>& distances_;
//! Number of nearest neighbors to search for
size_t knn_;
//! The search parameters to take into account
const SearchParams& params_;
//! The nearest neighbor index to perform the search with
NNIndex<Distance>* index_;
//! Atomic count variable to keep track of the number of neighbors found
//! \note must be mutable because body will be casted as const in parallel_for
tbb::atomic<int>& count_;
};
template<typename Distance>
class parallel_knnSearch2
{
public:
typedef typename Distance::ElementType ElementType;
typedef typename Distance::ResultType DistanceType;
parallel_knnSearch2(const Matrix<ElementType>& queries,
std::vector< std::vector<size_t> >& indices,
std::vector<std::vector<DistanceType> >& distances,
size_t knn,
const SearchParams& params,
NNIndex<Distance>* index,
tbb::atomic<int>& count)
: queries_(queries),
indices_(indices),
distances_(distances),
knn_(knn),
params_(params),
index_(index),
count_(count)
{}
/* default destructor will do */
/* default copy constructor will do,
parallel for will use this to create a separate parallel_knnSearch object
for each worker thread (pointers will be copied, which is OK) */
/**
* Perform knnSearch for the query points assigned to this worker thread
* (specified by the blocked_range parameter)
*/
void operator()( const tbb::blocked_range<size_t>& r ) const
{
if (params_.use_heap==FLANN_True) {
KNNResultSet2<DistanceType> resultSet(knn_);
for (size_t i=r.begin(); i!=r.end(); ++i)
{
resultSet.clear();
index_->findNeighbors(resultSet, queries_[i], params_);
size_t n = std::min(resultSet.size(), knn_);
indices_[i].resize(n);
distances_[i].resize(n);
if (n>0) {
resultSet.copy(&indices_[i][0], &distances_[i][0], n, params_.sorted);
}
count_ += n;
}
}
else {
KNNSimpleResultSet<DistanceType> resultSet(knn_);
for (size_t i=r.begin(); i!=r.end(); ++i)
{
resultSet.clear();
index_->findNeighbors(resultSet, queries_[i], params_);
size_t n = std::min(resultSet.size(), knn_);
indices_[i].resize(n);
distances_[i].resize(n);
if (n>0) {
resultSet.copy(&indices_[i][0], &distances_[i][0], n, params_.sorted);
}
count_ += n;
}
}
}
private:
//! All query points to perform search on
//! \note each worker thread only operates on a specified range
const Matrix<ElementType>& queries_;
//! Vector for storing the indices of the nearest neighbors
//! \note no need for this to be a parallel container, each worker thread
//! solely operates on its specified range!
std::vector< std::vector<size_t> >& indices_;
//! Vector for storing the distances to the nearest neighbors
//! \note no need for this to be a parallel container, each worker thread
//! solely operates on its specified range!
std::vector< std::vector<DistanceType> >& distances_;
//! Number of nearest neighbors to search for
size_t knn_;
//! The search parameters to take into account
const SearchParams& params_;
//! The nearest neighbor index to perform the search with
NNIndex<Distance>* index_;
//! Atomic count variable to keep track of the number of neighbors found
//! \note must be mutable because body will be casted as const in parallel_for
tbb::atomic<int>& count_;
};
template<typename Distance>
class parallel_radiusSearch
{
public:
typedef typename Distance::ElementType ElementType;
typedef typename Distance::ResultType DistanceType;
/* default destructor will do */
/* default copy constructor will do,
parallel for will use this to create a separate parallel_knnSearch object
for each worker thread (pointers will be copied, which is OK) */
/**
* Perform radiusSearch for the query points assigned to this worker thread
* (specified by the blocked_range parameter)
*/
parallel_radiusSearch(const Matrix<ElementType>& queries,
Matrix<size_t>& indices,
Matrix<DistanceType>& distances,
float radius,
const SearchParams& params,
NNIndex<Distance>* index,
tbb::atomic<int>& count)
: queries_(queries),
indices_(indices),
distances_(distances),
radius_(radius),
params_(params),
index_(index),
count_(count)
{}
void operator()( const tbb::blocked_range<size_t>& r ) const
{
size_t num_neighbors = std::min(indices_.cols, distances_.cols);
int max_neighbors = params_.max_neighbors;
if (max_neighbors<0) max_neighbors = num_neighbors;
else max_neighbors = std::min(max_neighbors,(int)num_neighbors);
if (max_neighbors==0) {
CountRadiusResultSet<DistanceType> resultSet(radius_);
for (size_t i=r.begin(); i!=r.end(); ++i)
{
resultSet.clear();
index_->findNeighbors(resultSet, queries_[i], params_);
count_ += resultSet.size();
}
}
else {
// explicitly indicated to use unbounded radius result set
// or we know there'll be enough room for resulting indices and dists
if (params_.max_neighbors<0 && (num_neighbors>= index_->size())) {
RadiusResultSet<DistanceType> resultSet(radius_);
for (size_t i=r.begin(); i!=r.end(); ++i)
{
resultSet.clear();
index_->findNeighbors(resultSet, queries_[i], params_);
size_t n = resultSet.size();
count_ += n;
if (n>num_neighbors) n = num_neighbors;
resultSet.copy(indices_[i], distances_[i], n, params_.sorted);
// mark the next element in the output buffers as unused
if (n<indices_.cols) indices_[i][n] = -1;
if (n<distances_.cols) distances_[i][n] = std::numeric_limits<DistanceType>::infinity();
}
}
else {
// number of neighbors limited to max_neighbors
KNNRadiusResultSet<DistanceType> resultSet(radius_, max_neighbors);
for (size_t i=r.begin(); i!=r.end(); ++i)
{
resultSet.clear();
index_->findNeighbors(resultSet, queries_[i], params_);
size_t n = resultSet.size();
count_ += n ;
if ((int)n>max_neighbors) n = max_neighbors;
resultSet.copy(indices_[i], distances_[i], n, params_.sorted);
// mark the next element in the output buffers as unused
if (n<indices_.cols) indices_[i][n] = -1;
if (n<distances_.cols) distances_[i][n] = std::numeric_limits<DistanceType>::infinity();
}
}
}
}
private:
//! All query points to perform search on
//! \note each worker thread only operates on a specified range
const Matrix<ElementType>& queries_;
//! Matrix for storing the indices of the nearest neighbors
//! \note no need for this to be a parallel container, each worker thread
//! solely operates on its specified range!
Matrix<size_t>& indices_;
//! Matrix for storing the distances to the nearest neighbors
//! \note no need for this to be a parallel container, each worker thread
//! solely operates on its specified range!
Matrix<DistanceType>& distances_;
//! Radius size bound on the search for nearest neighbors
float radius_;
//! The search parameters to take into account
const SearchParams& params_;
//! The nearest neighbor index to perform the search with
NNIndex<Distance>* index_;
//! Atomic count variable to keep track of the number of neighbors found
//! \note must be mutable because body will be casted as const in parallel_for
tbb::atomic<int>& count_;
};
template<typename Distance>
class parallel_radiusSearch2
{
public:
typedef typename Distance::ElementType ElementType;
typedef typename Distance::ResultType DistanceType;
/* default destructor will do */
/* default copy constructor will do,
parallel for will use this to create a separate parallel_knnSearch object
for each worker thread (pointers will be copied, which is OK) */
/**
* Perform radiusSearch for the query points assigned to this worker thread
* (specified by the blocked_range parameter)
*/
parallel_radiusSearch2(const Matrix<ElementType>& queries,
std::vector< std::vector<size_t> >& indices,
std::vector<std::vector<DistanceType> >& distances,
float radius,
const SearchParams& params,
NNIndex<Distance>* index,
tbb::atomic<int>& count)
: queries_(queries),
indices_(indices),
distances_(distances),
radius_(radius),
params_(params),
index_(index),
count_(count)
{}
void operator()( const tbb::blocked_range<size_t>& r ) const
{
int max_neighbors = params_.max_neighbors;
// just count neighbors
if (max_neighbors==0) {
CountRadiusResultSet<DistanceType> resultSet(radius_);
for (size_t i=r.begin(); i!=r.end(); ++i)
{
resultSet.clear();
index_->findNeighbors(resultSet, queries_[i], params_);
count_ += resultSet.size();
}
}
else {
if (indices_.size() < queries_.rows ) indices_.resize(queries_.rows);
if (distances_.size() < queries_.rows ) distances_.resize(queries_.rows);
if (max_neighbors<0) {
// search for all neighbors
RadiusResultSet<DistanceType> resultSet(radius_);
for (size_t i=r.begin(); i!=r.end(); ++i)
{
resultSet.clear();
index_->findNeighbors(resultSet, queries_[i], params_);
size_t n = resultSet.size();
count_ += n;
indices_[i].resize(n);
distances_[i].resize(n);
if (n>0) {
resultSet.copy(&indices_[i][0], &distances_[i][0], n, params_.sorted);
}
}
}
else {
// number of neighbors limited to max_neighbors
KNNRadiusResultSet<DistanceType> resultSet(radius_, params_.max_neighbors);
for (size_t i=r.begin(); i!=r.end(); ++i)
{
resultSet.clear();
index_->findNeighbors(resultSet, queries_[i], params_);
size_t n = resultSet.size();
count_ += n;
if ((int)n>max_neighbors) n = max_neighbors;
indices_[i].resize(n);
distances_[i].resize(n);
if (n>0) {
resultSet.copy(&indices_[i][0], &distances_[i][0], n, params_.sorted);
}
}
}
}
}
private:
//! All query points to perform search on
//! \note each worker thread only operates on a specified range
const Matrix<ElementType>& queries_;
//! Vector for storing the indices of the nearest neighbors
//! \note no need for this to be a parallel container, each worker thread
//! solely operates on its specified range!
std::vector< std::vector<size_t> >& indices_;
//! Vector for storing the distances to the nearest neighbors
//! \note no need for this to be a parallel container, each worker thread
//! solely operates on its specified range!
std::vector< std::vector<DistanceType> >& distances_;
//! Radius size bound on the search for nearest neighbors
float radius_;
//! The search parameters to take into account
const SearchParams& params_;
//! The nearest neighbor index to perform the search with
NNIndex<Distance>* index_;
//! Atomic count variable to keep track of the number of neighbors found
//! \note must be mutable because body will be casted as const in parallel_for
tbb::atomic<int>& count_;
};
}
#endif //FLANN_TBB_BODIES_H
......@@ -79,8 +79,7 @@ struct SearchParams
int max_neighbors;
// use a heap to manage the result set (default: FLANN_Undefined)
tri_type use_heap;
// how many cores to assign to the search
// this parameter will be ignored if Intel TBB isn't available on the system or no "TBB" macro is defined
// how many cores to assign to the search (used only if compiled with OpenMP capable compiler) (0 for auto)
int cores;
// for GPU search indicates if matrices are already in GPU ram
bool matrices_in_gpu_ram;
......
......@@ -10,10 +10,6 @@ add_dependencies(test tests)
set(EXECUTABLE_OUTPUT_PATH ${TEST_OUTPUT_PATH})
#add_executable(flann_mt_test flann_mt_test.cpp)
#find_package(Boost COMPONENTS system thread REQUIRED)
#target_link_libraries(flann_mt_test ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} flann)
if (PYTHON_EXECUTABLE)
flann_download_test_data(sift10K.h5 0964a910946d2dd5fe28337507a8abc3)
flann_download_test_data(sift10K_byte.h5 f835e0148df4618a81f67febfda2b4d0)
......@@ -25,34 +21,38 @@ endif()
if (GTEST_FOUND AND HDF5_FOUND)
include_directories(${HDF5_INCLUDE_DIR})
flann_add_gtest(flann_linear_test flann_linear_test.cpp)
set(TEST_LIBRARIES "${HDF5_LIBRARIES}")
if (HDF5_IS_PARALLEL)
set(TEST_LINK_LIBRARIES "${TEST_LIBRARIES} ${MPI_LIBRARIES}")
endif()
flann_add_gtest(flann_linear_test flann_linear_test.cpp)
target_link_libraries(flann_linear_test flann_cpp ${TEST_LIBRARIES})
flann_add_gtest(flann_kdtree_test flann_kdtree_test.cpp)
target_link_libraries(flann_kdtree_test flann_cpp ${TEST_LIBRARIES})
flann_add_gtest(flann_kmeans_test flann_kmeans_test.cpp)
target_link_libraries(flann_kmeans_test flann_cpp ${TEST_LIBRARIES})
flann_add_gtest(flann_kdtree_single_test flann_kdtree_single_test.cpp)
target_link_libraries(flann_kdtree_single_test flann_cpp ${TEST_LIBRARIES})
flann_add_gtest(flann_hierarchical_test flann_hierarchical_test.cpp)
target_link_libraries(flann_hierarchical_test flann_cpp ${TEST_LIBRARIES})
flann_add_gtest(flann_lsh_test flann_lsh_test.cpp)
flann_add_gtest(flann_autotuned_test flann_autotuned_test.cpp)
if(TBB_FOUND)
add_definitions(-DTBB)
target_link_libraries(flann_lsh_test flann_cpp ${TEST_LIBRARIES})
flann_add_gtest(flann_autotuned_test flann_autotuned_test.cpp)
target_link_libraries(flann_autotuned_test flann_cpp ${TEST_LIBRARIES})
if (OPENMP_FOUND)
flann_add_gtest(flann_multithreaded_test flann_multithreaded_test.cpp)
target_link_libraries(flann_multithreaded_test ${TBB_LIBRARIES})
endif()
target_link_libraries(flann_linear_test flann_cpp ${HDF5_LIBRARIES})
target_link_libraries(flann_kdtree_test flann_cpp ${HDF5_LIBRARIES})
target_link_libraries(flann_kmeans_test flann_cpp ${HDF5_LIBRARIES})
target_link_libraries(flann_kdtree_single_test flann_cpp ${HDF5_LIBRARIES})
target_link_libraries(flann_hierarchical_test flann_cpp ${HDF5_LIBRARIES})
target_link_libraries(flann_lsh_test flann_cpp ${HDF5_LIBRARIES})
target_link_libraries(flann_autotuned_test flann_cpp ${HDF5_LIBRARIES})
if(TBB_FOUND)
target_link_libraries(flann_multithreaded_test flann_cpp ${HDF5_LIBRARIES})
endif()
if (HDF5_IS_PARALLEL)
target_link_libraries(flann_simple_test ${MPI_LIBRARIES})
if(TBB_FOUND)
target_link_libraries(flann_multithreaded_test ${MPI_LIBRARIES})
endif()
target_link_libraries(flann_multithreaded_test flann_cpp ${TEST_LIBRARIES})
endif()
endif()
if (GTEST_FOUND AND HDF5_FOUND AND BUILD_CUDA_LIB)
......@@ -62,7 +62,6 @@ if (GTEST_FOUND AND HDF5_FOUND AND BUILD_CUDA_LIB)
endif()
flann_add_cuda_gtest(flann_cuda_test flann_cuda_test.cu)
target_link_libraries(flann_cuda_test flann_cpp ${HDF5_LIBRARIES} flann_cuda)
endif()
#---------- pyunit tests --------------
......
......@@ -7,7 +7,8 @@
using namespace flann;
float compute_precision(const flann::Matrix<int>& match, const flann::Matrix<int>& indices)
template<typename T>
float compute_precision(const flann::Matrix<T>& match, const flann::Matrix<T>& indices)
{
int count = 0;
......@@ -29,7 +30,7 @@ float compute_precision(const flann::Matrix<int>& match, const flann::Matrix<int
class FLANNTestFixture : public ::testing::Test {
protected:
clock_t start_time_;
timespec ts_;
void start_timer(const std::string& message = "")
{
......@@ -37,12 +38,14 @@ protected:
printf("%s", message.c_str());
fflush(stdout);
}
start_time_ = clock();
clock_gettime(CLOCK_REALTIME, &ts_);
}
double stop_timer()
{
return double(clock()-start_time_)/CLOCKS_PER_SEC;
timespec ts2;
clock_gettime(CLOCK_REALTIME, &ts2);
return double((ts2.tv_sec-ts_.tv_sec)+(ts2.tv_nsec-ts_.tv_nsec)/1e9);
}
};
......@@ -51,45 +54,44 @@ protected:
/* Test Fixture which loads the cloud.h5 cloud as data and query matrix */
class FlannTest : public FLANNTestFixture {
protected:
flann::Matrix<float> data;
flann::Matrix<float> query;
flann::Matrix<int> match;
flann::Matrix<float> dists;
flann::Matrix<int> indices;
flann::Matrix<float> data_;
flann::Matrix<float> query_;
flann::Matrix<size_t> match_;
flann::Matrix<float> dists_;
flann::Matrix<size_t> indices_;
int nn;
int knn_;
void SetUp()
{
nn = 5;
knn_ = 5;
printf("Reading test data...");
fflush(stdout);
flann::load_from_file(data, "cloud.h5","dataset");
flann::load_from_file(query,"cloud.h5","query");
flann::load_from_file(match,"cloud.h5","match");
flann::load_from_file(data_, "cloud.h5","dataset");
flann::load_from_file(query_,"cloud.h5","query");
flann::load_from_file(match_,"cloud.h5","match");
dists = flann::Matrix<float>(new float[query.rows*nn], query.rows, nn);
indices = flann::Matrix<int>(new int[query.rows*nn], query.rows, nn);
dists_ = flann::Matrix<float>(new float[query_.rows*knn_], query_.rows, knn_);
indices_ = flann::Matrix<size_t>(new size_t[query_.rows*knn_], query_.rows, knn_);
printf("done\n");
}
void TearDown()
{
delete[] data.ptr();
delete[] query.ptr();
delete[] match.ptr();
delete[] dists.ptr();
delete[] indices.ptr();
delete[] data_.ptr();
delete[] query_.ptr();
delete[] match_.ptr();
delete[] dists_.ptr();
delete[] indices_.ptr();
}
int GetNN() { return nn; }
};
TEST_F(FlannTest, HandlesSingleCoreSearch)
{
flann::Index<L2_Simple<float> > index(data, flann::KDTreeSingleIndexParams(50, false));
flann::Index<L2_Simple<float> > index(data_, flann::KDTreeSingleIndexParams(50, false));
start_timer("Building kd-tree index...");
index.buildIndex();
printf("done (%g seconds)\n", stop_timer());
......@@ -102,17 +104,17 @@ TEST_F(FlannTest, HandlesSingleCoreSearch)
start_timer("Searching KNN...");
SearchParams params(checks,eps,sorted);
params.cores = cores;
index.knnSearch(query, indices, dists, GetNN(), params);
index.knnSearch(query_, indices_, dists_, knn_, params);
printf("done (%g seconds)\n", stop_timer());
float precision = compute_precision(match, indices);
float precision = compute_precision(match_, indices_);
EXPECT_GE(precision, 0.99);
printf("Precision: %g\n", precision);
}
TEST_F(FlannTest, HandlesMultiCoreSearch)
{
flann::Index<L2_Simple<float> > index(data, flann::KDTreeSingleIndexParams(50, false));
flann::Index<L2_Simple<float> > index(data_, flann::KDTreeSingleIndexParams(50, false));
start_timer("Building kd-tree index...");
index.buildIndex();
printf("done (%g seconds)\n", stop_timer());
......@@ -125,10 +127,10 @@ TEST_F(FlannTest, HandlesMultiCoreSearch)
start_timer("Searching KNN...");
SearchParams params(checks,eps,sorted);
params.cores = cores;
index.knnSearch(query, indices, dists, GetNN(), params);
index.knnSearch(query_, indices_, dists_, knn_, params);
printf("done (%g seconds)\n", stop_timer());
float precision = compute_precision(match, indices);
float precision = compute_precision(match_, indices_);
EXPECT_GE(precision, 0.99);
printf("Precision: %g\n", precision);
}
......@@ -138,217 +140,167 @@ TEST_F(FlannTest, HandlesMultiCoreSearch)
and indices matrices for comparing single and multi core KNN search */
class FlannCompareKnnTest : public FLANNTestFixture {
protected:
flann::Matrix<float> data;
flann::Matrix<float> query;
flann::Matrix<float> dists_single;
flann::Matrix<int> indices_single;
flann::Matrix<float> dists_multi;
flann::Matrix<int> indices_multi;
flann::Matrix<float> data_;
flann::Matrix<float> query_;
flann::Matrix<float> dists_single_;
flann::Matrix<size_t> indices_single_;
flann::Matrix<float> dists_multi_;
flann::Matrix<size_t> indices_multi_;
int nn;
int knn_;
void SetUp()
{
nn = 5;
knn_ = 5;
printf("Reading test data...");
fflush(stdout);
flann::load_from_file(data, "cloud.h5","dataset");
flann::load_from_file(query,"cloud.h5","query");
flann::load_from_file(data_, "cloud.h5","dataset");
flann::load_from_file(query_,"cloud.h5","query");
dists_single = flann::Matrix<float>(new float[query.rows*nn], query.rows, nn);
indices_single = flann::Matrix<int>(new int[query.rows*nn], query.rows, nn);
dists_multi = flann::Matrix<float>(new float[query.rows*nn], query.rows, nn);
indices_multi = flann::Matrix<int>(new int[query.rows*nn], query.rows, nn);
dists_single_ = flann::Matrix<float>(new float[query_.rows*knn_], query_.rows, knn_);
indices_single_ = flann::Matrix<size_t>(new size_t[query_.rows*knn_], query_.rows, knn_);
dists_multi_ = flann::Matrix<float>(new float[query_.rows*knn_], query_.rows, knn_);
indices_multi_ = flann::Matrix<size_t>(new size_t[query_.rows*knn_], query_.rows, knn_);
printf("done\n");
}
void TearDown()
{
delete[] data.ptr();
delete[] query.ptr();
delete[] dists_single.ptr();
delete[] indices_single.ptr();
delete[] dists_multi.ptr();
delete[] indices_multi.ptr();
delete[] data_.ptr();
delete[] query_.ptr();
delete[] dists_single_.ptr();
delete[] indices_single_.ptr();
delete[] dists_multi_.ptr();
delete[] indices_multi_.ptr();
}
int GetNN() { return nn; }
};
TEST_F(FlannCompareKnnTest, CompareMultiSingleCoreKnnSearchSorted)
{
flann::Index<L2_Simple<float> > index(data, flann::KDTreeSingleIndexParams(50, false));
start_timer("Building kd-tree index...");
index.buildIndex();
printf("done (%g seconds)\n", stop_timer());
int checks = -1;
float eps = 0.0f;
bool sorted = true;
int single_core = 1;
int multi_core = -1;
start_timer("Searching KNN (single core)...");
SearchParams params(checks,eps,sorted);
params.cores = single_core;
int single_neighbor_count = index.knnSearch(query, indices_single, dists_single, GetNN(), params);
printf("done (%g seconds)\n", stop_timer());
start_timer("Searching KNN (multi core)...");
params.cores = multi_core;
int multi_neighbor_count = index.knnSearch(query, indices_multi, dists_multi, GetNN(), params);
printf("done (%g seconds)\n", stop_timer());
EXPECT_EQ(single_neighbor_count, multi_neighbor_count);
float precision = compute_precision(indices_single, indices_multi);
EXPECT_GE(precision, 0.99);
printf("Precision: %g\n", precision);
}
TEST_F(FlannCompareKnnTest, CompareMultiSingleCoreKnnSearchUnsorted)
TEST_F(FlannCompareKnnTest, CompareMultiSingleCoreKnnSearch)
{
flann::Index<L2_Simple<float> > index(data, flann::KDTreeSingleIndexParams(50, false));
flann::Index<L2_Simple<float> > index(data_, flann::KDTreeSingleIndexParams(50, false));
start_timer("Building kd-tree index...");
index.buildIndex();
printf("done (%g seconds)\n", stop_timer());
int checks = -1;
float eps = 0.0f;
bool sorted = false;
int single_core = 1;
int multi_core = -1;
SearchParams params;
params.checks = -1;
params.eps = 0.0f;
params.sorted = true;
start_timer("Searching KNN (single core)...");
SearchParams params(checks,eps,sorted);
params.cores = single_core;
int single_neighbor_count = index.knnSearch(query, indices_single, dists_single, GetNN(), params);
params.cores = 1;
int single_neighbor_count = index.knnSearch(query_, indices_single_, dists_single_, knn_, params);
printf("done (%g seconds)\n", stop_timer());
start_timer("Searching KNN (multi core)...");
params.cores = multi_core;
int multi_neighbor_count = index.knnSearch(query, indices_multi, dists_multi, GetNN(), params);
params.cores = 0;
int multi_neighbor_count = index.knnSearch(query_, indices_multi_, dists_multi_, knn_, params);
printf("done (%g seconds)\n", stop_timer());
EXPECT_EQ(single_neighbor_count, multi_neighbor_count);
float precision = compute_precision(indices_single, indices_multi);
printf("Checking results...\n");
float precision = compute_precision(indices_single_, indices_multi_);
EXPECT_GE(precision, 0.99);
printf("Precision: %g\n", precision);
}
/* Test Fixture which loads the cloud.h5 cloud as data and query matrix and holds two dists
and indices matrices for comparing single and multi core radius search */
class FlannCompareRadiusTest : public FLANNTestFixture {
protected:
flann::Matrix<float> data;
flann::Matrix<float> query;
flann::Matrix<float> dists_single;
flann::Matrix<int> indices_single;
flann::Matrix<float> dists_multi;
flann::Matrix<int> indices_multi;
flann::Matrix<float> data_;
flann::Matrix<float> query_;
flann::Matrix<float> dists_single_;
flann::Matrix<int> indices_single_;
flann::Matrix<float> dists_multi_;
flann::Matrix<int> indices_multi_;
float radius;
float radius_;
void SetUp()
{
radius = 0.1f;
radius_ = 0.1f;
printf("Reading test data...");
fflush(stdout);
flann::load_from_file(data, "cloud.h5","dataset");
flann::load_from_file(query,"cloud.h5","query");
flann::load_from_file(data_, "cloud.h5","dataset");
flann::load_from_file(query_,"cloud.h5","query");
// If the indices / dists matrix cannot contain all points found in the radius, only the points
// that can be stored in the matrix will be returned and search is stopped. For each query point
// we reserve as many space as we think is needed. For large point clouds, reserving 'cloudsize'
// space for each query point might cause memory errors.
int reserve_size = data.rows / 1000;
int reserve_size = data_.rows / 1000;
dists_single = flann::Matrix<float>(new float[query.rows*reserve_size], query.rows, reserve_size);
indices_single = flann::Matrix<int>(new int[query.rows*reserve_size], query.rows, reserve_size);
dists_multi = flann::Matrix<float>(new float[query.rows*reserve_size], query.rows, reserve_size);
indices_multi = flann::Matrix<int>(new int[query.rows*reserve_size], query.rows, reserve_size);
dists_single_ = flann::Matrix<float>(new float[query_.rows*reserve_size], query_.rows, reserve_size);
indices_single_ = flann::Matrix<int>(new int[query_.rows*reserve_size], query_.rows, reserve_size);
dists_multi_ = flann::Matrix<float>(new float[query_.rows*reserve_size], query_.rows, reserve_size);
indices_multi_ = flann::Matrix<int>(new int[query_.rows*reserve_size], query_.rows, reserve_size);
printf("done\n");
}
void TearDown()
{
delete[] data.ptr();
delete[] query.ptr();
delete[] dists_single.ptr();
delete[] indices_single.ptr();
delete[] dists_multi.ptr();
delete[] indices_multi.ptr();
delete[] data_.ptr();
delete[] query_.ptr();
delete[] dists_single_.ptr();
delete[] indices_single_.ptr();
delete[] dists_multi_.ptr();
delete[] indices_multi_.ptr();
}
float GetRadius() { return radius; }
void runTest(const flann::Index<L2_Simple<float> >& index, SearchParams params)
{
start_timer("Searching Radius (single core)...");
params.cores = 1;
int single_neighbor_count = index.radiusSearch(query_, indices_single_, dists_single_, radius_, params);
printf("done (%g seconds)\n", stop_timer());
start_timer("Searching Radius (multi core)...");
params.cores = 0;
int multi_neighbor_count = index.radiusSearch(query_, indices_multi_, dists_multi_, radius_, params);
printf("done (%g seconds)\n", stop_timer());
EXPECT_EQ(single_neighbor_count, multi_neighbor_count);
printf("Checking results...\n");
float precision = compute_precision(indices_single_, indices_multi_);
EXPECT_GE(precision, 0.99);
printf("Precision: %g\n", precision);
}
};
TEST_F(FlannCompareRadiusTest, CompareMultiSingleCoreRadiusSearchSorted)
{
flann::Index<L2_Simple<float> > index(data, flann::KDTreeSingleIndexParams(50, false));
flann::Index<L2_Simple<float> > index(data_, flann::KDTreeSingleIndexParams(50, false));
start_timer("Building kd-tree index...");
index.buildIndex();
printf("done (%g seconds)\n", stop_timer());
int checks = -1;
float eps = 0.0f;
bool sorted = true;
int single_core = 1;
int multi_core = -1;
start_timer("Searching Radius (single core)...");
SearchParams params(checks,eps,sorted);
params.cores = single_core;
int single_neighbor_count = index.radiusSearch(query, indices_single, dists_single, GetRadius(), params);
printf("done (%g seconds)\n", stop_timer());
start_timer("Searching Radius (multi core)...");
params.cores = multi_core;
int multi_neighbor_count = index.radiusSearch(query, indices_multi, dists_multi, GetRadius(), params);
printf("done (%g seconds)\n", stop_timer());
EXPECT_EQ(single_neighbor_count, multi_neighbor_count);
SearchParams params;
params.checks = -1;
params.eps = 0.0f;
params.sorted = true;
float precision = compute_precision(indices_single, indices_multi);
EXPECT_GE(precision, 0.99);
printf("Precision: %g\n", precision);
runTest(index, params);
}
TEST_F(FlannCompareRadiusTest, CompareMultiSingleCoreRadiusSearchUnsorted)
{
flann::Index<L2_Simple<float> > index(data, flann::KDTreeSingleIndexParams(50, false));
flann::Index<L2_Simple<float> > index(data_, flann::KDTreeSingleIndexParams(50, false));
start_timer("Building kd-tree index...");
index.buildIndex();
printf("done (%g seconds)\n", stop_timer());
int checks = -1;
float eps = 0.0f;
bool sorted = false;
int single_core = 1;
int multi_core = -1;
start_timer("Searching Radius (single core)...");
SearchParams params(checks,eps,sorted);
params.cores = single_core;
int single_neighbor_count = index.radiusSearch(query, indices_single, dists_single, GetRadius(), params);
printf("done (%g seconds)\n", stop_timer());
start_timer("Searching Radius (multi core)...");
params.cores = multi_core;
int multi_neighbor_count = index.radiusSearch(query, indices_multi, dists_multi, GetRadius(), params);
printf("done (%g seconds)\n", stop_timer());
EXPECT_EQ(single_neighbor_count, multi_neighbor_count);
SearchParams params;
params.checks = -1;
params.eps = 0.0f;
params.sorted = false;
float precision = compute_precision(indices_single, indices_multi);
EXPECT_GE(precision, 0.99);
printf("Precision: %g\n", precision);
runTest(index, params);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册