Skip to content

Commit acd42a6

Browse files
committed
code formatting
1 parent 007b172 commit acd42a6

7 files changed

Lines changed: 95 additions & 72 deletions

File tree

benchmarks/filtered_search_benchmark.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,8 @@ static void BM_HNSW_Search_Filter_Bitset(benchmark::State& state) {
9090

9191
for (auto _ : state) {
9292
for (const auto& q : data.queries) {
93-
auto results =
94-
data.index.search_with_filter(std::span<const float>{q}, k, ef,
95-
[&](size_t id) { return data.allowed[id] != 0; });
93+
auto results = data.index.search_with_filter(
94+
std::span<const float>{q}, k, ef, [&](size_t id) { return data.allowed[id] != 0; });
9695
benchmark::DoNotOptimize(results);
9796
}
9897
}
@@ -113,9 +112,10 @@ static void BM_HNSW_Search_Filter_Set(benchmark::State& state) {
113112

114113
for (auto _ : state) {
115114
for (const auto& q : data.queries) {
116-
auto results = data.index.search_with_filter(
117-
std::span<const float>{q}, k, ef,
118-
[&](size_t id) { return data.allowed_set.contains(id); });
115+
auto results =
116+
data.index.search_with_filter(std::span<const float>{q}, k, ef, [&](size_t id) {
117+
return data.allowed_set.contains(id);
118+
});
119119
benchmark::DoNotOptimize(results);
120120
}
121121
}

benchmarks/hnsw_768d_m_comparison.cpp

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,21 @@ std::vector<float> gen_vec(size_t dim, std::mt19937& rng) {
1919
std::uniform_real_distribution<float> dist(-1.0f, 1.0f);
2020
std::vector<float> vec(dim);
2121
float norm = 0.0f;
22-
for (auto& v : vec) { v = dist(rng); norm += v * v; }
22+
for (auto& v : vec) {
23+
v = dist(rng);
24+
norm += v * v;
25+
}
2326
norm = std::sqrt(norm);
24-
for (auto& v : vec) { v /= norm; }
27+
for (auto& v : vec) {
28+
v /= norm;
29+
}
2530
return vec;
2631
}
2732

2833
// Compute ground truth top-k for a single query (brute force)
29-
std::unordered_set<size_t> compute_gt(
30-
const std::vector<float>& query,
31-
const std::vector<std::vector<float>>& corpus,
32-
size_t k, const CosineMetric<float>& metric
33-
) {
34+
std::unordered_set<size_t> compute_gt(const std::vector<float>& query,
35+
const std::vector<std::vector<float>>& corpus, size_t k,
36+
const CosineMetric<float>& metric) {
3437
std::vector<std::pair<size_t, float>> dists;
3538
dists.reserve(corpus.size());
3639
for (size_t i = 0; i < corpus.size(); ++i) {
@@ -40,7 +43,8 @@ std::unordered_set<size_t> compute_gt(
4043
std::partial_sort(dists.begin(), dists.begin() + k, dists.end(),
4144
[](auto& a, auto& b) { return a.second < b.second; });
4245
std::unordered_set<size_t> result;
43-
for (size_t i = 0; i < k; ++i) result.insert(dists[i].first);
46+
for (size_t i = 0; i < k; ++i)
47+
result.insert(dists[i].first);
4448
return result;
4549
}
4650

@@ -51,24 +55,29 @@ int main() {
5155

5256
printf("=================================================================\n");
5357
printf("768d Recall Benchmark: M=24 vs M=32\n");
54-
printf("Corpus: %zu, Dim: %zu, k: %zu, Queries: %zu, Threads: %zu\n",
55-
corpus_size, dim, k, num_queries, num_threads);
58+
printf("Corpus: %zu, Dim: %zu, k: %zu, Queries: %zu, Threads: %zu\n", corpus_size, dim, k,
59+
num_queries, num_threads);
5660
printf("=================================================================\n\n");
5761
fflush(stdout);
5862

5963
// Generate corpus
60-
printf("Generating corpus...\n"); fflush(stdout);
64+
printf("Generating corpus...\n");
65+
fflush(stdout);
6166
std::vector<std::vector<float>> vecs;
6267
vecs.reserve(corpus_size);
63-
for (size_t i = 0; i < corpus_size; ++i) vecs.push_back(gen_vec(dim, rng));
68+
for (size_t i = 0; i < corpus_size; ++i)
69+
vecs.push_back(gen_vec(dim, rng));
6470

6571
// Generate queries
66-
printf("Generating queries...\n"); fflush(stdout);
72+
printf("Generating queries...\n");
73+
fflush(stdout);
6774
std::vector<std::vector<float>> qvecs;
68-
for (size_t i = 0; i < num_queries; ++i) qvecs.push_back(gen_vec(dim, rng));
75+
for (size_t i = 0; i < num_queries; ++i)
76+
qvecs.push_back(gen_vec(dim, rng));
6977

7078
// Parallel ground truth computation
71-
printf("Computing ground truth (parallel, %zu threads)...\n", num_threads); fflush(stdout);
79+
printf("Computing ground truth (parallel, %zu threads)...\n", num_threads);
80+
fflush(stdout);
7281
auto gt_start = std::chrono::high_resolution_clock::now();
7382

7483
std::vector<std::unordered_set<size_t>> gt_sets(num_queries);
@@ -85,42 +94,49 @@ int main() {
8594
for (size_t t = 0; t < num_threads; ++t) {
8695
size_t start = t * chunk;
8796
size_t end = std::min(start + chunk, num_queries);
88-
if (start < end) threads.emplace_back(worker, start, end);
97+
if (start < end)
98+
threads.emplace_back(worker, start, end);
8999
}
90-
for (auto& t : threads) t.join();
100+
for (auto& t : threads)
101+
t.join();
91102

92103
auto gt_end = std::chrono::high_resolution_clock::now();
93-
printf("Ground truth: %.1fs\n\n",
94-
std::chrono::duration<double>(gt_end - gt_start).count());
104+
printf("Ground truth: %.1fs\n\n", std::chrono::duration<double>(gt_end - gt_start).count());
95105
fflush(stdout);
96106

97107
printf("%-6s | %-10s | %-12s | %-12s\n", "M", "ef_search", "Recall@10", "Latency(us)");
98108
printf("-------|------------|--------------|-------------\n");
99109
fflush(stdout);
100110

101-
for (auto [M, M_max, M_max_0] : {std::tuple{24,48,96}, std::tuple{32,64,128}}) {
111+
for (auto [M, M_max, M_max_0] : {std::tuple{24, 48, 96}, std::tuple{32, 64, 128}}) {
102112
// Build index
103113
HNSWIndex<float, CosineMetric<float>>::Config cfg;
104-
cfg.M = M; cfg.M_max = M_max; cfg.M_max_0 = M_max_0; cfg.ef_construction = 200;
114+
cfg.M = M;
115+
cfg.M_max = M_max;
116+
cfg.M_max_0 = M_max_0;
117+
cfg.ef_construction = 200;
105118
HNSWIndex<float, CosineMetric<float>> idx(cfg);
106119

107120
auto build_start = std::chrono::high_resolution_clock::now();
108121
for (size_t i = 0; i < corpus_size; ++i)
109122
idx.insert(i, std::span<const float>{vecs[i]});
110123
auto build_end = std::chrono::high_resolution_clock::now();
111124
double build_s = std::chrono::duration<double>(build_end - build_start).count();
112-
printf("M=%d built in %.1fs\n", M, build_s); fflush(stdout);
125+
printf("M=%d built in %.1fs\n", M, build_s);
126+
fflush(stdout);
113127

114128
for (size_t ef : {50UL, 100UL, 200UL}) {
115129
size_t hits = 0;
116130
auto start = std::chrono::high_resolution_clock::now();
117131
for (size_t q = 0; q < num_queries; ++q) {
118132
auto results = idx.search(std::span<const float>{qvecs[q]}, k, ef);
119133
for (const auto& [id, _] : results)
120-
if (gt_sets[q].count(id)) ++hits;
134+
if (gt_sets[q].count(id))
135+
++hits;
121136
}
122137
auto end = std::chrono::high_resolution_clock::now();
123-
double lat_us = std::chrono::duration<double, std::micro>(end - start).count() / num_queries;
138+
double lat_us =
139+
std::chrono::duration<double, std::micro>(end - start).count() / num_queries;
124140
double recall = 100.0 * hits / (num_queries * k);
125141
printf("%-6d | %-10zu | %10.1f%% | %10.1f\n", M, ef, recall, lat_us);
126142
fflush(stdout);
@@ -129,6 +145,7 @@ int main() {
129145
fflush(stdout);
130146
}
131147

132-
printf("\nConclusion: If M=32 recall > M=24 by >3%%, consider extending Config::for_corpus()\n");
148+
printf(
149+
"\nConclusion: If M=32 recall > M=24 by >3%%, consider extending Config::for_corpus()\n");
133150
return 0;
134151
}

benchmarks/hnsw_768d_quick.cpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@ std::vector<float> gen_vec(size_t dim, std::mt19937& rng) {
1414
std::uniform_real_distribution<float> dist(-1.0f, 1.0f);
1515
std::vector<float> vec(dim);
1616
float norm = 0.0f;
17-
for (auto& v : vec) { v = dist(rng); norm += v * v; }
17+
for (auto& v : vec) {
18+
v = dist(rng);
19+
norm += v * v;
20+
}
1821
norm = std::sqrt(norm);
19-
for (auto& v : vec) { v /= norm; }
22+
for (auto& v : vec) {
23+
v /= norm;
24+
}
2025
return vec;
2126
}
2227

@@ -28,19 +33,24 @@ int main() {
2833

2934
// Generate data once
3035
std::vector<std::vector<float>> vecs, qvecs;
31-
for (size_t i = 0; i < corpus; ++i) vecs.push_back(gen_vec(dim, rng));
32-
for (size_t i = 0; i < queries; ++i) qvecs.push_back(gen_vec(dim, rng));
36+
for (size_t i = 0; i < corpus; ++i)
37+
vecs.push_back(gen_vec(dim, rng));
38+
for (size_t i = 0; i < queries; ++i)
39+
qvecs.push_back(gen_vec(dim, rng));
3340

34-
for (auto [M, M_max, M_max_0] : {std::tuple{24,48,96}, std::tuple{32,64,128}}) {
41+
for (auto [M, M_max, M_max_0] : {std::tuple{24, 48, 96}, std::tuple{32, 64, 128}}) {
3542
HNSWIndex<float, CosineMetric<float>>::Config cfg;
36-
cfg.M = M; cfg.M_max = M_max; cfg.M_max_0 = M_max_0; cfg.ef_construction = 200;
43+
cfg.M = M;
44+
cfg.M_max = M_max;
45+
cfg.M_max_0 = M_max_0;
46+
cfg.ef_construction = 200;
3747
HNSWIndex<float, CosineMetric<float>> idx(cfg);
3848

3949
auto t1 = std::chrono::high_resolution_clock::now();
4050
for (size_t i = 0; i < corpus; ++i)
4151
idx.insert(i, std::span<const float>{vecs[i]});
4252
auto t2 = std::chrono::high_resolution_clock::now();
43-
double build_ms = std::chrono::duration<double, std::milli>(t2-t1).count();
53+
double build_ms = std::chrono::duration<double, std::milli>(t2 - t1).count();
4454

4555
printf("M=%d: build=%.0fms", M, build_ms);
4656

@@ -49,7 +59,7 @@ int main() {
4959
for (size_t q = 0; q < queries; ++q)
5060
idx.search(std::span<const float>{qvecs[q]}, k, ef);
5161
auto e = std::chrono::high_resolution_clock::now();
52-
double lat_us = std::chrono::duration<double, std::micro>(e-s).count() / queries;
62+
double lat_us = std::chrono::duration<double, std::micro>(e - s).count() / queries;
5363
printf(" | ef=%zu: %.0fus", ef, lat_us);
5464
}
5565
printf("\n");

benchmarks/hnsw_benchmark.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,7 @@ static void BM_HNSW_FP16_Drift(benchmark::State& state) {
449449
if (it != f32_dist.end()) {
450450
++total_hits;
451451
if (it->second > 0.0f) {
452-
ratio_sum += static_cast<double>(dist) /
453-
static_cast<double>(it->second);
452+
ratio_sum += static_cast<double>(dist) / static_cast<double>(it->second);
454453
++ratio_count;
455454
}
456455
}

include/sqlite-vec-cpp/index/hnsw.hpp

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ template <concepts::VectorElement StorageT, typename MetricT> class HNSWIndex {
5656
size_t ef_construction = 200; ///< Exploration factor during construction (100-500)
5757
float ml_factor = 1.0f / std::log(2.0f); ///< Layer selection multiplier (1/ln(2))
5858
MetricT metric{}; ///< Distance metric (operates on float spans)
59-
bool clamp_negative_distances = true; ///< Clamp negative distances to 0 (safe for L2/cosine)
59+
bool clamp_negative_distances =
60+
true; ///< Clamp negative distances to 0 (safe for L2/cosine)
6061

6162
/// Create config optimized for high recall on large corpora
6263
/// @param corpus_size Expected number of vectors
@@ -478,9 +479,8 @@ template <concepts::VectorElement StorageT, typename MetricT> class HNSWIndex {
478479

479480
{
480481
std::unique_lock lock(nodes_mutex_);
481-
auto [it, inserted] =
482-
nodes_.emplace(ids_span[i],
483-
NodeType(ids_span[i], vectors_span[i], layer, config_.M_max));
482+
auto [it, inserted] = nodes_.emplace(
483+
ids_span[i], NodeType(ids_span[i], vectors_span[i], layer, config_.M_max));
484484
if (!inserted) {
485485
return;
486486
}
@@ -526,8 +526,8 @@ template <concepts::VectorElement StorageT, typename MetricT> class HNSWIndex {
526526
}
527527

528528
for (size_t lc = layer;; --lc) {
529-
auto candidates = beam_search_layer_batch(vector_f32, current,
530-
config_.ef_construction, lc);
529+
auto candidates =
530+
beam_search_layer_batch(vector_f32, current, config_.ef_construction, lc);
531531

532532
size_t M = (lc == 0) ? config_.M_max_0 : config_.M;
533533
size_t num_connections = std::min(M, candidates.size());
@@ -824,8 +824,8 @@ template <concepts::VectorElement StorageT, typename MetricT> class HNSWIndex {
824824
// Remove edges to deleted nodes at each layer
825825
for (size_t layer = 0; layer < node.edges.size(); ++layer) {
826826
auto& layer_edges = node.edges[layer];
827-
std::erase_if(
828-
layer_edges, [this](size_t neighbor) { return is_deleted_unlocked(neighbor); });
827+
std::erase_if(layer_edges,
828+
[this](size_t neighbor) { return is_deleted_unlocked(neighbor); });
829829
}
830830
}
831831
}
@@ -904,9 +904,7 @@ template <concepts::VectorElement StorageT, typename MetricT> class HNSWIndex {
904904
return current;
905905
float current_dist = distance_query_node(query, *current_node);
906906

907-
auto passes_filter = [&](size_t id) {
908-
return !is_deleted_unlocked(id);
909-
};
907+
auto passes_filter = [&](size_t id) { return !is_deleted_unlocked(id); };
910908
size_t best_active = passes_filter(current) ? current : static_cast<size_t>(-1);
911909
float best_active_dist =
912910
passes_filter(current) ? current_dist : std::numeric_limits<float>::max();
@@ -951,9 +949,9 @@ template <concepts::VectorElement StorageT, typename MetricT> class HNSWIndex {
951949
return (best_active != static_cast<size_t>(-1)) ? best_active : current;
952950
}
953951

954-
std::vector<std::pair<size_t, float>>
955-
beam_search_layer_batch(std::span<const float> query, size_t entry_point, size_t ef,
956-
size_t layer) const {
952+
std::vector<std::pair<size_t, float>> beam_search_layer_batch(std::span<const float> query,
953+
size_t entry_point, size_t ef,
954+
size_t layer) const {
957955
auto cmp = [](const auto& a, const auto& b) { return a.first < b.first; };
958956
std::priority_queue<std::pair<float, size_t>, std::vector<std::pair<float, size_t>>,
959957
decltype(cmp)>
@@ -978,9 +976,7 @@ template <concepts::VectorElement StorageT, typename MetricT> class HNSWIndex {
978976
}
979977
visited.visit(entry_dense);
980978

981-
auto passes_filter = [&](size_t id) {
982-
return !is_deleted_unlocked(id);
983-
};
979+
auto passes_filter = [&](size_t id) { return !is_deleted_unlocked(id); };
984980

985981
const float kDistanceEpsilon =
986982
config_.clamp_negative_distances ? -1e-5f : std::numeric_limits<float>::lowest();
@@ -1054,17 +1050,16 @@ template <concepts::VectorElement StorageT, typename MetricT> class HNSWIndex {
10541050
neighbor_dist < top_candidates.top().first;
10551051

10561052
if (should_explore) {
1057-
float scored =
1058-
config_.clamp_negative_distances ? std::max(0.0f, neighbor_dist)
1059-
: neighbor_dist;
1053+
float scored = config_.clamp_negative_distances ? std::max(0.0f, neighbor_dist)
1054+
: neighbor_dist;
10601055
candidates.emplace(scored, neighbor);
10611056
}
10621057

10631058
if (passes_filter(neighbor)) {
10641059
if (top_candidates.size() < ef || neighbor_dist < top_candidates.top().first) {
1065-
float scored =
1066-
config_.clamp_negative_distances ? std::max(0.0f, neighbor_dist)
1067-
: neighbor_dist;
1060+
float scored = config_.clamp_negative_distances
1061+
? std::max(0.0f, neighbor_dist)
1062+
: neighbor_dist;
10681063
top_candidates.emplace(scored, neighbor);
10691064
if (top_candidates.size() > ef) {
10701065
top_candidates.pop();
@@ -1088,7 +1083,9 @@ template <concepts::VectorElement StorageT, typename MetricT> class HNSWIndex {
10881083
return result;
10891084
}
10901085

1091-
void prune_connections_batch(size_t node_id, size_t layer) { prune_connections(node_id, layer); }
1086+
void prune_connections_batch(size_t node_id, size_t layer) {
1087+
prune_connections(node_id, layer);
1088+
}
10921089

10931090
/// Greedy search (read-only, called under shared lock)
10941091
size_t greedy_search_layer_locked(std::span<const float> query, size_t entry_point,

include/sqlite-vec-cpp/index/hnsw_node.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ template <concepts::VectorElement T> struct HNSWNode {
4949
std::lock_guard<std::mutex> lock(edge_mutex_);
5050
if (layer >= edges.size())
5151
return {};
52-
return edges[layer]; // Return copy to avoid data race after lock release
52+
return edges[layer]; // Return copy to avoid data race after lock release
5353
}
5454

5555
/// Add bidirectional edge at layer (thread-safe)

tests/test_distances.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
#include <cmath>
33
#include <iostream>
44
#include <vector>
5-
#include <sqlite-vec-cpp/sqlite_vec.hpp>
6-
#include <sqlite-vec-cpp/distances/l2.hpp>
75
#include <sqlite-vec-cpp/distances/cosine.hpp>
86
#include <sqlite-vec-cpp/distances/inner_product.hpp>
7+
#include <sqlite-vec-cpp/distances/l2.hpp>
98
#include <sqlite-vec-cpp/simd/avx.hpp>
109
#include <sqlite-vec-cpp/simd/neon.hpp>
10+
#include <sqlite-vec-cpp/sqlite_vec.hpp>
1111

1212
using namespace sqlite_vec_cpp;
1313
using namespace sqlite_vec_cpp::distances;
@@ -218,8 +218,8 @@ void test_simd_consistency() {
218218
inner_product_distance_float(std::span<const float>(a), std::span<const float>(b));
219219

220220
#ifdef SQLITE_VEC_ENABLE_AVX
221-
float l2_avx = simd::l2_distance_float_avx(std::span<const float>(a),
222-
std::span<const float>(b));
221+
float l2_avx =
222+
simd::l2_distance_float_avx(std::span<const float>(a), std::span<const float>(b));
223223
float cosine_avx =
224224
simd::cosine_distance_float_avx(std::span<const float>(a), std::span<const float>(b));
225225
float ip_avx =
@@ -230,8 +230,8 @@ void test_simd_consistency() {
230230
#endif
231231

232232
#ifdef SQLITE_VEC_ENABLE_NEON
233-
float l2_neon = simd::l2_distance_float_neon(std::span<const float>(a),
234-
std::span<const float>(b));
233+
float l2_neon =
234+
simd::l2_distance_float_neon(std::span<const float>(a), std::span<const float>(b));
235235
float cosine_neon =
236236
simd::cosine_distance_float_neon(std::span<const float>(a), std::span<const float>(b));
237237
float ip_neon =

0 commit comments

Comments
 (0)