Skip to content

Commit 092155f

Browse files
mdouzefacebook-github-bot
authored andcommitted
group SWIG tests into one file (facebookresearch#3807)
Summary: Pull Request resolved: facebookresearch#3807 This diff re-organizes the tests a bit: * groups tests related to SWIG into a single file * enable doxygen test conditionally * removes a dep on platform.Version that does not exist on some envs * move a few tests out of build_blocks to avoid it being a catch-all file for uncategorized tests Differential Revision: D61959750
1 parent 95e0a66 commit 092155f

7 files changed

+214
-199
lines changed

faiss/python/loader.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
# This source code is licensed under the MIT license found in the
44
# LICENSE file in the root directory of this source tree.
55

6-
from packaging.version import Version
76
import platform
87
import subprocess
98
import logging
109
import os
1110

1211

12+
def Version(v):
13+
return [int(x) for x in v.split('.')]
14+
1315
def supported_instruction_sets():
1416
"""
1517
Returns the set of supported CPU features, see

faiss/python/swigfaiss.swig

+8-5
Original file line numberDiff line numberDiff line change
@@ -1245,10 +1245,13 @@ void * cast_integer_to_void_ptr (int64_t x) {
12451245
%}
12461246

12471247
%inline %{
1248-
void wait() {
1249-
// in gdb, use return to get out of this function
1250-
for(int i = 0; i == 0; i += 0);
1251-
}
1252-
%}
1248+
1249+
// the SWIG version is a 6-digit hex string, eg. version 3.2.1 is encoded as
1250+
// 0x030201
1251+
uint64_t swig_version() {
1252+
return SWIG_VERSION;
1253+
}
1254+
1255+
%}
12531256

12541257
// End of file...

tests/test_build_blocks.py

+1-174
Original file line numberDiff line numberDiff line change
@@ -66,43 +66,6 @@ def test_pca_epsilon(self):
6666
self.assertTrue(np.all(np.isfinite(y)))
6767

6868

69-
class TestRevSwigPtr(unittest.TestCase):
70-
71-
def test_rev_swig_ptr(self):
72-
73-
index = faiss.IndexFlatL2(4)
74-
xb0 = np.vstack([
75-
i * 10 + np.array([1, 2, 3, 4], dtype='float32')
76-
for i in range(5)])
77-
index.add(xb0)
78-
xb = faiss.rev_swig_ptr(index.get_xb(), 4 * 5).reshape(5, 4)
79-
self.assertEqual(np.abs(xb0 - xb).sum(), 0)
80-
81-
82-
class TestException(unittest.TestCase):
83-
84-
def test_exception(self):
85-
86-
index = faiss.IndexFlatL2(10)
87-
88-
a = np.zeros((5, 10), dtype='float32')
89-
b = np.zeros(5, dtype='int64')
90-
91-
# an unsupported operation for IndexFlat
92-
self.assertRaises(
93-
RuntimeError,
94-
index.add_with_ids, a, b
95-
)
96-
# assert 'add_with_ids not implemented' in str(e)
97-
98-
def test_exception_2(self):
99-
self.assertRaises(
100-
RuntimeError,
101-
faiss.index_factory, 12, 'IVF256,Flat,PQ8'
102-
)
103-
# assert 'could not parse' in str(e)
104-
105-
10669
class TestMapLong2Long(unittest.TestCase):
10770

10871
def test_maplong2long(self):
@@ -380,7 +343,6 @@ def test_rand_vector(self):
380343
self.assertLess(ninter, 460)
381344

382345

383-
384346
class TestPairwiseDis(unittest.TestCase):
385347

386348
def test_L2(self):
@@ -418,142 +380,6 @@ def test_IP(self):
418380
dis[i], np.dot(x[ix[i]], y[iy[i]]))
419381

420382

421-
class TestSWIGWrap(unittest.TestCase):
422-
""" various regressions with the SWIG wrapper """
423-
424-
def test_size_t_ptr(self):
425-
# issue 1064
426-
index = faiss.IndexHNSWFlat(10, 32)
427-
428-
hnsw = index.hnsw
429-
index.add(np.random.rand(100, 10).astype('float32'))
430-
be = np.empty(2, 'uint64')
431-
hnsw.neighbor_range(23, 0, faiss.swig_ptr(be), faiss.swig_ptr(be[1:]))
432-
433-
def test_id_map_at(self):
434-
# issue 1020
435-
n_features = 100
436-
feature_dims = 10
437-
438-
features = np.random.random((n_features, feature_dims)).astype(np.float32)
439-
idx = np.arange(n_features).astype(np.int64)
440-
441-
index = faiss.IndexFlatL2(feature_dims)
442-
index = faiss.IndexIDMap2(index)
443-
index.add_with_ids(features, idx)
444-
445-
[index.id_map.at(int(i)) for i in range(index.ntotal)]
446-
447-
def test_downcast_Refine(self):
448-
449-
index = faiss.IndexRefineFlat(
450-
faiss.IndexScalarQuantizer(10, faiss.ScalarQuantizer.QT_8bit)
451-
)
452-
453-
# serialize and deserialize
454-
index2 = faiss.deserialize_index(
455-
faiss.serialize_index(index)
456-
)
457-
458-
assert isinstance(index2, faiss.IndexRefineFlat)
459-
460-
def do_test_array_type(self, dtype):
461-
""" tests swig_ptr and rev_swig_ptr for this type of array """
462-
a = np.arange(12).astype(dtype)
463-
ptr = faiss.swig_ptr(a)
464-
a2 = faiss.rev_swig_ptr(ptr, 12)
465-
np.testing.assert_array_equal(a, a2)
466-
467-
def test_all_array_types(self):
468-
self.do_test_array_type('float32')
469-
self.do_test_array_type('float64')
470-
self.do_test_array_type('int8')
471-
self.do_test_array_type('uint8')
472-
self.do_test_array_type('int16')
473-
self.do_test_array_type('uint16')
474-
self.do_test_array_type('int32')
475-
self.do_test_array_type('uint32')
476-
self.do_test_array_type('int64')
477-
self.do_test_array_type('uint64')
478-
479-
def test_int64(self):
480-
# see https://github.com/facebookresearch/faiss/issues/1529
481-
v = faiss.Int64Vector()
482-
483-
for i in range(10):
484-
v.push_back(i)
485-
a = faiss.vector_to_array(v)
486-
assert a.dtype == 'int64'
487-
np.testing.assert_array_equal(a, np.arange(10, dtype='int64'))
488-
489-
# check if it works in an IDMap
490-
idx = faiss.IndexIDMap(faiss.IndexFlatL2(32))
491-
idx.add_with_ids(
492-
np.random.rand(10, 32).astype('float32'),
493-
np.random.randint(1000, size=10, dtype='int64')
494-
)
495-
faiss.vector_to_array(idx.id_map)
496-
497-
498-
class TestNNDescentKNNG(unittest.TestCase):
499-
500-
def test_knng_L2(self):
501-
self.subtest(32, 10, faiss.METRIC_L2)
502-
503-
def test_knng_IP(self):
504-
self.subtest(32, 10, faiss.METRIC_INNER_PRODUCT)
505-
506-
def subtest(self, d, K, metric):
507-
metric_names = {faiss.METRIC_L1: 'L1',
508-
faiss.METRIC_L2: 'L2',
509-
faiss.METRIC_INNER_PRODUCT: 'IP'}
510-
511-
nb = 1000
512-
_, xb, _ = get_dataset_2(d, 0, nb, 0)
513-
514-
_, knn = faiss.knn(xb, xb, K + 1, metric)
515-
knn = knn[:, 1:]
516-
517-
index = faiss.IndexNNDescentFlat(d, K, metric)
518-
index.nndescent.S = 10
519-
index.nndescent.R = 32
520-
index.nndescent.L = K + 20
521-
index.nndescent.iter = 5
522-
index.verbose = True
523-
524-
index.add(xb)
525-
graph = index.nndescent.final_graph
526-
graph = faiss.vector_to_array(graph)
527-
graph = graph.reshape(nb, K)
528-
529-
recalls = 0
530-
for i in range(nb):
531-
for j in range(K):
532-
for k in range(K):
533-
if graph[i, j] == knn[i, k]:
534-
recalls += 1
535-
break
536-
recall = 1.0 * recalls / (nb * K)
537-
assert recall > 0.99
538-
539-
def test_small_nndescent(self):
540-
""" building a too small graph used to crash, make sure it raises
541-
an exception instead.
542-
TODO: build the exact knn graph for small cases
543-
"""
544-
d = 32
545-
K = 10
546-
index = faiss.IndexNNDescentFlat(d, K, faiss.METRIC_L2)
547-
index.nndescent.S = 10
548-
index.nndescent.R = 32
549-
index.nndescent.L = K + 20
550-
index.nndescent.iter = 5
551-
index.verbose = True
552-
553-
xb = np.zeros((78, d), dtype='float32')
554-
self.assertRaises(RuntimeError, index.add, xb)
555-
556-
557383
class TestResultHeap(unittest.TestCase):
558384

559385
def test_keep_min(self):
@@ -663,6 +489,7 @@ def test_bucket_sort_inplace_int64(self):
663489
def test_bucket_sort_inplace_parallel_int64(self):
664490
self.do_test_bucket_sort_inplace(4, dtype='int64')
665491

492+
666493
class TestMergeKNNResults(unittest.TestCase):
667494

668495
def do_test(self, ismax, dtype):

tests/test_documentation.py

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# LICENSE file in the root directory of this source tree.
55

66
import unittest
7-
87
import faiss
98

109

tests/test_doxygen_documentation.py

-17
This file was deleted.

tests/test_graph_based.py

+60-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# This source code is licensed under the MIT license found in the
44
# LICENSE file in the root directory of this source tree.
55

6-
""" a few tests for graph-based indices (HNSW and NSG)"""
6+
""" a few tests for graph-based indices (HNSW, nndescent and NSG)"""
77

88
import numpy as np
99
import unittest
@@ -506,3 +506,62 @@ def test_order(self):
506506
gt = np.arange(0, k)[np.newaxis, :] # [1, k]
507507
gt = np.repeat(gt, nq, axis=0) # [nq, k]
508508
np.testing.assert_array_equal(indices, gt)
509+
510+
511+
class TestNNDescentKNNG(unittest.TestCase):
512+
513+
def test_knng_L2(self):
514+
self.subtest(32, 10, faiss.METRIC_L2)
515+
516+
def test_knng_IP(self):
517+
self.subtest(32, 10, faiss.METRIC_INNER_PRODUCT)
518+
519+
def subtest(self, d, K, metric):
520+
metric_names = {faiss.METRIC_L1: 'L1',
521+
faiss.METRIC_L2: 'L2',
522+
faiss.METRIC_INNER_PRODUCT: 'IP'}
523+
524+
nb = 1000
525+
_, xb, _ = get_dataset_2(d, 0, nb, 0)
526+
527+
_, knn = faiss.knn(xb, xb, K + 1, metric)
528+
knn = knn[:, 1:]
529+
530+
index = faiss.IndexNNDescentFlat(d, K, metric)
531+
index.nndescent.S = 10
532+
index.nndescent.R = 32
533+
index.nndescent.L = K + 20
534+
index.nndescent.iter = 5
535+
index.verbose = True
536+
537+
index.add(xb)
538+
graph = index.nndescent.final_graph
539+
graph = faiss.vector_to_array(graph)
540+
graph = graph.reshape(nb, K)
541+
542+
recalls = 0
543+
for i in range(nb):
544+
for j in range(K):
545+
for k in range(K):
546+
if graph[i, j] == knn[i, k]:
547+
recalls += 1
548+
break
549+
recall = 1.0 * recalls / (nb * K)
550+
assert recall > 0.99
551+
552+
def test_small_nndescent(self):
553+
""" building a too small graph used to crash, make sure it raises
554+
an exception instead.
555+
TODO: build the exact knn graph for small cases
556+
"""
557+
d = 32
558+
K = 10
559+
index = faiss.IndexNNDescentFlat(d, K, faiss.METRIC_L2)
560+
index.nndescent.S = 10
561+
index.nndescent.R = 32
562+
index.nndescent.L = K + 20
563+
index.nndescent.iter = 5
564+
index.verbose = True
565+
566+
xb = np.zeros((78, d), dtype='float32')
567+
self.assertRaises(RuntimeError, index.add, xb)

0 commit comments

Comments
 (0)