// Unit tests for ragger::vector_codec â round-trip fidelity across storage
// dtypes, offset-parameterized format, and legacy blob decoding. main()-based
// per this project's test convention.
#include "vector_codec.h"
#include
#include
#include
#include
#include
#include
#include
using namespace ragger::vector_codec;
static int failures = 0;
static void check(bool cond, const char* what) {
if (!cond) {
std::printf("FAIL %s\n", what);
++failures;
}
}
// Mean absolute error of a round-trip through dtype `t` with a 1-byte
// version-tag header (offset=1), matching the legacy on-disk format.
static float roundtrip_mae(VectorType t, const std::vector& v,
uint8_t ver = 42) {
std::vector blob = encode(t, v, /*offset=*/1, ver);
std::vector back;
bool ok = decode(blob.data(), static_cast(blob.size()),
static_cast(v.size()), t, back, /*offset=*/1);
if (!ok || back.size() != v.size()) return 1e9f;
float acc = 0.0f;
for (size_t i = 0; i < v.size(); ++i) acc += std::fabs(v[i] - back[i]);
return acc / static_cast(v.size());
}
int main() {
// --- string parsing / canonicalization -----------------------------
check(parse("f32").value() == VectorType::F32, "parse f32");
check(parse("F16").value() == VectorType::F16, "parse F16 (case-insensitive)");
check(parse("bf16").value() == VectorType::BF16, "parse bf16");
check(parse("int8").value() == VectorType::INT8, "parse int8");
check(parse("bfloat16").value() == VectorType::BF16, "parse bfloat16 alias");
check(!parse("f8").has_value(), "parse unknown -> nullopt");
check(canonical("garbage") == "f16", "canonical fallback -> f16");
check(canonical("BF16") == "bf16", "canonical normalizes case");
check(is_supported("int8") && !is_supported("q4"), "is_supported");
check(std::string(supported_csv()) == "f32,f16,bf16,int8", "supported_csv");
// --- deterministic normalized-ish embedding ------------------------
std::mt19937 rng(12345);
std::normal_distribution nd(0.0f, 0.3f);
std::vector v(384);
for (auto& x : v) x = nd(rng);
// f32 must be exactly lossless.
check(roundtrip_mae(VectorType::F32, v) == 0.0f, "f32 lossless round-trip");
// f16/bf16/int8 lossy but bounded. Thresholds are generous but catch
// gross breakage (wrong shift, endianness, missing dequant scale).
float mae_f16 = roundtrip_mae(VectorType::F16, v);
float mae_bf16 = roundtrip_mae(VectorType::BF16, v);
float mae_int8 = roundtrip_mae(VectorType::INT8, v);
std::printf("MAE f16=%.6g bf16=%.6g int8=%.6g\n", mae_f16, mae_bf16, mae_int8);
check(mae_f16 < 1e-3f, "f16 round-trip within tolerance");
check(mae_bf16 < 5e-3f, "bf16 round-trip within tolerance");
check(mae_int8 < 5e-3f, "int8 round-trip within tolerance");
// f16 has more mantissa bits than bf16 -> should be more accurate here.
check(mae_f16 < mae_bf16, "f16 more accurate than bf16 for small values");
// --- blob sizes (version byte + payload, int8 gets +2 for f16 scale) --
check(encode(VectorType::F32, v, 1, 0).size() == 1u + 384u * 4, "f32 blob size");
check(encode(VectorType::F16, v, 1, 0).size() == 1u + 384u * 2, "f16 blob size");
check(encode(VectorType::BF16, v, 1, 0).size() == 1u + 384u * 2, "bf16 blob size");
check(encode(VectorType::INT8, v, 1, 0).size() == 1u + 384u * 1 + 2u, "int8 blob size");
// --- expected_blob_size matches actual encode output ----------------
for (auto t : {VectorType::F32, VectorType::F16, VectorType::BF16, VectorType::INT8}) {
check(static_cast(encode(t, v, 1, 7).size()) == expected_blob_size(t, 384, 1),
"expected_blob_size matches encode");
}
// --- version byte is correctly stored and read ----------------------
{
auto blob = encode(VectorType::F16, v, 1, 99);
check(blob_version(blob.data(), (int)blob.size()) == 99, "version byte stored");
// Decode with correct dtype should succeed regardless of version value.
std::vector back;
bool ok = decode(blob.data(), (int)blob.size(), 384, VectorType::F16, back, 1);
check(ok, "decode succeeds for version-tagged blob");
}
// --- version byte 0 works (edge case) ------------------------------
{
auto blob = encode(VectorType::F16, v, 1, 0);
check(blob_version(blob.data(), (int)blob.size()) == 0, "version 0 works");
}
// --- f16 vs bf16 are distinguishable via the caller knowing dtype ---
// (caller gets dtype from settings, not from the blob itself)
{
std::vector one = {2.5f};
auto bf = encode(VectorType::BF16, one, 1, 1);
std::vector back;
check(decode(bf.data(), (int)bf.size(), 1, VectorType::BF16, back, 1) &&
std::fabs(back[0] - 2.5f) < 1e-6f,
"bf16 decodes correctly with dtype hint");
// Decoding bf16 blob as f16 should fail (size matches but produces wrong answer
// only if dims match â with 1 dim both are 3 bytes so it succeeds; that's fine,
// the point is the CALLER passes the correct dtype from settings).
}
// --- dimension-mismatch rejection ----------------------------------
{
auto blob = encode(VectorType::F16, v, 1, 5);
std::vector back;
bool ok = decode(blob.data(), (int)blob.size(), 128 /*wrong*/, VectorType::F16, back, 1);
check(!ok, "dim mismatch rejected");
check(back.size() == 128 && back[0] == 0.0f, "dim mismatch -> zero vector");
}
// --- null / empty ---------------------------------------------------
{
std::vector back;
check(!decode(nullptr, 0, 384, VectorType::F16, back, 1), "null blob rejected");
check(back.size() == 384, "null -> zero vector of expected dims");
}
// --- blob_version edge cases ----------------------------------------
check(blob_version(nullptr, 0) == -1, "blob_version null -> -1");
{
uint8_t b = 255;
check(blob_version(&b, 1) == 255, "blob_version 255");
}
// --- int8 f16 scale precision test ----------------------------------
// Verify the f16 scale is sufficient for unit-norm embeddings.
{
// Normalize v to unit norm like real embeddings
float norm = 0.0f;
for (float x : v) norm += x * x;
norm = std::sqrt(norm);
std::vector vn(v.size());
for (size_t i = 0; i < v.size(); ++i) vn[i] = v[i] / norm;
float mae = roundtrip_mae(VectorType::INT8, vn);
std::printf("MAE int8 unit-norm=%.6g\n", mae);
check(mae < 5e-3f, "int8 unit-norm round-trip within tolerance");
}
// --- offset=0 (payload-only) encode/decode (Ragger db_version 0.15+:
// version tag moved out of the blob into its own embedding_version
// column) ------------------------------------------------------------
{
for (auto t : {VectorType::F32, VectorType::F16, VectorType::BF16, VectorType::INT8}) {
// expected_blob_size(t, dims, 0) is exactly expected_blob_size(t,
// dims, 1) minus 1 (the version byte) for every dtype.
check(expected_blob_size(t, 384, 0) == expected_blob_size(t, 384, 1) - 1,
"offset=0 size == offset=1 size - 1");
auto payload = encode(t, v, /*offset=*/0);
check(static_cast(payload.size()) == expected_blob_size(t, 384, 0),
"offset=0 encode size matches expected_blob_size");
// offset=0 encode's bytes must equal offset=1 encode()'s bytes
// with the leading version byte stripped -- same encoding, just
// no tag.
auto tagged = encode(t, v, /*offset=*/1, 123);
check(std::vector(tagged.begin() + 1, tagged.end()) == payload,
"offset=0 encode matches offset=1 encode() minus version byte");
std::vector back;
bool ok = decode(payload.data(), static_cast(payload.size()),
static_cast(v.size()), t, back, /*offset=*/0);
check(ok, "offset=0 decode succeeds");
check(back.size() == v.size(), "offset=0 decode produces expected_dims");
// Cross-check against offset=1 decode() on the tagged blob --
// both must agree exactly (same payload bytes, same dequant math).
std::vector back_tagged;
decode(tagged.data(), static_cast(tagged.size()),
static_cast(v.size()), t, back_tagged, /*offset=*/1);
check(back == back_tagged,
"offset=0 decode agrees with offset=1 decode() on the equivalent tagged blob");
}
// Size-mismatch rejection mirrors decode()'s behavior.
{
auto payload = encode(VectorType::F16, v, /*offset=*/0);
std::vector back;
bool ok = decode(payload.data(), static_cast(payload.size()),
128 /*wrong*/, VectorType::F16, back, /*offset=*/0);
check(!ok, "offset=0 decode dim mismatch rejected");
check(back.size() == 128 && back[0] == 0.0f,
"offset=0 decode dim mismatch -> zero vector");
}
// Null blob rejection.
{
std::vector back;
check(!decode(nullptr, 0, 384, VectorType::F16, back, /*offset=*/0),
"offset=0 decode null blob rejected");
check(back.size() == 384, "offset=0 decode null -> zero vector of expected dims");
}
}
if (failures == 0) std::printf("all vector_codec tests passed\n");
else std::printf("%d vector_codec test(s) FAILED\n", failures);
return failures == 0 ? 0 : 1;
}