Adapt LSHSearch to allow MatType template parameter.

This commit is contained in:
Ryan Curtin
2020-05-07 13:31:54 -04:00
parent 28d724140b
commit b0b7f3ff48
2 changed files with 89 additions and 78 deletions
+11 -7
View File
@@ -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<typename SortPolicy = NearestNeighborSort>
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<size_t>& 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<size_t>& neighbors,
arma::mat& distances) const;
@@ -415,7 +419,7 @@ class LSHSearch
bool PerturbationValid(const std::vector<bool>& A) const;
//! Reference dataset.
arma::mat referenceSet;
MatType referenceSet;
//! The number of projections.
size_t numProj;
+78 -71
View File
@@ -19,9 +19,9 @@ namespace mlpack {
namespace neighbor {
// Construct the object with random tables
template<typename SortPolicy>
LSHSearch<SortPolicy>::
LSHSearch(arma::mat referenceSet,
template<typename SortPolicy, typename MatType>
LSHSearch<SortPolicy, MatType>::
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<typename SortPolicy>
LSHSearch<SortPolicy>::
LSHSearch(arma::mat referenceSet,
template<typename SortPolicy, typename MatType>
LSHSearch<SortPolicy, MatType>::
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<typename SortPolicy>
LSHSearch<SortPolicy>::LSHSearch() :
template<typename SortPolicy, typename MatType>
LSHSearch<SortPolicy, MatType>::LSHSearch() :
numProj(0),
numTables(0),
hashWidth(0),
@@ -72,8 +72,8 @@ LSHSearch<SortPolicy>::LSHSearch() :
}
// Copy constructor.
template<typename SortPolicy>
LSHSearch<SortPolicy>::LSHSearch(const LSHSearch& other) :
template<typename SortPolicy, typename MatType>
LSHSearch<SortPolicy, MatType>::LSHSearch(const LSHSearch& other) :
referenceSet(other.referenceSet), // Copy the other set.
numProj(other.numProj),
numTables(other.numTables),
@@ -92,8 +92,8 @@ LSHSearch<SortPolicy>::LSHSearch(const LSHSearch& other) :
}
// Move constructor.
template<typename SortPolicy>
LSHSearch<SortPolicy>::LSHSearch(LSHSearch&& other) :
template<typename SortPolicy, typename MatType>
LSHSearch<SortPolicy, MatType>::LSHSearch(LSHSearch&& other) :
referenceSet(std::move(other.referenceSet)),
numProj(other.numProj),
numTables(other.numTables),
@@ -118,8 +118,9 @@ LSHSearch<SortPolicy>::LSHSearch(LSHSearch&& other) :
}
// Copy operator.
template<typename SortPolicy>
LSHSearch<SortPolicy>& LSHSearch<SortPolicy>::operator=(const LSHSearch& other)
template<typename SortPolicy, typename MatType>
LSHSearch<SortPolicy, MatType>& LSHSearch<SortPolicy, MatType>::operator=(
const LSHSearch& other)
{
referenceSet = other.referenceSet;
numProj = other.numProj;
@@ -139,8 +140,9 @@ LSHSearch<SortPolicy>& LSHSearch<SortPolicy>::operator=(const LSHSearch& other)
}
// Move operator.
template<typename SortPolicy>
LSHSearch<SortPolicy>& LSHSearch<SortPolicy>::operator=(LSHSearch&& other)
template<typename SortPolicy, typename MatType>
LSHSearch<SortPolicy, MatType>& LSHSearch<SortPolicy, MatType>::operator=(
LSHSearch&& other)
{
referenceSet = std::move(other.referenceSet);
numProj = other.numProj;
@@ -168,14 +170,14 @@ LSHSearch<SortPolicy>& LSHSearch<SortPolicy>::operator=(LSHSearch&& other)
}
// Train on a new reference set.
template<typename SortPolicy>
void LSHSearch<SortPolicy>::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<typename SortPolicy, typename MatType>
void LSHSearch<SortPolicy, MatType>::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<SortPolicy>::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<SortPolicy>::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<typename SortPolicy>
template<typename SortPolicy, typename MatType>
inline force_inline
void LSHSearch<SortPolicy>::BaseCase(const size_t queryIndex,
const arma::uvec& referenceIndices,
const size_t k,
arma::Mat<size_t>& neighbors,
arma::mat& distances) const
void LSHSearch<SortPolicy, MatType>::BaseCase(
const size_t queryIndex,
const arma::uvec& referenceIndices,
const size_t k,
arma::Mat<size_t>& 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<SortPolicy>::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<SortPolicy>::BaseCase(const size_t queryIndex,
}
// Base case for bichromatic search.
template<typename SortPolicy>
template<typename SortPolicy, typename MatType>
inline force_inline
void LSHSearch<SortPolicy>::BaseCase(const size_t queryIndex,
const arma::uvec& referenceIndices,
const size_t k,
const arma::mat& querySet,
arma::Mat<size_t>& neighbors,
arma::mat& distances) const
void LSHSearch<SortPolicy, MatType>::BaseCase(
const size_t queryIndex,
const arma::uvec& referenceIndices,
const size_t k,
const MatType& querySet,
arma::Mat<size_t>& 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<SortPolicy>::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<SortPolicy>::BaseCase(const size_t queryIndex,
}
}
template<typename SortPolicy>
template<typename SortPolicy, typename MatType>
inline force_inline
double LSHSearch<SortPolicy>::PerturbationScore(
double LSHSearch<SortPolicy, MatType>::PerturbationScore(
const std::vector<bool>& A,
const arma::vec& scores) const
{
@@ -448,9 +452,10 @@ double LSHSearch<SortPolicy>::PerturbationScore(
return score;
}
template<typename SortPolicy>
template<typename SortPolicy, typename MatType>
inline force_inline
bool LSHSearch<SortPolicy>::PerturbationShift(std::vector<bool>& A) const
bool LSHSearch<SortPolicy, MatType>::PerturbationShift(
std::vector<bool>& A) const
{
size_t maxPos = 0;
for (size_t i = 0; i < A.size(); ++i)
@@ -466,9 +471,10 @@ bool LSHSearch<SortPolicy>::PerturbationShift(std::vector<bool>& A) const
return false; // invalid
}
template<typename SortPolicy>
template<typename SortPolicy, typename MatType>
inline force_inline
bool LSHSearch<SortPolicy>::PerturbationExpand(std::vector<bool>& A) const
bool LSHSearch<SortPolicy, MatType>::PerturbationExpand(
std::vector<bool>& A) const
{
// Find the last '1' in A.
size_t maxPos = 0;
@@ -484,9 +490,9 @@ bool LSHSearch<SortPolicy>::PerturbationExpand(std::vector<bool>& A) const
return false;
}
template<typename SortPolicy>
template<typename SortPolicy, typename MatType>
inline force_inline
bool LSHSearch<SortPolicy>::PerturbationValid(
bool LSHSearch<SortPolicy, MatType>::PerturbationValid(
const std::vector<bool>& A) const
{
// Use check to mark dimensions we have seen before in A. If a dimension is
@@ -514,8 +520,8 @@ bool LSHSearch<SortPolicy>::PerturbationValid(
}
// Compute additional probing bins for a query
template<typename SortPolicy>
void LSHSearch<SortPolicy>::GetAdditionalProbingBins(
template<typename SortPolicy, typename MatType>
void LSHSearch<SortPolicy, MatType>::GetAdditionalProbingBins(
const arma::vec& queryCode,
const arma::vec& queryCodeNotFloored,
const size_t T,
@@ -696,9 +702,9 @@ void LSHSearch<SortPolicy>::GetAdditionalProbingBins(
}
}
template<typename SortPolicy>
template<typename SortPolicy, typename MatType>
template<typename VecType>
void LSHSearch<SortPolicy>::ReturnIndicesFromTable(
void LSHSearch<SortPolicy, MatType>::ReturnIndicesFromTable(
const VecType& queryPoint,
arma::uvec& referenceIndices,
size_t numTablesToSearch,
@@ -849,13 +855,14 @@ void LSHSearch<SortPolicy>::ReturnIndicesFromTable(
}
// Search for nearest neighbors in a given query set.
template<typename SortPolicy>
void LSHSearch<SortPolicy>::Search(const arma::mat& querySet,
const size_t k,
arma::Mat<size_t>& resultingNeighbors,
arma::mat& distances,
const size_t numTablesToSearch,
const size_t T)
template<typename SortPolicy, typename MatType>
void LSHSearch<SortPolicy, MatType>::Search(
const MatType& querySet,
const size_t k,
arma::Mat<size_t>& 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<SortPolicy>::Search(const arma::mat& querySet,
}
// Search for approximate neighbors of the reference set.
template<typename SortPolicy>
void LSHSearch<SortPolicy>::
template<typename SortPolicy, typename MatType>
void LSHSearch<SortPolicy, MatType>::
Search(const size_t k,
arma::Mat<size_t>& resultingNeighbors,
arma::mat& distances,
@@ -1003,8 +1010,8 @@ Search(const size_t k,
std::endl;
}
template<typename SortPolicy>
double LSHSearch<SortPolicy>::ComputeRecall(
template<typename SortPolicy, typename MatType>
double LSHSearch<SortPolicy, MatType>::ComputeRecall(
const arma::Mat<size_t>& foundNeighbors,
const arma::Mat<size_t>& realNeighbors)
{
@@ -1030,10 +1037,10 @@ double LSHSearch<SortPolicy>::ComputeRecall(
return ((double) found) / realNeighbors.n_elem;
}
template<typename SortPolicy>
template<typename SortPolicy, typename MatType>
template<typename Archive>
void LSHSearch<SortPolicy>::serialize(Archive& ar,
const unsigned int version)
void LSHSearch<SortPolicy, MatType>::serialize(Archive& ar,
const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(referenceSet);
ar & BOOST_SERIALIZATION_NVP(numProj);