Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions include/rabitqlib/fastscan/detail/qg_estimator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include <array>
#include <cstddef>
#include <cstdint>

#include "rabitqlib/core/detail/eigen.hpp"
#include "rabitqlib/fastscan/data_layout.hpp"
#include "rabitqlib/fastscan/pack_codes.hpp"
#include "rabitqlib/fastscan/query.hpp"

namespace rabitqlib::fastscan::detail {
// Share QG accumulation and correction while callers select the accumulator.
// TU-local linkage keeps each ISA's Eigen expression compiled with its own flags.
template <typename T, auto Accumulate>
static inline void qg_batch_estdist_impl(
const char* batch_data,
const BatchQuery<T>& query_wrapper,
size_t padded_dim,
T* estimated_distances
) {
ConstQGBatchDataMap<T> cur_batch(batch_data, padded_dim);
std::array<int32_t, fastscan::kBatchSize> accu_values{};
Accumulate(cur_batch.bin_code(), query_wrapper.lut(), accu_values.data(), padded_dim);

ConstRowMajorArrayMap<int32_t> ip_arr(accu_values.data(), 1, fastscan::kBatchSize);
std::array<T, fastscan::kBatchSize> f_add_values;
std::array<T, fastscan::kBatchSize> f_rescale_values;
cur_batch.f_add().copy_to(f_add_values.data(), f_add_values.size());
cur_batch.f_rescale().copy_to(f_rescale_values.data(), f_rescale_values.size());
ConstRowMajorArrayMap<T> f_add_arr(f_add_values.data(), 1, fastscan::kBatchSize);
ConstRowMajorArrayMap<T> f_rescale_arr(
f_rescale_values.data(), 1, fastscan::kBatchSize
);

RowMajorArrayMap<T> est_dist_arr(estimated_distances, 1, fastscan::kBatchSize);

est_dist_arr = f_add_arr + query_wrapper.g_add() +
(f_rescale_arr * (query_wrapper.delta() * (ip_arr.template cast<T>()) +
query_wrapper.sum_vl_lut() + query_wrapper.k1xsumq()));
}
} // namespace rabitqlib::fastscan::detail
26 changes: 3 additions & 23 deletions include/rabitqlib/fastscan/estimator.hpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
#pragma once

#include <array>
#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <type_traits>

#include "rabitqlib/core/detail/eigen.hpp"
#include "rabitqlib/fastscan/data_layout.hpp"
#include "rabitqlib/fastscan/detail/estimator_dispatch.hpp"
#include "rabitqlib/fastscan/detail/qg_estimator.hpp"
#include "rabitqlib/fastscan/fastscan.hpp"
#include "rabitqlib/fastscan/pack_codes.hpp"
#include "rabitqlib/fastscan/query.hpp"

