From 758fdcaa1b4aceb1499319eff4d9a9722b478b7e Mon Sep 17 00:00:00 2001 From: Trenton Holmes <797416+stumpylog@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:36:59 -0700 Subject: [PATCH 1/2] Fix test-unit.c structural corruption so it compiles and links Feature functions were spliced into other functions' bodies by mis-anchored IVF/DiskANN hunks, with mismatched #if/#endif guards and an unterminated #ifdef in main(). Regroup each test back into a whole function under the correct feature guard, restoring the rescore tests from their last-clean revision and reassembling the IVF/DiskANN tests. Also align the IVF test guard (SQLITE_VEC_ENABLE_IVF) with the implementation flag (SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE) so the binary links, and add the sqlite-vec.h / $(prefix) prerequisites to the test-unit target. Compiles and links across the flag matrix. The suite does not yet pass at runtime: the rescore int8 assertions are stale (separate pre-existing bug). --- Makefile | 2 +- tests/sqlite-vec-internal.h | 9 +- tests/test-unit.c | 287 +++++++++++++++++++----------------- 3 files changed, 164 insertions(+), 134 deletions(-) diff --git a/Makefile b/Makefile index 175ab169..45c66118 100644 --- a/Makefile +++ b/Makefile @@ -203,7 +203,7 @@ test-loadable-snapshot-update: loadable test-loadable-watch: watchexec --exts c,py,Makefile --clear -- make test-loadable -test-unit: +test-unit: sqlite-vec.h $(prefix) $(CC) -DSQLITE_CORE -DSQLITE_VEC_TEST -DSQLITE_VEC_ENABLE_RESCORE -DSQLITE_VEC_ENABLE_DISKANN=1 tests/test-unit.c sqlite-vec.c vendor/sqlite3.c -I./ -Ivendor $(CFLAGS) -o $(prefix)/test-unit && $(prefix)/test-unit # Standalone sqlite3 CLI with vec0 compiled in. Useful for benchmarking, diff --git a/tests/sqlite-vec-internal.h b/tests/sqlite-vec-internal.h index 313add4d..f0ce5ce2 100644 --- a/tests/sqlite-vec-internal.h +++ b/tests/sqlite-vec-internal.h @@ -5,8 +5,15 @@ #include #include +// The IVF implementation in sqlite-vec.c is gated on +// SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE (default 0). Keep the test guard's default +// consistent with it, otherwise the IVF tests reference ivf_* symbols that were +// never compiled into the extension and the unit-test binary fails to link. +#ifndef SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE +#define SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE 0 +#endif #ifndef SQLITE_VEC_ENABLE_IVF -#define SQLITE_VEC_ENABLE_IVF 1 +#define SQLITE_VEC_ENABLE_IVF SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE #endif int min_idx( diff --git a/tests/test-unit.c b/tests/test-unit.c index 83cedd5f..487f7f23 100644 --- a/tests/test-unit.c +++ b/tests/test-unit.c @@ -997,38 +997,6 @@ void test_rescore_quantize_float_to_int8() { float src[8] = {5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f}; _test_rescore_quantize_float_to_int8(src, dst, 8); for (int i = 0; i < 8; i++) { -#if SQLITE_VEC_ENABLE_IVF -void test_ivf_quantize_int8() { - printf("Starting %s...\n", __func__); - - // Basic values in [-1, 1] range - { - float src[] = {0.0f, 1.0f, -1.0f, 0.5f}; - int8_t dst[4]; - ivf_quantize_int8(src, dst, 4); - assert(dst[0] == 0); - assert(dst[1] == 127); - assert(dst[2] == -127); - assert(dst[3] == 63); // 0.5 * 127 = 63.5, truncated to 63 - } - - // Clamping: values beyond [-1, 1] - { - float src[] = {2.0f, -3.0f, 100.0f, -0.01f}; - int8_t dst[4]; - ivf_quantize_int8(src, dst, 4); - assert(dst[0] == 127); // clamped to 1.0 - assert(dst[1] == -127); // clamped to -1.0 - assert(dst[2] == 127); // clamped to 1.0 - assert(dst[3] == (int8_t)(-0.01f * 127.0f)); - } - - // Zero vector - { - float src[] = {0.0f, 0.0f, 0.0f, 0.0f}; - int8_t dst[4]; - ivf_quantize_int8(src, dst, 4); - for (int i = 0; i < 4; i++) { assert(dst[i] == 0); } } @@ -1090,6 +1058,116 @@ void test_rescore_quantized_byte_size() { } void test_vec0_parse_vector_column_rescore() { + printf("Starting %s...\n", __func__); + struct VectorColumnDefinition col; + int rc; + + // Basic bit quantizer + { + const char *input = "emb float[128] indexed by rescore(quantizer=bit)"; + rc = vec0_parse_vector_column(input, (int)strlen(input), &col); + assert(rc == SQLITE_OK); + assert(col.index_type == VEC0_INDEX_TYPE_RESCORE); + assert(col.rescore.quantizer_type == VEC0_RESCORE_QUANTIZER_BIT); + assert(col.rescore.oversample == 8); // default + assert(col.dimensions == 128); + sqlite3_free(col.name); + } + + // Int8 quantizer + { + const char *input = "emb float[128] indexed by rescore(quantizer=int8)"; + rc = vec0_parse_vector_column(input, (int)strlen(input), &col); + assert(rc == SQLITE_OK); + assert(col.index_type == VEC0_INDEX_TYPE_RESCORE); + assert(col.rescore.quantizer_type == VEC0_RESCORE_QUANTIZER_INT8); + sqlite3_free(col.name); + } + + // Bit quantizer with oversample + { + const char *input = "emb float[128] indexed by rescore(quantizer=bit, oversample=16)"; + rc = vec0_parse_vector_column(input, (int)strlen(input), &col); + assert(rc == SQLITE_OK); + assert(col.index_type == VEC0_INDEX_TYPE_RESCORE); + assert(col.rescore.quantizer_type == VEC0_RESCORE_QUANTIZER_BIT); + assert(col.rescore.oversample == 16); + sqlite3_free(col.name); + } + + // Error: non-float element type + { + const char *input = "emb int8[128] indexed by rescore(quantizer=bit)"; + rc = vec0_parse_vector_column(input, (int)strlen(input), &col); + assert(rc == SQLITE_ERROR); + } + + // Error: dims not divisible by 8 for bit quantizer + { + const char *input = "emb float[100] indexed by rescore(quantizer=bit)"; + rc = vec0_parse_vector_column(input, (int)strlen(input), &col); + assert(rc == SQLITE_ERROR); + } + + // Error: missing quantizer + { + const char *input = "emb float[128] indexed by rescore(oversample=8)"; + rc = vec0_parse_vector_column(input, (int)strlen(input), &col); + assert(rc == SQLITE_ERROR); + } + + // With distance_metric=cosine + { + const char *input = "emb float[128] distance_metric=cosine indexed by rescore(quantizer=int8)"; + rc = vec0_parse_vector_column(input, (int)strlen(input), &col); + assert(rc == SQLITE_OK); + assert(col.index_type == VEC0_INDEX_TYPE_RESCORE); + assert(col.distance_metric == VEC0_DISTANCE_METRIC_COSINE); + assert(col.rescore.quantizer_type == VEC0_RESCORE_QUANTIZER_INT8); + sqlite3_free(col.name); + } + + printf(" All vec0_parse_vector_column_rescore tests passed.\n"); +} + +#endif /* SQLITE_VEC_ENABLE_RESCORE */ + +#if SQLITE_VEC_ENABLE_IVF + +void test_ivf_quantize_int8() { + printf("Starting %s...\n", __func__); + + // Basic values in [-1, 1] range + { + float src[] = {0.0f, 1.0f, -1.0f, 0.5f}; + int8_t dst[4]; + ivf_quantize_int8(src, dst, 4); + assert(dst[0] == 0); + assert(dst[1] == 127); + assert(dst[2] == -127); + assert(dst[3] == 63); // 0.5 * 127 = 63.5, truncated to 63 + } + + // Clamping: values beyond [-1, 1] + { + float src[] = {2.0f, -3.0f, 100.0f, -0.01f}; + int8_t dst[4]; + ivf_quantize_int8(src, dst, 4); + assert(dst[0] == 127); // clamped to 1.0 + assert(dst[1] == -127); // clamped to -1.0 + assert(dst[2] == 127); // clamped to 1.0 + assert(dst[3] == (int8_t)(-0.01f * 127.0f)); + } + + // Zero vector + { + float src[] = {0.0f, 0.0f, 0.0f, 0.0f}; + int8_t dst[4]; + ivf_quantize_int8(src, dst, 4); + for (int i = 0; i < 4; i++) { + assert(dst[i] == 0); + } + } // Negative zero { float src[] = {-0.0f}; @@ -1187,108 +1265,9 @@ void test_ivf_quantize_binary() { } void test_ivf_config_parsing() { -void test_vec0_parse_vector_column_diskann() { printf("Starting %s...\n", __func__); struct VectorColumnDefinition col; int rc; - - // Basic bit quantizer - { - const char *input = "emb float[128] indexed by rescore(quantizer=bit)"; - rc = vec0_parse_vector_column(input, (int)strlen(input), &col); - assert(rc == SQLITE_OK); - assert(col.index_type == VEC0_INDEX_TYPE_RESCORE); - assert(col.rescore.quantizer_type == VEC0_RESCORE_QUANTIZER_BIT); - assert(col.rescore.oversample == 8); // default - // Existing syntax (no INDEXED BY) should have diskann.enabled == 0 - { - const char *input = "emb float[128]"; - rc = vec0_parse_vector_column(input, (int)strlen(input), &col); - assert(rc == SQLITE_OK); - assert(col.index_type != VEC0_INDEX_TYPE_DISKANN); - sqlite3_free(col.name); - } - - // With distance_metric but no INDEXED BY - { - const char *input = "emb float[128] distance_metric=cosine"; - rc = vec0_parse_vector_column(input, (int)strlen(input), &col); - assert(rc == SQLITE_OK); - assert(col.index_type != VEC0_INDEX_TYPE_DISKANN); - assert(col.distance_metric == VEC0_DISTANCE_METRIC_COSINE); - sqlite3_free(col.name); - } - - // Basic binary quantizer - { - const char *input = "emb float[128] INDEXED BY diskann(neighbor_quantizer=binary)"; - rc = vec0_parse_vector_column(input, (int)strlen(input), &col); - assert(rc == SQLITE_OK); - assert(col.index_type == VEC0_INDEX_TYPE_DISKANN); - assert(col.diskann.quantizer_type == VEC0_DISKANN_QUANTIZER_BINARY); - assert(col.diskann.n_neighbors == 72); // default - assert(col.diskann.search_list_size == 128); // default - assert(col.dimensions == 128); - sqlite3_free(col.name); - } - - // Int8 quantizer - { - const char *input = "emb float[128] indexed by rescore(quantizer=int8)"; - rc = vec0_parse_vector_column(input, (int)strlen(input), &col); - assert(rc == SQLITE_OK); - assert(col.index_type == VEC0_INDEX_TYPE_RESCORE); - assert(col.rescore.quantizer_type == VEC0_RESCORE_QUANTIZER_INT8); - sqlite3_free(col.name); - } - - // Bit quantizer with oversample - { - const char *input = "emb float[128] indexed by rescore(quantizer=bit, oversample=16)"; - rc = vec0_parse_vector_column(input, (int)strlen(input), &col); - assert(rc == SQLITE_OK); - assert(col.index_type == VEC0_INDEX_TYPE_RESCORE); - assert(col.rescore.quantizer_type == VEC0_RESCORE_QUANTIZER_BIT); - assert(col.rescore.oversample == 16); - sqlite3_free(col.name); - } - - // Error: non-float element type - { - const char *input = "emb int8[128] indexed by rescore(quantizer=bit)"; - rc = vec0_parse_vector_column(input, (int)strlen(input), &col); - assert(rc == SQLITE_ERROR); - } - - // Error: dims not divisible by 8 for bit quantizer - { - const char *input = "emb float[100] indexed by rescore(quantizer=bit)"; - rc = vec0_parse_vector_column(input, (int)strlen(input), &col); - assert(rc == SQLITE_ERROR); - } - - // Error: missing quantizer - { - const char *input = "emb float[128] indexed by rescore(oversample=8)"; - rc = vec0_parse_vector_column(input, (int)strlen(input), &col); - assert(rc == SQLITE_ERROR); - } - - // With distance_metric=cosine - { - const char *input = "emb float[128] distance_metric=cosine indexed by rescore(quantizer=int8)"; - rc = vec0_parse_vector_column(input, (int)strlen(input), &col); - assert(rc == SQLITE_OK); - assert(col.index_type == VEC0_INDEX_TYPE_RESCORE); - assert(col.distance_metric == VEC0_DISTANCE_METRIC_COSINE); - assert(col.rescore.quantizer_type == VEC0_RESCORE_QUANTIZER_INT8); - sqlite3_free(col.name); - } - - printf(" All vec0_parse_vector_column_rescore tests passed.\n"); -} - -#endif /* SQLITE_VEC_ENABLE_RESCORE */ // Default IVF config { const char *s = "v float[4] indexed by ivf()"; @@ -1398,7 +1377,46 @@ void test_vec0_parse_vector_column_diskann() { printf(" All ivf_config_parsing tests passed.\n"); } + #endif /* SQLITE_VEC_ENABLE_IVF */ + +#ifdef SQLITE_VEC_ENABLE_DISKANN + +void test_vec0_parse_vector_column_diskann() { + printf("Starting %s...\n", __func__); + struct VectorColumnDefinition col; + int rc; + // Existing syntax (no INDEXED BY) should have diskann.enabled == 0 + { + const char *input = "emb float[128]"; + rc = vec0_parse_vector_column(input, (int)strlen(input), &col); + assert(rc == SQLITE_OK); + assert(col.index_type != VEC0_INDEX_TYPE_DISKANN); + sqlite3_free(col.name); + } + + // With distance_metric but no INDEXED BY + { + const char *input = "emb float[128] distance_metric=cosine"; + rc = vec0_parse_vector_column(input, (int)strlen(input), &col); + assert(rc == SQLITE_OK); + assert(col.index_type != VEC0_INDEX_TYPE_DISKANN); + assert(col.distance_metric == VEC0_DISTANCE_METRIC_COSINE); + sqlite3_free(col.name); + } + + // Basic binary quantizer + { + const char *input = "emb float[128] INDEXED BY diskann(neighbor_quantizer=binary)"; + rc = vec0_parse_vector_column(input, (int)strlen(input), &col); + assert(rc == SQLITE_OK); + assert(col.index_type == VEC0_INDEX_TYPE_DISKANN); + assert(col.diskann.quantizer_type == VEC0_DISKANN_QUANTIZER_BINARY); + assert(col.diskann.n_neighbors == 72); // default + assert(col.diskann.search_list_size == 128); // default + assert(col.dimensions == 128); + sqlite3_free(col.name); + } // INT8 quantizer { const char *input = "v float[64] INDEXED BY diskann(neighbor_quantizer=int8)"; @@ -2075,6 +2093,8 @@ void test_diskann_prune_select_max_neighbors_1() { printf(" All diskann_prune_select_max_neighbors_1 tests passed.\n"); } +#endif /* SQLITE_VEC_ENABLE_DISKANN */ + int main() { printf("Starting unit tests...\n"); #ifdef SQLITE_VEC_ENABLE_AVX @@ -2105,7 +2125,9 @@ int main() { test_ivf_quantize_int8(); test_ivf_quantize_binary(); test_ivf_config_parsing(); -#endif +#endif /* SQLITE_VEC_ENABLE_IVF */ +#endif /* SQLITE_VEC_ENABLE_RESCORE */ +#ifdef SQLITE_VEC_ENABLE_DISKANN test_vec0_parse_vector_column_diskann(); test_diskann_validity_bitmap(); test_diskann_neighbor_ids(); @@ -2124,5 +2146,6 @@ int main() { test_diskann_prune_select_single_candidate(); test_diskann_prune_select_all_identical_distances(); test_diskann_prune_select_max_neighbors_1(); +#endif /* SQLITE_VEC_ENABLE_DISKANN */ printf("All unit tests passed.\n"); } From dcc5730a2a73fac22daa8ffdf119a7f817201ffa Mon Sep 17 00:00:00 2001 From: Trenton Holmes <797416+stumpylog@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:56:33 -0700 Subject: [PATCH 2/2] Make test-unit pass: fix struct-mirror ABI drift and stale int8 assertions The test's hand-maintained struct mirror in sqlite-vec-internal.h had drifted from sqlite-vec.c: Vec0RescoreConfig was missing the oversample_search field (8 vs 12 bytes), shifting ivf/diskann by 4 bytes so the diskann parse tests read the wrong fields. The header also didn't default RESCORE/DISKANN on (the extension does), so a no-flag build disagreed on struct sizes and smashed the stack. Sync the mirror, default the flags to match sqlite-vec.c, drop a duplicated rescore definition, and switch the feature guards from #ifdef to #if so explicit -DFLAG=0 builds stay consistent. Rewrite test_rescore_quantize_float_to_int8 against the actual quantizer (a fixed [-1,1] -> [-128,127] mapping); the old assertions expected a range-normalizing quantizer that no longer exists. All unit tests pass across the flag matrix (defaults, RESCORE, RESCORE+DISKANN, RESCORE+DISKANN+IVF, and explicit all-off). --- tests/sqlite-vec-internal.h | 44 +++++++++++++----------- tests/test-unit.c | 68 ++++++++++++++++++------------------- 2 files changed, 58 insertions(+), 54 deletions(-) diff --git a/tests/sqlite-vec-internal.h b/tests/sqlite-vec-internal.h index f0ce5ce2..f4977feb 100644 --- a/tests/sqlite-vec-internal.h +++ b/tests/sqlite-vec-internal.h @@ -5,13 +5,24 @@ #include #include -// The IVF implementation in sqlite-vec.c is gated on -// SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE (default 0). Keep the test guard's default -// consistent with it, otherwise the IVF tests reference ivf_* symbols that were -// never compiled into the extension and the unit-test binary fails to link. +// Mirror sqlite-vec.c's own feature-flag defaults so the struct definitions +// below match the ones the extension is compiled with. sqlite-vec.c defaults +// RESCORE and DISKANN on and IVF (experimental) off; if these defaults drift, +// the test reads parsed fields at the wrong offsets (or overflows `col`). +// Guards below use `#if FLAG` (not `#ifdef`) so an explicit `-DFLAG=0` build +// stays consistent with the extension. +#ifndef SQLITE_VEC_ENABLE_RESCORE +#define SQLITE_VEC_ENABLE_RESCORE 1 +#endif +#ifndef SQLITE_VEC_ENABLE_DISKANN +#define SQLITE_VEC_ENABLE_DISKANN 1 +#endif #ifndef SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE #define SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE 0 #endif +// The IVF tests gate on SQLITE_VEC_ENABLE_IVF; the implementation gates on +// SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE. Track the implementation flag so the IVF +// tests are only built when the ivf_* symbols actually exist. #ifndef SQLITE_VEC_ENABLE_IVF #define SQLITE_VEC_ENABLE_IVF SQLITE_VEC_EXPERIMENTAL_IVF_ENABLE #endif @@ -76,13 +87,16 @@ enum Vec0DistanceMetrics { enum Vec0IndexType { VEC0_INDEX_TYPE_FLAT = 1, -#ifdef SQLITE_VEC_ENABLE_RESCORE +#if SQLITE_VEC_ENABLE_RESCORE VEC0_INDEX_TYPE_RESCORE = 2, #endif VEC0_INDEX_TYPE_IVF = 3, VEC0_INDEX_TYPE_DISKANN = 4, }; +// These struct mirrors must stay byte-compatible with the definitions in +// sqlite-vec.c, otherwise the test reads parsed fields at the wrong offsets. +#if SQLITE_VEC_ENABLE_RESCORE enum Vec0RescoreQuantizerType { VEC0_RESCORE_QUANTIZER_BIT = 1, VEC0_RESCORE_QUANTIZER_INT8 = 2, @@ -90,8 +104,10 @@ enum Vec0RescoreQuantizerType { struct Vec0RescoreConfig { enum Vec0RescoreQuantizerType quantizer_type; - int oversample; + int oversample; // CREATE-time default + int oversample_search; // runtime override (0 = use default) }; +#endif #if SQLITE_VEC_ENABLE_IVF enum Vec0IvfQuantizer { @@ -110,18 +126,6 @@ struct Vec0IvfConfig { struct Vec0IvfConfig { char _unused; }; #endif -#ifdef SQLITE_VEC_ENABLE_RESCORE -enum Vec0RescoreQuantizerType { - VEC0_RESCORE_QUANTIZER_BIT = 1, - VEC0_RESCORE_QUANTIZER_INT8 = 2, -}; - -struct Vec0RescoreConfig { - enum Vec0RescoreQuantizerType quantizer_type; - int oversample; -}; -#endif - enum Vec0DiskannQuantizerType { VEC0_DISKANN_QUANTIZER_BINARY = 1, VEC0_DISKANN_QUANTIZER_INT8 = 2, @@ -144,7 +148,7 @@ struct VectorColumnDefinition { enum VectorElementType element_type; enum Vec0DistanceMetrics distance_metric; enum Vec0IndexType index_type; -#ifdef SQLITE_VEC_ENABLE_RESCORE +#if SQLITE_VEC_ENABLE_RESCORE struct Vec0RescoreConfig rescore; #endif struct Vec0IvfConfig ivf; @@ -206,7 +210,7 @@ float _test_distance_l2_sqr_float(const float *a, const float *b, size_t dims); float _test_distance_cosine_float(const float *a, const float *b, size_t dims); float _test_distance_hamming(const unsigned char *a, const unsigned char *b, size_t dims); -#ifdef SQLITE_VEC_ENABLE_RESCORE +#if SQLITE_VEC_ENABLE_RESCORE void _test_rescore_quantize_float_to_bit(const float *src, uint8_t *dst, size_t dim); void _test_rescore_quantize_float_to_int8(const float *src, int8_t *dst, size_t dim); size_t _test_rescore_quantized_byte_size_bit(size_t dimensions); diff --git a/tests/test-unit.c b/tests/test-unit.c index 487f7f23..bbc30153 100644 --- a/tests/test-unit.c +++ b/tests/test-unit.c @@ -936,7 +936,7 @@ void test_distance_hamming() { printf(" All distance_hamming tests passed.\n"); } -#ifdef SQLITE_VEC_ENABLE_RESCORE +#if SQLITE_VEC_ENABLE_RESCORE void test_rescore_quantize_float_to_bit() { printf("Starting %s...\n", __func__); @@ -992,50 +992,50 @@ void test_rescore_quantize_float_to_int8() { printf("Starting %s...\n", __func__); int8_t dst[256]; - // Uniform vector -> all zeros (range=0) + // Fixed [-1, 1] -> [-128, 127] mapping (no range normalization): -1.0 maps + // to -128 exactly, 1.0 to the top of the range (127, modulo float rounding). { - float src[8] = {5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f, 5.0f}; - _test_rescore_quantize_float_to_int8(src, dst, 8); - for (int i = 0; i < 8; i++) { - assert(dst[i] == 0); - } + float src[2] = {-1.0f, 1.0f}; + _test_rescore_quantize_float_to_int8(src, dst, 2); + assert(dst[0] == -128); + assert(dst[1] >= 126 && dst[1] <= 127); } - // [0.0, 1.0] -> should map to [-128, 127] + // 0.0 sits at the midpoint and maps to ~0. { - float src[2] = {0.0f, 1.0f}; - _test_rescore_quantize_float_to_int8(src, dst, 2); - assert(dst[0] == -128); - assert(dst[1] == 127); + float src[1] = {0.0f}; + _test_rescore_quantize_float_to_int8(src, dst, 1); + assert(dst[0] >= -1 && dst[0] <= 0); } - // [-1.0, 0.0] -> should map to [-128, 127] + // Values outside [-1, 1] clamp to the endpoints. { - float src[2] = {-1.0f, 0.0f}; - _test_rescore_quantize_float_to_int8(src, dst, 2); - assert(dst[0] == -128); - assert(dst[1] == 127); + float src[4] = {5.0f, -5.0f, 100.0f, -100.0f}; + _test_rescore_quantize_float_to_int8(src, dst, 4); + assert(dst[0] == 127); + assert(dst[1] == -128); + assert(dst[2] == 127); + assert(dst[3] == -128); } - // Single-element: range=0 -> 0 + // A uniform in-range vector maps every element to the same code. { - float src[1] = {42.0f}; - _test_rescore_quantize_float_to_int8(src, dst, 1); - assert(dst[0] == 0); + float src[8] = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f}; + _test_rescore_quantize_float_to_int8(src, dst, 8); + for (int i = 1; i < 8; i++) { + assert(dst[i] == dst[0]); + } + assert(dst[0] > 0); // positive half maps to a positive code } - // Verify range: all outputs in [-128, 127], min near -128, max near 127 + // Monotonic: increasing inputs produce non-decreasing codes. { - float src[4] = {-100.0f, 0.0f, 100.0f, 50.0f}; - _test_rescore_quantize_float_to_int8(src, dst, 4); - for (int i = 0; i < 4; i++) { - assert(dst[i] >= -128 && dst[i] <= 127); + float src[5] = {-1.0f, -0.5f, 0.0f, 0.5f, 1.0f}; + _test_rescore_quantize_float_to_int8(src, dst, 5); + for (int i = 1; i < 5; i++) { + assert(dst[i] >= dst[i - 1]); } - // Min maps to -128 (exact), max maps to ~127 (may lose 1 to float rounding) assert(dst[0] == -128); - assert(dst[2] >= 126 && dst[2] <= 127); - // Middle value (50) should be positive - assert(dst[3] > 0); } printf(" All rescore_quantize_float_to_int8 tests passed.\n"); @@ -1380,7 +1380,7 @@ void test_ivf_config_parsing() { #endif /* SQLITE_VEC_ENABLE_IVF */ -#ifdef SQLITE_VEC_ENABLE_DISKANN +#if SQLITE_VEC_ENABLE_DISKANN void test_vec0_parse_vector_column_diskann() { printf("Starting %s...\n", __func__); @@ -2103,7 +2103,7 @@ int main() { #ifdef SQLITE_VEC_ENABLE_NEON printf("SQLITE_VEC_ENABLE_NEON=1\n"); #endif -#ifdef SQLITE_VEC_ENABLE_RESCORE +#if SQLITE_VEC_ENABLE_RESCORE printf("SQLITE_VEC_ENABLE_RESCORE=1\n"); #endif #if !defined(SQLITE_VEC_ENABLE_AVX) && !defined(SQLITE_VEC_ENABLE_NEON) @@ -2116,7 +2116,7 @@ int main() { test_distance_l2_sqr_float(); test_distance_cosine_float(); test_distance_hamming(); -#ifdef SQLITE_VEC_ENABLE_RESCORE +#if SQLITE_VEC_ENABLE_RESCORE test_rescore_quantize_float_to_bit(); test_rescore_quantize_float_to_int8(); test_rescore_quantized_byte_size(); @@ -2127,7 +2127,7 @@ int main() { test_ivf_config_parsing(); #endif /* SQLITE_VEC_ENABLE_IVF */ #endif /* SQLITE_VEC_ENABLE_RESCORE */ -#ifdef SQLITE_VEC_ENABLE_DISKANN +#if SQLITE_VEC_ENABLE_DISKANN test_vec0_parse_vector_column_diskann(); test_diskann_validity_bitmap(); test_diskann_neighbor_ids();