import math
import struct
import numpy as np
import pytest
from apexbase.client import ApexClient, encode_vector, decode_vector
@pytest.fixture
def client(tmp_path):
c = ApexClient(dirpath=str(tmp_path), drop_if_exists=True)
c.create_table("vecs")
yield c
c.close()
def test_encode_decode_list():
v = [1.0, 2.0, 3.0]
assert decode_vector(encode_vector(v)) == pytest.approx(v, abs=1e-6)
def test_encode_decode_numpy():
v = np.array([1.0, 2.0, 3.0], dtype=np.float32)
decoded = decode_vector(encode_vector(v))
assert decoded == pytest.approx(v.tolist(), abs=1e-6)
def test_encode_decode_empty():
assert decode_vector(encode_vector([])) == []
def test_auto_encode_list_vectors(client):
rows = [
{"name": "a", "vec": [1.0, 0.0, 0.0]},
{"name": "b", "vec": [0.0, 1.0, 0.0]},
{"name": "c", "vec": [0.0, 0.0, 1.0]},
]
client.store(rows)
result = client.execute("SELECT name FROM vecs ORDER BY name").to_dict()
assert [r["name"] for r in result] == ["a", "b", "c"]
def test_auto_encode_numpy_vectors(client):
rows = [
{"name": "x", "vec": np.array([1.0, 2.0, 3.0], dtype=np.float32)},
{"name": "y", "vec": np.array([4.0, 5.0, 6.0], dtype=np.float32)},
]
client.store(rows)
result = client.execute("SELECT COUNT(*) FROM vecs").to_dict()
assert result[0]["COUNT(*)"] == 2
def _load_3d_vecs(client):
rows = [
{"name": "origin", "vec": [0.0, 0.0, 0.0]},
{"name": "unit_x", "vec": [1.0, 0.0, 0.0]},
{"name": "unit_y", "vec": [0.0, 1.0, 0.0]},
{"name": "unit_z", "vec": [0.0, 0.0, 1.0]},
{"name": "diag", "vec": [1.0, 1.0, 1.0]},
]
client.store(rows)
def test_l2_distance(client):
_load_3d_vecs(client)
rows = client.execute(
"SELECT name, array_distance(vec, [1.0, 0.0, 0.0]) AS dist FROM vecs "
"ORDER BY name"
).to_dict()
dist = {r["name"]: r["dist"] for r in rows}
assert dist["unit_x"] == pytest.approx(0.0, abs=1e-5)
assert dist["origin"] == pytest.approx(1.0, abs=1e-5)
assert dist["unit_y"] == pytest.approx(math.sqrt(2), abs=1e-5)
def test_l2_distance_alias(client):
_load_3d_vecs(client)
rows = client.execute(
"SELECT name, l2_distance(vec, [1.0, 0.0, 0.0]) AS dist FROM vecs "
"ORDER BY name"
).to_dict()
dist = {r["name"]: r["dist"] for r in rows}
assert dist["unit_x"] == pytest.approx(0.0, abs=1e-5)
def test_cosine_similarity(client):
_load_3d_vecs(client)
rows = client.execute(
"SELECT name, cosine_similarity(vec, [1.0, 0.0, 0.0]) AS sim FROM vecs "
"ORDER BY name"
).to_dict()
sim = {r["name"]: r["sim"] for r in rows}
assert sim["unit_x"] == pytest.approx(1.0, abs=1e-5)
assert sim["unit_y"] == pytest.approx(0.0, abs=1e-5)
assert sim["diag"] == pytest.approx(1.0 / math.sqrt(3), abs=1e-5)
def test_cosine_distance(client):
_load_3d_vecs(client)
rows = client.execute(
"SELECT name, cosine_distance(vec, [1.0, 0.0, 0.0]) AS d FROM vecs "
"ORDER BY name"
).to_dict()
d = {r["name"]: r["d"] for r in rows}
assert d["unit_x"] == pytest.approx(0.0, abs=1e-5)
assert d["unit_y"] == pytest.approx(1.0, abs=1e-5)
def test_inner_product(client):
_load_3d_vecs(client)
rows = client.execute(
"SELECT name, inner_product(vec, [1.0, 2.0, 3.0]) AS ip FROM vecs "
"ORDER BY name"
).to_dict()
ip = {r["name"]: r["ip"] for r in rows}
assert ip["origin"] == pytest.approx(0.0, abs=1e-5)
assert ip["unit_x"] == pytest.approx(1.0, abs=1e-5)
assert ip["unit_y"] == pytest.approx(2.0, abs=1e-5)
assert ip["unit_z"] == pytest.approx(3.0, abs=1e-5)
assert ip["diag"] == pytest.approx(6.0, abs=1e-5)
def test_l1_distance(client):
_load_3d_vecs(client)
rows = client.execute(
"SELECT name, l1_distance(vec, [1.0, 0.0, 0.0]) AS d FROM vecs "
"ORDER BY name"
).to_dict()
d = {r["name"]: r["d"] for r in rows}
assert d["unit_x"] == pytest.approx(0.0, abs=1e-5)
assert d["origin"] == pytest.approx(1.0, abs=1e-5)
assert d["diag"] == pytest.approx(2.0, abs=1e-5)
def test_linf_distance(client):
_load_3d_vecs(client)
rows = client.execute(
"SELECT name, linf_distance(vec, [0.5, 0.5, 0.5]) AS d FROM vecs "
"ORDER BY name"
).to_dict()
d = {r["name"]: r["d"] for r in rows}
assert d["origin"] == pytest.approx(0.5, abs=1e-5)
assert d["unit_x"] == pytest.approx(0.5, abs=1e-5)
assert d["diag"] == pytest.approx(0.5, abs=1e-5)
def _load_many(client, n=100, dim=8):
rng = np.random.default_rng(42)
rows = [
{"id": i, "vec": (rng.random(dim).astype(np.float32)).tolist()}
for i in range(n)
]
client.store(rows)
return rows
def test_topk_l2_with_alias(client):
rows = _load_many(client, n=50, dim=4)
query = [0.5, 0.5, 0.5, 0.5]
result = client.execute(
f"SELECT id, array_distance(vec, [{','.join(map(str, query))}]) AS dist "
"FROM vecs ORDER BY dist LIMIT 5"
).to_dict()
assert len(result) == 5
dists = [r["dist"] for r in result]
assert dists == sorted(dists)
def test_topk_l2_expression_orderby(client):
rows = _load_many(client, n=50, dim=4)
query = [0.5, 0.5, 0.5, 0.5]
result = client.execute(
f"SELECT id FROM vecs "
f"ORDER BY array_distance(vec, [{','.join(map(str, query))}]) LIMIT 5"
).to_dict()
assert len(result) == 5
result_alias = client.execute(
f"SELECT id, array_distance(vec, [{','.join(map(str, query))}]) AS dist "
"FROM vecs ORDER BY dist LIMIT 5"
).to_dict()
ids_expr = {r["id"] for r in result}
ids_alias = {r["id"] for r in result_alias}
assert ids_expr == ids_alias
def test_topk_cosine_similarity_desc(client):
rows = _load_many(client, n=50, dim=4)
query = [1.0, 0.0, 0.0, 0.0]
result = client.execute(
f"SELECT id, cosine_similarity(vec, [{','.join(map(str, query))}]) AS sim "
"FROM vecs ORDER BY sim DESC LIMIT 5"
).to_dict()
assert len(result) == 5
sims = [r["sim"] for r in result]
assert sims == sorted(sims, reverse=True)
def test_vector_dim(client):
client.store([{"vec": [1.0, 2.0, 3.0]}, {"vec": [4.0, 5.0]}])
result = client.execute("SELECT vector_dim(vec) AS dim FROM vecs ORDER BY dim").to_dict()
dims = sorted([r["dim"] for r in result])
assert dims == [2, 3]
def test_vector_norm(client):
client.store([{"vec": [3.0, 4.0]}])
result = client.execute("SELECT vector_norm(vec) AS n FROM vecs").to_dict()
assert result[0]["n"] == pytest.approx(5.0, abs=1e-5)
def test_vector_to_string(client):
client.store([{"vec": [1.0, 0.0]}])
result = client.execute("SELECT vector_to_string(vec) AS s FROM vecs").to_dict()
assert result[0]["s"].startswith("[")
assert "1" in result[0]["s"]
def test_string_literal_query(client):
_load_3d_vecs(client)
result = client.execute(
"SELECT name, array_distance(vec, '[1.0,0.0,0.0]') AS dist FROM vecs "
"ORDER BY name"
).to_dict()
d = {r["name"]: r["dist"] for r in result}
assert d["unit_x"] == pytest.approx(0.0, abs=1e-5)
def test_duckdb_names(client):
_load_3d_vecs(client)
for fn in ["array_distance", "array_cosine_similarity", "array_inner_product",
"array_l1_distance", "array_cosine_distance"]:
result = client.execute(
f"SELECT {fn}(vec, [1.0, 0.0, 0.0]) AS v FROM vecs LIMIT 1"
).to_dict()
assert len(result) == 1
assert result[0]["v"] is not None
def _bootstrap_vec_schema(client):
client.store([{"id": 0, "vec": encode_vector([0.0, 0.0, 0.0])}])
client.flush()
def test_sql_insert_array_literal(client):
_bootstrap_vec_schema(client)
client.execute("INSERT INTO vecs (id, vec) VALUES (1, [1.0, 0.0, 0.0])")
client.execute("INSERT INTO vecs (id, vec) VALUES (2, [0.0, 1.0, 0.0])")
client.flush()
result = client.execute(
"SELECT id, array_distance(vec, [1.0, 0.0, 0.0]) AS dist FROM vecs ORDER BY dist"
).to_dict()
assert result[0]["id"] == 1
assert result[0]["dist"] == pytest.approx(0.0, abs=1e-5)
assert result[1]["dist"] == pytest.approx(1.0, abs=1e-5)
assert result[2]["dist"] == pytest.approx(math.sqrt(2), abs=1e-4)
def test_sql_insert_string_literal(client):
_bootstrap_vec_schema(client)
client.execute("INSERT INTO vecs (id, vec) VALUES (1, '[1.0, 0.0, 0.0]')")
client.execute("INSERT INTO vecs (id, vec) VALUES (2, '[0.0, 1.0, 0.0]')")
client.flush()
result = client.execute(
"SELECT id, array_distance(vec, [1.0, 0.0, 0.0]) AS dist FROM vecs ORDER BY dist"
).to_dict()
assert result[0]["id"] == 1
assert result[0]["dist"] == pytest.approx(0.0, abs=1e-5)
def test_sql_insert_multi_values(client):
_bootstrap_vec_schema(client)
client.execute(
"INSERT INTO vecs (id, vec) VALUES "
"(1, [1.0, 0.0, 0.0]), "
"(2, [0.0, 1.0, 0.0]), "
"(3, [0.0, 0.0, 1.0])"
)
client.flush()
result = client.execute("SELECT id FROM vecs ORDER BY id").to_dict()
assert [r["id"] for r in result] == [0, 1, 2, 3]
def test_sql_insert_negative_components(client):
_bootstrap_vec_schema(client)
client.execute("INSERT INTO vecs (id, vec) VALUES (1, [-1.0, -0.5, 0.0])")
client.flush()
result = client.execute(
"SELECT vector_dim(vec) AS d FROM vecs WHERE id = 1"
).to_dict()
assert result[0]["d"] == 3
def test_sql_insert_then_topk(client):
_bootstrap_vec_schema(client)
client.execute(
"INSERT INTO vecs (id, vec) VALUES "
"(1, [1.0, 0.0, 0.0]), "
"(2, [0.9, 0.1, 0.0]), "
"(3, [0.0, 0.0, 1.0])"
)
client.flush()
result = client.execute(
"SELECT id, array_distance(vec, [1.0, 0.0, 0.0]) AS dist "
"FROM vecs ORDER BY dist LIMIT 2"
).to_dict()
assert len(result) == 2
ids = [r["id"] for r in result]
assert 1 in ids
dists = [r["dist"] for r in result]
assert dists == sorted(dists)
def test_l2_squared_distance(client):
_load_3d_vecs(client)
q = [1.0, 0.0, 0.0]
rows = client.execute(
f"SELECT name, l2_squared_distance(vec, [{','.join(map(str,q))}]) AS d FROM vecs ORDER BY name"
).to_dict()
d = {r["name"]: r["d"] for r in rows}
assert d["unit_x"] == pytest.approx(0.0, abs=1e-5)
assert d["origin"] == pytest.approx(1.0, abs=1e-5) assert d["unit_y"] == pytest.approx(2.0, abs=1e-5) assert d["diag"] == pytest.approx(2.0, abs=1e-5)
def test_l2_squared_equals_l2_squared_numpy(client):
rng = np.random.default_rng(7)
vecs = rng.random((10, 4), dtype=np.float32)
q = rng.random(4, dtype=np.float32)
rows = [{"id": i, "vec": vecs[i].tolist()} for i in range(len(vecs))]
client.store(rows)
result = client.execute(
"SELECT id, l2_squared_distance(vec, [{}]) AS d FROM vecs ORDER BY id".format(
",".join(f"{v:.6f}" for v in q)
)
).to_dict()
for r in result:
np_sq = float(np.sum((vecs[r["id"]] - q) ** 2))
assert r["d"] == pytest.approx(np_sq, rel=1e-4)
def test_l2_squared_topk_consistent_with_l2(client):
rows = _load_many(client, n=60, dim=4)
q = [0.3, 0.6, 0.1, 0.8]
q_str = ",".join(map(str, q))
ids_l2 = {r["id"] for r in client.execute(
f"SELECT id FROM vecs ORDER BY array_distance(vec, [{q_str}]) LIMIT 5"
).to_dict()}
ids_sq = {r["id"] for r in client.execute(
f"SELECT id FROM vecs ORDER BY l2_squared_distance(vec, [{q_str}]) LIMIT 5"
).to_dict()}
assert ids_l2 == ids_sq
def test_negative_inner_product_values(client):
_load_3d_vecs(client)
q = [1.0, 2.0, 3.0]
rows = client.execute(
"SELECT name, negative_inner_product(vec, [1.0, 2.0, 3.0]) AS v FROM vecs ORDER BY name"
).to_dict()
v = {r["name"]: r["v"] for r in rows}
assert v["origin"] == pytest.approx(0.0, abs=1e-5)
assert v["unit_x"] == pytest.approx(-1.0, abs=1e-5)
assert v["unit_y"] == pytest.approx(-2.0, abs=1e-5)
assert v["unit_z"] == pytest.approx(-3.0, abs=1e-5)
assert v["diag"] == pytest.approx(-6.0, abs=1e-5)
def test_topk_negative_inner_product(client):
rows = _load_many(client, n=60, dim=4)
q = [1.0, 0.0, 0.0, 0.0]
q_str = ",".join(map(str, q))
result = client.execute(
f"SELECT id, negative_inner_product(vec, [{q_str}]) AS nip "
"FROM vecs ORDER BY nip LIMIT 5"
).to_dict()
assert len(result) == 5
nips = [r["nip"] for r in result]
assert nips == sorted(nips)
assert all(v <= 0.0 for v in nips)
def test_topk_l1_distance(client):
rows = _load_many(client, n=60, dim=4)
q = [0.5, 0.5, 0.5, 0.5]
q_str = ",".join(map(str, q))
result = client.execute(
f"SELECT id, l1_distance(vec, [{q_str}]) AS dist FROM vecs ORDER BY dist LIMIT 5"
).to_dict()
assert len(result) == 5
dists = [r["dist"] for r in result]
assert dists == sorted(dists)
def test_topk_linf_distance(client):
rows = _load_many(client, n=60, dim=4)
q = [0.5, 0.5, 0.5, 0.5]
q_str = ",".join(map(str, q))
result = client.execute(
f"SELECT id, linf_distance(vec, [{q_str}]) AS dist FROM vecs ORDER BY dist LIMIT 5"
).to_dict()
assert len(result) == 5
dists = [r["dist"] for r in result]
assert dists == sorted(dists)
def test_l1_l2_linf_inequality(client):
_load_3d_vecs(client)
q = [0.5, 0.5, 0.5]
q_str = ",".join(map(str, q))
rows = client.execute(
f"SELECT name, "
f"l1_distance(vec, [{q_str}]) AS l1, "
f"array_distance(vec, [{q_str}]) AS l2, "
f"linf_distance(vec, [{q_str}]) AS linf "
f"FROM vecs"
).to_dict()
for r in rows:
assert r["linf"] <= r["l2"] + 1e-5
assert r["l2"] <= r["l1"] + 1e-5
def _np_l2(a, b):
return float(np.sqrt(np.sum((np.array(a, dtype=np.float32) - np.array(b, dtype=np.float32)) ** 2)))
def _np_l1(a, b):
return float(np.sum(np.abs(np.array(a, dtype=np.float32) - np.array(b, dtype=np.float32))))
def _np_linf(a, b):
return float(np.max(np.abs(np.array(a, dtype=np.float32) - np.array(b, dtype=np.float32))))
def _np_cosine_sim(a, b):
a, b = np.array(a, dtype=np.float32), np.array(b, dtype=np.float32)
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-12))
def _np_dot(a, b):
return float(np.dot(np.array(a, dtype=np.float32), np.array(b, dtype=np.float32)))
def test_numpy_correctness_all_metrics(client):
rng = np.random.default_rng(99)
vecs = rng.random((10, 5), dtype=np.float32)
q = rng.random(5, dtype=np.float32)
q_str = ",".join(f"{v:.7f}" for v in q)
client.store([{"id": i, "vec": vecs[i].tolist()} for i in range(len(vecs))])
queries = {
"l2": f"SELECT id, array_distance(vec, [{q_str}]) AS v FROM vecs ORDER BY id",
"l1": f"SELECT id, l1_distance(vec, [{q_str}]) AS v FROM vecs ORDER BY id",
"linf": f"SELECT id, linf_distance(vec, [{q_str}]) AS v FROM vecs ORDER BY id",
"cosine": f"SELECT id, cosine_similarity(vec, [{q_str}]) AS v FROM vecs ORDER BY id",
"dot": f"SELECT id, inner_product(vec, [{q_str}]) AS v FROM vecs ORDER BY id",
}
refs = {
"l2": lambda v: _np_l2(v, q),
"l1": lambda v: _np_l1(v, q),
"linf": lambda v: _np_linf(v, q),
"cosine": lambda v: _np_cosine_sim(v, q),
"dot": lambda v: _np_dot(v, q),
}
for metric, sql in queries.items():
rows = client.execute(sql).to_dict()
for r in rows:
expected = refs[metric](vecs[r["id"]])
assert r["v"] == pytest.approx(expected, rel=1e-3, abs=1e-5), \
f"metric={metric} id={r['id']} got={r['v']} expected={expected}"
def test_cosine_identical_vectors(client):
stored = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[3.0, 4.0, 0.0],
[1.0, 2.0, 3.0],
]
client.store([{"id": i, "vec": v} for i, v in enumerate(stored)])
for i, v in enumerate(stored):
q_str = ",".join(map(str, v))
r = client.execute(
f"SELECT cosine_similarity(vec, [{q_str}]) AS sim FROM vecs WHERE id = {i}"
).to_dict()
assert r[0]["sim"] == pytest.approx(1.0, abs=1e-5), \
f"id={i} vec={v} got={r[0]['sim']}"
def test_cosine_distance_plus_similarity_equals_one(client):
_load_3d_vecs(client)
q = [0.6, 0.8, 0.0]
q_str = ",".join(map(str, q))
rows = client.execute(
f"SELECT cosine_similarity(vec, [{q_str}]) AS sim, "
f"cosine_distance(vec, [{q_str}]) AS dist FROM vecs"
).to_dict()
for r in rows:
assert r["sim"] + r["dist"] == pytest.approx(1.0, abs=1e-5)
def test_l2_distance_symmetric(client):
_load_3d_vecs(client)
q = [0.3, 0.4, 0.5]
q_str = ",".join(map(str, q))
rows_fwd = client.execute(
f"SELECT name, array_distance(vec, [{q_str}]) AS d FROM vecs ORDER BY name"
).to_dict()
for r in rows_fwd:
stored = {"unit_x": [1,0,0], "unit_y": [0,1,0], "unit_z": [0,0,1],
"origin": [0,0,0], "diag": [1,1,1]}.get(r["name"])
if stored:
expected_sym = _np_l2(q, stored)
assert r["d"] == pytest.approx(expected_sym, abs=1e-5)
def test_negative_components_all_metrics(client):
vecs_data = [
{"id": 0, "vec": [-1.0, 0.0, 0.0]},
{"id": 1, "vec": [ 0.0, -1.0, 0.0]},
{"id": 2, "vec": [-1.0, -1.0, -1.0]},
]
client.store(vecs_data)
q = [-1.0, 0.0, 0.0]
q_str = ",".join(map(str, q))
r = client.execute(
f"SELECT id, array_distance(vec, [{q_str}]) AS d FROM vecs ORDER BY d LIMIT 1"
).to_dict()
assert r[0]["id"] == 0
assert r[0]["d"] == pytest.approx(0.0, abs=1e-5)
r = client.execute(
f"SELECT id, l1_distance(vec, [{q_str}]) AS d FROM vecs ORDER BY d LIMIT 1"
).to_dict()
assert r[0]["id"] == 0
r = client.execute(
f"SELECT id, cosine_similarity(vec, [{q_str}]) AS s FROM vecs WHERE id = 0"
).to_dict()
assert r[0]["s"] == pytest.approx(1.0, abs=1e-5)
def test_large_dim_128_topk(client):
rng = np.random.default_rng(55)
n, dim = 200, 128
vecs = rng.random((n, dim), dtype=np.float32)
q = rng.random(dim, dtype=np.float32)
client.store([{"id": i, "vec": vecs[i].tolist()} for i in range(n)])
q_str = ",".join(f"{v:.6f}" for v in q)
result = client.execute(
f"SELECT id, array_distance(vec, [{q_str}]) AS dist FROM vecs ORDER BY dist LIMIT 10"
).to_dict()
assert len(result) == 10
dists = [r["dist"] for r in result]
assert dists == sorted(dists)
np_dists = np.sqrt(np.sum((vecs - q) ** 2, axis=1))
best_id = int(np.argmin(np_dists))
assert result[0]["id"] == best_id
def test_large_dim_128_numpy_correctness(client):
rng = np.random.default_rng(77)
vec = rng.random(128, dtype=np.float32)
q = rng.random(128, dtype=np.float32)
client.store([{"id": 0, "vec": vec.tolist()}])
q_str = ",".join(f"{v:.7f}" for v in q)
result = client.execute(
f"SELECT array_distance(vec, [{q_str}]) AS d FROM vecs"
).to_dict()
np_dist = float(np.sqrt(np.sum((vec - q) ** 2)))
assert result[0]["d"] == pytest.approx(np_dist, rel=1e-3)
def test_filter_then_topk(client):
rng = np.random.default_rng(13)
vecs = rng.random((50, 4), dtype=np.float32)
rows = [{"id": i, "tag": "A" if i < 25 else "B", "vec": vecs[i].tolist()} for i in range(50)]
client.store(rows)
q_str = "0.5,0.5,0.5,0.5"
result_all = client.execute(
f"SELECT id FROM vecs ORDER BY array_distance(vec, [{q_str}]) LIMIT 5"
).to_dict()
result_a = client.execute(
f"SELECT id, array_distance(vec, [{q_str}]) AS dist FROM vecs "
f"WHERE tag = 'A' ORDER BY dist LIMIT 5"
).to_dict()
assert all(r["id"] < 25 for r in result_a)
assert len(result_a) == 5
dists = [r["dist"] for r in result_a]
assert dists == sorted(dists)
def test_topk_result_via_tolist(client):
rows = _load_many(client, n=30, dim=4)
q_str = "0.5,0.5,0.5,0.5"
result = client.execute(
f"SELECT id, array_distance(vec, [{q_str}]) AS dist FROM vecs ORDER BY dist LIMIT 5"
)
lst = result.tolist()
assert isinstance(lst, list)
assert len(lst) == 5
assert isinstance(lst[0], dict)
assert "dist" in lst[0]
assert "_id" not in lst[0]
assert lst == result.to_dict()
dists = [r["dist"] for r in lst]
assert dists == sorted(dists)
def test_vector_norm_unit_vectors(client):
client.store([
{"id": 0, "vec": [1.0, 0.0, 0.0]},
{"id": 1, "vec": [0.0, 1.0, 0.0]},
{"id": 2, "vec": [0.0, 0.0, 1.0]},
])
rows = client.execute("SELECT id, vector_norm(vec) AS n FROM vecs ORDER BY id").to_dict()
for r in rows:
assert r["n"] == pytest.approx(1.0, abs=1e-5)
def test_vector_norm_matches_numpy(client):
rng = np.random.default_rng(21)
v = rng.random(8, dtype=np.float32)
client.store([{"id": 0, "vec": v.tolist()}])
result = client.execute("SELECT vector_norm(vec) AS n FROM vecs").to_dict()
assert result[0]["n"] == pytest.approx(float(np.linalg.norm(v)), rel=1e-4)
def _load_topk_vecs(client):
client.store([
{"name": "origin", "vec": encode_vector([0.0, 0.0, 0.0])},
{"name": "unit_x", "vec": encode_vector([1.0, 0.0, 0.0])},
{"name": "unit_y", "vec": encode_vector([0.0, 1.0, 0.0])},
{"name": "unit_z", "vec": encode_vector([0.0, 0.0, 1.0])},
{"name": "diag", "vec": encode_vector([1.0, 1.0, 1.0])},
])
def _topk_name(client, row_id):
rows = client.execute(f"SELECT name FROM vecs WHERE _id = {row_id}").to_dict()
return rows[0]["name"] if rows else None
def test_topk_distance_python_l2_basic(client):
_load_topk_vecs(client)
rows = client.topk_distance("vec", [1.0, 0.0, 0.0], k=3, metric="l2").to_dict()
assert len(rows) == 3
assert "_id" in rows[0] and "dist" in rows[0]
assert rows[0]["dist"] == pytest.approx(0.0, abs=1e-5)
assert rows[1]["dist"] == pytest.approx(1.0, abs=1e-5)
assert _topk_name(client, rows[0]["_id"]) == "unit_x"
def test_topk_distance_python_returns_id_and_dist(client):
_load_topk_vecs(client)
rows = client.topk_distance("vec", [0.0, 0.0, 0.0], k=2).to_dict()
assert set(rows[0].keys()) == {"_id", "dist"}
assert rows[0]["dist"] == pytest.approx(0.0, abs=1e-5)
def test_topk_distance_python_custom_column_names(client):
_load_topk_vecs(client)
rows = client.topk_distance(
"vec", [1.0, 0.0, 0.0], k=2, id_col="row_id", dist_col="distance"
).to_dict()
assert "row_id" in rows[0] and "distance" in rows[0]
def test_topk_distance_python_k_limits_results(client):
_load_topk_vecs(client)
for k in (1, 3, 5, 10):
rows = client.topk_distance("vec", [1.0, 0.0, 0.0], k=k).to_dict()
assert len(rows) == min(k, 5)
def test_topk_distance_python_sorted_ascending(client):
_load_topk_vecs(client)
rows = client.topk_distance("vec", [1.0, 0.0, 0.0], k=5).to_dict()
dists = [r["dist"] for r in rows]
assert dists == sorted(dists)
def test_topk_distance_python_cosine_metric(client):
_load_topk_vecs(client)
rows = client.topk_distance("vec", [1.0, 0.0, 0.0], k=2, metric="cosine_distance").to_dict()
assert rows[0]["dist"] == pytest.approx(0.0, abs=1e-5)
assert _topk_name(client, rows[0]["_id"]) == "unit_x"
def test_topk_distance_python_l1_metric(client):
_load_topk_vecs(client)
rows = client.topk_distance("vec", [0.0, 0.0, 0.0], k=5, metric="l1").to_dict()
assert rows[0]["dist"] == pytest.approx(0.0, abs=1e-5)
assert rows[-1]["dist"] == pytest.approx(3.0, abs=1e-5)
assert _topk_name(client, rows[0]["_id"]) == "origin"
assert _topk_name(client, rows[-1]["_id"]) == "diag"
def test_topk_distance_python_l2_squared_metric(client):
_load_topk_vecs(client)
rows_l2 = client.topk_distance("vec", [1.0, 0.0, 0.0], k=5, metric="l2").to_dict()
rows_sq = client.topk_distance("vec", [1.0, 0.0, 0.0], k=5, metric="l2_squared").to_dict()
assert [r["_id"] for r in rows_l2] == [r["_id"] for r in rows_sq]
for l2_row, sq_row in zip(rows_l2, rows_sq):
assert sq_row["dist"] == pytest.approx(l2_row["dist"] ** 2, rel=1e-4)
def test_topk_distance_python_numpy_query(client):
_load_topk_vecs(client)
q = np.array([1.0, 0.0, 0.0], dtype=np.float32)
rows = client.topk_distance("vec", q, k=1).to_dict()
assert _topk_name(client, rows[0]["_id"]) == "unit_x"
def test_topk_distance_python_matches_order_by(client):
_load_topk_vecs(client)
q = [0.6, 0.3, 0.0]
k = 3
topk_rows = client.topk_distance("vec", q, k=k, metric="l2").to_dict()
sql_rows = client.execute(
f"SELECT _id, array_distance(vec, [{q[0]}, {q[1]}, {q[2]}]) AS dist "
f"FROM vecs ORDER BY dist LIMIT {k}"
).to_dict()
topk_rows.sort(key=lambda r: (round(r["dist"], 5), r["_id"]))
sql_rows.sort(key=lambda r: (round(r["dist"], 5), r["_id"]))
assert [r["_id"] for r in topk_rows] == [r["_id"] for r in sql_rows]
@pytest.mark.parametrize("metric", ["l2", "l2_squared", "cosine_distance", "dot", "l1", "linf"])
def test_batch_topk_distance_matches_single_queries(client, metric):
rng = np.random.default_rng(123)
n, dim = 80, 8
vecs = rng.random((n, dim), dtype=np.float32)
client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
queries = rng.random((3, dim), dtype=np.float32)
k = 5
batch = client.batch_topk_distance("vec", queries, k=k, metric=metric)
assert batch.shape == (3, k, 2)
for qi, query in enumerate(queries):
single = client.topk_distance("vec", query, k=k, metric=metric).to_dict()
batch_ids = [int(batch[qi, j, 0]) for j in range(k)]
batch_dists = [float(batch[qi, j, 1]) for j in range(k)]
assert batch_ids == [int(row["_id"]) for row in single]
assert batch_dists == pytest.approx(
[float(row["dist"]) for row in single], rel=1e-5, abs=1e-5
)
def test_topk_distance_sql_explode_rename_basic(client):
_load_topk_vecs(client)
rows = client.execute(
"SELECT explode_rename(topk_distance(vec, [1.0, 0.0, 0.0], 3, 'l2'), 'my_id', 'my_dist') FROM vecs"
).to_dict()
assert len(rows) == 3
assert set(rows[0].keys()) == {"my_id", "my_dist"}
assert rows[0]["my_dist"] == pytest.approx(0.0, abs=1e-5)
def test_topk_distance_sql_subquery(client):
_load_topk_vecs(client)
rows = client.execute("""
SELECT my_id, my_dist
FROM (SELECT explode_rename(topk_distance(vec, [1.0, 0.0, 0.0], 3, 'l2'),
'my_id', 'my_dist') FROM vecs) a
""").to_dict()
assert len(rows) == 3
assert rows[0]["my_dist"] == pytest.approx(0.0, abs=1e-5)
def test_topk_distance_sql_join_back(client):
_load_topk_vecs(client)
rows = client.execute("""
SELECT v.name, k.my_dist
FROM vecs v
JOIN (SELECT explode_rename(topk_distance(vec, [1.0, 0.0, 0.0], 3, 'l2'),
'my_id', 'my_dist') FROM vecs) k
ON v._id = k.my_id
ORDER BY k.my_dist
""").to_dict()
assert len(rows) == 3
assert rows[0]["name"] == "unit_x"
assert rows[0]["my_dist"] == pytest.approx(0.0, abs=1e-5)
def test_topk_distance_sql_cosine_metric(client):
_load_topk_vecs(client)
rows = client.execute(
"SELECT explode_rename(topk_distance(vec, [1.0, 0.0, 0.0], 2, 'cosine_distance'), '_id', 'dist') FROM vecs"
).to_dict()
assert rows[0]["dist"] == pytest.approx(0.0, abs=1e-5)
assert _topk_name(client, rows[0]["_id"]) == "unit_x"
def test_topk_distance_sql_matches_python(client):
_load_topk_vecs(client)
q = [0.3, 0.6, 0.1]
k = 4
py_rows = client.topk_distance("vec", q, k=k, metric="l2").to_dict()
sql_rows = client.execute(
f"SELECT explode_rename(topk_distance(vec, [{q[0]}, {q[1]}, {q[2]}], {k}, 'l2'), '_id', 'dist') FROM vecs"
).to_dict()
assert [r["_id"] for r in py_rows] == [r["_id"] for r in sql_rows]
for a, b in zip(py_rows, sql_rows):
assert a["dist"] == pytest.approx(b["dist"], rel=1e-4)
def test_topk_distance_large_k(client):
_load_topk_vecs(client)
rows = client.topk_distance("vec", [0.0, 0.0, 0.0], k=100).to_dict()
assert len(rows) == 5
def test_topk_distance_large_table(client):
rng = np.random.default_rng(42)
n, dim = 500, 16
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
client.store([{"vec": encode_vector(vecs[i])} for i in range(n)])
k = 10
topk = client.topk_distance("vec", query, k=k, metric="l2").to_dict()
assert len(topk) == k
dists = np.linalg.norm(vecs - query, axis=1)
gt_ids = set(int(i) + 1 for i in np.argsort(dists)[:k])
result_ids = set(int(r["_id"]) for r in topk)
assert result_ids == gt_ids
@pytest.fixture
def f16_client(tmp_path):
c = ApexClient(dirpath=str(tmp_path), drop_if_exists=True)
c.execute("CREATE TABLE f16vecs (name TEXT, vec FLOAT16_VECTOR)")
c.use_table("f16vecs")
yield c
c.close()
def test_f16_create_table(tmp_path):
c = ApexClient(dirpath=str(tmp_path), drop_if_exists=True)
c.execute("CREATE TABLE t (name TEXT, vec FLOAT16_VECTOR)")
c.close()
def test_f16_store_and_count(f16_client):
rows = [
{"name": "a", "vec": np.array([1.0, 0.0, 0.0], dtype=np.float32)},
{"name": "b", "vec": np.array([0.0, 1.0, 0.0], dtype=np.float32)},
{"name": "c", "vec": np.array([0.0, 0.0, 1.0], dtype=np.float32)},
]
f16_client.store(rows)
result = f16_client.execute("SELECT COUNT(*) FROM f16vecs").to_dict()
assert result[0]["COUNT(*)"] == 3
def test_f16_topk_distance_l2(f16_client):
rng = np.random.default_rng(7)
n, dim = 200, 16
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
k = 5
topk = f16_client.topk_distance("vec", query, k=k, metric="l2").to_dict()
assert len(topk) == k
dists_np = np.linalg.norm(vecs - query, axis=1)
gt_top20_ids = set(int(i) + 1 for i in np.argsort(dists_np)[:20])
result_ids = set(int(r["_id"]) for r in topk)
assert len(result_ids & gt_top20_ids) >= 4
def test_f16_topk_distance_cosine(f16_client):
rng = np.random.default_rng(13)
n, dim = 100, 8
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
topk = f16_client.topk_distance("vec", query, k=3, metric="cosine_distance").to_dict()
assert len(topk) == 3
for r in topk:
assert 0.0 <= r["dist"] <= 2.0 + 1e-4
def test_f16_memory_savings(tmp_path):
import os
dim = 64
n = 1000
rng = np.random.default_rng(0)
vecs = rng.random((n, dim), dtype=np.float32)
c32 = ApexClient(dirpath=str(tmp_path / "f32"), drop_if_exists=True)
c32.create_table("t")
c32.store([{"vec": vecs[i]} for i in range(n)])
c32.close()
c16 = ApexClient(dirpath=str(tmp_path / "f16"), drop_if_exists=True)
c16.execute("CREATE TABLE t (vec FLOAT16_VECTOR)")
c16.use_table("t")
c16.store([{"vec": vecs[i]} for i in range(n)])
c16.close()
def dir_size(p):
return sum(
os.path.getsize(p / f)
for f in os.listdir(p)
if os.path.isfile(p / f)
)
f32_size = dir_size(tmp_path / "f32")
f16_size = dir_size(tmp_path / "f16")
assert f16_size < f32_size, (
f"Expected f16 ({f16_size}B) < f32 ({f32_size}B) for {n}×{dim} vectors"
)
def test_f16_topk_all_metrics(f16_client):
rng = np.random.default_rng(55)
n, dim = 60, 8
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
metrics = ["l2", "l2_squared", "cosine_distance", "l1", "linf", "dot"]
for m in metrics:
rows = f16_client.topk_distance("vec", query, k=5, metric=m).to_dict()
assert len(rows) == 5, f"metric={m}: expected 5 rows"
dists = [r["dist"] for r in rows]
assert dists == sorted(dists), f"metric={m}: results not sorted ascending"
def test_f16_topk_l2_squared(f16_client):
rng = np.random.default_rng(3)
n, dim = 80, 8
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
k = 5
rows_l2 = f16_client.topk_distance("vec", query, k=k, metric="l2").to_dict()
rows_sq = f16_client.topk_distance("vec", query, k=k, metric="l2_squared").to_dict()
assert [r["_id"] for r in rows_l2] == [r["_id"] for r in rows_sq]
for l2r, sqr in zip(rows_l2, rows_sq):
assert sqr["dist"] == pytest.approx(l2r["dist"] ** 2, rel=5e-3)
def test_f16_topk_l1(f16_client):
rng = np.random.default_rng(77)
n, dim = 80, 8
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
k = 5
rows = f16_client.topk_distance("vec", query, k=k, metric="l1").to_dict()
assert len(rows) == k
dists = [r["dist"] for r in rows]
assert dists == sorted(dists)
vecs_q = vecs.astype(np.float16).astype(np.float32)
np_l1 = np.sum(np.abs(vecs_q - query), axis=1)
gt_top20 = set(int(i) + 1 for i in np.argsort(np_l1)[:20])
result_ids = set(int(r["_id"]) for r in rows)
assert len(result_ids & gt_top20) >= 4
def test_f16_topk_linf(f16_client):
rng = np.random.default_rng(99)
n, dim = 80, 8
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
rows = f16_client.topk_distance("vec", query, k=5, metric="linf").to_dict()
assert len(rows) == 5
dists = [r["dist"] for r in rows]
assert dists == sorted(dists)
def test_f16_topk_inner_product(f16_client):
rng = np.random.default_rng(17)
n, dim = 80, 8
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
rows = f16_client.topk_distance("vec", query, k=5, metric="dot").to_dict()
assert len(rows) == 5
dists = [r["dist"] for r in rows]
assert dists == sorted(dists)
def _f16_quantize(v):
return v.astype(np.float16).astype(np.float32)
def test_f16_l2_correctness_vs_numpy(f16_client):
rng = np.random.default_rng(42)
n, dim = 30, 16
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
rows = f16_client.topk_distance("vec", query, k=n, metric="l2").to_dict()
vecs_q = _f16_quantize(vecs)
for r in rows:
idx = int(r["_id"]) - 1
expected = float(np.sqrt(np.sum((vecs_q[idx] - query) ** 2)))
assert r["dist"] == pytest.approx(expected, rel=5e-3, abs=1e-4), \
f"id={idx} got={r['dist']} expected={expected}"
def test_f16_cosine_correctness_vs_numpy(f16_client):
rng = np.random.default_rng(11)
n, dim = 30, 16
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
rows = f16_client.topk_distance("vec", query, k=n, metric="cosine_distance").to_dict()
vecs_q = _f16_quantize(vecs)
for r in rows:
idx = int(r["_id"]) - 1
a, b = vecs_q[idx], query
na, nb = np.linalg.norm(a), np.linalg.norm(b)
expected = 1.0 - float(np.dot(a, b)) / (na * nb) if na > 0 and nb > 0 else 0.0
assert r["dist"] == pytest.approx(expected, rel=5e-3, abs=1e-4), \
f"id={idx} got={r['dist']} expected={expected}"
def test_f16_l1_correctness_vs_numpy(f16_client):
rng = np.random.default_rng(23)
n, dim = 30, 16
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
rows = f16_client.topk_distance("vec", query, k=n, metric="l1").to_dict()
vecs_q = _f16_quantize(vecs)
for r in rows:
idx = int(r["_id"]) - 1
expected = float(np.sum(np.abs(vecs_q[idx] - query)))
assert r["dist"] == pytest.approx(expected, rel=5e-3, abs=1e-4), \
f"id={idx} got={r['dist']} expected={expected}"
def test_f16_dim_not_multiple_of_8(f16_client):
rng = np.random.default_rng(7)
dim = 13 n = 30
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
rows = f16_client.topk_distance("vec", query, k=5, metric="l2").to_dict()
assert len(rows) == 5
dists = [r["dist"] for r in rows]
assert dists == sorted(dists)
def test_f16_dim_1(f16_client):
f16_client.store([
{"name": "a", "vec": np.array([1.0], dtype=np.float32)},
{"name": "b", "vec": np.array([2.0], dtype=np.float32)},
{"name": "c", "vec": np.array([3.0], dtype=np.float32)},
])
rows = f16_client.topk_distance("vec", [1.0], k=3, metric="l2").to_dict()
assert len(rows) == 3
assert rows[0]["dist"] == pytest.approx(0.0, abs=1e-4)
def test_f16_negative_components(f16_client):
vecs = [
{"name": "neg_x", "vec": np.array([-1.0, 0.0, 0.0], dtype=np.float32)},
{"name": "pos_x", "vec": np.array([ 1.0, 0.0, 0.0], dtype=np.float32)},
{"name": "neg_all", "vec": np.array([-1.0, -1.0, -1.0], dtype=np.float32)},
]
f16_client.store(vecs)
query = [-1.0, 0.0, 0.0]
rows = f16_client.topk_distance("vec", query, k=1, metric="l2").to_dict()
assert rows[0]["dist"] == pytest.approx(0.0, abs=1e-3)
rows_l1 = f16_client.topk_distance("vec", query, k=1, metric="l1").to_dict()
assert rows_l1[0]["dist"] == pytest.approx(0.0, abs=1e-3)
def test_f16_zero_query_vector(f16_client):
rng = np.random.default_rng(5)
n, dim = 20, 4
vecs = rng.random((n, dim), dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
query = [0.0] * dim
rows = f16_client.topk_distance("vec", query, k=5, metric="l2").to_dict()
assert len(rows) == 5
dists = [r["dist"] for r in rows]
assert dists == sorted(dists)
assert all(d >= 0.0 for d in dists)
def test_f16_large_dim_128(f16_client):
rng = np.random.default_rng(99)
n, dim = 200, 128
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
rows = f16_client.topk_distance("vec", query, k=10, metric="l2").to_dict()
assert len(rows) == 10
dists = [r["dist"] for r in rows]
assert dists == sorted(dists)
vecs_q = _f16_quantize(vecs)
np_dists = np.linalg.norm(vecs_q - query, axis=1)
gt_top30 = set(int(i) + 1 for i in np.argsort(np_dists)[:30])
result_ids = set(int(r["_id"]) for r in rows)
assert len(result_ids & gt_top30) >= 8
def test_f16_sql_order_by_distance(f16_client):
rng = np.random.default_rng(31)
n, dim = 50, 4
vecs = rng.random((n, dim), dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
q = rng.random(dim, dtype=np.float32)
q_str = ",".join(f"{v:.6f}" for v in q)
rows = f16_client.execute(
f"SELECT _id, array_distance(vec, [{q_str}]) AS dist FROM f16vecs ORDER BY dist LIMIT 5"
).to_dict()
assert len(rows) == 5
dists = [r["dist"] for r in rows]
assert dists == sorted(dists)
def test_f16_sql_cosine_similarity(f16_client):
f16_client.store([
{"name": "same", "vec": np.array([1.0, 0.0, 0.0], dtype=np.float32)},
{"name": "ortho", "vec": np.array([0.0, 1.0, 0.0], dtype=np.float32)},
])
rows = f16_client.execute(
"SELECT name, cosine_similarity(vec, [1.0, 0.0, 0.0]) AS sim FROM f16vecs ORDER BY sim DESC"
).to_dict()
assert rows[0]["name"] == "same"
assert rows[0]["sim"] == pytest.approx(1.0, abs=2e-3)
assert rows[1]["sim"] == pytest.approx(0.0, abs=2e-3)
def test_f16_sql_l1_l2_linf(f16_client):
f16_client.store([
{"name": "a", "vec": np.array([1.0, 2.0, 3.0, 4.0], dtype=np.float32)},
{"name": "b", "vec": np.array([0.0, 0.0, 0.0, 0.0], dtype=np.float32)},
])
q_str = "1.0, 2.0, 3.0, 4.0"
r = f16_client.execute(
f"SELECT name, l1_distance(vec, [{q_str}]) AS l1, "
f"array_distance(vec, [{q_str}]) AS l2, "
f"linf_distance(vec, [{q_str}]) AS linf FROM f16vecs ORDER BY l2"
).to_dict()
assert r[0]["name"] == "a"
assert r[0]["l1"] == pytest.approx(0.0, abs=2e-3)
assert r[0]["l2"] == pytest.approx(0.0, abs=2e-3)
assert r[0]["linf"] == pytest.approx(0.0, abs=2e-3)
def test_f16_sql_explode_rename(f16_client):
rng = np.random.default_rng(61)
n, dim = 40, 4
vecs = rng.random((n, dim), dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
q_str = ",".join(f"{v:.6f}" for v in rng.random(dim, dtype=np.float32))
rows = f16_client.execute(
f"SELECT explode_rename(topk_distance(vec, [{q_str}], 5, 'l2'), '_id', 'dist') FROM f16vecs"
).to_dict()
assert len(rows) == 5
dists = [r["dist"] for r in rows]
assert dists == sorted(dists)
def test_f16_sql_type_aliases(tmp_path):
c = ApexClient(dirpath=str(tmp_path), drop_if_exists=True)
c.execute("CREATE TABLE t1 (vec FLOAT16VECTOR)")
c.execute("CREATE TABLE t2 (vec F16_VECTOR)")
c.close()
def test_f16_batch_topk(f16_client):
rng = np.random.default_rng(19)
n, dim = 200, 16
vecs = rng.random((n, dim), dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
N, k = 10, 5
queries = rng.random((N, dim), dtype=np.float32)
result = f16_client.batch_topk_distance("vec", queries, k=k, metric="l2")
assert result.shape == (N, k, 2)
for i in range(N):
dists = result[i, :, 1]
assert list(dists) == sorted(dists), f"query {i}: not sorted"
assert (result[:, :, 1] >= 0).all()
def test_f16_batch_topk_consistent_with_single(f16_client):
rng = np.random.default_rng(71)
n, dim = 100, 8
vecs = rng.random((n, dim), dtype=np.float32)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(n)])
query = rng.random(dim, dtype=np.float32)
k = 5
single = f16_client.topk_distance("vec", query, k=k, metric="l2").to_dict()
batch = f16_client.batch_topk_distance("vec", query.reshape(1, -1), k=k, metric="l2")
single_ids = set(int(r["_id"]) for r in single)
batch_ids = set(int(batch[0, j, 0]) for j in range(k))
assert single_ids == batch_ids
def test_f16_store_python_list(f16_client):
f16_client.store([
{"name": "a", "vec": np.array([1.0, 0.0, 0.0], dtype=np.float32)},
{"name": "b", "vec": np.array([0.0, 1.0, 0.0], dtype=np.float32)},
])
result = f16_client.execute("SELECT COUNT(*) FROM f16vecs").to_dict()
assert result[0]["COUNT(*)"] == 2
rows = f16_client.topk_distance("vec", [1.0, 0.0, 0.0], k=1, metric="l2").to_dict()
assert rows[0]["dist"] == pytest.approx(0.0, abs=1e-3)
def test_f16_store_numpy_float16(f16_client):
vecs = [
{"name": "a", "vec": np.array([1.0, 0.0, 0.0], dtype=np.float16)},
{"name": "b", "vec": np.array([0.0, 1.0, 0.0], dtype=np.float16)},
]
f16_client.store(vecs)
result = f16_client.execute("SELECT COUNT(*) FROM f16vecs").to_dict()
assert result[0]["COUNT(*)"] == 2
rows = f16_client.topk_distance("vec", [1.0, 0.0, 0.0], k=1, metric="l2").to_dict()
assert rows[0]["dist"] == pytest.approx(0.0, abs=1e-3)
def test_f16_store_numpy_float32(f16_client):
vecs = [
{"name": "a", "vec": np.array([0.1, 0.2, 0.3, 0.4], dtype=np.float32)},
{"name": "b", "vec": np.array([0.5, 0.6, 0.7, 0.8], dtype=np.float32)},
]
f16_client.store(vecs)
q = [0.1, 0.2, 0.3, 0.4]
rows = f16_client.topk_distance("vec", q, k=1, metric="l2").to_dict()
assert rows[0]["dist"] == pytest.approx(0.0, abs=5e-3)
def test_f16_quantization_error_bound(f16_client):
rng = np.random.default_rng(100)
dim = 64
vec = rng.random(dim, dtype=np.float32) * 2.0 - 1.0 vec2 = rng.random(dim, dtype=np.float32) * 2.0 - 1.0 query = rng.random(dim, dtype=np.float32) * 2.0 - 1.0
f16_client.store([{"name": "v", "vec": vec}, {"name": "v2", "vec": vec2}])
q_str = ",".join(f"{v:.7f}" for v in query)
rows = f16_client.execute(
f"SELECT name, array_distance(vec, [{q_str}]) AS dist FROM f16vecs WHERE name = 'v'"
).to_dict()
assert len(rows) == 1, "record 'v' not found"
got = rows[0]["dist"]
expected = float(np.sqrt(np.sum((_f16_quantize(vec) - query) ** 2)))
assert got == pytest.approx(expected, rel=2e-3, abs=1e-4)
def test_f16_cosine_unit_vectors(f16_client):
rng = np.random.default_rng(200)
vecs = rng.random((5, 8), dtype=np.float32)
vecs = vecs / np.linalg.norm(vecs, axis=1, keepdims=True)
f16_client.store([{"name": str(i), "vec": vecs[i]} for i in range(len(vecs))])
for i, v in enumerate(vecs):
rows = f16_client.topk_distance("vec", v.tolist(), k=1, metric="cosine_distance").to_dict()
assert rows[0]["dist"] == pytest.approx(0.0, abs=0.15), \
f"unit vec {i}: cosine self-distance = {rows[0]['dist']}"
def test_f16_topk_ordering_consistent_with_f32(tmp_path):
rng = np.random.default_rng(42)
n, dim, k = 300, 32, 10
vecs = rng.random((n, dim), dtype=np.float32)
query = rng.random(dim, dtype=np.float32)
c32 = ApexClient(dirpath=str(tmp_path / "f32"), drop_if_exists=True)
c32.create_table("t")
c32.store([{"vec": vecs[i]} for i in range(n)])
ids_f32 = set(int(r["_id"]) for r in c32.topk_distance("vec", query, k=k).to_dict())
c32.close()
c16 = ApexClient(dirpath=str(tmp_path / "f16"), drop_if_exists=True)
c16.execute("CREATE TABLE t (vec FLOAT16_VECTOR)")
c16.use_table("t")
c16.store([{"vec": vecs[i]} for i in range(n)])
ids_f16 = set(int(r["_id"]) for r in c16.topk_distance("vec", query, k=k).to_dict())
c16.close()
overlap = len(ids_f32 & ids_f16)
assert overlap >= int(k * 0.8), (
f"f16 vs f32 TopK overlap {overlap}/{k} < 80% for dim={dim}"
)