namespace rabitqlib {
Expand Down Expand Up @@ -81,26 +78,9 @@ inline void qg_batch_estdist(
return;
}

ConstQGBatchDataMap<T> cur_batch(batch_data, padded_dim);
std::array<TA, fastscan::kBatchSize> accumulated_values{};
fastscan::accumulate(
cur_batch.bin_code(), query_wrapper.lut(), accumulated_values.data(), padded_dim
fastscan::detail::qg_batch_estdist_impl<T, fastscan::accumulate>(
batch_data, query_wrapper, padded_dim, estimated_distances
);
ConstRowMajorArrayMap<TA> ip_arr(accumulated_values.data(), 1, fastscan::kBatchSize);
std::array<T, fastscan::kBatchSize> f_add_values;
std::array<T, fastscan::kBatchSize> f_rescale_values;
cur_batch.f_add().copy_to(f_add_values.data(), f_add_values.size());
cur_batch.f_rescale().copy_to(f_rescale_values.data(), f_rescale_values.size());
ConstRowMajorArrayMap<T> f_add_arr(f_add_values.data(), 1, fastscan::kBatchSize);
ConstRowMajorArrayMap<T> f_rescale_arr(
f_rescale_values.data(), 1, fastscan::kBatchSize
);

RowMajorArrayMap<T> est_dist_arr(estimated_distances, 1, fastscan::kBatchSize);

est_dist_arr = f_add_arr + query_wrapper.g_add() +
(f_rescale_arr * (query_wrapper.delta() * (ip_arr.template cast<T>()) +
query_wrapper.sum_vl_lut() + query_wrapper.k1xsumq()));
}

} // namespace rabitqlib
4 changes: 1 addition & 3 deletions include/rabitqlib/index/detail/visited_set_hash.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ class HashBasedVisitedSet {
static constexpr size_t kNoSizeHint = std::numeric_limits<size_t>::max();

private:
size_t table_size_ = 0;
PID mask_ = 0;
std::vector<PID, memory::AlignedAllocator<PID>> table_;
std::unordered_set<PID> stl_hash_;
Expand All @@ -44,8 +43,7 @@ class HashBasedVisitedSet {
void initialize_table(const size_t table_size) {
// Allocate before changing the mask so failure preserves the previous table.
table_ = std::vector<PID, memory::AlignedAllocator<PID>>(table_size);
table_size_ = table_size;
mask_ = static_cast<PID>(table_size_ - 1);
mask_ = static_cast<PID>(table_size - 1);
assert(hash1(static_cast<PID>(table_size)) == 0);

std::fill(table_.begin(), table_.end(), kPidMax);
Expand Down
1 change: 0 additions & 1 deletion include/rabitqlib/index/hnsw/hnsw.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,6 @@ class HierarchicalNSW {
size_t k,
const SplitSingleQuery<float>& query_wrapper,
const std::vector<float>& q_to_centroids,
const float* query,
BoundedKNN& nearest_candidates
) const;

Expand Down
31 changes: 2 additions & 29 deletions include/rabitqlib/utils/space.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "rabitqlib/utils/bitops.hpp"
#include "rabitqlib/utils/openmp.hpp" // IWYU pragma: keep (configuration macros)
#include "rabitqlib/utils/tools.hpp"
#include "rabitqlib/utils/warmup_space.hpp"

#if RABITQ_USE_OPENMP
#include <limits>
Expand Down Expand Up @@ -319,35 +320,7 @@ inline float ip_x0_q(
size_t padded_dim,
size_t b_query
) {
auto num_blk = padded_dim / 64;
const auto* it_data = reinterpret_cast<const uint8_t*>(data);
const auto* it_query = query;

size_t ip = 0;
size_t ppc = 0;

for (size_t i = 0; i < num_blk; ++i) {
const uint64_t x = rabitqlib::bitops::load_word(it_data, sizeof(uint64_t));
ppc += bitops::popcount64(x);

for (size_t j = 0; j < b_query; ++j) {
uint64_t y = *static_cast<const uint64_t*>(it_query);
ip += (bitops::popcount64(x & y) << j);
it_query++;
}
it_data += sizeof(uint64_t);
}

if (padded_dim % 64 != 0) {
const uint64_t x = rabitqlib::bitops::load_word(it_data, (padded_dim % 64) / 8);
ppc += bitops::popcount64(x);
for (size_t j = 0; j < b_query; ++j) {
ip += (bitops::popcount64(x & *it_query) << j);
++it_query;
}
}

return (delta * static_cast<float>(ip)) + (vl * static_cast<float>(ppc));
return detail::ip_x0_q_impl(data, query, delta, vl, padded_dim, b_query);
}

static inline uint32_t ip_bin_bin(const uint64_t* q, const uint64_t* d, size_t padded_dim) {
Expand Down
21 changes: 18 additions & 3 deletions include/rabitqlib/utils/warmup_space.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@ float warmup_ip_x0_q_512(
size_t b_query
);

template <uint32_t b_query>
inline float warmup_ip_x0_q(
namespace detail {
// Scalar word-interleaved query planes; distinct from the 512-coordinate layout.
// Keep the shared loop local to each translation unit's ISA configuration.
static inline float ip_x0_q_impl(
const uint64_t* data,
const uint64_t* query,
float delta,
float vl,
size_t padded_dim,
[[maybe_unused]] size_t unused_query_bits = 0 // not used
size_t b_query
) {
auto num_blk = padded_dim / 64;
const auto* it_data = reinterpret_cast<const uint8_t*>(data);
Expand Down Expand Up @@ -64,5 +66,18 @@ inline float warmup_ip_x0_q(

return (delta * static_cast<float>(ip)) + (vl * static_cast<float>(ppc));
}
} // namespace detail

template <uint32_t b_query>
inline float warmup_ip_x0_q(
const uint64_t* data,
const uint64_t* query,
float delta,
float vl,
size_t padded_dim,
[[maybe_unused]] size_t unused_query_bits = 0 // not used
) {
return detail::ip_x0_q_impl(data, query, delta, vl, padded_dim, b_query);
}

} // namespace rabitqlib
5 changes: 3 additions & 2 deletions src/fastscan/estimator_avx2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "estimator_kernels.hpp"
#include "rabitqlib/fastscan/detail/estimator_dispatch.hpp"
#include "rabitqlib/fastscan/detail/qg_estimator.hpp"
#include "rabitqlib/fastscan/fastscan.hpp"
#include "rabitqlib/fastscan/highacc_fastscan.hpp"

Expand Down Expand Up @@ -50,7 +51,7 @@ void qg_batch_estdist_avx2(
size_t padded_dim,
float* estimated_distances
) {
qg_batch_estdist_impl<fastscan::accumulate>(
fastscan::detail::qg_batch_estdist_impl<float, fastscan::accumulate>(
batch_data, query_wrapper, padded_dim, estimated_distances
);
}
Expand All @@ -66,7 +67,7 @@ uint32_t qg_batch_estdist_mask_avx2(
float* estimated_distances,
float threshold
) {
qg_batch_estdist_impl<fastscan::accumulate>(
fastscan::detail::qg_batch_estdist_impl<float, fastscan::accumulate>(
batch_data, query_wrapper, padded_dim, estimated_distances
);
return candidate_mask_impl(estimated_distances, threshold);
Expand Down
3 changes: 2 additions & 1 deletion src/fastscan/estimator_avx512.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "estimator_kernels.hpp"
#include "rabitqlib/fastscan/detail/estimator_dispatch.hpp"
#include "rabitqlib/fastscan/detail/qg_estimator.hpp"
#include "rabitqlib/fastscan/detail/simd.hpp"

namespace rabitqlib::simd {
Expand Down Expand Up @@ -45,7 +46,7 @@ void qg_batch_estdist_avx512(
if (padded_dim == 0 || padded_dim % 16 != 0) {
throw std::invalid_argument("FastScan dimension must be a positive multiple of 16");
}
qg_batch_estdist_impl<fastscan::simd::accumulate_avx512>(
fastscan::detail::qg_batch_estdist_impl<float, fastscan::simd::accumulate_avx512>(
batch_data, query_wrapper, padded_dim, estimated_distances
);
}
Expand Down
5 changes: 3 additions & 2 deletions src/fastscan/estimator_generic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "estimator_kernels.hpp"
#include "rabitqlib/fastscan/detail/estimator_dispatch.hpp"
#include "rabitqlib/fastscan/detail/qg_estimator.hpp"
#include "rabitqlib/fastscan/fastscan.hpp"
#include "rabitqlib/fastscan/highacc_fastscan.hpp"

Expand Down Expand Up @@ -45,7 +46,7 @@ void qg_batch_estdist_generic(
size_t padded_dim,
float* estimated_distances
) {
qg_batch_estdist_impl<fastscan::accumulate>(
fastscan::detail::qg_batch_estdist_impl<float, fastscan::accumulate>(
batch_data, query_wrapper, padded_dim, estimated_distances
);
}
Expand All @@ -61,7 +62,7 @@ uint32_t qg_batch_estdist_mask_generic(
float* estimated_distances,
float threshold
) {
qg_batch_estdist_impl<fastscan::accumulate>(
fastscan::detail::qg_batch_estdist_impl<float, fastscan::accumulate>(
batch_data, query_wrapper, padded_dim, estimated_distances
);
return candidate_mask_impl(estimated_distances, threshold);
Expand Down
29 changes: 0 additions & 29 deletions src/fastscan/estimator_kernels.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,34 +63,5 @@ inline void split_batch_estdist_impl(
low_dist_arr = est_dist_arr - f_error_arr * query_wrapper.g_error();
}

template <auto Accumulate>
inline void qg_batch_estdist_impl(
const char* batch_data,
const BatchQuery<float>& query_wrapper,
size_t padded_dim,
float* estimated_distances
) {
using T = float;
ConstQGBatchDataMap<T> cur_batch(batch_data, padded_dim);
std::array<int32_t, fastscan::kBatchSize> accu_values{};
Accumulate(cur_batch.bin_code(), query_wrapper.lut(), accu_values.data(), padded_dim);

ConstRowMajorArrayMap<int32_t> ip_arr(accu_values.data(), 1, fastscan::kBatchSize);
std::array<T, fastscan::kBatchSize> f_add_values;
std::array<T, fastscan::kBatchSize> f_rescale_values;
cur_batch.f_add().copy_to(f_add_values.data(), f_add_values.size());
cur_batch.f_rescale().copy_to(f_rescale_values.data(), f_rescale_values.size());
ConstRowMajorArrayMap<T> f_add_arr(f_add_values.data(), 1, fastscan::kBatchSize);
ConstRowMajorArrayMap<T> f_rescale_arr(
f_rescale_values.data(), 1, fastscan::kBatchSize
);

RowMajorArrayMap<T> est_dist_arr(estimated_distances, 1, fastscan::kBatchSize);

est_dist_arr = f_add_arr + query_wrapper.g_add() +
(f_rescale_arr * (query_wrapper.delta() * (ip_arr.template cast<T>()) +
query_wrapper.sum_vl_lut() + query_wrapper.k1xsumq()));
}

} // namespace
} // namespace rabitqlib::simd
2 changes: 0 additions & 2 deletions src/index/hnsw_search_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ inline std::vector<std::pair<float, PID>> HierarchicalNSW::search_knn_sorted_dir
k,
query_wrapper,
q_to_centroids,
rotated_query,
nearest_candidates
);
result.reserve(nearest_candidates.size());
Expand All @@ -204,7 +203,6 @@ inline void HierarchicalNSW::search_base_layer_direct(
size_t k,
const SplitSingleQuery<float>& query_wrapper,
const std::vector<float>& q_to_centroids,
[[maybe_unused]] const float* query,
BoundedKNN& nearest_candidates
) const {
auto visited = visited_list_pool_->get_free_vislist();
Expand Down
Loading