1#ifndef KNNCOLLE_L2_NORMALIZED_HP
2#define KNNCOLLE_L2_NORMALIZED_HP
32inline static constexpr const char* l2normalized_prebuilt_save_name =
"knncolle::L2Normalized";
49template<
typename Normalized_>
51 static std::function<void(
const std::filesystem::path&)> fun;
58template<
typename Data_,
typename Normalized_>
59void l2norm(
const Data_* ptr, std::size_t ndim, Normalized_* buffer) {
60 if constexpr(std::is_same<Data_, Normalized_>::value) {
63 for (std::size_t d = 0; d < ndim; ++d) {
64 l2 += ptr[d] * ptr[d];
69 for (std::size_t d = 0; d < ndim; ++d) {
70 buffer[d] = ptr[d] / l2;
73 std::fill_n(buffer, ndim, 0);
78 std::copy_n(ptr, ndim, buffer);
81 for (std::size_t d = 0; d < ndim; ++d) {
82 l2 += buffer[d] * buffer[d];
87 for (std::size_t d = 0; d < ndim; ++d) {
94template<
typename Index_,
typename Data_,
typename Distance_,
typename Normalized_,
class Searcher_>
95class L2NormalizedSearcher final :
public Searcher<Index_, Data_, Distance_> {
97 L2NormalizedSearcher(std::unique_ptr<Searcher_> searcher, std::size_t num_dimensions) :
98 my_searcher(std::move(searcher)),
99 buffer(sanisizer::cast<I<decltype(buffer.size())> >(num_dimensions))
105 static_assert(std::is_floating_point<Normalized_>::value);
107 std::unique_ptr<Searcher_> my_searcher;
108 std::vector<Normalized_> buffer;
111 void search(Index_ i, Index_ k, std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
112 my_searcher->search(i, k, output_indices, output_distances);
115 void search(
const Data_* ptr, Index_ k, std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
116 auto normalized = buffer.data();
117 l2norm(ptr, buffer.size(), normalized);
118 my_searcher->search(normalized, k, output_indices, output_distances);
122 bool can_search_all()
const {
123 return my_searcher->can_search_all();
126 Index_ search_all(Index_ i, Distance_ threshold, std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
127 return my_searcher->search_all(i, threshold, output_indices, output_distances);
130 Index_ search_all(
const Data_* ptr, Distance_ threshold, std::vector<Index_>* output_indices, std::vector<Distance_>* output_distances) {
131 auto normalized = buffer.data();
132 l2norm(ptr, buffer.size(), normalized);
133 return my_searcher->search_all(normalized, threshold, output_indices, output_distances);
137template<
typename Index_,
typename Data_,
typename Distance_>
138Prebuilt<Index_, Data_, Distance_>*
load_prebuilt_raw(
const std::filesystem::path&);
140template<
typename Index_,
typename Data_,
typename Distance_,
typename Normalized_>
141class L2NormalizedPrebuilt final :
public Prebuilt<Index_, Data_, Distance_> {
143 L2NormalizedPrebuilt(std::unique_ptr<Prebuilt<Index_, Normalized_, Distance_> > prebuilt) : my_prebuilt(std::move(prebuilt)) {}
146 std::unique_ptr<Prebuilt<Index_, Normalized_, Distance_> > my_prebuilt;
149 Index_ num_observations()
const {
150 return my_prebuilt->num_observations();
153 std::size_t num_dimensions()
const {
154 return my_prebuilt->num_dimensions();
158 std::unique_ptr<Searcher<Index_, Data_, Distance_> > initialize()
const {
159 return initialize_known();
162 auto initialize_known()
const {
163 typedef I<
decltype(*(my_prebuilt->initialize_known()))> KnownSearcher;
164 return std::make_unique<L2NormalizedSearcher<Index_, Data_, Distance_, Normalized_, KnownSearcher> >(my_prebuilt->initialize_known(), my_prebuilt->num_dimensions());
168 void save(
const std::filesystem::path& dir)
const {
169 quick_save(dir /
"ALGORITHM", l2normalized_prebuilt_save_name, std::strlen(l2normalized_prebuilt_save_name));
170 auto norm_type = get_numeric_type<Normalized_>();
171 quick_save(dir /
"NORMALIZED", &norm_type, 1);
173 auto& cust = custom_save_for_l2normalized_normalized<Normalized_>();
178 const auto indexdir = dir /
"INDEX";
179 std::filesystem::create_directory(indexdir);
180 my_prebuilt->save(indexdir);
183 L2NormalizedPrebuilt(
const std::filesystem::path& dir) : my_prebuilt(
load_prebuilt_raw<Index_, Normalized_, Distance_>(dir /
"INDEX")) {}
186template<
typename Index_,
typename Data_,
typename Normalized_,
typename Matrix_>
187class L2NormalizedMatrix;
189template<
typename Index_,
typename Data_,
typename Normalized_,
class Extractor_ = MatrixExtractor<Data_> >
190class L2NormalizedMatrixExtractor final :
public MatrixExtractor<Normalized_> {
192 L2NormalizedMatrixExtractor(std::unique_ptr<Extractor_> extractor, std::size_t dim) :
193 my_extractor(std::move(extractor)),
194 buffer(sanisizer::cast<I<decltype(buffer.size())> >(dim))
198 std::unique_ptr<Extractor_> my_extractor;
199 std::vector<Normalized_> buffer;
202 const Normalized_* next() {
203 auto raw = my_extractor->next();
204 auto normalized = buffer.data();
205 l2norm(raw, buffer.size(), normalized);
226template<
typename Index_,
typename Data_,
typename Normalized_,
typename Matrix_ = Matrix<Index_, Data_> >
238 static_assert(std::is_same<decltype(std::declval<Matrix_>().num_observations()), Index_>::value);
239 static_assert(std::is_same<typename std::remove_pointer<decltype(std::declval<Matrix_>().new_extractor()->next())>::type,
const Data_>::value);
241 const Matrix_& my_matrix;
245 return my_matrix.num_dimensions();
249 return my_matrix.num_observations();
256 typedef I<
decltype(*(my_matrix.new_known_extractor()))> KnownExtractor;
257 return std::make_unique<L2NormalizedMatrixExtractor<Index_, Data_, Normalized_, KnownExtractor> >(my_matrix.new_known_extractor(),
num_dimensions());
280template<
typename Index_,
typename Data_,
typename Distance_,
typename Normalized_,
class Matrix_ = Matrix<Index_, Data_> >
299 typedef typename std::conditional<
300 std::is_base_of<Matrix_, NormalizedMatrix>::value,
312 std::shared_ptr<const Builder<Index_, Normalized_, Distance_, BuilderMatrix> > my_builder;
331 return new L2NormalizedPrebuilt<Index_, Data_, Distance_, Normalized_>(my_builder->build_unique(normalized));
Interface to build nearest-neighbor indices.
Interface for the input matrix.
Preserve numeric types when saving prebuilt indices.
Interface for prebuilt nearest-neighbor indices.
Interface for searching nearest-neighbor indices.
Interface to build nearest-neighbor search indices.
Definition Builder.hpp:28
virtual Prebuilt< Index_, Data_, Distance_ > * build_raw(const Matrix_ &data) const =0
Wrapper around a builder with L2 normalization.
Definition L2Normalized.hpp:281
L2NormalizedMatrix< Index_, Data_, Normalized_, Matrix_ > NormalizedMatrix
Definition L2Normalized.hpp:286
L2NormalizedBuilder(std::shared_ptr< const Builder< Index_, Normalized_, Distance_, BuilderMatrix > > builder)
Definition L2Normalized.hpp:309
auto build_known_raw(const Matrix_ &data) const
Definition L2Normalized.hpp:329
std::conditional< std::is_base_of< Matrix_, NormalizedMatrix >::value, Matrix_, NormalizedMatrix >::type BuilderMatrix
Definition L2Normalized.hpp:303
auto build_known_shared(const Matrix_ &data) const
Definition L2Normalized.hpp:344
auto build_known_unique(const Matrix_ &data) const
Definition L2Normalized.hpp:337
Wrapper around a matrix with L2 normalization.
Definition L2Normalized.hpp:227
std::size_t num_dimensions() const
Definition L2Normalized.hpp:244
Index_ num_observations() const
Definition L2Normalized.hpp:248
auto new_known_extractor() const
Definition L2Normalized.hpp:255
std::unique_ptr< MatrixExtractor< Normalized_ > > new_extractor() const
Definition L2Normalized.hpp:260
Interface for matrix data.
Definition Matrix.hpp:59
Interface for prebuilt nearest-neighbor search indices.
Definition Prebuilt.hpp:29
Collection of KNN algorithms.
Definition Bruteforce.hpp:31
Prebuilt< Index_, Data_, Distance_ > * load_prebuilt_raw(const std::filesystem::path &dir)
Definition load_prebuilt.hpp:105
void quick_save(const std::filesystem::path &path, const Input_ *const contents, const Length_ length)
Definition utils.hpp:33
std::function< void(const std::filesystem::path &)> & custom_save_for_l2normalized_normalized()
Definition L2Normalized.hpp:50
Miscellaneous utilities for knncolle