From b0b7f3ff486c7396dc3bfdd7f54bf89970ff1971 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 7 May 2020 13:31:54 -0400 Subject: [PATCH] Adapt LSHSearch to allow MatType template parameter. --- src/mlpack/methods/lsh/lsh_search.hpp | 18 ++- src/mlpack/methods/lsh/lsh_search_impl.hpp | 149 +++++++++++---------- 2 files changed, 89 insertions(+), 78 deletions(-) diff --git a/src/mlpack/methods/lsh/lsh_search.hpp b/src/mlpack/methods/lsh/lsh_search.hpp index d906db147d..a19e8bbfbf 100644 --- a/src/mlpack/methods/lsh/lsh_search.hpp +++ b/src/mlpack/methods/lsh/lsh_search.hpp @@ -59,8 +59,12 @@ namespace neighbor { * queries. * * @tparam SortPolicy The sort policy for distances; see NearestNeighborSort. + * @tparam MatType Type of matrix to use to store the data. */ -template +template< + typename SortPolicy = NearestNeighborSort, + typename MatType = arma::mat +> class LSHSearch { public: @@ -86,7 +90,7 @@ class LSHSearch * value of 0 indicates that there is no limit (so the second hash table * can be arbitrarily large---be careful!). */ - LSHSearch(arma::mat referenceSet, + LSHSearch(MatType referenceSet, const arma::cube& projections, const double hashWidth = 0.0, const size_t secondHashSize = 99901, @@ -114,7 +118,7 @@ class LSHSearch * value of 0 indicates that there is no limit (so the second hash table * can be arbitrarily large---be careful!). */ - LSHSearch(arma::mat referenceSet, + LSHSearch(MatType referenceSet, const size_t numProj, const size_t numTables, const double hashWidth = 0.0, @@ -180,7 +184,7 @@ class LSHSearch * we set numProj = a, numTables = c. b is the reference set * dimensionality. */ - void Train(arma::mat referenceSet, + void Train(MatType referenceSet, const size_t numProj, const size_t numTables, const double hashWidth = 0.0, @@ -209,7 +213,7 @@ class LSHSearch * @param T The number of additional probing bins to examine with multiprobe * LSH. If T = 0, classic single-probe LSH is run (default). */ - void Search(const arma::mat& querySet, + void Search(const MatType& querySet, const size_t k, arma::Mat& resultingNeighbors, arma::mat& distances, @@ -353,7 +357,7 @@ class LSHSearch void BaseCase(const size_t queryIndex, const arma::uvec& referenceIndices, const size_t k, - const arma::mat& querySet, + const MatType& querySet, arma::Mat& neighbors, arma::mat& distances) const; @@ -415,7 +419,7 @@ class LSHSearch bool PerturbationValid(const std::vector& A) const; //! Reference dataset. - arma::mat referenceSet; + MatType referenceSet; //! The number of projections. size_t numProj; diff --git a/src/mlpack/methods/lsh/lsh_search_impl.hpp b/src/mlpack/methods/lsh/lsh_search_impl.hpp index 82a239a83c..ad1e8b6e81 100644 --- a/src/mlpack/methods/lsh/lsh_search_impl.hpp +++ b/src/mlpack/methods/lsh/lsh_search_impl.hpp @@ -19,9 +19,9 @@ namespace mlpack { namespace neighbor { // Construct the object with random tables -template -LSHSearch:: -LSHSearch(arma::mat referenceSet, +template +LSHSearch:: +LSHSearch(MatType referenceSet, const size_t numProj, const size_t numTables, const double hashWidthIn, @@ -35,14 +35,14 @@ LSHSearch(arma::mat referenceSet, distanceEvaluations(0) { // Pass work to training function. - Train(referenceSet, numProj, numTables, hashWidthIn, secondHashSize, - bucketSize); + Train(std::move(referenceSet), numProj, numTables, hashWidthIn, + secondHashSize, bucketSize); } // Construct the object with given tables -template -LSHSearch:: -LSHSearch(arma::mat referenceSet, +template +LSHSearch:: +LSHSearch(MatType referenceSet, const arma::cube& projections, const double hashWidthIn, const size_t secondHashSize, @@ -60,8 +60,8 @@ LSHSearch(arma::mat referenceSet, } // Empty constructor. -template -LSHSearch::LSHSearch() : +template +LSHSearch::LSHSearch() : numProj(0), numTables(0), hashWidth(0), @@ -72,8 +72,8 @@ LSHSearch::LSHSearch() : } // Copy constructor. -template -LSHSearch::LSHSearch(const LSHSearch& other) : +template +LSHSearch::LSHSearch(const LSHSearch& other) : referenceSet(other.referenceSet), // Copy the other set. numProj(other.numProj), numTables(other.numTables), @@ -92,8 +92,8 @@ LSHSearch::LSHSearch(const LSHSearch& other) : } // Move constructor. -template -LSHSearch::LSHSearch(LSHSearch&& other) : +template +LSHSearch::LSHSearch(LSHSearch&& other) : referenceSet(std::move(other.referenceSet)), numProj(other.numProj), numTables(other.numTables), @@ -118,8 +118,9 @@ LSHSearch::LSHSearch(LSHSearch&& other) : } // Copy operator. -template -LSHSearch& LSHSearch::operator=(const LSHSearch& other) +template +LSHSearch& LSHSearch::operator=( + const LSHSearch& other) { referenceSet = other.referenceSet; numProj = other.numProj; @@ -139,8 +140,9 @@ LSHSearch& LSHSearch::operator=(const LSHSearch& other) } // Move operator. -template -LSHSearch& LSHSearch::operator=(LSHSearch&& other) +template +LSHSearch& LSHSearch::operator=( + LSHSearch&& other) { referenceSet = std::move(other.referenceSet); numProj = other.numProj; @@ -168,14 +170,14 @@ LSHSearch& LSHSearch::operator=(LSHSearch&& other) } // Train on a new reference set. -template -void LSHSearch::Train(arma::mat referenceSet, - const size_t numProj, - const size_t numTables, - const double hashWidthIn, - const size_t secondHashSize, - const size_t bucketSize, - const arma::cube &projection) +template +void LSHSearch::Train(MatType referenceSet, + const size_t numProj, + const size_t numTables, + const double hashWidthIn, + const size_t secondHashSize, + const size_t bucketSize, + const arma::cube& projection) { // Set new reference set. this->referenceSet = std::move(referenceSet); @@ -197,8 +199,8 @@ void LSHSearch::Train(arma::mat referenceSet, size_t p2 = (size_t) math::RandInt(this->referenceSet.n_cols); hashWidth += std::sqrt(metric::EuclideanDistance::Evaluate( - this->referenceSet.unsafe_col(p1), - this->referenceSet.unsafe_col(p2))); + this->referenceSet.col(p1), + this->referenceSet.col(p2))); } hashWidth /= numSamples; @@ -349,13 +351,14 @@ void LSHSearch::Train(arma::mat referenceSet, // Base case where the query set is the reference set. (So, we can't return // ourselves as the nearest neighbor.) -template +template inline force_inline -void LSHSearch::BaseCase(const size_t queryIndex, - const arma::uvec& referenceIndices, - const size_t k, - arma::Mat& neighbors, - arma::mat& distances) const +void LSHSearch::BaseCase( + const size_t queryIndex, + const arma::uvec& referenceIndices, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances) const { // Let's build the list of candidate neighbors for the given query point. // It will be initialized with k candidates: @@ -373,8 +376,8 @@ void LSHSearch::BaseCase(const size_t queryIndex, continue; const double distance = metric::EuclideanDistance::Evaluate( - referenceSet.unsafe_col(queryIndex), - referenceSet.unsafe_col(referenceIndex)); + referenceSet.col(queryIndex), + referenceSet.col(referenceIndex)); Candidate c = std::make_pair(distance, referenceIndex); // If this distance is better than the worst candidate, let's insert it. @@ -394,14 +397,15 @@ void LSHSearch::BaseCase(const size_t queryIndex, } // Base case for bichromatic search. -template +template inline force_inline -void LSHSearch::BaseCase(const size_t queryIndex, - const arma::uvec& referenceIndices, - const size_t k, - const arma::mat& querySet, - arma::Mat& neighbors, - arma::mat& distances) const +void LSHSearch::BaseCase( + const size_t queryIndex, + const arma::uvec& referenceIndices, + const size_t k, + const MatType& querySet, + arma::Mat& neighbors, + arma::mat& distances) const { // Let's build the list of candidate neighbors for the given query point. // It will be initialized with k candidates: @@ -415,8 +419,8 @@ void LSHSearch::BaseCase(const size_t queryIndex, { const size_t referenceIndex = referenceIndices[j]; const double distance = metric::EuclideanDistance::Evaluate( - querySet.unsafe_col(queryIndex), - referenceSet.unsafe_col(referenceIndex)); + querySet.col(queryIndex), + referenceSet.col(referenceIndex)); Candidate c = std::make_pair(distance, referenceIndex); // If this distance is better than the worst candidate, let's insert it. @@ -435,9 +439,9 @@ void LSHSearch::BaseCase(const size_t queryIndex, } } -template +template inline force_inline -double LSHSearch::PerturbationScore( +double LSHSearch::PerturbationScore( const std::vector& A, const arma::vec& scores) const { @@ -448,9 +452,10 @@ double LSHSearch::PerturbationScore( return score; } -template +template inline force_inline -bool LSHSearch::PerturbationShift(std::vector& A) const +bool LSHSearch::PerturbationShift( + std::vector& A) const { size_t maxPos = 0; for (size_t i = 0; i < A.size(); ++i) @@ -466,9 +471,10 @@ bool LSHSearch::PerturbationShift(std::vector& A) const return false; // invalid } -template +template inline force_inline -bool LSHSearch::PerturbationExpand(std::vector& A) const +bool LSHSearch::PerturbationExpand( + std::vector& A) const { // Find the last '1' in A. size_t maxPos = 0; @@ -484,9 +490,9 @@ bool LSHSearch::PerturbationExpand(std::vector& A) const return false; } -template +template inline force_inline -bool LSHSearch::PerturbationValid( +bool LSHSearch::PerturbationValid( const std::vector& A) const { // Use check to mark dimensions we have seen before in A. If a dimension is @@ -514,8 +520,8 @@ bool LSHSearch::PerturbationValid( } // Compute additional probing bins for a query -template -void LSHSearch::GetAdditionalProbingBins( +template +void LSHSearch::GetAdditionalProbingBins( const arma::vec& queryCode, const arma::vec& queryCodeNotFloored, const size_t T, @@ -696,9 +702,9 @@ void LSHSearch::GetAdditionalProbingBins( } } -template +template template -void LSHSearch::ReturnIndicesFromTable( +void LSHSearch::ReturnIndicesFromTable( const VecType& queryPoint, arma::uvec& referenceIndices, size_t numTablesToSearch, @@ -849,13 +855,14 @@ void LSHSearch::ReturnIndicesFromTable( } // Search for nearest neighbors in a given query set. -template -void LSHSearch::Search(const arma::mat& querySet, - const size_t k, - arma::Mat& resultingNeighbors, - arma::mat& distances, - const size_t numTablesToSearch, - const size_t T) +template +void LSHSearch::Search( + const MatType& querySet, + const size_t k, + arma::Mat& resultingNeighbors, + arma::mat& distances, + const size_t numTablesToSearch, + const size_t T) { // Ensure the dimensionality of the query set is correct. if (querySet.n_rows != referenceSet.n_rows) @@ -938,8 +945,8 @@ void LSHSearch::Search(const arma::mat& querySet, } // Search for approximate neighbors of the reference set. -template -void LSHSearch:: +template +void LSHSearch:: Search(const size_t k, arma::Mat& resultingNeighbors, arma::mat& distances, @@ -1003,8 +1010,8 @@ Search(const size_t k, std::endl; } -template -double LSHSearch::ComputeRecall( +template +double LSHSearch::ComputeRecall( const arma::Mat& foundNeighbors, const arma::Mat& realNeighbors) { @@ -1030,10 +1037,10 @@ double LSHSearch::ComputeRecall( return ((double) found) / realNeighbors.n_elem; } -template +template template -void LSHSearch::serialize(Archive& ar, - const unsigned int version) +void LSHSearch::serialize(Archive& ar, + const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(referenceSet); ar & BOOST_SERIALIZATION_NVP(numProj);