hnswlib 0.6.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/README.md +14 -7
- data/ext/hnswlib/hnswlibext.cpp +1 -3
- data/ext/hnswlib/hnswlibext.hpp +326 -93
- data/ext/hnswlib/src/bruteforce.h +142 -131
- data/ext/hnswlib/src/hnswalg.h +1028 -964
- data/ext/hnswlib/src/hnswlib.h +74 -66
- data/ext/hnswlib/src/space_ip.h +299 -299
- data/ext/hnswlib/src/space_l2.h +268 -273
- data/ext/hnswlib/src/visited_list_pool.h +54 -55
- data/lib/hnswlib/version.rb +2 -2
- data/lib/hnswlib.rb +21 -18
- data/sig/hnswlib.rbs +9 -7
- metadata +3 -3
data/ext/hnswlib/src/space_l2.h
CHANGED
@@ -3,329 +3,324 @@
|
|
3
3
|
|
4
4
|
namespace hnswlib {
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
}
|
19
|
-
return (res);
|
6
|
+
static float
|
7
|
+
L2Sqr(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
|
8
|
+
float *pVect1 = (float *) pVect1v;
|
9
|
+
float *pVect2 = (float *) pVect2v;
|
10
|
+
size_t qty = *((size_t *) qty_ptr);
|
11
|
+
|
12
|
+
float res = 0;
|
13
|
+
for (size_t i = 0; i < qty; i++) {
|
14
|
+
float t = *pVect1 - *pVect2;
|
15
|
+
pVect1++;
|
16
|
+
pVect2++;
|
17
|
+
res += t * t;
|
20
18
|
}
|
19
|
+
return (res);
|
20
|
+
}
|
21
21
|
|
22
22
|
#if defined(USE_AVX512)
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
24
|
+
// Favor using AVX512 if available.
|
25
|
+
static float
|
26
|
+
L2SqrSIMD16ExtAVX512(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
|
27
|
+
float *pVect1 = (float *) pVect1v;
|
28
|
+
float *pVect2 = (float *) pVect2v;
|
29
|
+
size_t qty = *((size_t *) qty_ptr);
|
30
|
+
float PORTABLE_ALIGN64 TmpRes[16];
|
31
|
+
size_t qty16 = qty >> 4;
|
32
|
+
|
33
|
+
const float *pEnd1 = pVect1 + (qty16 << 4);
|
34
|
+
|
35
|
+
__m512 diff, v1, v2;
|
36
|
+
__m512 sum = _mm512_set1_ps(0);
|
37
|
+
|
38
|
+
while (pVect1 < pEnd1) {
|
39
|
+
v1 = _mm512_loadu_ps(pVect1);
|
40
|
+
pVect1 += 16;
|
41
|
+
v2 = _mm512_loadu_ps(pVect2);
|
42
|
+
pVect2 += 16;
|
43
|
+
diff = _mm512_sub_ps(v1, v2);
|
44
|
+
// sum = _mm512_fmadd_ps(diff, diff, sum);
|
45
|
+
sum = _mm512_add_ps(sum, _mm512_mul_ps(diff, diff));
|
46
|
+
}
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
_mm512_store_ps(TmpRes, sum);
|
49
|
+
float res = TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3] + TmpRes[4] + TmpRes[5] + TmpRes[6] +
|
50
|
+
TmpRes[7] + TmpRes[8] + TmpRes[9] + TmpRes[10] + TmpRes[11] + TmpRes[12] +
|
51
|
+
TmpRes[13] + TmpRes[14] + TmpRes[15];
|
52
52
|
|
53
|
-
|
53
|
+
return (res);
|
54
54
|
}
|
55
55
|
#endif
|
56
56
|
|
57
57
|
#if defined(USE_AVX)
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
}
|
88
|
-
|
89
|
-
_mm256_store_ps(TmpRes, sum);
|
90
|
-
return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3] + TmpRes[4] + TmpRes[5] + TmpRes[6] + TmpRes[7];
|
59
|
+
// Favor using AVX if available.
|
60
|
+
static float
|
61
|
+
L2SqrSIMD16ExtAVX(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
|
62
|
+
float *pVect1 = (float *) pVect1v;
|
63
|
+
float *pVect2 = (float *) pVect2v;
|
64
|
+
size_t qty = *((size_t *) qty_ptr);
|
65
|
+
float PORTABLE_ALIGN32 TmpRes[8];
|
66
|
+
size_t qty16 = qty >> 4;
|
67
|
+
|
68
|
+
const float *pEnd1 = pVect1 + (qty16 << 4);
|
69
|
+
|
70
|
+
__m256 diff, v1, v2;
|
71
|
+
__m256 sum = _mm256_set1_ps(0);
|
72
|
+
|
73
|
+
while (pVect1 < pEnd1) {
|
74
|
+
v1 = _mm256_loadu_ps(pVect1);
|
75
|
+
pVect1 += 8;
|
76
|
+
v2 = _mm256_loadu_ps(pVect2);
|
77
|
+
pVect2 += 8;
|
78
|
+
diff = _mm256_sub_ps(v1, v2);
|
79
|
+
sum = _mm256_add_ps(sum, _mm256_mul_ps(diff, diff));
|
80
|
+
|
81
|
+
v1 = _mm256_loadu_ps(pVect1);
|
82
|
+
pVect1 += 8;
|
83
|
+
v2 = _mm256_loadu_ps(pVect2);
|
84
|
+
pVect2 += 8;
|
85
|
+
diff = _mm256_sub_ps(v1, v2);
|
86
|
+
sum = _mm256_add_ps(sum, _mm256_mul_ps(diff, diff));
|
91
87
|
}
|
92
88
|
|
89
|
+
_mm256_store_ps(TmpRes, sum);
|
90
|
+
return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3] + TmpRes[4] + TmpRes[5] + TmpRes[6] + TmpRes[7];
|
91
|
+
}
|
92
|
+
|
93
93
|
#endif
|
94
94
|
|
95
95
|
#if defined(USE_SSE)
|
96
96
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
}
|
140
|
-
|
141
|
-
_mm_store_ps(TmpRes, sum);
|
142
|
-
return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3];
|
97
|
+
static float
|
98
|
+
L2SqrSIMD16ExtSSE(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
|
99
|
+
float *pVect1 = (float *) pVect1v;
|
100
|
+
float *pVect2 = (float *) pVect2v;
|
101
|
+
size_t qty = *((size_t *) qty_ptr);
|
102
|
+
float PORTABLE_ALIGN32 TmpRes[8];
|
103
|
+
size_t qty16 = qty >> 4;
|
104
|
+
|
105
|
+
const float *pEnd1 = pVect1 + (qty16 << 4);
|
106
|
+
|
107
|
+
__m128 diff, v1, v2;
|
108
|
+
__m128 sum = _mm_set1_ps(0);
|
109
|
+
|
110
|
+
while (pVect1 < pEnd1) {
|
111
|
+
//_mm_prefetch((char*)(pVect2 + 16), _MM_HINT_T0);
|
112
|
+
v1 = _mm_loadu_ps(pVect1);
|
113
|
+
pVect1 += 4;
|
114
|
+
v2 = _mm_loadu_ps(pVect2);
|
115
|
+
pVect2 += 4;
|
116
|
+
diff = _mm_sub_ps(v1, v2);
|
117
|
+
sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
|
118
|
+
|
119
|
+
v1 = _mm_loadu_ps(pVect1);
|
120
|
+
pVect1 += 4;
|
121
|
+
v2 = _mm_loadu_ps(pVect2);
|
122
|
+
pVect2 += 4;
|
123
|
+
diff = _mm_sub_ps(v1, v2);
|
124
|
+
sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
|
125
|
+
|
126
|
+
v1 = _mm_loadu_ps(pVect1);
|
127
|
+
pVect1 += 4;
|
128
|
+
v2 = _mm_loadu_ps(pVect2);
|
129
|
+
pVect2 += 4;
|
130
|
+
diff = _mm_sub_ps(v1, v2);
|
131
|
+
sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
|
132
|
+
|
133
|
+
v1 = _mm_loadu_ps(pVect1);
|
134
|
+
pVect1 += 4;
|
135
|
+
v2 = _mm_loadu_ps(pVect2);
|
136
|
+
pVect2 += 4;
|
137
|
+
diff = _mm_sub_ps(v1, v2);
|
138
|
+
sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
|
143
139
|
}
|
140
|
+
|
141
|
+
_mm_store_ps(TmpRes, sum);
|
142
|
+
return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3];
|
143
|
+
}
|
144
144
|
#endif
|
145
145
|
|
146
146
|
#if defined(USE_SSE) || defined(USE_AVX) || defined(USE_AVX512)
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
147
|
+
static DISTFUNC<float> L2SqrSIMD16Ext = L2SqrSIMD16ExtSSE;
|
148
|
+
|
149
|
+
static float
|
150
|
+
L2SqrSIMD16ExtResiduals(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
|
151
|
+
size_t qty = *((size_t *) qty_ptr);
|
152
|
+
size_t qty16 = qty >> 4 << 4;
|
153
|
+
float res = L2SqrSIMD16Ext(pVect1v, pVect2v, &qty16);
|
154
|
+
float *pVect1 = (float *) pVect1v + qty16;
|
155
|
+
float *pVect2 = (float *) pVect2v + qty16;
|
156
|
+
|
157
|
+
size_t qty_left = qty - qty16;
|
158
|
+
float res_tail = L2Sqr(pVect1, pVect2, &qty_left);
|
159
|
+
return (res + res_tail);
|
160
|
+
}
|
161
161
|
#endif
|
162
162
|
|
163
163
|
|
164
164
|
#if defined(USE_SSE)
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
165
|
+
static float
|
166
|
+
L2SqrSIMD4Ext(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
|
167
|
+
float PORTABLE_ALIGN32 TmpRes[8];
|
168
|
+
float *pVect1 = (float *) pVect1v;
|
169
|
+
float *pVect2 = (float *) pVect2v;
|
170
|
+
size_t qty = *((size_t *) qty_ptr);
|
171
171
|
|
172
172
|
|
173
|
-
|
173
|
+
size_t qty4 = qty >> 2;
|
174
174
|
|
175
|
-
|
175
|
+
const float *pEnd1 = pVect1 + (qty4 << 2);
|
176
176
|
|
177
|
-
|
178
|
-
|
177
|
+
__m128 diff, v1, v2;
|
178
|
+
__m128 sum = _mm_set1_ps(0);
|
179
179
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
}
|
188
|
-
_mm_store_ps(TmpRes, sum);
|
189
|
-
return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3];
|
180
|
+
while (pVect1 < pEnd1) {
|
181
|
+
v1 = _mm_loadu_ps(pVect1);
|
182
|
+
pVect1 += 4;
|
183
|
+
v2 = _mm_loadu_ps(pVect2);
|
184
|
+
pVect2 += 4;
|
185
|
+
diff = _mm_sub_ps(v1, v2);
|
186
|
+
sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
|
190
187
|
}
|
188
|
+
_mm_store_ps(TmpRes, sum);
|
189
|
+
return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3];
|
190
|
+
}
|
191
191
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
192
|
+
static float
|
193
|
+
L2SqrSIMD4ExtResiduals(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
|
194
|
+
size_t qty = *((size_t *) qty_ptr);
|
195
|
+
size_t qty4 = qty >> 2 << 2;
|
196
196
|
|
197
|
-
|
198
|
-
|
197
|
+
float res = L2SqrSIMD4Ext(pVect1v, pVect2v, &qty4);
|
198
|
+
size_t qty_left = qty - qty4;
|
199
199
|
|
200
|
-
|
201
|
-
|
202
|
-
|
200
|
+
float *pVect1 = (float *) pVect1v + qty4;
|
201
|
+
float *pVect2 = (float *) pVect2v + qty4;
|
202
|
+
float res_tail = L2Sqr(pVect1, pVect2, &qty_left);
|
203
203
|
|
204
|
-
|
205
|
-
|
204
|
+
return (res + res_tail);
|
205
|
+
}
|
206
206
|
#endif
|
207
207
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
if (dim % 16 == 0)
|
229
|
-
fstdistfunc_ = L2SqrSIMD16Ext;
|
230
|
-
else if (dim % 4 == 0)
|
231
|
-
fstdistfunc_ = L2SqrSIMD4Ext;
|
232
|
-
else if (dim > 16)
|
233
|
-
fstdistfunc_ = L2SqrSIMD16ExtResiduals;
|
234
|
-
else if (dim > 4)
|
235
|
-
fstdistfunc_ = L2SqrSIMD4ExtResiduals;
|
208
|
+
class L2Space : public SpaceInterface<float> {
|
209
|
+
DISTFUNC<float> fstdistfunc_;
|
210
|
+
size_t data_size_;
|
211
|
+
size_t dim_;
|
212
|
+
|
213
|
+
public:
|
214
|
+
L2Space() : data_size_(0), dim_(0) { }
|
215
|
+
|
216
|
+
L2Space(size_t dim) {
|
217
|
+
fstdistfunc_ = L2Sqr;
|
218
|
+
#if defined(USE_SSE) || defined(USE_AVX) || defined(USE_AVX512)
|
219
|
+
#if defined(USE_AVX512)
|
220
|
+
if (AVX512Capable())
|
221
|
+
L2SqrSIMD16Ext = L2SqrSIMD16ExtAVX512;
|
222
|
+
else if (AVXCapable())
|
223
|
+
L2SqrSIMD16Ext = L2SqrSIMD16ExtAVX;
|
224
|
+
#elif defined(USE_AVX)
|
225
|
+
if (AVXCapable())
|
226
|
+
L2SqrSIMD16Ext = L2SqrSIMD16ExtAVX;
|
236
227
|
#endif
|
237
|
-
dim_ = dim;
|
238
|
-
data_size_ = dim * sizeof(float);
|
239
|
-
}
|
240
228
|
|
241
|
-
|
242
|
-
|
243
|
-
|
229
|
+
if (dim % 16 == 0)
|
230
|
+
fstdistfunc_ = L2SqrSIMD16Ext;
|
231
|
+
else if (dim % 4 == 0)
|
232
|
+
fstdistfunc_ = L2SqrSIMD4Ext;
|
233
|
+
else if (dim > 16)
|
234
|
+
fstdistfunc_ = L2SqrSIMD16ExtResiduals;
|
235
|
+
else if (dim > 4)
|
236
|
+
fstdistfunc_ = L2SqrSIMD4ExtResiduals;
|
237
|
+
#endif
|
238
|
+
dim_ = dim;
|
239
|
+
data_size_ = dim * sizeof(float);
|
240
|
+
}
|
244
241
|
|
245
|
-
|
246
|
-
|
247
|
-
|
242
|
+
size_t get_data_size() {
|
243
|
+
return data_size_;
|
244
|
+
}
|
248
245
|
|
249
|
-
|
250
|
-
|
251
|
-
|
246
|
+
DISTFUNC<float> get_dist_func() {
|
247
|
+
return fstdistfunc_;
|
248
|
+
}
|
252
249
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
static int
|
257
|
-
L2SqrI4x(const void *__restrict pVect1, const void *__restrict pVect2, const void *__restrict qty_ptr) {
|
258
|
-
|
259
|
-
size_t qty = *((size_t *) qty_ptr);
|
260
|
-
int res = 0;
|
261
|
-
unsigned char *a = (unsigned char *) pVect1;
|
262
|
-
unsigned char *b = (unsigned char *) pVect2;
|
263
|
-
|
264
|
-
qty = qty >> 2;
|
265
|
-
for (size_t i = 0; i < qty; i++) {
|
266
|
-
|
267
|
-
res += ((*a) - (*b)) * ((*a) - (*b));
|
268
|
-
a++;
|
269
|
-
b++;
|
270
|
-
res += ((*a) - (*b)) * ((*a) - (*b));
|
271
|
-
a++;
|
272
|
-
b++;
|
273
|
-
res += ((*a) - (*b)) * ((*a) - (*b));
|
274
|
-
a++;
|
275
|
-
b++;
|
276
|
-
res += ((*a) - (*b)) * ((*a) - (*b));
|
277
|
-
a++;
|
278
|
-
b++;
|
279
|
-
}
|
280
|
-
return (res);
|
250
|
+
void *get_dist_func_param() {
|
251
|
+
return &dim_;
|
281
252
|
}
|
282
253
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
254
|
+
~L2Space() {}
|
255
|
+
};
|
256
|
+
|
257
|
+
static int
|
258
|
+
L2SqrI4x(const void *__restrict pVect1, const void *__restrict pVect2, const void *__restrict qty_ptr) {
|
259
|
+
size_t qty = *((size_t *) qty_ptr);
|
260
|
+
int res = 0;
|
261
|
+
unsigned char *a = (unsigned char *) pVect1;
|
262
|
+
unsigned char *b = (unsigned char *) pVect2;
|
263
|
+
|
264
|
+
qty = qty >> 2;
|
265
|
+
for (size_t i = 0; i < qty; i++) {
|
266
|
+
res += ((*a) - (*b)) * ((*a) - (*b));
|
267
|
+
a++;
|
268
|
+
b++;
|
269
|
+
res += ((*a) - (*b)) * ((*a) - (*b));
|
270
|
+
a++;
|
271
|
+
b++;
|
272
|
+
res += ((*a) - (*b)) * ((*a) - (*b));
|
273
|
+
a++;
|
274
|
+
b++;
|
275
|
+
res += ((*a) - (*b)) * ((*a) - (*b));
|
276
|
+
a++;
|
277
|
+
b++;
|
296
278
|
}
|
279
|
+
return (res);
|
280
|
+
}
|
297
281
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
public:
|
304
|
-
L2SpaceI(size_t dim) {
|
305
|
-
if(dim % 4 == 0) {
|
306
|
-
fstdistfunc_ = L2SqrI4x;
|
307
|
-
}
|
308
|
-
else {
|
309
|
-
fstdistfunc_ = L2SqrI;
|
310
|
-
}
|
311
|
-
dim_ = dim;
|
312
|
-
data_size_ = dim * sizeof(unsigned char);
|
313
|
-
}
|
282
|
+
static int L2SqrI(const void* __restrict pVect1, const void* __restrict pVect2, const void* __restrict qty_ptr) {
|
283
|
+
size_t qty = *((size_t*)qty_ptr);
|
284
|
+
int res = 0;
|
285
|
+
unsigned char* a = (unsigned char*)pVect1;
|
286
|
+
unsigned char* b = (unsigned char*)pVect2;
|
314
287
|
|
315
|
-
|
316
|
-
|
317
|
-
|
288
|
+
for (size_t i = 0; i < qty; i++) {
|
289
|
+
res += ((*a) - (*b)) * ((*a) - (*b));
|
290
|
+
a++;
|
291
|
+
b++;
|
292
|
+
}
|
293
|
+
return (res);
|
294
|
+
}
|
318
295
|
|
319
|
-
|
320
|
-
|
296
|
+
class L2SpaceI : public SpaceInterface<int> {
|
297
|
+
DISTFUNC<int> fstdistfunc_;
|
298
|
+
size_t data_size_;
|
299
|
+
size_t dim_;
|
300
|
+
|
301
|
+
public:
|
302
|
+
L2SpaceI(size_t dim) {
|
303
|
+
if (dim % 4 == 0) {
|
304
|
+
fstdistfunc_ = L2SqrI4x;
|
305
|
+
} else {
|
306
|
+
fstdistfunc_ = L2SqrI;
|
321
307
|
}
|
308
|
+
dim_ = dim;
|
309
|
+
data_size_ = dim * sizeof(unsigned char);
|
310
|
+
}
|
322
311
|
|
323
|
-
|
324
|
-
|
325
|
-
|
312
|
+
size_t get_data_size() {
|
313
|
+
return data_size_;
|
314
|
+
}
|
326
315
|
|
327
|
-
|
328
|
-
|
316
|
+
DISTFUNC<int> get_dist_func() {
|
317
|
+
return fstdistfunc_;
|
318
|
+
}
|
329
319
|
|
320
|
+
void *get_dist_func_param() {
|
321
|
+
return &dim_;
|
322
|
+
}
|
330
323
|
|
331
|
-
}
|
324
|
+
~L2SpaceI() {}
|
325
|
+
};
|
326
|
+
} // namespace hnswlib
|