157 lines
4.9 KiB
C++
157 lines
4.9 KiB
C++
#include <catch2/catch_test_macros.hpp>
|
|
|
|
#include <yams/compat/unistd.h>
|
|
#include <yams/vector/embedding_generator.h>
|
|
#include <yams/vector/simeon_embedding_backend.h>
|
|
|
|
#include <array>
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <catch2/matchers/catch_matchers_string.hpp>
|
|
|
|
using namespace yams::vector;
|
|
using Catch::Matchers::StartsWith;
|
|
|
|
namespace {
|
|
|
|
EmbeddingConfig make_cfg(size_t dim = 256) {
|
|
EmbeddingConfig cfg;
|
|
cfg.backend = EmbeddingConfig::Backend::Simeon;
|
|
cfg.embedding_dim = dim;
|
|
cfg.normalize_embeddings = true;
|
|
cfg.max_sequence_length = 512;
|
|
return cfg;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("SimeonBackend initializes and reports its dimension", "[vector][simeon]") {
|
|
auto backend = makeSimeonBackend(make_cfg(384));
|
|
REQUIRE(backend != nullptr);
|
|
REQUIRE(backend->isAvailable());
|
|
REQUIRE(backend->initialize());
|
|
REQUIRE(backend->isInitialized());
|
|
REQUIRE(backend->getEmbeddingDimension() == 384u);
|
|
REQUIRE(backend->getBackendName() == "Simeon");
|
|
}
|
|
|
|
TEST_CASE("SimeonBackend produces deterministic, unit-norm embeddings", "[vector][simeon]") {
|
|
auto backend = makeSimeonBackend(make_cfg(256));
|
|
REQUIRE(backend->initialize());
|
|
|
|
const std::string text = "The quick brown fox jumps over the lazy dog.";
|
|
auto r1 = backend->generateEmbedding(text);
|
|
auto r2 = backend->generateEmbedding(text);
|
|
REQUIRE(r1);
|
|
REQUIRE(r2);
|
|
REQUIRE(r1.value().size() == 256u);
|
|
REQUIRE(r1.value() == r2.value());
|
|
|
|
double acc = 0.0;
|
|
for (float f : r1.value())
|
|
acc += static_cast<double>(f) * static_cast<double>(f);
|
|
REQUIRE(std::fabs(std::sqrt(acc) - 1.0) < 1e-4);
|
|
}
|
|
|
|
TEST_CASE("SimeonBackend batch matches per-item encoding", "[vector][simeon]") {
|
|
auto backend = makeSimeonBackend(make_cfg(128));
|
|
REQUIRE(backend->initialize());
|
|
|
|
const std::vector<std::string> texts = {"alpha bravo charlie", "delta echo foxtrot",
|
|
"golf hotel india"};
|
|
auto per = std::vector<std::vector<float>>{};
|
|
for (const auto& t : texts) {
|
|
auto r = backend->generateEmbedding(t);
|
|
REQUIRE(r);
|
|
per.push_back(std::move(r).value());
|
|
}
|
|
auto batch = backend->generateEmbeddings(std::span<const std::string>(texts));
|
|
REQUIRE(batch);
|
|
REQUIRE(batch.value().size() == per.size());
|
|
for (size_t i = 0; i < per.size(); ++i) {
|
|
REQUIRE(batch.value()[i] == per[i]);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("EmbeddingGenerator selects Simeon via env override", "[vector][simeon]") {
|
|
setenv("YAMS_EMBED_BACKEND", "simeon", 1);
|
|
|
|
EmbeddingConfig cfg;
|
|
cfg.embedding_dim = 384;
|
|
cfg.normalize_embeddings = true;
|
|
EmbeddingGenerator gen(cfg);
|
|
REQUIRE(gen.initialize());
|
|
REQUIRE(gen.getBackendName() == "Simeon");
|
|
REQUIRE(gen.getEmbeddingDimension() == 384u);
|
|
|
|
auto v = gen.generateEmbedding("hello world");
|
|
REQUIRE(v.size() == 384u);
|
|
|
|
unsetenv("YAMS_EMBED_BACKEND");
|
|
}
|
|
|
|
TEST_CASE("EmbeddingGenerator selects Simeon when configured directly", "[vector][simeon]") {
|
|
EmbeddingConfig cfg;
|
|
cfg.backend = EmbeddingConfig::Backend::Simeon;
|
|
cfg.embedding_dim = 128;
|
|
cfg.normalize_embeddings = true;
|
|
|
|
EmbeddingGenerator gen(cfg);
|
|
REQUIRE(gen.initialize());
|
|
REQUIRE(gen.getBackendName() == "Simeon");
|
|
REQUIRE(gen.getEmbeddingDimension() == 128u);
|
|
}
|
|
|
|
TEST_CASE("EmbeddingGenerator selects Daemon via env override", "[vector][daemon]") {
|
|
setenv("YAMS_EMBED_BACKEND", "daemon", 1);
|
|
|
|
EmbeddingConfig cfg;
|
|
cfg.backend = EmbeddingConfig::Backend::Simeon;
|
|
EmbeddingGenerator gen(cfg);
|
|
|
|
REQUIRE_THAT(gen.getBackendName(), StartsWith("Daemon"));
|
|
|
|
unsetenv("YAMS_EMBED_BACKEND");
|
|
}
|
|
|
|
TEST_CASE("EmbeddingGenerator maps legacy onnx env override to Daemon", "[vector][daemon]") {
|
|
setenv("YAMS_EMBED_BACKEND", "onnx", 1);
|
|
|
|
EmbeddingConfig cfg;
|
|
cfg.backend = EmbeddingConfig::Backend::Simeon;
|
|
EmbeddingGenerator gen(cfg);
|
|
|
|
REQUIRE_THAT(gen.getBackendName(), StartsWith("Daemon"));
|
|
|
|
unsetenv("YAMS_EMBED_BACKEND");
|
|
}
|
|
|
|
TEST_CASE("EmbeddingGenerator maps onnxruntime env override to Daemon path", "[vector][daemon]") {
|
|
setenv("YAMS_EMBED_BACKEND", "onnxruntime", 1);
|
|
|
|
EmbeddingConfig cfg;
|
|
cfg.backend = EmbeddingConfig::Backend::Simeon;
|
|
EmbeddingGenerator gen(cfg);
|
|
|
|
REQUIRE_THAT(gen.getBackendName(), StartsWith("Daemon"));
|
|
|
|
unsetenv("YAMS_EMBED_BACKEND");
|
|
}
|
|
|
|
TEST_CASE("EmbeddingGenerator maps OnnxRuntime config to Daemon path", "[vector][daemon]") {
|
|
EmbeddingConfig cfg;
|
|
cfg.backend = EmbeddingConfig::Backend::OnnxRuntime;
|
|
|
|
EmbeddingGenerator gen(cfg);
|
|
REQUIRE_THAT(gen.getBackendName(), StartsWith("Daemon"));
|
|
}
|
|
|
|
TEST_CASE("EmbeddingGenerator selects Daemon when configured directly", "[vector][daemon]") {
|
|
EmbeddingConfig cfg;
|
|
cfg.backend = EmbeddingConfig::Backend::Daemon;
|
|
|
|
EmbeddingGenerator gen(cfg);
|
|
REQUIRE_THAT(gen.getBackendName(), StartsWith("Daemon"));
|
|
}
|