diff --git a/src/mlpack/methods/lsh/lsh_search_impl.hpp b/src/mlpack/methods/lsh/lsh_search_impl.hpp index 149beaba97..64ad80ab34 100644 --- a/src/mlpack/methods/lsh/lsh_search_impl.hpp +++ b/src/mlpack/methods/lsh/lsh_search_impl.hpp @@ -166,7 +166,8 @@ void LSHSearch::Train(const arma::mat& referenceSet, } // We will store the second hash vectors in this matrix; the second hash - // vector for table i will be held in row i. + // vector for table i will be held in row i. We have to use int and not + // size_t, otherwise negative numbers are cast to 0. arma::Mat secondHashVectors(numTables, referenceSet.n_cols); for (size_t i = 0; i < numTables; i++) @@ -189,15 +190,20 @@ void LSHSearch::Train(const arma::mat& referenceSet, hashMat /= hashWidth; // Step V: Putting the points in the 'secondHashTable' by hashing the key. - // Now we hash every key, point ID to its corresponding bucket. - secondHashVectors.row(i) = arma::conv_to>::from( - secondHashWeights.t() * arma::floor(hashMat)); + // Now we hash every key, point ID to its corresponding bucket. We must + // also normalize the hashes to the range [0, secondHashSize). + arma::rowvec unmodVector = secondHashWeights.t() * arma::floor(hashMat); + for (size_t j = 0; j < secondHashVectors.n_cols; ++j) + { + double shs = (double) secondHashSize; // Convenience cast. + if (unmodVector[j] >= 0.0) + secondHashVectors[j] = size_t(fmod(unmodVector[j], shs)); + else + secondHashVectors[j] = secondHashSize - + size_t(fmod(-unmodVector[j], shs)); + } } - // Normalize hashes (take modulus with secondHashSize). - secondHashVectors.transform([secondHashSize](size_t val) - { return val % secondHashSize; }); - // Now, using the hash vectors for each table, count the number of rows we // have in the second hash table. arma::Row secondHashBinCounts(secondHashSize, arma::fill::zeros);