Skip to content

Commit 45af1e5

Browse files
committed
test(nphd): add regression tests for NPHD metric persistence
Add comprehensive regression tests to catch future metric persistence bugs: - test_load_preserves_nphd_metric(): Verifies that load() preserves the custom NPHD metric instead of falling back to standard Hamming distance - test_view_preserves_nphd_metric(): Same test for the view() method Both tests create vectors with known differences, verify correct NPHD distances before save, then validate identical distances after load/view. This ensures the custom metric is properly restored and not overwritten by usearch's default. Covers the critical persistence bug where searches on loaded indexes were returning incorrect results.
1 parent 518f907 commit 45af1e5

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

tests/test_nphd_load.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,40 @@ def test_loaded_index_supports_operations(tmp_path):
8989

9090
matches = loaded.search(vector1, count=1)
9191
assert matches.keys[0] == 1
92+
93+
94+
def test_load_preserves_nphd_metric(tmp_path):
95+
"""Regression test: Load preserves custom NPHD metric instead of using standard Hamming."""
96+
# Create index with two similar vectors (differ by 1 bit)
97+
index = NphdIndex(max_dim=256)
98+
vector1 = np.array([1, 2, 3, 4, 5, 6, 7, 8], dtype=np.uint8)
99+
vector2 = np.array([1, 2, 3, 4, 5, 6, 7, 9], dtype=np.uint8) # Last byte differs by 1 bit
100+
index.add([100, 200], [vector1, vector2])
101+
102+
# Search before save - should use NPHD metric
103+
results_before = index.search(vector1, count=2)
104+
distances_before = results_before.distances
105+
106+
# The NPHD distance should be small (around 0.015625 for 1 bit difference in 64-bit vector)
107+
# If using standard Hamming, it would be 1.0
108+
assert distances_before[0] == 0.0 # Exact match
109+
assert distances_before[1] < 0.1 # Small NPHD distance, not 1.0
110+
111+
# Save and load
112+
file_path = tmp_path / "index.usearch"
113+
index.save(str(file_path))
114+
115+
loaded = NphdIndex(max_dim=256)
116+
loaded.load(str(file_path))
117+
118+
# Search after load - MUST use same NPHD metric
119+
results_after = loaded.search(vector1, count=2)
120+
distances_after = results_after.distances
121+
122+
# Critical: Distances must match (proves NPHD metric is preserved)
123+
np.testing.assert_array_almost_equal(
124+
distances_before,
125+
distances_after,
126+
decimal=6,
127+
err_msg="NPHD metric was not preserved after load() - distances changed",
128+
)

tests/test_nphd_view.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,40 @@ def test_viewed_index_supports_search(tmp_path):
8585

8686
matches = viewed.search(vector, count=1)
8787
assert matches.keys[0] == 1
88+
89+
90+
def test_view_preserves_nphd_metric(tmp_path):
91+
"""Regression test: View preserves custom NPHD metric instead of using standard Hamming."""
92+
# Create index with two similar vectors (differ by 1 bit)
93+
index = NphdIndex(max_dim=256)
94+
vector1 = np.array([1, 2, 3, 4, 5, 6, 7, 8], dtype=np.uint8)
95+
vector2 = np.array([1, 2, 3, 4, 5, 6, 7, 9], dtype=np.uint8) # Last byte differs by 1 bit
96+
index.add([100, 200], [vector1, vector2])
97+
98+
# Search before save - should use NPHD metric
99+
results_before = index.search(vector1, count=2)
100+
distances_before = results_before.distances
101+
102+
# The NPHD distance should be small (around 0.015625 for 1 bit difference in 64-bit vector)
103+
# If using standard Hamming, it would be 1.0
104+
assert distances_before[0] == 0.0 # Exact match
105+
assert distances_before[1] < 0.1 # Small NPHD distance, not 1.0
106+
107+
# Save and view
108+
file_path = tmp_path / "index.usearch"
109+
index.save(str(file_path))
110+
111+
viewed = NphdIndex(max_dim=256)
112+
viewed.view(str(file_path))
113+
114+
# Search after view - MUST use same NPHD metric
115+
results_after = viewed.search(vector1, count=2)
116+
distances_after = results_after.distances
117+
118+
# Critical: Distances must match (proves NPHD metric is preserved)
119+
np.testing.assert_array_almost_equal(
120+
distances_before,
121+
distances_after,
122+
decimal=6,
123+
err_msg="NPHD metric was not preserved after view() - distances changed",
124+
)

0 commit comments

Comments
 (0)