From 0f4531a10e7cd2ff5cdb069ff6d07fa3721754c7 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 13:45:38 +0400 Subject: [PATCH 01/20] add support for vector indices over f64 embeddings --- libsql-sqlite3/src/vectorIndex.c | 4 ++-- libsql-sqlite3/src/vectordiskann.c | 10 +++++----- libsql-sqlite3/test/libsql_vector_index.test | 9 ++++++++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libsql-sqlite3/src/vectorIndex.c b/libsql-sqlite3/src/vectorIndex.c index 11a9585ed2..35c7b6908b 100644 --- a/libsql-sqlite3/src/vectorIndex.c +++ b/libsql-sqlite3/src/vectorIndex.c @@ -967,8 +967,8 @@ int vectorIndexSearch( rc = SQLITE_ERROR; goto out; } - if( type != VECTOR_TYPE_FLOAT32 ){ - *pzErrMsg = sqlite3_mprintf("vector index(search): only f32 vectors are supported"); + if( type != VECTOR_TYPE_FLOAT32 && type != VECTOR_TYPE_FLOAT64 ){ + *pzErrMsg = sqlite3_mprintf("vector index(search): unsupported vector type: only FLOAT32/FLOAT64 are available for indexing"); rc = SQLITE_ERROR; goto out; } diff --git a/libsql-sqlite3/src/vectordiskann.c b/libsql-sqlite3/src/vectordiskann.c index 1f9973d38c..c28cf075e9 100644 --- a/libsql-sqlite3/src/vectordiskann.c +++ b/libsql-sqlite3/src/vectordiskann.c @@ -1428,12 +1428,12 @@ int diskAnnSearch( *pzErrMsg = sqlite3_mprintf("vector index(search): k must be a non-negative integer"); return SQLITE_ERROR; } - if( pIndex->nVectorDims != pVector->dims ){ + if( pVector->dims != pIndex->nVectorDims ){ *pzErrMsg = sqlite3_mprintf("vector index(search): dimensions are different: %d != %d", pVector->dims, pIndex->nVectorDims); return SQLITE_ERROR; } - if( pVector->type != VECTOR_TYPE_FLOAT32 ){ - *pzErrMsg = sqlite3_mprintf("vector index(search): only f32 vectors are supported"); + if( pVector->type != pIndex->nNodeVectorType ){ + *pzErrMsg = sqlite3_mprintf("vector index(search): vector type differs from column type: %d != %d", pVector->type, pIndex->nNodeVectorType); return SQLITE_ERROR; } @@ -1498,8 +1498,8 @@ int diskAnnInsert( *pzErrMsg = sqlite3_mprintf("vector index(insert): dimensions are different: %d != %d", pVectorInRow->pVector->dims, pIndex->nVectorDims); return SQLITE_ERROR; } - if( pVectorInRow->pVector->type != VECTOR_TYPE_FLOAT32 ){ - *pzErrMsg = sqlite3_mprintf("vector index(insert): only f32 vectors are supported"); + if( pVectorInRow->pVector->type != pIndex->nNodeVectorType ){ + *pzErrMsg = sqlite3_mprintf("vector index(insert): vector type differs from column type: %d != %d", pVectorInRow->pVector->type, pIndex->nNodeVectorType); return SQLITE_ERROR; } diff --git a/libsql-sqlite3/test/libsql_vector_index.test b/libsql-sqlite3/test/libsql_vector_index.test index 281943e7c2..98d11208fa 100644 --- a/libsql-sqlite3/test/libsql_vector_index.test +++ b/libsql-sqlite3/test/libsql_vector_index.test @@ -290,6 +290,13 @@ do_execsql_test vector-all-params { SELECT * FROM vector_top_k('t_all_params_idx', vector('[1,2]'), 2); } {1 2} +do_execsql_test vector-f64-index { + CREATE TABLE t_f64 ( emb FLOAT64(2) ); + CREATE INDEX t_f64_idx ON t_f64(libsql_vector_idx(emb)); + INSERT INTO t_f64 VALUES (vector64('[1,2]')), (vector64('[3,4]')); + SELECT * FROM vector_top_k('t_f64_idx', vector64('[1,2]'), 2); +} {1 2} + do_execsql_test vector-partial { CREATE TABLE t_partial( name TEXT, type INT, v FLOAT32(3)); INSERT INTO t_partial VALUES ( 'a', 0, vector('[1,2,3]') ); @@ -368,7 +375,7 @@ do_test vector-errors { {vector index: unsupported for tables without ROWID and composite primary key} {vector index(insert): dimensions are different: 1 != 4} {vector index(insert): dimensions are different: 5 != 4} - {vector index(insert): only f32 vectors are supported} + {vector index(insert): vector type differs from column type: 2 != 1} {vector index(search): dimensions are different: 2 != 4} {vector index(insert): dimensions are different: 1 != 3} }] From 626ff8c62c48786afcc5535b94b1cbbf7c73999d Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 15:12:18 +0400 Subject: [PATCH 02/20] prepare conversion function for mooore types --- libsql-sqlite3/src/vector.c | 115 ++++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 10 deletions(-) diff --git a/libsql-sqlite3/src/vector.c b/libsql-sqlite3/src/vector.c index c622d977e1..5903e62294 100644 --- a/libsql-sqlite3/src/vector.c +++ b/libsql-sqlite3/src/vector.c @@ -481,26 +481,121 @@ void vectorInitFromBlob(Vector *pVector, const unsigned char *pBlob, size_t nBlo } } -void vectorConvert(const Vector *pFrom, Vector *pTo){ +static void vectorConvertFromF32(const Vector *pFrom, Vector *pTo){ int i; - u8 *bitData; - float *floatData; + float *src; + + u8 *dst1Bit; + double *dstF64; assert( pFrom->dims == pTo->dims ); + assert( pFrom->type != pTo->type ); + assert( pFrom->type == VECTOR_TYPE_FLOAT32 ); - if( pFrom->type == VECTOR_TYPE_FLOAT32 && pTo->type == VECTOR_TYPE_1BIT ){ - floatData = pFrom->data; - bitData = pTo->data; + src = pFrom->data; + if( pTo->type == VECTOR_TYPE_FLOAT64 ){ + dstF64 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + dstF64[i] = src[i]; + } + }else if( pTo->type == VECTOR_TYPE_1BIT ){ + dst1Bit = pTo->data; for(i = 0; i < pFrom->dims; i += 8){ - bitData[i / 8] = 0; + dst1Bit[i / 8] = 0; } for(i = 0; i < pFrom->dims; i++){ - if( floatData[i] > 0 ){ - bitData[i / 8] |= (1 << (i & 7)); + if( src[i] > 0 ){ + dst1Bit[i / 8] |= (1 << (i & 7)); } } }else{ - assert(0); + assert( 0 ); + } +} + +static void vectorConvertFromF64(const Vector *pFrom, Vector *pTo){ + int i; + double *src; + + u8 *dst1Bit; + float *dstF32; + + assert( pFrom->dims == pTo->dims ); + assert( pFrom->type != pTo->type ); + assert( pFrom->type == VECTOR_TYPE_FLOAT64 ); + + src = pFrom->data; + if( pTo->type == VECTOR_TYPE_FLOAT32 ){ + dstF32 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + dstF32[i] = src[i]; + } + }else if( pTo->type == VECTOR_TYPE_1BIT ){ + dst1Bit = pTo->data; + for(i = 0; i < pFrom->dims; i += 8){ + dst1Bit[i / 8] = 0; + } + for(i = 0; i < pFrom->dims; i++){ + if( src[i] > 0 ){ + dst1Bit[i / 8] |= (1 << (i & 7)); + } + } + }else{ + assert( 0 ); + } +} + +static void vectorConvertFrom1Bit(const Vector *pFrom, Vector *pTo){ + int i; + u8 *src; + + float *dstF32; + double *dstF64; + + assert( pFrom->dims == pTo->dims ); + assert( pFrom->type != pTo->type ); + assert( pFrom->type == VECTOR_TYPE_1BIT ); + + src = pFrom->data; + if( pTo->type == VECTOR_TYPE_FLOAT32 ){ + dstF32 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + if( ((src[i / 8] >> (i & 7)) & 1) == 1 ){ + dstF32[i] = +1; + }else{ + dstF32[i] = -1; + } + } + }else if( pTo->type == VECTOR_TYPE_FLOAT64 ){ + dstF64 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + if( ((src[i / 8] >> (i & 7)) & 1) == 1 ){ + dstF64[i] = +1; + }else{ + dstF64[i] = -1; + } + } + }else{ + assert( 0 ); + } +} + +void vectorConvert(const Vector *pFrom, Vector *pTo){ + assert( pFrom->dims == pTo->dims ); + + if( pFrom->type == pTo->type ){ + memcpy(pTo->data, pFrom->data, vectorDataSize(pFrom->type, pFrom->dims)); + return; + } + + if( pFrom->type == VECTOR_TYPE_FLOAT32 ){ + vectorConvertFromF32(pFrom, pTo); + }else if( pFrom->type == VECTOR_TYPE_FLOAT64 ){ + vectorConvertFromF64(pFrom, pTo); + }else if( pFrom->type == VECTOR_TYPE_1BIT ){ + vectorConvertFrom1Bit(pFrom, pTo); + }else{ + assert( 0 ); } } From 4a57f02b78764b056cb5cc95a07bd28ed4cc0ad9 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 15:20:52 +0400 Subject: [PATCH 03/20] add simple conversion test --- libsql-sqlite3/src/vector.c | 36 ++++++++++++++++++-------- libsql-sqlite3/test/libsql_vector.test | 17 ++++++++++++ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/libsql-sqlite3/src/vector.c b/libsql-sqlite3/src/vector.c index 5903e62294..b1289e2e85 100644 --- a/libsql-sqlite3/src/vector.c +++ b/libsql-sqlite3/src/vector.c @@ -610,31 +610,45 @@ static void vectorFuncHintedType( sqlite3_context *context, int argc, sqlite3_value **argv, - int typeHint + int targetType ){ char *pzErrMsg = NULL; - Vector *pVector; + Vector *pVector = NULL, *pTarget = NULL; int type, dims; if( argc < 1 ){ - return; + goto out; } - if( detectVectorParameters(argv[0], typeHint, &type, &dims, &pzErrMsg) != 0 ){ + if( detectVectorParameters(argv[0], targetType, &type, &dims, &pzErrMsg) != 0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - return; + goto out; } pVector = vectorContextAlloc(context, type, dims); - if( pVector==NULL ){ - return; + if( pVector == NULL ){ + goto out; } if( vectorParseWithType(argv[0], pVector, &pzErrMsg) != 0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - goto out_free_vec; + goto out; + } + if( type == targetType ){ + vectorSerializeWithType(context, pVector); + }else{ + pTarget = vectorContextAlloc(context, targetType, dims); + if( pTarget == NULL ){ + goto out; + } + vectorConvert(pVector, pTarget); + vectorSerializeWithType(context, pTarget); + } +out: + if( pVector != NULL ){ + vectorFree(pVector); + } + if( pTarget != NULL ){ + vectorFree(pTarget); } - vectorSerializeWithType(context, pVector); -out_free_vec: - vectorFree(pVector); } static void vector32Func( diff --git a/libsql-sqlite3/test/libsql_vector.test b/libsql-sqlite3/test/libsql_vector.test index cf91a7fa18..e541e9e977 100644 --- a/libsql-sqlite3/test/libsql_vector.test +++ b/libsql-sqlite3/test/libsql_vector.test @@ -67,6 +67,23 @@ do_execsql_test vector-1-func-valid { {0.200000002980232} } +do_execsql_test vector-1-conversion { + SELECT hex(vector32('[]')); + SELECT hex(vector64(vector32('[]'))); + + SELECT hex(vector32(vector32('[0.000001,1e-100,1e100,1e10,1e-10,0,1.5]'))); + SELECT hex(vector32(vector64('[0.000001,1e-100,1e100,1e10,1e-10,0,1.5]'))); + SELECT hex(vector64(vector32('[0.000001,1e-100,1e100,1e10,1e-10,0,1.5]'))); + SELECT hex(vector64(vector64('[0.000001,1e-100,1e100,1e10,1e-10,0,1.5]'))); +} { + {} + 02 + BD378635000000000000807FF9021550FFE6DB2E000000000000C03F + BD378635000000000000807FF9021550FFE6DB2E000000000000C03F + 000000A0F7C6B03E0000000000000000000000000000F07F000000205FA00242000000E0DF7CDB3D0000000000000000000000000000F83F02 + 8DEDB5A0F7C6B03E30058EE42EFF2B2B7DC39425AD49B254000000205FA00242BBBDD7D9DF7CDB3D0000000000000000000000000000F83F02 +} + proc error_messages {sql} { set ret "" set stmt [sqlite3_prepare db $sql -1 dummy] From 4b562ed9055b4b108d81f102fa65489807831519 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 15:22:47 +0400 Subject: [PATCH 04/20] small refactoring --- libsql-sqlite3/src/vectorIndex.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/libsql-sqlite3/src/vectorIndex.c b/libsql-sqlite3/src/vectorIndex.c index 35c7b6908b..4ee9dbe313 100644 --- a/libsql-sqlite3/src/vectorIndex.c +++ b/libsql-sqlite3/src/vectorIndex.c @@ -24,6 +24,7 @@ ** ** libSQL vector search. */ +#include "vectorInt.h" #ifndef SQLITE_OMIT_VECTOR #include "sqlite3.h" #include "vdbeInt.h" @@ -373,14 +374,14 @@ void vectorOutRowsFree(sqlite3 *db, VectorOutRows *pRows) { */ struct VectorColumnType { const char *zName; - int nBits; + int type; }; static struct VectorColumnType VECTOR_COLUMN_TYPES[] = { - { "FLOAT32", 32 }, - { "FLOAT64", 64 }, - { "F32_BLOB", 32 }, - { "F64_BLOB", 64 } + { "FLOAT32", VECTOR_TYPE_FLOAT32 }, + { "FLOAT64", VECTOR_TYPE_FLOAT64 }, + { "F32_BLOB", VECTOR_TYPE_FLOAT32 }, + { "F64_BLOB", VECTOR_TYPE_FLOAT64 } }; /* @@ -569,14 +570,7 @@ int vectorIdxParseColumnType(const char *zType, int *pType, int *pDims, const ch } *pDims = dimensions; - if( VECTOR_COLUMN_TYPES[i].nBits == 32 ) { - *pType = VECTOR_TYPE_FLOAT32; - } else if( VECTOR_COLUMN_TYPES[i].nBits == 64 ) { - *pType = VECTOR_TYPE_FLOAT64; - } else { - *pErrMsg = "unsupported vector type"; - return -1; - } + *pType = VECTOR_COLUMN_TYPES[i].type; return 0; } *pErrMsg = "unexpected vector column type"; From 181464f14eff80b12c95864d0259749f72ee884e Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 16:10:52 +0400 Subject: [PATCH 05/20] add support for 1bit vector functions --- libsql-sqlite3/src/vector.c | 186 +++++++++++++++++++++++++------ libsql-sqlite3/src/vector1bit.c | 14 +++ libsql-sqlite3/src/vectorIndex.c | 10 +- libsql-sqlite3/src/vectorInt.h | 7 +- 4 files changed, 176 insertions(+), 41 deletions(-) diff --git a/libsql-sqlite3/src/vector.c b/libsql-sqlite3/src/vector.c index b1289e2e85..6d86619409 100644 --- a/libsql-sqlite3/src/vector.c +++ b/libsql-sqlite3/src/vector.c @@ -42,7 +42,6 @@ size_t vectorDataSize(VectorType type, VectorDims dims){ case VECTOR_TYPE_FLOAT64: return dims * sizeof(double); case VECTOR_TYPE_1BIT: - assert( dims > 0 ); return (dims + 7) / 8; default: assert(0); @@ -253,33 +252,84 @@ static int vectorParseSqliteText( return -1; } +static int vectorParseMeta(const unsigned char *pBlob, size_t nBlobSize, int *pType, int *pDims, size_t *pDataSize, char **pzErrMsg){ + int nLeftoverBits; + + if( nBlobSize % 2 == 0 ){ + *pType = VECTOR_TYPE_FLOAT32; + *pDims = nBlobSize / sizeof(float); + *pDataSize = nBlobSize; + return SQLITE_OK; + } + *pType = pBlob[nBlobSize - 1]; + nBlobSize--; + + if( *pType == VECTOR_TYPE_FLOAT32 ){ + if( nBlobSize % 4 != 0 ){ + *pzErrMsg = sqlite3_mprintf("invalid vector: f32 vector blob length must be divisible by 4 (excluding optional 'type'-byte): length=%d", nBlobSize); + return SQLITE_ERROR; + } + *pDims = nBlobSize / sizeof(float); + *pDataSize = nBlobSize; + }else if( *pType == VECTOR_TYPE_FLOAT64 ){ + if( nBlobSize % 8 != 0 ){ + *pzErrMsg = sqlite3_mprintf("invalid vector: f64 vector blob length must be divisible by 8 (excluding 'type'-byte): length=%d", nBlobSize); + return SQLITE_ERROR; + } + *pDims = nBlobSize / sizeof(double); + *pDataSize = nBlobSize; + }else if( *pType == VECTOR_TYPE_1BIT ){ + if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ + *pzErrMsg = sqlite3_mprintf("invalid vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); + return SQLITE_ERROR; + } + nLeftoverBits = pBlob[nBlobSize - 1]; + *pDims = nBlobSize * 8 - nLeftoverBits; + *pDataSize = (*pDims + 7) / 8; + }else{ + *pzErrMsg = sqlite3_mprintf("invalid vector: unexpected type: %d", *pType); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + int vectorParseSqliteBlobWithType( sqlite3_value *arg, Vector *pVector, char **pzErrMsg ){ const unsigned char *pBlob; - size_t nBlobSize; + size_t nBlobSize, nDataSize; + int type, dims; assert( sqlite3_value_type(arg) == SQLITE_BLOB ); pBlob = sqlite3_value_blob(arg); nBlobSize = sqlite3_value_bytes(arg); - if( nBlobSize % 2 == 1 ){ - nBlobSize--; + if( vectorParseMeta(pBlob, nBlobSize, &type, &dims, &nDataSize, pzErrMsg) != SQLITE_OK ){ + return SQLITE_ERROR; } - if( nBlobSize < vectorDataSize(pVector->type, pVector->dims) ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: not enough bytes: type=%d, dims=%d, size=%ull", pVector->type, pVector->dims, nBlobSize); + if( nDataSize != vectorDataSize(pVector->type, pVector->dims) ){ + *pzErrMsg = sqlite3_mprintf( + "invalid vector: unexpected data size bytes: type=%d, dims=%d, %ull != %ull", + pVector->type, + pVector->dims, + nDataSize, + vectorDataSize(pVector->type, pVector->dims) + ); return SQLITE_ERROR; } switch (pVector->type) { case VECTOR_TYPE_FLOAT32: - vectorF32DeserializeFromBlob(pVector, pBlob, nBlobSize); + vectorF32DeserializeFromBlob(pVector, pBlob, nDataSize); return 0; case VECTOR_TYPE_FLOAT64: - vectorF64DeserializeFromBlob(pVector, pBlob, nBlobSize); + vectorF64DeserializeFromBlob(pVector, pBlob, nDataSize); + return 0; + case VECTOR_TYPE_1BIT: + vector1BitDeserializeFromBlob(pVector, pBlob, nDataSize); return 0; default: assert(0); @@ -298,15 +348,22 @@ int detectBlobVectorParameters(sqlite3_value *arg, int *pType, int *pDims, char if( nBlobSize % 2 != 0 ){ // we have trailing byte with explicit type definition *pType = pBlob[nBlobSize - 1]; + nBlobSize--; } else { // else, fallback to FLOAT32 *pType = VECTOR_TYPE_FLOAT32; } if( *pType == VECTOR_TYPE_FLOAT32 ){ *pDims = nBlobSize / sizeof(float); - } else if( *pType == VECTOR_TYPE_FLOAT64 ){ + }else if( *pType == VECTOR_TYPE_FLOAT64 ){ *pDims = nBlobSize / sizeof(double); - } else{ + }else if( *pType == VECTOR_TYPE_1BIT ){ + if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ + *pzErrMsg = sqlite3_mprintf("vector: malformed 1bit float: blob size must has even size (without last byte): size=%d", nBlobSize); + return -1; + } + *pDims = nBlobSize * 8 - pBlob[nBlobSize - 1]; + }else{ *pzErrMsg = sqlite3_mprintf("vector: unexpected binary type: got %d, expected %d or %d", *pType, VECTOR_TYPE_FLOAT32, VECTOR_TYPE_FLOAT64); return -1; } @@ -411,21 +468,55 @@ void vectorMarshalToText( } } -void vectorSerializeWithType( +static int vectorMetaSize(VectorType type, VectorDims dims){ + int nMetaSize = 0; + int nDataSize; + if( type == VECTOR_TYPE_FLOAT32 ){ + return 0; + }else if( type == VECTOR_TYPE_FLOAT64 ){ + return 1; + }else if( type == VECTOR_TYPE_1BIT ){ + nDataSize = vectorDataSize(type, dims); + nMetaSize++; // one byte which specify amount of leftover bits + if( nDataSize % 2 == 0 ){ + nMetaSize++; // pad "leftover-bits" byte to the even length + } + nMetaSize++; // one byte for vector type + return nMetaSize; + }else{ + assert( 0 ); + } +} + +static void vectorSerializeMeta(const Vector *pVector, size_t nDataSize, unsigned char *pBlob, size_t nBlobSize){ + if( pVector->type == VECTOR_TYPE_FLOAT32 ){ + // no meta for f32 type as this is "default" vector type + }else if( pVector->type == VECTOR_TYPE_FLOAT64 ){ + assert( nDataSize % 2 == 0 ); + assert( nBlobSize == nDataSize + 1 ); + pBlob[nBlobSize - 1] = VECTOR_TYPE_FLOAT64; + }else if( pVector->type == VECTOR_TYPE_1BIT ){ + assert( nBlobSize % 2 == 1 ); + assert( nBlobSize >= 3 ); + pBlob[nBlobSize - 1] = VECTOR_TYPE_1BIT; + pBlob[nBlobSize - 2] = 8 * (nBlobSize - 1) - pVector->dims; + }else{ + assert( 0 ); + } +} + +void vectorSerializeWithMeta( sqlite3_context *context, const Vector *pVector ){ unsigned char *pBlob; - size_t nBlobSize, nDataSize; + size_t nBlobSize, nDataSize, nMetaSize; assert( pVector->dims <= MAX_VECTOR_SZ ); nDataSize = vectorDataSize(pVector->type, pVector->dims); - nBlobSize = nDataSize; - if( pVector->type != VECTOR_TYPE_FLOAT32 ){ - nBlobSize += (nBlobSize % 2 == 0 ? 1 : 2); - } - + nMetaSize = vectorMetaSize(pVector->type, pVector->dims); + nBlobSize = nDataSize + nMetaSize; if( nBlobSize == 0 ){ sqlite3_result_zeroblob(context, 0); return; @@ -437,10 +528,6 @@ void vectorSerializeWithType( return; } - if( pVector->type != VECTOR_TYPE_FLOAT32 ){ - pBlob[nBlobSize - 1] = pVector->type; - } - switch (pVector->type) { case VECTOR_TYPE_FLOAT32: vectorF32SerializeToBlob(pVector, pBlob, nDataSize); @@ -448,9 +535,13 @@ void vectorSerializeWithType( case VECTOR_TYPE_FLOAT64: vectorF64SerializeToBlob(pVector, pBlob, nDataSize); break; + case VECTOR_TYPE_1BIT: + vector1BitSerializeToBlob(pVector, pBlob, nDataSize); + break; default: assert(0); } + vectorSerializeMeta(pVector, nDataSize, pBlob, nBlobSize); sqlite3_result_blob(context, (char*)pBlob, nBlobSize, sqlite3_free); } @@ -614,11 +705,15 @@ static void vectorFuncHintedType( ){ char *pzErrMsg = NULL; Vector *pVector = NULL, *pTarget = NULL; - int type, dims; + int type, dims, typeHint = VECTOR_TYPE_FLOAT32; if( argc < 1 ){ goto out; } - if( detectVectorParameters(argv[0], targetType, &type, &dims, &pzErrMsg) != 0 ){ + // simplification in order to support only parsing from text to f32 and f64 vectors + if( targetType == VECTOR_TYPE_FLOAT64 ){ + typeHint = targetType; + } + if( detectVectorParameters(argv[0], typeHint, &type, &dims, &pzErrMsg) != 0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); goto out; @@ -633,14 +728,14 @@ static void vectorFuncHintedType( goto out; } if( type == targetType ){ - vectorSerializeWithType(context, pVector); + vectorSerializeWithMeta(context, pVector); }else{ pTarget = vectorContextAlloc(context, targetType, dims); if( pTarget == NULL ){ goto out; } vectorConvert(pVector, pTarget); - vectorSerializeWithType(context, pTarget); + vectorSerializeWithMeta(context, pTarget); } out: if( pVector != NULL ){ @@ -666,6 +761,14 @@ static void vector64Func( vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_FLOAT64); } +static void vector1BitFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_1BIT); +} + /* ** Implementation of vector_extract(X) function. */ @@ -675,30 +778,44 @@ static void vectorExtractFunc( sqlite3_value **argv ){ char *pzErrMsg = NULL; - Vector *pVector; + Vector *pVector = NULL, *pTarget = NULL; unsigned i; int type, dims; if( argc < 1 ){ - return; + goto out; } if( detectVectorParameters(argv[0], 0, &type, &dims, &pzErrMsg) != 0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - return; + goto out; } pVector = vectorContextAlloc(context, type, dims); - if( pVector==NULL ){ - return; + if( pVector == NULL ){ + goto out; } if( vectorParseWithType(argv[0], pVector, &pzErrMsg)<0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - goto out_free; + goto out; + } + if( pVector->type == VECTOR_TYPE_FLOAT32 || pVector->type == VECTOR_TYPE_FLOAT64 ){ + vectorMarshalToText(context, pVector); + }else{ + pTarget = vectorContextAlloc(context, VECTOR_TYPE_FLOAT32, dims); + if( pTarget == NULL ){ + goto out; + } + vectorConvert(pVector, pTarget); + vectorMarshalToText(context, pTarget); + } +out: + if( pVector != NULL ){ + vectorFree(pVector); + } + if( pTarget != NULL ){ + vectorFree(pTarget); } - vectorMarshalToText(context, pVector); -out_free: - vectorFree(pVector); } /* @@ -782,6 +899,7 @@ void sqlite3RegisterVectorFunctions(void){ FUNCTION(vector, 1, 0, 0, vector32Func), FUNCTION(vector32, 1, 0, 0, vector32Func), FUNCTION(vector64, 1, 0, 0, vector64Func), + FUNCTION(vector1bit, 1, 0, 0, vector1BitFunc), FUNCTION(vector_extract, 1, 0, 0, vectorExtractFunc), FUNCTION(vector_distance_cos, 2, 0, 0, vectorDistanceCosFunc), diff --git a/libsql-sqlite3/src/vector1bit.c b/libsql-sqlite3/src/vector1bit.c index f4fd5f9100..b80c166522 100644 --- a/libsql-sqlite3/src/vector1bit.c +++ b/libsql-sqlite3/src/vector1bit.c @@ -124,4 +124,18 @@ int vector1BitDistanceHamming(const Vector *v1, const Vector *v2){ return diff; } +void vector1BitDeserializeFromBlob( + Vector *pVector, + const unsigned char *pBlob, + size_t nBlobSize +){ + u8 *elems = pVector->data; + + assert( pVector->type == VECTOR_TYPE_1BIT ); + assert( 0 <= pVector->dims && pVector->dims <= MAX_VECTOR_SZ ); + assert( nBlobSize >= (pVector->dims + 7) / 8 ); + + memcpy(elems, pBlob, (pVector->dims + 7) / 8); +} + #endif /* !defined(SQLITE_OMIT_VECTOR) */ diff --git a/libsql-sqlite3/src/vectorIndex.c b/libsql-sqlite3/src/vectorIndex.c index 4ee9dbe313..b8eb17262a 100644 --- a/libsql-sqlite3/src/vectorIndex.c +++ b/libsql-sqlite3/src/vectorIndex.c @@ -378,10 +378,12 @@ struct VectorColumnType { }; static struct VectorColumnType VECTOR_COLUMN_TYPES[] = { - { "FLOAT32", VECTOR_TYPE_FLOAT32 }, - { "FLOAT64", VECTOR_TYPE_FLOAT64 }, - { "F32_BLOB", VECTOR_TYPE_FLOAT32 }, - { "F64_BLOB", VECTOR_TYPE_FLOAT64 } + { "FLOAT32", VECTOR_TYPE_FLOAT32 }, + { "F32_BLOB", VECTOR_TYPE_FLOAT32 }, + { "FLOAT64", VECTOR_TYPE_FLOAT64 }, + { "F64_BLOB", VECTOR_TYPE_FLOAT64 }, + { "FLOAT1BIT", VECTOR_TYPE_1BIT }, + { "F1BIT_BLOB", VECTOR_TYPE_1BIT }, }; /* diff --git a/libsql-sqlite3/src/vectorInt.h b/libsql-sqlite3/src/vectorInt.h index efe8f3cf38..e703585224 100644 --- a/libsql-sqlite3/src/vectorInt.h +++ b/libsql-sqlite3/src/vectorInt.h @@ -92,15 +92,16 @@ double vectorF64DistanceL2(const Vector *, const Vector *); * LibSQL can append one trailing byte in the end of final blob. This byte will be later used to determine type of the blob * By default, blob with even length will be treated as a f32 blob */ -void vectorSerializeWithType(sqlite3_context *, const Vector *); +void vectorSerializeWithMeta(sqlite3_context *, const Vector *); /* * Parses Vector content from the blob; vector type and dimensions must be filled already */ int vectorParseSqliteBlobWithType(sqlite3_value *, Vector *, char **); -void vectorF32DeserializeFromBlob(Vector *, const unsigned char *, size_t); -void vectorF64DeserializeFromBlob(Vector *, const unsigned char *, size_t); +void vectorF32DeserializeFromBlob (Vector *, const unsigned char *, size_t); +void vectorF64DeserializeFromBlob (Vector *, const unsigned char *, size_t); +void vector1BitDeserializeFromBlob(Vector *, const unsigned char *, size_t); void vectorInitStatic(Vector *, VectorType, VectorDims, void *); void vectorInitFromBlob(Vector *, const unsigned char *, size_t); From 307139fda9bd0140ea62709f3a3e97d6485d98cd Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 16:15:24 +0400 Subject: [PATCH 06/20] add conversion tests --- libsql-sqlite3/test/libsql_vector.test | 33 +++++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/libsql-sqlite3/test/libsql_vector.test b/libsql-sqlite3/test/libsql_vector.test index e541e9e977..c6480be9a3 100644 --- a/libsql-sqlite3/test/libsql_vector.test +++ b/libsql-sqlite3/test/libsql_vector.test @@ -71,17 +71,32 @@ do_execsql_test vector-1-conversion { SELECT hex(vector32('[]')); SELECT hex(vector64(vector32('[]'))); - SELECT hex(vector32(vector32('[0.000001,1e-100,1e100,1e10,1e-10,0,1.5]'))); - SELECT hex(vector32(vector64('[0.000001,1e-100,1e100,1e10,1e-10,0,1.5]'))); - SELECT hex(vector64(vector32('[0.000001,1e-100,1e100,1e10,1e-10,0,1.5]'))); - SELECT hex(vector64(vector64('[0.000001,1e-100,1e100,1e10,1e-10,0,1.5]'))); + SELECT vector_extract(vector32(vector1bit('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))), hex(vector32(vector1bit('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))); + SELECT vector_extract(vector32(vector32('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))), hex(vector32(vector32('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))); + SELECT vector_extract(vector32(vector64('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))), hex(vector32(vector64('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))); + + SELECT vector_extract(vector64(vector1bit('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))), hex(vector64(vector1bit('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))); + SELECT vector_extract(vector64(vector32('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))), hex(vector64(vector32('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))); + SELECT vector_extract(vector64(vector64('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))), hex(vector64(vector64('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))); + + SELECT vector_extract(vector1bit(vector1bit('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))), hex(vector1bit(vector1bit('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))); + SELECT vector_extract(vector1bit(vector32('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))), hex(vector1bit(vector32('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))); + SELECT vector_extract(vector1bit(vector64('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))), hex(vector1bit(vector64('[-0.000001,1e-100,1e100,-1e10,1e-10,0,1.5]'))); } { {} - 02 - BD378635000000000000807FF9021550FFE6DB2E000000000000C03F - BD378635000000000000807FF9021550FFE6DB2E000000000000C03F - 000000A0F7C6B03E0000000000000000000000000000F07F000000205FA00242000000E0DF7CDB3D0000000000000000000000000000F83F02 - 8DEDB5A0F7C6B03E30058EE42EFF2B2B7DC39425AD49B254000000205FA00242BBBDD7D9DF7CDB3D0000000000000000000000000000F83F02 + 02 + + {[-1,-1,1,-1,1,-1,1]} 000080BF000080BF0000803F000080BF0000803F000080BF0000803F + {[-1e-06,0,Inf,-1e+10,1e-10,0,1.5]} BD3786B5000000000000807FF90215D0FFE6DB2E000000000000C03F + {[-1e-06,0,Inf,-1e+10,1e-10,0,1.5]} BD3786B5000000000000807FF90215D0FFE6DB2E000000000000C03F + + {[-1,-1,1,-1,1,-1,1]} 000000000000F0BF000000000000F0BF000000000000F03F000000000000F0BF000000000000F03F000000000000F0BF000000000000F03F02 + {[-1e-06,0,Inf,-1e+10,1e-10,0,1.5]} 000000A0F7C6B0BE0000000000000000000000000000F07F000000205FA002C2000000E0DF7CDB3D0000000000000000000000000000F83F02 + {[-1e-06,1e-100,1e+100,-1e+10,1e-10,0,1.5]} 8DEDB5A0F7C6B0BE30058EE42EFF2B2B7DC39425AD49B254000000205FA002C2BBBDD7D9DF7CDB3D0000000000000000000000000000F83F02 + + {[-1,-1,1,-1,1,-1,1]} 540903 + {[-1,-1,1,-1,1,-1,1]} 540903 + {[-1,1,1,-1,1,-1,1]} 560903 } proc error_messages {sql} { From 1216f17e0ea911ec62d3797870a4d734f09c5f65 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 17:19:34 +0400 Subject: [PATCH 07/20] remove unused function --- libsql-sqlite3/src/vector.c | 41 +++++------------------------- libsql-sqlite3/src/vectorIndex.c | 8 ++---- libsql-sqlite3/src/vectorInt.h | 2 -- libsql-sqlite3/src/vectorfloat32.c | 5 ---- libsql-sqlite3/src/vectorfloat64.c | 5 ---- 5 files changed, 9 insertions(+), 52 deletions(-) diff --git a/libsql-sqlite3/src/vector.c b/libsql-sqlite3/src/vector.c index 6d86619409..b5c43901e8 100644 --- a/libsql-sqlite3/src/vector.c +++ b/libsql-sqlite3/src/vector.c @@ -339,39 +339,21 @@ int vectorParseSqliteBlobWithType( int detectBlobVectorParameters(sqlite3_value *arg, int *pType, int *pDims, char **pzErrMsg) { const u8 *pBlob; - int nBlobSize; + size_t nBlobSize, nDataSize; assert( sqlite3_value_type(arg) == SQLITE_BLOB ); pBlob = sqlite3_value_blob(arg); nBlobSize = sqlite3_value_bytes(arg); - if( nBlobSize % 2 != 0 ){ - // we have trailing byte with explicit type definition - *pType = pBlob[nBlobSize - 1]; - nBlobSize--; - } else { - // else, fallback to FLOAT32 - *pType = VECTOR_TYPE_FLOAT32; - } - if( *pType == VECTOR_TYPE_FLOAT32 ){ - *pDims = nBlobSize / sizeof(float); - }else if( *pType == VECTOR_TYPE_FLOAT64 ){ - *pDims = nBlobSize / sizeof(double); - }else if( *pType == VECTOR_TYPE_1BIT ){ - if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ - *pzErrMsg = sqlite3_mprintf("vector: malformed 1bit float: blob size must has even size (without last byte): size=%d", nBlobSize); - return -1; - } - *pDims = nBlobSize * 8 - pBlob[nBlobSize - 1]; - }else{ - *pzErrMsg = sqlite3_mprintf("vector: unexpected binary type: got %d, expected %d or %d", *pType, VECTOR_TYPE_FLOAT32, VECTOR_TYPE_FLOAT64); - return -1; + + if( vectorParseMeta(pBlob, nBlobSize, pType, pDims, &nDataSize, pzErrMsg) != SQLITE_OK ){ + return SQLITE_ERROR; } if( *pDims > MAX_VECTOR_SZ ){ *pzErrMsg = sqlite3_mprintf("vector: max size exceeded: %d > %d", *pDims, MAX_VECTOR_SZ); - return -1; + return SQLITE_ERROR; } - return 0; + return SQLITE_OK; } int detectTextVectorParameters(sqlite3_value *arg, int typeHint, int *pType, int *pDims, char **pzErrMsg) { @@ -560,16 +542,7 @@ size_t vectorSerializeToBlob(const Vector *pVector, unsigned char *pBlob, size_t } void vectorInitFromBlob(Vector *pVector, const unsigned char *pBlob, size_t nBlobSize){ - switch (pVector->type) { - case VECTOR_TYPE_FLOAT32: - vectorF32InitFromBlob(pVector, pBlob, nBlobSize); - break; - case VECTOR_TYPE_FLOAT64: - vectorF64InitFromBlob(pVector, pBlob, nBlobSize); - break; - default: - assert(0); - } + pVector->data = (void*)pBlob; } static void vectorConvertFromF32(const Vector *pFrom, Vector *pTo){ diff --git a/libsql-sqlite3/src/vectorIndex.c b/libsql-sqlite3/src/vectorIndex.c index b8eb17262a..6413bf0822 100644 --- a/libsql-sqlite3/src/vectorIndex.c +++ b/libsql-sqlite3/src/vectorIndex.c @@ -883,7 +883,6 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co sqlite3ErrorMsg(pParse, "vector index: %s: %s", pzErrMsg, zEmbeddingColumnTypeName); return CREATE_FAIL; } - // schema is locked while db is initializing and we need to just proceed here if( db->init.busy == 1 ){ return CREATE_OK; @@ -963,11 +962,8 @@ int vectorIndexSearch( rc = SQLITE_ERROR; goto out; } - if( type != VECTOR_TYPE_FLOAT32 && type != VECTOR_TYPE_FLOAT64 ){ - *pzErrMsg = sqlite3_mprintf("vector index(search): unsupported vector type: only FLOAT32/FLOAT64 are available for indexing"); - rc = SQLITE_ERROR; - goto out; - } + assert( type == VECTOR_TYPE_FLOAT32 || type == VECTOR_TYPE_FLOAT64 || type == VECTOR_TYPE_1BIT ); + pVector = vectorAlloc(type, dims); if( pVector == NULL ){ rc = SQLITE_NOMEM_BKPT; diff --git a/libsql-sqlite3/src/vectorInt.h b/libsql-sqlite3/src/vectorInt.h index e703585224..350a9ae9bd 100644 --- a/libsql-sqlite3/src/vectorInt.h +++ b/libsql-sqlite3/src/vectorInt.h @@ -105,8 +105,6 @@ void vector1BitDeserializeFromBlob(Vector *, const unsigned char *, size_t); void vectorInitStatic(Vector *, VectorType, VectorDims, void *); void vectorInitFromBlob(Vector *, const unsigned char *, size_t); -void vectorF32InitFromBlob(Vector *, const unsigned char *, size_t); -void vectorF64InitFromBlob(Vector *, const unsigned char *, size_t); void vectorConvert(const Vector *, Vector *); diff --git a/libsql-sqlite3/src/vectorfloat32.c b/libsql-sqlite3/src/vectorfloat32.c index d53d10d593..9749a84835 100644 --- a/libsql-sqlite3/src/vectorfloat32.c +++ b/libsql-sqlite3/src/vectorfloat32.c @@ -168,11 +168,6 @@ float vectorF32DistanceL2(const Vector *v1, const Vector *v2){ return sqrt(sum); } -void vectorF32InitFromBlob(Vector *pVector, const unsigned char *pBlob, size_t nBlobSize){ - pVector->dims = nBlobSize / sizeof(float); - pVector->data = (void*)pBlob; -} - void vectorF32DeserializeFromBlob( Vector *pVector, const unsigned char *pBlob, diff --git a/libsql-sqlite3/src/vectorfloat64.c b/libsql-sqlite3/src/vectorfloat64.c index 885306c8c6..9f854793ab 100644 --- a/libsql-sqlite3/src/vectorfloat64.c +++ b/libsql-sqlite3/src/vectorfloat64.c @@ -175,11 +175,6 @@ double vectorF64DistanceL2(const Vector *v1, const Vector *v2){ return sqrt(sum); } -void vectorF64InitFromBlob(Vector *pVector, const unsigned char *pBlob, size_t nBlobSize){ - pVector->dims = nBlobSize / sizeof(double); - pVector->data = (void*)pBlob; -} - void vectorF64DeserializeFromBlob( Vector *pVector, const unsigned char *pBlob, From 1a704d8ba48fab105028d834decc7bf449fae061 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 17:19:40 +0400 Subject: [PATCH 08/20] fix test --- libsql-sqlite3/test/libsql_vector.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsql-sqlite3/test/libsql_vector.test b/libsql-sqlite3/test/libsql_vector.test index c6480be9a3..5118cae6a0 100644 --- a/libsql-sqlite3/test/libsql_vector.test +++ b/libsql-sqlite3/test/libsql_vector.test @@ -131,7 +131,7 @@ do_test vector-1-func-errors { {vector: invalid float at position 0: '[1'} {vector: invalid float at position 2: '1.1.1'} {vector: must end with ']'} - {vector: unexpected binary type: got 0, expected 1 or 2} + {invalid vector: unexpected type: 0} {vector_distance_cos: vectors must have the same length: 3 != 2} {vector_distance_cos: vectors must have the same type: 1 != 2} }] From e0035d6e17645681d71bdd8dc394cfe8fd69ec02 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 17:25:29 +0400 Subject: [PATCH 09/20] add more tests --- libsql-sqlite3/test/libsql_vector.test | 6 ++++++ libsql-sqlite3/test/libsql_vector_index.test | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/libsql-sqlite3/test/libsql_vector.test b/libsql-sqlite3/test/libsql_vector.test index 5118cae6a0..7afb0f8bb0 100644 --- a/libsql-sqlite3/test/libsql_vector.test +++ b/libsql-sqlite3/test/libsql_vector.test @@ -50,6 +50,9 @@ do_execsql_test vector-1-func-valid { SELECT vector_distance_cos('[1,1]', '[-1,-1]'); SELECT vector_distance_cos('[1,1]', '[-1,1]'); SELECT vector_distance_cos('[1,2]', '[2,1]'); + SELECT vector_distance_cos(vector1bit('[10,-10]'), vector1bit('[-5,4]')); + SELECT vector_distance_cos(vector1bit('[10,-10]'), vector1bit('[20,4]')); + SELECT vector_distance_cos(vector1bit('[10,-10]'), vector1bit('[20,-2]')); } { {[]} {[]} @@ -65,6 +68,9 @@ do_execsql_test vector-1-func-valid { {2.0} {1.0} {0.200000002980232} + {2.0} + {1.0} + {0.0} } do_execsql_test vector-1-conversion { diff --git a/libsql-sqlite3/test/libsql_vector_index.test b/libsql-sqlite3/test/libsql_vector_index.test index 98d11208fa..0756566914 100644 --- a/libsql-sqlite3/test/libsql_vector_index.test +++ b/libsql-sqlite3/test/libsql_vector_index.test @@ -327,6 +327,15 @@ do_execsql_test vector-partial { 2 3 5 6 8 9 } +do_execsql_test vector-1bit-table { + CREATE TABLE t_1bit_table( v FLOAT1BIT(4) ); + INSERT INTO t_1bit_table VALUES ( vector1bit('[1,-1,1,-1]') ); + CREATE INDEX t_1bit_table_idx ON t_1bit_table( libsql_vector_idx(v) ); + INSERT INTO t_1bit_table VALUES ( vector1bit('[-1,1,1,-1]') ); + INSERT INTO t_1bit_table VALUES ( vector1bit('[1,-1,-1,1]') ); + SELECT * FROM vector_top_k('t_1bit_table_idx', vector1bit('[10,-10,-20,20]'), 4); +} {3 1 2} + proc error_messages {sql} { set ret "" catch { From 51fc1daa1e16157d42dae26808942cf6d841b38b Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 17:27:15 +0400 Subject: [PATCH 10/20] build bundles --- .../SQLite3MultipleCiphers/src/sqlite3.c | 423 +++++++++++++----- libsql-ffi/bundled/src/sqlite3.c | 423 +++++++++++++----- 2 files changed, 618 insertions(+), 228 deletions(-) diff --git a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c index 8ceabfc713..3568559303 100644 --- a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c +++ b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c @@ -85311,20 +85311,19 @@ double vectorF64DistanceL2(const Vector *, const Vector *); * LibSQL can append one trailing byte in the end of final blob. This byte will be later used to determine type of the blob * By default, blob with even length will be treated as a f32 blob */ -void vectorSerializeWithType(sqlite3_context *, const Vector *); +void vectorSerializeWithMeta(sqlite3_context *, const Vector *); /* * Parses Vector content from the blob; vector type and dimensions must be filled already */ int vectorParseSqliteBlobWithType(sqlite3_value *, Vector *, char **); -void vectorF32DeserializeFromBlob(Vector *, const unsigned char *, size_t); -void vectorF64DeserializeFromBlob(Vector *, const unsigned char *, size_t); +void vectorF32DeserializeFromBlob (Vector *, const unsigned char *, size_t); +void vectorF64DeserializeFromBlob (Vector *, const unsigned char *, size_t); +void vector1BitDeserializeFromBlob(Vector *, const unsigned char *, size_t); void vectorInitStatic(Vector *, VectorType, VectorDims, void *); void vectorInitFromBlob(Vector *, const unsigned char *, size_t); -void vectorF32InitFromBlob(Vector *, const unsigned char *, size_t); -void vectorF64InitFromBlob(Vector *, const unsigned char *, size_t); void vectorConvert(const Vector *, Vector *); @@ -210981,7 +210980,6 @@ size_t vectorDataSize(VectorType type, VectorDims dims){ case VECTOR_TYPE_FLOAT64: return dims * sizeof(double); case VECTOR_TYPE_1BIT: - assert( dims > 0 ); return (dims + 7) / 8; default: assert(0); @@ -211192,33 +211190,84 @@ static int vectorParseSqliteText( return -1; } +static int vectorParseMeta(const unsigned char *pBlob, size_t nBlobSize, int *pType, int *pDims, size_t *pDataSize, char **pzErrMsg){ + int nLeftoverBits; + + if( nBlobSize % 2 == 0 ){ + *pType = VECTOR_TYPE_FLOAT32; + *pDims = nBlobSize / sizeof(float); + *pDataSize = nBlobSize; + return SQLITE_OK; + } + *pType = pBlob[nBlobSize - 1]; + nBlobSize--; + + if( *pType == VECTOR_TYPE_FLOAT32 ){ + if( nBlobSize % 4 != 0 ){ + *pzErrMsg = sqlite3_mprintf("invalid vector: f32 vector blob length must be divisible by 4 (excluding optional 'type'-byte): length=%d", nBlobSize); + return SQLITE_ERROR; + } + *pDims = nBlobSize / sizeof(float); + *pDataSize = nBlobSize; + }else if( *pType == VECTOR_TYPE_FLOAT64 ){ + if( nBlobSize % 8 != 0 ){ + *pzErrMsg = sqlite3_mprintf("invalid vector: f64 vector blob length must be divisible by 8 (excluding 'type'-byte): length=%d", nBlobSize); + return SQLITE_ERROR; + } + *pDims = nBlobSize / sizeof(double); + *pDataSize = nBlobSize; + }else if( *pType == VECTOR_TYPE_1BIT ){ + if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ + *pzErrMsg = sqlite3_mprintf("invalid vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); + return SQLITE_ERROR; + } + nLeftoverBits = pBlob[nBlobSize - 1]; + *pDims = nBlobSize * 8 - nLeftoverBits; + *pDataSize = (*pDims + 7) / 8; + }else{ + *pzErrMsg = sqlite3_mprintf("invalid vector: unexpected type: %d", *pType); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + int vectorParseSqliteBlobWithType( sqlite3_value *arg, Vector *pVector, char **pzErrMsg ){ const unsigned char *pBlob; - size_t nBlobSize; + size_t nBlobSize, nDataSize; + int type, dims; assert( sqlite3_value_type(arg) == SQLITE_BLOB ); pBlob = sqlite3_value_blob(arg); nBlobSize = sqlite3_value_bytes(arg); - if( nBlobSize % 2 == 1 ){ - nBlobSize--; + if( vectorParseMeta(pBlob, nBlobSize, &type, &dims, &nDataSize, pzErrMsg) != SQLITE_OK ){ + return SQLITE_ERROR; } - if( nBlobSize < vectorDataSize(pVector->type, pVector->dims) ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: not enough bytes: type=%d, dims=%d, size=%ull", pVector->type, pVector->dims, nBlobSize); + if( nDataSize != vectorDataSize(pVector->type, pVector->dims) ){ + *pzErrMsg = sqlite3_mprintf( + "invalid vector: unexpected data size bytes: type=%d, dims=%d, %ull != %ull", + pVector->type, + pVector->dims, + nDataSize, + vectorDataSize(pVector->type, pVector->dims) + ); return SQLITE_ERROR; } switch (pVector->type) { case VECTOR_TYPE_FLOAT32: - vectorF32DeserializeFromBlob(pVector, pBlob, nBlobSize); + vectorF32DeserializeFromBlob(pVector, pBlob, nDataSize); return 0; case VECTOR_TYPE_FLOAT64: - vectorF64DeserializeFromBlob(pVector, pBlob, nBlobSize); + vectorF64DeserializeFromBlob(pVector, pBlob, nDataSize); + return 0; + case VECTOR_TYPE_1BIT: + vector1BitDeserializeFromBlob(pVector, pBlob, nDataSize); return 0; default: assert(0); @@ -211228,32 +211277,21 @@ int vectorParseSqliteBlobWithType( int detectBlobVectorParameters(sqlite3_value *arg, int *pType, int *pDims, char **pzErrMsg) { const u8 *pBlob; - int nBlobSize; + size_t nBlobSize, nDataSize; assert( sqlite3_value_type(arg) == SQLITE_BLOB ); pBlob = sqlite3_value_blob(arg); nBlobSize = sqlite3_value_bytes(arg); - if( nBlobSize % 2 != 0 ){ - // we have trailing byte with explicit type definition - *pType = pBlob[nBlobSize - 1]; - } else { - // else, fallback to FLOAT32 - *pType = VECTOR_TYPE_FLOAT32; - } - if( *pType == VECTOR_TYPE_FLOAT32 ){ - *pDims = nBlobSize / sizeof(float); - } else if( *pType == VECTOR_TYPE_FLOAT64 ){ - *pDims = nBlobSize / sizeof(double); - } else{ - *pzErrMsg = sqlite3_mprintf("vector: unexpected binary type: got %d, expected %d or %d", *pType, VECTOR_TYPE_FLOAT32, VECTOR_TYPE_FLOAT64); - return -1; + + if( vectorParseMeta(pBlob, nBlobSize, pType, pDims, &nDataSize, pzErrMsg) != SQLITE_OK ){ + return SQLITE_ERROR; } if( *pDims > MAX_VECTOR_SZ ){ *pzErrMsg = sqlite3_mprintf("vector: max size exceeded: %d > %d", *pDims, MAX_VECTOR_SZ); - return -1; + return SQLITE_ERROR; } - return 0; + return SQLITE_OK; } int detectTextVectorParameters(sqlite3_value *arg, int typeHint, int *pType, int *pDims, char **pzErrMsg) { @@ -211350,21 +211388,55 @@ void vectorMarshalToText( } } -void vectorSerializeWithType( +static int vectorMetaSize(VectorType type, VectorDims dims){ + int nMetaSize = 0; + int nDataSize; + if( type == VECTOR_TYPE_FLOAT32 ){ + return 0; + }else if( type == VECTOR_TYPE_FLOAT64 ){ + return 1; + }else if( type == VECTOR_TYPE_1BIT ){ + nDataSize = vectorDataSize(type, dims); + nMetaSize++; // one byte which specify amount of leftover bits + if( nDataSize % 2 == 0 ){ + nMetaSize++; // pad "leftover-bits" byte to the even length + } + nMetaSize++; // one byte for vector type + return nMetaSize; + }else{ + assert( 0 ); + } +} + +static void vectorSerializeMeta(const Vector *pVector, size_t nDataSize, unsigned char *pBlob, size_t nBlobSize){ + if( pVector->type == VECTOR_TYPE_FLOAT32 ){ + // no meta for f32 type as this is "default" vector type + }else if( pVector->type == VECTOR_TYPE_FLOAT64 ){ + assert( nDataSize % 2 == 0 ); + assert( nBlobSize == nDataSize + 1 ); + pBlob[nBlobSize - 1] = VECTOR_TYPE_FLOAT64; + }else if( pVector->type == VECTOR_TYPE_1BIT ){ + assert( nBlobSize % 2 == 1 ); + assert( nBlobSize >= 3 ); + pBlob[nBlobSize - 1] = VECTOR_TYPE_1BIT; + pBlob[nBlobSize - 2] = 8 * (nBlobSize - 1) - pVector->dims; + }else{ + assert( 0 ); + } +} + +void vectorSerializeWithMeta( sqlite3_context *context, const Vector *pVector ){ unsigned char *pBlob; - size_t nBlobSize, nDataSize; + size_t nBlobSize, nDataSize, nMetaSize; assert( pVector->dims <= MAX_VECTOR_SZ ); nDataSize = vectorDataSize(pVector->type, pVector->dims); - nBlobSize = nDataSize; - if( pVector->type != VECTOR_TYPE_FLOAT32 ){ - nBlobSize += (nBlobSize % 2 == 0 ? 1 : 2); - } - + nMetaSize = vectorMetaSize(pVector->type, pVector->dims); + nBlobSize = nDataSize + nMetaSize; if( nBlobSize == 0 ){ sqlite3_result_zeroblob(context, 0); return; @@ -211376,10 +211448,6 @@ void vectorSerializeWithType( return; } - if( pVector->type != VECTOR_TYPE_FLOAT32 ){ - pBlob[nBlobSize - 1] = pVector->type; - } - switch (pVector->type) { case VECTOR_TYPE_FLOAT32: vectorF32SerializeToBlob(pVector, pBlob, nDataSize); @@ -211387,9 +211455,13 @@ void vectorSerializeWithType( case VECTOR_TYPE_FLOAT64: vectorF64SerializeToBlob(pVector, pBlob, nDataSize); break; + case VECTOR_TYPE_1BIT: + vector1BitSerializeToBlob(pVector, pBlob, nDataSize); + break; default: assert(0); } + vectorSerializeMeta(pVector, nDataSize, pBlob, nBlobSize); sqlite3_result_blob(context, (char*)pBlob, nBlobSize, sqlite3_free); } @@ -211408,38 +211480,124 @@ size_t vectorSerializeToBlob(const Vector *pVector, unsigned char *pBlob, size_t } void vectorInitFromBlob(Vector *pVector, const unsigned char *pBlob, size_t nBlobSize){ - switch (pVector->type) { - case VECTOR_TYPE_FLOAT32: - vectorF32InitFromBlob(pVector, pBlob, nBlobSize); - break; - case VECTOR_TYPE_FLOAT64: - vectorF64InitFromBlob(pVector, pBlob, nBlobSize); - break; - default: - assert(0); + pVector->data = (void*)pBlob; +} + +static void vectorConvertFromF32(const Vector *pFrom, Vector *pTo){ + int i; + float *src; + + u8 *dst1Bit; + double *dstF64; + + assert( pFrom->dims == pTo->dims ); + assert( pFrom->type != pTo->type ); + assert( pFrom->type == VECTOR_TYPE_FLOAT32 ); + + src = pFrom->data; + if( pTo->type == VECTOR_TYPE_FLOAT64 ){ + dstF64 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + dstF64[i] = src[i]; + } + }else if( pTo->type == VECTOR_TYPE_1BIT ){ + dst1Bit = pTo->data; + for(i = 0; i < pFrom->dims; i += 8){ + dst1Bit[i / 8] = 0; + } + for(i = 0; i < pFrom->dims; i++){ + if( src[i] > 0 ){ + dst1Bit[i / 8] |= (1 << (i & 7)); + } + } + }else{ + assert( 0 ); } } -void vectorConvert(const Vector *pFrom, Vector *pTo){ +static void vectorConvertFromF64(const Vector *pFrom, Vector *pTo){ int i; - u8 *bitData; - float *floatData; + double *src; + + u8 *dst1Bit; + float *dstF32; assert( pFrom->dims == pTo->dims ); + assert( pFrom->type != pTo->type ); + assert( pFrom->type == VECTOR_TYPE_FLOAT64 ); - if( pFrom->type == VECTOR_TYPE_FLOAT32 && pTo->type == VECTOR_TYPE_1BIT ){ - floatData = pFrom->data; - bitData = pTo->data; + src = pFrom->data; + if( pTo->type == VECTOR_TYPE_FLOAT32 ){ + dstF32 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + dstF32[i] = src[i]; + } + }else if( pTo->type == VECTOR_TYPE_1BIT ){ + dst1Bit = pTo->data; for(i = 0; i < pFrom->dims; i += 8){ - bitData[i / 8] = 0; + dst1Bit[i / 8] = 0; } for(i = 0; i < pFrom->dims; i++){ - if( floatData[i] > 0 ){ - bitData[i / 8] |= (1 << (i & 7)); + if( src[i] > 0 ){ + dst1Bit[i / 8] |= (1 << (i & 7)); } } }else{ - assert(0); + assert( 0 ); + } +} + +static void vectorConvertFrom1Bit(const Vector *pFrom, Vector *pTo){ + int i; + u8 *src; + + float *dstF32; + double *dstF64; + + assert( pFrom->dims == pTo->dims ); + assert( pFrom->type != pTo->type ); + assert( pFrom->type == VECTOR_TYPE_1BIT ); + + src = pFrom->data; + if( pTo->type == VECTOR_TYPE_FLOAT32 ){ + dstF32 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + if( ((src[i / 8] >> (i & 7)) & 1) == 1 ){ + dstF32[i] = +1; + }else{ + dstF32[i] = -1; + } + } + }else if( pTo->type == VECTOR_TYPE_FLOAT64 ){ + dstF64 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + if( ((src[i / 8] >> (i & 7)) & 1) == 1 ){ + dstF64[i] = +1; + }else{ + dstF64[i] = -1; + } + } + }else{ + assert( 0 ); + } +} + +void vectorConvert(const Vector *pFrom, Vector *pTo){ + assert( pFrom->dims == pTo->dims ); + + if( pFrom->type == pTo->type ){ + memcpy(pTo->data, pFrom->data, vectorDataSize(pFrom->type, pFrom->dims)); + return; + } + + if( pFrom->type == VECTOR_TYPE_FLOAT32 ){ + vectorConvertFromF32(pFrom, pTo); + }else if( pFrom->type == VECTOR_TYPE_FLOAT64 ){ + vectorConvertFromF64(pFrom, pTo); + }else if( pFrom->type == VECTOR_TYPE_1BIT ){ + vectorConvertFrom1Bit(pFrom, pTo); + }else{ + assert( 0 ); } } @@ -211454,31 +211612,49 @@ static void vectorFuncHintedType( sqlite3_context *context, int argc, sqlite3_value **argv, - int typeHint + int targetType ){ char *pzErrMsg = NULL; - Vector *pVector; - int type, dims; + Vector *pVector = NULL, *pTarget = NULL; + int type, dims, typeHint = VECTOR_TYPE_FLOAT32; if( argc < 1 ){ - return; + goto out; + } + // simplification in order to support only parsing from text to f32 and f64 vectors + if( targetType == VECTOR_TYPE_FLOAT64 ){ + typeHint = targetType; } if( detectVectorParameters(argv[0], typeHint, &type, &dims, &pzErrMsg) != 0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - return; + goto out; } pVector = vectorContextAlloc(context, type, dims); - if( pVector==NULL ){ - return; + if( pVector == NULL ){ + goto out; } if( vectorParseWithType(argv[0], pVector, &pzErrMsg) != 0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - goto out_free_vec; + goto out; + } + if( type == targetType ){ + vectorSerializeWithMeta(context, pVector); + }else{ + pTarget = vectorContextAlloc(context, targetType, dims); + if( pTarget == NULL ){ + goto out; + } + vectorConvert(pVector, pTarget); + vectorSerializeWithMeta(context, pTarget); + } +out: + if( pVector != NULL ){ + vectorFree(pVector); + } + if( pTarget != NULL ){ + vectorFree(pTarget); } - vectorSerializeWithType(context, pVector); -out_free_vec: - vectorFree(pVector); } static void vector32Func( @@ -211496,6 +211672,14 @@ static void vector64Func( vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_FLOAT64); } +static void vector1BitFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_1BIT); +} + /* ** Implementation of vector_extract(X) function. */ @@ -211505,30 +211689,44 @@ static void vectorExtractFunc( sqlite3_value **argv ){ char *pzErrMsg = NULL; - Vector *pVector; + Vector *pVector = NULL, *pTarget = NULL; unsigned i; int type, dims; if( argc < 1 ){ - return; + goto out; } if( detectVectorParameters(argv[0], 0, &type, &dims, &pzErrMsg) != 0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - return; + goto out; } pVector = vectorContextAlloc(context, type, dims); - if( pVector==NULL ){ - return; + if( pVector == NULL ){ + goto out; } if( vectorParseWithType(argv[0], pVector, &pzErrMsg)<0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - goto out_free; + goto out; + } + if( pVector->type == VECTOR_TYPE_FLOAT32 || pVector->type == VECTOR_TYPE_FLOAT64 ){ + vectorMarshalToText(context, pVector); + }else{ + pTarget = vectorContextAlloc(context, VECTOR_TYPE_FLOAT32, dims); + if( pTarget == NULL ){ + goto out; + } + vectorConvert(pVector, pTarget); + vectorMarshalToText(context, pTarget); + } +out: + if( pVector != NULL ){ + vectorFree(pVector); + } + if( pTarget != NULL ){ + vectorFree(pTarget); } - vectorMarshalToText(context, pVector); -out_free: - vectorFree(pVector); } /* @@ -211612,6 +211810,7 @@ SQLITE_PRIVATE void sqlite3RegisterVectorFunctions(void){ FUNCTION(vector, 1, 0, 0, vector32Func), FUNCTION(vector32, 1, 0, 0, vector32Func), FUNCTION(vector64, 1, 0, 0, vector64Func), + FUNCTION(vector1bit, 1, 0, 0, vector1BitFunc), FUNCTION(vector_extract, 1, 0, 0, vectorExtractFunc), FUNCTION(vector_distance_cos, 2, 0, 0, vectorDistanceCosFunc), @@ -211750,6 +211949,20 @@ int vector1BitDistanceHamming(const Vector *v1, const Vector *v2){ return diff; } +void vector1BitDeserializeFromBlob( + Vector *pVector, + const unsigned char *pBlob, + size_t nBlobSize +){ + u8 *elems = pVector->data; + + assert( pVector->type == VECTOR_TYPE_1BIT ); + assert( 0 <= pVector->dims && pVector->dims <= MAX_VECTOR_SZ ); + assert( nBlobSize >= (pVector->dims + 7) / 8 ); + + memcpy(elems, pBlob, (pVector->dims + 7) / 8); +} + #endif /* !defined(SQLITE_OMIT_VECTOR) */ /************** End of vector1bit.c ******************************************/ @@ -213184,12 +213397,12 @@ int diskAnnSearch( *pzErrMsg = sqlite3_mprintf("vector index(search): k must be a non-negative integer"); return SQLITE_ERROR; } - if( pIndex->nVectorDims != pVector->dims ){ + if( pVector->dims != pIndex->nVectorDims ){ *pzErrMsg = sqlite3_mprintf("vector index(search): dimensions are different: %d != %d", pVector->dims, pIndex->nVectorDims); return SQLITE_ERROR; } - if( pVector->type != VECTOR_TYPE_FLOAT32 ){ - *pzErrMsg = sqlite3_mprintf("vector index(search): only f32 vectors are supported"); + if( pVector->type != pIndex->nNodeVectorType ){ + *pzErrMsg = sqlite3_mprintf("vector index(search): vector type differs from column type: %d != %d", pVector->type, pIndex->nNodeVectorType); return SQLITE_ERROR; } @@ -213254,8 +213467,8 @@ int diskAnnInsert( *pzErrMsg = sqlite3_mprintf("vector index(insert): dimensions are different: %d != %d", pVectorInRow->pVector->dims, pIndex->nVectorDims); return SQLITE_ERROR; } - if( pVectorInRow->pVector->type != VECTOR_TYPE_FLOAT32 ){ - *pzErrMsg = sqlite3_mprintf("vector index(insert): only f32 vectors are supported"); + if( pVectorInRow->pVector->type != pIndex->nNodeVectorType ){ + *pzErrMsg = sqlite3_mprintf("vector index(insert): vector type differs from column type: %d != %d", pVectorInRow->pVector->type, pIndex->nNodeVectorType); return SQLITE_ERROR; } @@ -213703,11 +213916,6 @@ float vectorF32DistanceL2(const Vector *v1, const Vector *v2){ return sqrt(sum); } -void vectorF32InitFromBlob(Vector *pVector, const unsigned char *pBlob, size_t nBlobSize){ - pVector->dims = nBlobSize / sizeof(float); - pVector->data = (void*)pBlob; -} - void vectorF32DeserializeFromBlob( Vector *pVector, const unsigned char *pBlob, @@ -213907,11 +214115,6 @@ double vectorF64DistanceL2(const Vector *v1, const Vector *v2){ return sqrt(sum); } -void vectorF64InitFromBlob(Vector *pVector, const unsigned char *pBlob, size_t nBlobSize){ - pVector->dims = nBlobSize / sizeof(double); - pVector->data = (void*)pBlob; -} - void vectorF64DeserializeFromBlob( Vector *pVector, const unsigned char *pBlob, @@ -213960,6 +214163,7 @@ void vectorF64DeserializeFromBlob( ** ** libSQL vector search. */ +/* #include "vectorInt.h" */ #ifndef SQLITE_OMIT_VECTOR /* #include "sqlite3.h" */ /* #include "vdbeInt.h" */ @@ -214309,14 +214513,16 @@ void vectorOutRowsFree(sqlite3 *db, VectorOutRows *pRows) { */ struct VectorColumnType { const char *zName; - int nBits; + int type; }; static struct VectorColumnType VECTOR_COLUMN_TYPES[] = { - { "FLOAT32", 32 }, - { "FLOAT64", 64 }, - { "F32_BLOB", 32 }, - { "F64_BLOB", 64 } + { "FLOAT32", VECTOR_TYPE_FLOAT32 }, + { "F32_BLOB", VECTOR_TYPE_FLOAT32 }, + { "FLOAT64", VECTOR_TYPE_FLOAT64 }, + { "F64_BLOB", VECTOR_TYPE_FLOAT64 }, + { "FLOAT1BIT", VECTOR_TYPE_1BIT }, + { "F1BIT_BLOB", VECTOR_TYPE_1BIT }, }; /* @@ -214505,14 +214711,7 @@ int vectorIdxParseColumnType(const char *zType, int *pType, int *pDims, const ch } *pDims = dimensions; - if( VECTOR_COLUMN_TYPES[i].nBits == 32 ) { - *pType = VECTOR_TYPE_FLOAT32; - } else if( VECTOR_COLUMN_TYPES[i].nBits == 64 ) { - *pType = VECTOR_TYPE_FLOAT64; - } else { - *pErrMsg = "unsupported vector type"; - return -1; - } + *pType = VECTOR_COLUMN_TYPES[i].type; return 0; } *pErrMsg = "unexpected vector column type"; @@ -214823,7 +215022,6 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co sqlite3ErrorMsg(pParse, "vector index: %s: %s", pzErrMsg, zEmbeddingColumnTypeName); return CREATE_FAIL; } - // schema is locked while db is initializing and we need to just proceed here if( db->init.busy == 1 ){ return CREATE_OK; @@ -214903,11 +215101,8 @@ int vectorIndexSearch( rc = SQLITE_ERROR; goto out; } - if( type != VECTOR_TYPE_FLOAT32 ){ - *pzErrMsg = sqlite3_mprintf("vector index(search): only f32 vectors are supported"); - rc = SQLITE_ERROR; - goto out; - } + assert( type == VECTOR_TYPE_FLOAT32 || type == VECTOR_TYPE_FLOAT64 || type == VECTOR_TYPE_1BIT ); + pVector = vectorAlloc(type, dims); if( pVector == NULL ){ rc = SQLITE_NOMEM_BKPT; diff --git a/libsql-ffi/bundled/src/sqlite3.c b/libsql-ffi/bundled/src/sqlite3.c index 8ceabfc713..3568559303 100644 --- a/libsql-ffi/bundled/src/sqlite3.c +++ b/libsql-ffi/bundled/src/sqlite3.c @@ -85311,20 +85311,19 @@ double vectorF64DistanceL2(const Vector *, const Vector *); * LibSQL can append one trailing byte in the end of final blob. This byte will be later used to determine type of the blob * By default, blob with even length will be treated as a f32 blob */ -void vectorSerializeWithType(sqlite3_context *, const Vector *); +void vectorSerializeWithMeta(sqlite3_context *, const Vector *); /* * Parses Vector content from the blob; vector type and dimensions must be filled already */ int vectorParseSqliteBlobWithType(sqlite3_value *, Vector *, char **); -void vectorF32DeserializeFromBlob(Vector *, const unsigned char *, size_t); -void vectorF64DeserializeFromBlob(Vector *, const unsigned char *, size_t); +void vectorF32DeserializeFromBlob (Vector *, const unsigned char *, size_t); +void vectorF64DeserializeFromBlob (Vector *, const unsigned char *, size_t); +void vector1BitDeserializeFromBlob(Vector *, const unsigned char *, size_t); void vectorInitStatic(Vector *, VectorType, VectorDims, void *); void vectorInitFromBlob(Vector *, const unsigned char *, size_t); -void vectorF32InitFromBlob(Vector *, const unsigned char *, size_t); -void vectorF64InitFromBlob(Vector *, const unsigned char *, size_t); void vectorConvert(const Vector *, Vector *); @@ -210981,7 +210980,6 @@ size_t vectorDataSize(VectorType type, VectorDims dims){ case VECTOR_TYPE_FLOAT64: return dims * sizeof(double); case VECTOR_TYPE_1BIT: - assert( dims > 0 ); return (dims + 7) / 8; default: assert(0); @@ -211192,33 +211190,84 @@ static int vectorParseSqliteText( return -1; } +static int vectorParseMeta(const unsigned char *pBlob, size_t nBlobSize, int *pType, int *pDims, size_t *pDataSize, char **pzErrMsg){ + int nLeftoverBits; + + if( nBlobSize % 2 == 0 ){ + *pType = VECTOR_TYPE_FLOAT32; + *pDims = nBlobSize / sizeof(float); + *pDataSize = nBlobSize; + return SQLITE_OK; + } + *pType = pBlob[nBlobSize - 1]; + nBlobSize--; + + if( *pType == VECTOR_TYPE_FLOAT32 ){ + if( nBlobSize % 4 != 0 ){ + *pzErrMsg = sqlite3_mprintf("invalid vector: f32 vector blob length must be divisible by 4 (excluding optional 'type'-byte): length=%d", nBlobSize); + return SQLITE_ERROR; + } + *pDims = nBlobSize / sizeof(float); + *pDataSize = nBlobSize; + }else if( *pType == VECTOR_TYPE_FLOAT64 ){ + if( nBlobSize % 8 != 0 ){ + *pzErrMsg = sqlite3_mprintf("invalid vector: f64 vector blob length must be divisible by 8 (excluding 'type'-byte): length=%d", nBlobSize); + return SQLITE_ERROR; + } + *pDims = nBlobSize / sizeof(double); + *pDataSize = nBlobSize; + }else if( *pType == VECTOR_TYPE_1BIT ){ + if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ + *pzErrMsg = sqlite3_mprintf("invalid vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); + return SQLITE_ERROR; + } + nLeftoverBits = pBlob[nBlobSize - 1]; + *pDims = nBlobSize * 8 - nLeftoverBits; + *pDataSize = (*pDims + 7) / 8; + }else{ + *pzErrMsg = sqlite3_mprintf("invalid vector: unexpected type: %d", *pType); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + int vectorParseSqliteBlobWithType( sqlite3_value *arg, Vector *pVector, char **pzErrMsg ){ const unsigned char *pBlob; - size_t nBlobSize; + size_t nBlobSize, nDataSize; + int type, dims; assert( sqlite3_value_type(arg) == SQLITE_BLOB ); pBlob = sqlite3_value_blob(arg); nBlobSize = sqlite3_value_bytes(arg); - if( nBlobSize % 2 == 1 ){ - nBlobSize--; + if( vectorParseMeta(pBlob, nBlobSize, &type, &dims, &nDataSize, pzErrMsg) != SQLITE_OK ){ + return SQLITE_ERROR; } - if( nBlobSize < vectorDataSize(pVector->type, pVector->dims) ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: not enough bytes: type=%d, dims=%d, size=%ull", pVector->type, pVector->dims, nBlobSize); + if( nDataSize != vectorDataSize(pVector->type, pVector->dims) ){ + *pzErrMsg = sqlite3_mprintf( + "invalid vector: unexpected data size bytes: type=%d, dims=%d, %ull != %ull", + pVector->type, + pVector->dims, + nDataSize, + vectorDataSize(pVector->type, pVector->dims) + ); return SQLITE_ERROR; } switch (pVector->type) { case VECTOR_TYPE_FLOAT32: - vectorF32DeserializeFromBlob(pVector, pBlob, nBlobSize); + vectorF32DeserializeFromBlob(pVector, pBlob, nDataSize); return 0; case VECTOR_TYPE_FLOAT64: - vectorF64DeserializeFromBlob(pVector, pBlob, nBlobSize); + vectorF64DeserializeFromBlob(pVector, pBlob, nDataSize); + return 0; + case VECTOR_TYPE_1BIT: + vector1BitDeserializeFromBlob(pVector, pBlob, nDataSize); return 0; default: assert(0); @@ -211228,32 +211277,21 @@ int vectorParseSqliteBlobWithType( int detectBlobVectorParameters(sqlite3_value *arg, int *pType, int *pDims, char **pzErrMsg) { const u8 *pBlob; - int nBlobSize; + size_t nBlobSize, nDataSize; assert( sqlite3_value_type(arg) == SQLITE_BLOB ); pBlob = sqlite3_value_blob(arg); nBlobSize = sqlite3_value_bytes(arg); - if( nBlobSize % 2 != 0 ){ - // we have trailing byte with explicit type definition - *pType = pBlob[nBlobSize - 1]; - } else { - // else, fallback to FLOAT32 - *pType = VECTOR_TYPE_FLOAT32; - } - if( *pType == VECTOR_TYPE_FLOAT32 ){ - *pDims = nBlobSize / sizeof(float); - } else if( *pType == VECTOR_TYPE_FLOAT64 ){ - *pDims = nBlobSize / sizeof(double); - } else{ - *pzErrMsg = sqlite3_mprintf("vector: unexpected binary type: got %d, expected %d or %d", *pType, VECTOR_TYPE_FLOAT32, VECTOR_TYPE_FLOAT64); - return -1; + + if( vectorParseMeta(pBlob, nBlobSize, pType, pDims, &nDataSize, pzErrMsg) != SQLITE_OK ){ + return SQLITE_ERROR; } if( *pDims > MAX_VECTOR_SZ ){ *pzErrMsg = sqlite3_mprintf("vector: max size exceeded: %d > %d", *pDims, MAX_VECTOR_SZ); - return -1; + return SQLITE_ERROR; } - return 0; + return SQLITE_OK; } int detectTextVectorParameters(sqlite3_value *arg, int typeHint, int *pType, int *pDims, char **pzErrMsg) { @@ -211350,21 +211388,55 @@ void vectorMarshalToText( } } -void vectorSerializeWithType( +static int vectorMetaSize(VectorType type, VectorDims dims){ + int nMetaSize = 0; + int nDataSize; + if( type == VECTOR_TYPE_FLOAT32 ){ + return 0; + }else if( type == VECTOR_TYPE_FLOAT64 ){ + return 1; + }else if( type == VECTOR_TYPE_1BIT ){ + nDataSize = vectorDataSize(type, dims); + nMetaSize++; // one byte which specify amount of leftover bits + if( nDataSize % 2 == 0 ){ + nMetaSize++; // pad "leftover-bits" byte to the even length + } + nMetaSize++; // one byte for vector type + return nMetaSize; + }else{ + assert( 0 ); + } +} + +static void vectorSerializeMeta(const Vector *pVector, size_t nDataSize, unsigned char *pBlob, size_t nBlobSize){ + if( pVector->type == VECTOR_TYPE_FLOAT32 ){ + // no meta for f32 type as this is "default" vector type + }else if( pVector->type == VECTOR_TYPE_FLOAT64 ){ + assert( nDataSize % 2 == 0 ); + assert( nBlobSize == nDataSize + 1 ); + pBlob[nBlobSize - 1] = VECTOR_TYPE_FLOAT64; + }else if( pVector->type == VECTOR_TYPE_1BIT ){ + assert( nBlobSize % 2 == 1 ); + assert( nBlobSize >= 3 ); + pBlob[nBlobSize - 1] = VECTOR_TYPE_1BIT; + pBlob[nBlobSize - 2] = 8 * (nBlobSize - 1) - pVector->dims; + }else{ + assert( 0 ); + } +} + +void vectorSerializeWithMeta( sqlite3_context *context, const Vector *pVector ){ unsigned char *pBlob; - size_t nBlobSize, nDataSize; + size_t nBlobSize, nDataSize, nMetaSize; assert( pVector->dims <= MAX_VECTOR_SZ ); nDataSize = vectorDataSize(pVector->type, pVector->dims); - nBlobSize = nDataSize; - if( pVector->type != VECTOR_TYPE_FLOAT32 ){ - nBlobSize += (nBlobSize % 2 == 0 ? 1 : 2); - } - + nMetaSize = vectorMetaSize(pVector->type, pVector->dims); + nBlobSize = nDataSize + nMetaSize; if( nBlobSize == 0 ){ sqlite3_result_zeroblob(context, 0); return; @@ -211376,10 +211448,6 @@ void vectorSerializeWithType( return; } - if( pVector->type != VECTOR_TYPE_FLOAT32 ){ - pBlob[nBlobSize - 1] = pVector->type; - } - switch (pVector->type) { case VECTOR_TYPE_FLOAT32: vectorF32SerializeToBlob(pVector, pBlob, nDataSize); @@ -211387,9 +211455,13 @@ void vectorSerializeWithType( case VECTOR_TYPE_FLOAT64: vectorF64SerializeToBlob(pVector, pBlob, nDataSize); break; + case VECTOR_TYPE_1BIT: + vector1BitSerializeToBlob(pVector, pBlob, nDataSize); + break; default: assert(0); } + vectorSerializeMeta(pVector, nDataSize, pBlob, nBlobSize); sqlite3_result_blob(context, (char*)pBlob, nBlobSize, sqlite3_free); } @@ -211408,38 +211480,124 @@ size_t vectorSerializeToBlob(const Vector *pVector, unsigned char *pBlob, size_t } void vectorInitFromBlob(Vector *pVector, const unsigned char *pBlob, size_t nBlobSize){ - switch (pVector->type) { - case VECTOR_TYPE_FLOAT32: - vectorF32InitFromBlob(pVector, pBlob, nBlobSize); - break; - case VECTOR_TYPE_FLOAT64: - vectorF64InitFromBlob(pVector, pBlob, nBlobSize); - break; - default: - assert(0); + pVector->data = (void*)pBlob; +} + +static void vectorConvertFromF32(const Vector *pFrom, Vector *pTo){ + int i; + float *src; + + u8 *dst1Bit; + double *dstF64; + + assert( pFrom->dims == pTo->dims ); + assert( pFrom->type != pTo->type ); + assert( pFrom->type == VECTOR_TYPE_FLOAT32 ); + + src = pFrom->data; + if( pTo->type == VECTOR_TYPE_FLOAT64 ){ + dstF64 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + dstF64[i] = src[i]; + } + }else if( pTo->type == VECTOR_TYPE_1BIT ){ + dst1Bit = pTo->data; + for(i = 0; i < pFrom->dims; i += 8){ + dst1Bit[i / 8] = 0; + } + for(i = 0; i < pFrom->dims; i++){ + if( src[i] > 0 ){ + dst1Bit[i / 8] |= (1 << (i & 7)); + } + } + }else{ + assert( 0 ); } } -void vectorConvert(const Vector *pFrom, Vector *pTo){ +static void vectorConvertFromF64(const Vector *pFrom, Vector *pTo){ int i; - u8 *bitData; - float *floatData; + double *src; + + u8 *dst1Bit; + float *dstF32; assert( pFrom->dims == pTo->dims ); + assert( pFrom->type != pTo->type ); + assert( pFrom->type == VECTOR_TYPE_FLOAT64 ); - if( pFrom->type == VECTOR_TYPE_FLOAT32 && pTo->type == VECTOR_TYPE_1BIT ){ - floatData = pFrom->data; - bitData = pTo->data; + src = pFrom->data; + if( pTo->type == VECTOR_TYPE_FLOAT32 ){ + dstF32 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + dstF32[i] = src[i]; + } + }else if( pTo->type == VECTOR_TYPE_1BIT ){ + dst1Bit = pTo->data; for(i = 0; i < pFrom->dims; i += 8){ - bitData[i / 8] = 0; + dst1Bit[i / 8] = 0; } for(i = 0; i < pFrom->dims; i++){ - if( floatData[i] > 0 ){ - bitData[i / 8] |= (1 << (i & 7)); + if( src[i] > 0 ){ + dst1Bit[i / 8] |= (1 << (i & 7)); } } }else{ - assert(0); + assert( 0 ); + } +} + +static void vectorConvertFrom1Bit(const Vector *pFrom, Vector *pTo){ + int i; + u8 *src; + + float *dstF32; + double *dstF64; + + assert( pFrom->dims == pTo->dims ); + assert( pFrom->type != pTo->type ); + assert( pFrom->type == VECTOR_TYPE_1BIT ); + + src = pFrom->data; + if( pTo->type == VECTOR_TYPE_FLOAT32 ){ + dstF32 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + if( ((src[i / 8] >> (i & 7)) & 1) == 1 ){ + dstF32[i] = +1; + }else{ + dstF32[i] = -1; + } + } + }else if( pTo->type == VECTOR_TYPE_FLOAT64 ){ + dstF64 = pTo->data; + for(i = 0; i < pFrom->dims; i++){ + if( ((src[i / 8] >> (i & 7)) & 1) == 1 ){ + dstF64[i] = +1; + }else{ + dstF64[i] = -1; + } + } + }else{ + assert( 0 ); + } +} + +void vectorConvert(const Vector *pFrom, Vector *pTo){ + assert( pFrom->dims == pTo->dims ); + + if( pFrom->type == pTo->type ){ + memcpy(pTo->data, pFrom->data, vectorDataSize(pFrom->type, pFrom->dims)); + return; + } + + if( pFrom->type == VECTOR_TYPE_FLOAT32 ){ + vectorConvertFromF32(pFrom, pTo); + }else if( pFrom->type == VECTOR_TYPE_FLOAT64 ){ + vectorConvertFromF64(pFrom, pTo); + }else if( pFrom->type == VECTOR_TYPE_1BIT ){ + vectorConvertFrom1Bit(pFrom, pTo); + }else{ + assert( 0 ); } } @@ -211454,31 +211612,49 @@ static void vectorFuncHintedType( sqlite3_context *context, int argc, sqlite3_value **argv, - int typeHint + int targetType ){ char *pzErrMsg = NULL; - Vector *pVector; - int type, dims; + Vector *pVector = NULL, *pTarget = NULL; + int type, dims, typeHint = VECTOR_TYPE_FLOAT32; if( argc < 1 ){ - return; + goto out; + } + // simplification in order to support only parsing from text to f32 and f64 vectors + if( targetType == VECTOR_TYPE_FLOAT64 ){ + typeHint = targetType; } if( detectVectorParameters(argv[0], typeHint, &type, &dims, &pzErrMsg) != 0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - return; + goto out; } pVector = vectorContextAlloc(context, type, dims); - if( pVector==NULL ){ - return; + if( pVector == NULL ){ + goto out; } if( vectorParseWithType(argv[0], pVector, &pzErrMsg) != 0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - goto out_free_vec; + goto out; + } + if( type == targetType ){ + vectorSerializeWithMeta(context, pVector); + }else{ + pTarget = vectorContextAlloc(context, targetType, dims); + if( pTarget == NULL ){ + goto out; + } + vectorConvert(pVector, pTarget); + vectorSerializeWithMeta(context, pTarget); + } +out: + if( pVector != NULL ){ + vectorFree(pVector); + } + if( pTarget != NULL ){ + vectorFree(pTarget); } - vectorSerializeWithType(context, pVector); -out_free_vec: - vectorFree(pVector); } static void vector32Func( @@ -211496,6 +211672,14 @@ static void vector64Func( vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_FLOAT64); } +static void vector1BitFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_1BIT); +} + /* ** Implementation of vector_extract(X) function. */ @@ -211505,30 +211689,44 @@ static void vectorExtractFunc( sqlite3_value **argv ){ char *pzErrMsg = NULL; - Vector *pVector; + Vector *pVector = NULL, *pTarget = NULL; unsigned i; int type, dims; if( argc < 1 ){ - return; + goto out; } if( detectVectorParameters(argv[0], 0, &type, &dims, &pzErrMsg) != 0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - return; + goto out; } pVector = vectorContextAlloc(context, type, dims); - if( pVector==NULL ){ - return; + if( pVector == NULL ){ + goto out; } if( vectorParseWithType(argv[0], pVector, &pzErrMsg)<0 ){ sqlite3_result_error(context, pzErrMsg, -1); sqlite3_free(pzErrMsg); - goto out_free; + goto out; + } + if( pVector->type == VECTOR_TYPE_FLOAT32 || pVector->type == VECTOR_TYPE_FLOAT64 ){ + vectorMarshalToText(context, pVector); + }else{ + pTarget = vectorContextAlloc(context, VECTOR_TYPE_FLOAT32, dims); + if( pTarget == NULL ){ + goto out; + } + vectorConvert(pVector, pTarget); + vectorMarshalToText(context, pTarget); + } +out: + if( pVector != NULL ){ + vectorFree(pVector); + } + if( pTarget != NULL ){ + vectorFree(pTarget); } - vectorMarshalToText(context, pVector); -out_free: - vectorFree(pVector); } /* @@ -211612,6 +211810,7 @@ SQLITE_PRIVATE void sqlite3RegisterVectorFunctions(void){ FUNCTION(vector, 1, 0, 0, vector32Func), FUNCTION(vector32, 1, 0, 0, vector32Func), FUNCTION(vector64, 1, 0, 0, vector64Func), + FUNCTION(vector1bit, 1, 0, 0, vector1BitFunc), FUNCTION(vector_extract, 1, 0, 0, vectorExtractFunc), FUNCTION(vector_distance_cos, 2, 0, 0, vectorDistanceCosFunc), @@ -211750,6 +211949,20 @@ int vector1BitDistanceHamming(const Vector *v1, const Vector *v2){ return diff; } +void vector1BitDeserializeFromBlob( + Vector *pVector, + const unsigned char *pBlob, + size_t nBlobSize +){ + u8 *elems = pVector->data; + + assert( pVector->type == VECTOR_TYPE_1BIT ); + assert( 0 <= pVector->dims && pVector->dims <= MAX_VECTOR_SZ ); + assert( nBlobSize >= (pVector->dims + 7) / 8 ); + + memcpy(elems, pBlob, (pVector->dims + 7) / 8); +} + #endif /* !defined(SQLITE_OMIT_VECTOR) */ /************** End of vector1bit.c ******************************************/ @@ -213184,12 +213397,12 @@ int diskAnnSearch( *pzErrMsg = sqlite3_mprintf("vector index(search): k must be a non-negative integer"); return SQLITE_ERROR; } - if( pIndex->nVectorDims != pVector->dims ){ + if( pVector->dims != pIndex->nVectorDims ){ *pzErrMsg = sqlite3_mprintf("vector index(search): dimensions are different: %d != %d", pVector->dims, pIndex->nVectorDims); return SQLITE_ERROR; } - if( pVector->type != VECTOR_TYPE_FLOAT32 ){ - *pzErrMsg = sqlite3_mprintf("vector index(search): only f32 vectors are supported"); + if( pVector->type != pIndex->nNodeVectorType ){ + *pzErrMsg = sqlite3_mprintf("vector index(search): vector type differs from column type: %d != %d", pVector->type, pIndex->nNodeVectorType); return SQLITE_ERROR; } @@ -213254,8 +213467,8 @@ int diskAnnInsert( *pzErrMsg = sqlite3_mprintf("vector index(insert): dimensions are different: %d != %d", pVectorInRow->pVector->dims, pIndex->nVectorDims); return SQLITE_ERROR; } - if( pVectorInRow->pVector->type != VECTOR_TYPE_FLOAT32 ){ - *pzErrMsg = sqlite3_mprintf("vector index(insert): only f32 vectors are supported"); + if( pVectorInRow->pVector->type != pIndex->nNodeVectorType ){ + *pzErrMsg = sqlite3_mprintf("vector index(insert): vector type differs from column type: %d != %d", pVectorInRow->pVector->type, pIndex->nNodeVectorType); return SQLITE_ERROR; } @@ -213703,11 +213916,6 @@ float vectorF32DistanceL2(const Vector *v1, const Vector *v2){ return sqrt(sum); } -void vectorF32InitFromBlob(Vector *pVector, const unsigned char *pBlob, size_t nBlobSize){ - pVector->dims = nBlobSize / sizeof(float); - pVector->data = (void*)pBlob; -} - void vectorF32DeserializeFromBlob( Vector *pVector, const unsigned char *pBlob, @@ -213907,11 +214115,6 @@ double vectorF64DistanceL2(const Vector *v1, const Vector *v2){ return sqrt(sum); } -void vectorF64InitFromBlob(Vector *pVector, const unsigned char *pBlob, size_t nBlobSize){ - pVector->dims = nBlobSize / sizeof(double); - pVector->data = (void*)pBlob; -} - void vectorF64DeserializeFromBlob( Vector *pVector, const unsigned char *pBlob, @@ -213960,6 +214163,7 @@ void vectorF64DeserializeFromBlob( ** ** libSQL vector search. */ +/* #include "vectorInt.h" */ #ifndef SQLITE_OMIT_VECTOR /* #include "sqlite3.h" */ /* #include "vdbeInt.h" */ @@ -214309,14 +214513,16 @@ void vectorOutRowsFree(sqlite3 *db, VectorOutRows *pRows) { */ struct VectorColumnType { const char *zName; - int nBits; + int type; }; static struct VectorColumnType VECTOR_COLUMN_TYPES[] = { - { "FLOAT32", 32 }, - { "FLOAT64", 64 }, - { "F32_BLOB", 32 }, - { "F64_BLOB", 64 } + { "FLOAT32", VECTOR_TYPE_FLOAT32 }, + { "F32_BLOB", VECTOR_TYPE_FLOAT32 }, + { "FLOAT64", VECTOR_TYPE_FLOAT64 }, + { "F64_BLOB", VECTOR_TYPE_FLOAT64 }, + { "FLOAT1BIT", VECTOR_TYPE_1BIT }, + { "F1BIT_BLOB", VECTOR_TYPE_1BIT }, }; /* @@ -214505,14 +214711,7 @@ int vectorIdxParseColumnType(const char *zType, int *pType, int *pDims, const ch } *pDims = dimensions; - if( VECTOR_COLUMN_TYPES[i].nBits == 32 ) { - *pType = VECTOR_TYPE_FLOAT32; - } else if( VECTOR_COLUMN_TYPES[i].nBits == 64 ) { - *pType = VECTOR_TYPE_FLOAT64; - } else { - *pErrMsg = "unsupported vector type"; - return -1; - } + *pType = VECTOR_COLUMN_TYPES[i].type; return 0; } *pErrMsg = "unexpected vector column type"; @@ -214823,7 +215022,6 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co sqlite3ErrorMsg(pParse, "vector index: %s: %s", pzErrMsg, zEmbeddingColumnTypeName); return CREATE_FAIL; } - // schema is locked while db is initializing and we need to just proceed here if( db->init.busy == 1 ){ return CREATE_OK; @@ -214903,11 +215101,8 @@ int vectorIndexSearch( rc = SQLITE_ERROR; goto out; } - if( type != VECTOR_TYPE_FLOAT32 ){ - *pzErrMsg = sqlite3_mprintf("vector index(search): only f32 vectors are supported"); - rc = SQLITE_ERROR; - goto out; - } + assert( type == VECTOR_TYPE_FLOAT32 || type == VECTOR_TYPE_FLOAT64 || type == VECTOR_TYPE_1BIT ); + pVector = vectorAlloc(type, dims); if( pVector == NULL ){ rc = SQLITE_NOMEM_BKPT; From 30a198e962d7e23ac7b7c01ff181452d540f91c8 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 17:36:02 +0400 Subject: [PATCH 11/20] refine error messages --- libsql-sqlite3/src/vector.c | 10 +++++----- libsql-sqlite3/test/libsql_vector.test | 2 +- libsql-sqlite3/test/libsql_vector_index.test | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libsql-sqlite3/src/vector.c b/libsql-sqlite3/src/vector.c index b5c43901e8..6c4a424343 100644 --- a/libsql-sqlite3/src/vector.c +++ b/libsql-sqlite3/src/vector.c @@ -266,28 +266,28 @@ static int vectorParseMeta(const unsigned char *pBlob, size_t nBlobSize, int *pT if( *pType == VECTOR_TYPE_FLOAT32 ){ if( nBlobSize % 4 != 0 ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: f32 vector blob length must be divisible by 4 (excluding optional 'type'-byte): length=%d", nBlobSize); + *pzErrMsg = sqlite3_mprintf("vector: f32 vector blob length must be divisible by 4 (excluding optional 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; } *pDims = nBlobSize / sizeof(float); *pDataSize = nBlobSize; }else if( *pType == VECTOR_TYPE_FLOAT64 ){ if( nBlobSize % 8 != 0 ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: f64 vector blob length must be divisible by 8 (excluding 'type'-byte): length=%d", nBlobSize); + *pzErrMsg = sqlite3_mprintf("vector: f64 vector blob length must be divisible by 8 (excluding 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; } *pDims = nBlobSize / sizeof(double); *pDataSize = nBlobSize; }else if( *pType == VECTOR_TYPE_1BIT ){ if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); + *pzErrMsg = sqlite3_mprintf("vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; } nLeftoverBits = pBlob[nBlobSize - 1]; *pDims = nBlobSize * 8 - nLeftoverBits; *pDataSize = (*pDims + 7) / 8; }else{ - *pzErrMsg = sqlite3_mprintf("invalid vector: unexpected type: %d", *pType); + *pzErrMsg = sqlite3_mprintf("vector: unexpected binary type: %d", *pType); return SQLITE_ERROR; } return SQLITE_OK; @@ -312,7 +312,7 @@ int vectorParseSqliteBlobWithType( if( nDataSize != vectorDataSize(pVector->type, pVector->dims) ){ *pzErrMsg = sqlite3_mprintf( - "invalid vector: unexpected data size bytes: type=%d, dims=%d, %ull != %ull", + "vector: unexpected data part size: type=%d, dims=%d, %ull != %ull", pVector->type, pVector->dims, nDataSize, diff --git a/libsql-sqlite3/test/libsql_vector.test b/libsql-sqlite3/test/libsql_vector.test index 7afb0f8bb0..be2edc9397 100644 --- a/libsql-sqlite3/test/libsql_vector.test +++ b/libsql-sqlite3/test/libsql_vector.test @@ -137,7 +137,7 @@ do_test vector-1-func-errors { {vector: invalid float at position 0: '[1'} {vector: invalid float at position 2: '1.1.1'} {vector: must end with ']'} - {invalid vector: unexpected type: 0} + {vector: unexpected binary type: 0} {vector_distance_cos: vectors must have the same length: 3 != 2} {vector_distance_cos: vectors must have the same type: 1 != 2} }] diff --git a/libsql-sqlite3/test/libsql_vector_index.test b/libsql-sqlite3/test/libsql_vector_index.test index 0756566914..242383e376 100644 --- a/libsql-sqlite3/test/libsql_vector_index.test +++ b/libsql-sqlite3/test/libsql_vector_index.test @@ -327,7 +327,7 @@ do_execsql_test vector-partial { 2 3 5 6 8 9 } -do_execsql_test vector-1bit-table { +do_execsql_test vector-1bit-index { CREATE TABLE t_1bit_table( v FLOAT1BIT(4) ); INSERT INTO t_1bit_table VALUES ( vector1bit('[1,-1,1,-1]') ); CREATE INDEX t_1bit_table_idx ON t_1bit_table( libsql_vector_idx(v) ); From 66d374f52bb1b907403f1dc6cb980dd5d0530de7 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 17:45:01 +0400 Subject: [PATCH 12/20] specify binary format for vectors in comment --- libsql-sqlite3/src/vectorInt.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/libsql-sqlite3/src/vectorInt.h b/libsql-sqlite3/src/vectorInt.h index 350a9ae9bd..aaf219f52b 100644 --- a/libsql-sqlite3/src/vectorInt.h +++ b/libsql-sqlite3/src/vectorInt.h @@ -19,6 +19,26 @@ typedef u32 VectorDims; */ #define MAX_VECTOR_SZ 65536 +/* + * on-disk binary format for vector of different types: + * 1. float32 + * [data[0] as f32] [data[1] as f32] ... [data[dims - 1] as f32] [1 as u8]? + * - last 'type'-byte is optional for float32 vectors + * + * 2. float64 + * [data[0] as f64] [data[1] as f64] ... [data[dims - 1] as f64] [2 as u8] + * - last 'type'-byte is mandatory for float64 vectors + * + * 3. float1bit + * [data[0] as u8] [data[1] as u8] ... [data[(dims + 7) / 8] as u8] [_ as u8; padding]? [leftover as u8] [3 as u8] + * - every data byte (except for the last) represents exactly 8 components of the vector + * - last data byte represents [1..8] components of the vector + * - optional padding byte ensures that leftover byte will be written at the odd blob position (0-based) + * - leftover byte specify amount of trailing *bits* in the blob without last 'type'-byte which must be omitted + * (so, vector dimensions are equal to 8 * (blob_size - 1) - leftover) + * - last 'type'-byte is mandatory for float1bit vectors +*/ + /* * Enumerate of supported vector types (0 omitted intentionally as we can use zero as "undefined" value) */ From 3c09fcec950c3ab6101d46b9d679d95eb462e44a Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Mon, 12 Aug 2024 17:47:44 +0400 Subject: [PATCH 13/20] build bundles --- .../SQLite3MultipleCiphers/src/sqlite3.c | 30 +++++++++++++++---- libsql-ffi/bundled/src/sqlite3.c | 30 +++++++++++++++---- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c index 3568559303..3bac75359b 100644 --- a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c +++ b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c @@ -85238,6 +85238,26 @@ typedef u32 VectorDims; */ #define MAX_VECTOR_SZ 65536 +/* + * on-disk binary format for vector of different types: + * 1. float32 + * [data[0] as f32] [data[1] as f32] ... [data[dims - 1] as f32] [1 as u8]? + * - last 'type'-byte is optional for float32 vectors + * + * 2. float64 + * [data[0] as f64] [data[1] as f64] ... [data[dims - 1] as f64] [2 as u8] + * - last 'type'-byte is mandatory for float64 vectors + * + * 3. float1bit + * [data[0] as u8] [data[1] as u8] ... [data[(dims + 7) / 8] as u8] [_ as u8; padding]? [leftover as u8] [3 as u8] + * - every data byte (except for the last) represents exactly 8 components of the vector + * - last data byte represents [1..8] components of the vector + * - optional padding byte ensures that leftover byte will be written at the odd blob position (0-based) + * - leftover byte specify amount of trailing *bits* in the blob without last 'type'-byte which must be omitted + * (so, vector dimensions are equal to 8 * (blob_size - 1) - leftover) + * - last 'type'-byte is mandatory for float1bit vectors +*/ + /* * Enumerate of supported vector types (0 omitted intentionally as we can use zero as "undefined" value) */ @@ -211204,28 +211224,28 @@ static int vectorParseMeta(const unsigned char *pBlob, size_t nBlobSize, int *pT if( *pType == VECTOR_TYPE_FLOAT32 ){ if( nBlobSize % 4 != 0 ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: f32 vector blob length must be divisible by 4 (excluding optional 'type'-byte): length=%d", nBlobSize); + *pzErrMsg = sqlite3_mprintf("vector: f32 vector blob length must be divisible by 4 (excluding optional 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; } *pDims = nBlobSize / sizeof(float); *pDataSize = nBlobSize; }else if( *pType == VECTOR_TYPE_FLOAT64 ){ if( nBlobSize % 8 != 0 ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: f64 vector blob length must be divisible by 8 (excluding 'type'-byte): length=%d", nBlobSize); + *pzErrMsg = sqlite3_mprintf("vector: f64 vector blob length must be divisible by 8 (excluding 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; } *pDims = nBlobSize / sizeof(double); *pDataSize = nBlobSize; }else if( *pType == VECTOR_TYPE_1BIT ){ if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); + *pzErrMsg = sqlite3_mprintf("vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; } nLeftoverBits = pBlob[nBlobSize - 1]; *pDims = nBlobSize * 8 - nLeftoverBits; *pDataSize = (*pDims + 7) / 8; }else{ - *pzErrMsg = sqlite3_mprintf("invalid vector: unexpected type: %d", *pType); + *pzErrMsg = sqlite3_mprintf("vector: unexpected binary type: %d", *pType); return SQLITE_ERROR; } return SQLITE_OK; @@ -211250,7 +211270,7 @@ int vectorParseSqliteBlobWithType( if( nDataSize != vectorDataSize(pVector->type, pVector->dims) ){ *pzErrMsg = sqlite3_mprintf( - "invalid vector: unexpected data size bytes: type=%d, dims=%d, %ull != %ull", + "vector: unexpected data part size: type=%d, dims=%d, %ull != %ull", pVector->type, pVector->dims, nDataSize, diff --git a/libsql-ffi/bundled/src/sqlite3.c b/libsql-ffi/bundled/src/sqlite3.c index 3568559303..3bac75359b 100644 --- a/libsql-ffi/bundled/src/sqlite3.c +++ b/libsql-ffi/bundled/src/sqlite3.c @@ -85238,6 +85238,26 @@ typedef u32 VectorDims; */ #define MAX_VECTOR_SZ 65536 +/* + * on-disk binary format for vector of different types: + * 1. float32 + * [data[0] as f32] [data[1] as f32] ... [data[dims - 1] as f32] [1 as u8]? + * - last 'type'-byte is optional for float32 vectors + * + * 2. float64 + * [data[0] as f64] [data[1] as f64] ... [data[dims - 1] as f64] [2 as u8] + * - last 'type'-byte is mandatory for float64 vectors + * + * 3. float1bit + * [data[0] as u8] [data[1] as u8] ... [data[(dims + 7) / 8] as u8] [_ as u8; padding]? [leftover as u8] [3 as u8] + * - every data byte (except for the last) represents exactly 8 components of the vector + * - last data byte represents [1..8] components of the vector + * - optional padding byte ensures that leftover byte will be written at the odd blob position (0-based) + * - leftover byte specify amount of trailing *bits* in the blob without last 'type'-byte which must be omitted + * (so, vector dimensions are equal to 8 * (blob_size - 1) - leftover) + * - last 'type'-byte is mandatory for float1bit vectors +*/ + /* * Enumerate of supported vector types (0 omitted intentionally as we can use zero as "undefined" value) */ @@ -211204,28 +211224,28 @@ static int vectorParseMeta(const unsigned char *pBlob, size_t nBlobSize, int *pT if( *pType == VECTOR_TYPE_FLOAT32 ){ if( nBlobSize % 4 != 0 ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: f32 vector blob length must be divisible by 4 (excluding optional 'type'-byte): length=%d", nBlobSize); + *pzErrMsg = sqlite3_mprintf("vector: f32 vector blob length must be divisible by 4 (excluding optional 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; } *pDims = nBlobSize / sizeof(float); *pDataSize = nBlobSize; }else if( *pType == VECTOR_TYPE_FLOAT64 ){ if( nBlobSize % 8 != 0 ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: f64 vector blob length must be divisible by 8 (excluding 'type'-byte): length=%d", nBlobSize); + *pzErrMsg = sqlite3_mprintf("vector: f64 vector blob length must be divisible by 8 (excluding 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; } *pDims = nBlobSize / sizeof(double); *pDataSize = nBlobSize; }else if( *pType == VECTOR_TYPE_1BIT ){ if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ - *pzErrMsg = sqlite3_mprintf("invalid vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); + *pzErrMsg = sqlite3_mprintf("vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; } nLeftoverBits = pBlob[nBlobSize - 1]; *pDims = nBlobSize * 8 - nLeftoverBits; *pDataSize = (*pDims + 7) / 8; }else{ - *pzErrMsg = sqlite3_mprintf("invalid vector: unexpected type: %d", *pType); + *pzErrMsg = sqlite3_mprintf("vector: unexpected binary type: %d", *pType); return SQLITE_ERROR; } return SQLITE_OK; @@ -211250,7 +211270,7 @@ int vectorParseSqliteBlobWithType( if( nDataSize != vectorDataSize(pVector->type, pVector->dims) ){ *pzErrMsg = sqlite3_mprintf( - "invalid vector: unexpected data size bytes: type=%d, dims=%d, %ull != %ull", + "vector: unexpected data part size: type=%d, dims=%d, %ull != %ull", pVector->type, pVector->dims, nDataSize, From c75354e6b23724c00adddef748afa421aeca937d Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Tue, 13 Aug 2024 11:11:18 +0400 Subject: [PATCH 14/20] generate uniform values from [-1..1] in benchmark workloads --- libsql-sqlite3/benchmark/workload.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libsql-sqlite3/benchmark/workload.py b/libsql-sqlite3/benchmark/workload.py index 2d413531fa..728e375933 100644 --- a/libsql-sqlite3/benchmark/workload.py +++ b/libsql-sqlite3/benchmark/workload.py @@ -10,10 +10,10 @@ def recall_uniform(dim, n, q): print(f'CREATE TABLE queries ( emb FLOAT32({dim}) );') print(f'BEGIN TRANSACTION;') for i in range(n): - vector = f"[{','.join(map(str, np.random.uniform(size=dim)))}]" + vector = f"[{','.join(map(str, np.random.uniform(-1, 1, size=dim)))}]" print(f'INSERT INTO data VALUES ({i}, vector(\'{vector}\'));') for i in range(q): - vector = f"[{','.join(map(str, np.random.uniform(size=dim)))}]" + vector = f"[{','.join(map(str, np.random.uniform(-1, 1, size=dim)))}]" print(f'INSERT INTO queries VALUES (vector(\'{vector}\'));') print(f'COMMIT;') print('---insert everything') @@ -29,7 +29,7 @@ def recall_normal(dim, n, q): vector = f"[{','.join(map(str, np.random.uniform(size=64)))}]" print(f'INSERT INTO data VALUES ({i}, \'{vector}\');') for i in range(q): - vector = f"[{','.join(map(str, np.random.uniform(size=64)))}]" + vector = f"[{','.join(map(str, np.random.uniform(-1, 1, size=64)))}]" print(f'INSERT INTO queries VALUES (\'{vector}\');') print(f'COMMIT;') print('---insert everything') @@ -40,7 +40,7 @@ def no_vectors(n, q): print('PRAGMA journal_mode=WAL;') print(f'CREATE TABLE x ( id INTEGER PRIMARY KEY, value TEXT );') for i in range(n): - vector = f"[{','.join(map(str, np.random.uniform(size=64)))}]" + vector = f"[{','.join(map(str, np.random.uniform(-1, 1, size=64)))}]" print(f'INSERT INTO x VALUES ({i}, \'{vector}\');') print('---inserts') for i in range(q): @@ -54,11 +54,11 @@ def bruteforce(dim, n, q): print('PRAGMA journal_mode=WAL;') print(f'CREATE TABLE x ( id INTEGER PRIMARY KEY, embedding FLOAT32({dim}) );') for i in range(n): - vector = f"[{','.join(map(str, np.random.uniform(size=dim)))}]" + vector = f"[{','.join(map(str, np.random.uniform(-1, 1, size=dim)))}]" print(f'INSERT INTO x VALUES ({i}, vector(\'{vector}\'));') print('---inserts') for i in range(q): - vector = f"[{','.join(map(str, np.random.uniform(size=dim)))}]" + vector = f"[{','.join(map(str, np.random.uniform(-1, 1, size=dim)))}]" print(f'SELECT id FROM x ORDER BY vector_distance_cos(embedding, vector(\'{vector}\')) LIMIT 1;') print('---search') @@ -68,13 +68,13 @@ def diskann(dim, n, q): q = int(q) print('PRAGMA journal_mode=WAL;') print(f'CREATE TABLE x ( id INTEGER PRIMARY KEY, embedding FLOAT32({dim}) );') - print(f'CREATE INDEX x_idx ON x( libsql_vector_idx(embedding) );') + print(f"CREATE INDEX x_idx ON x( libsql_vector_idx(embedding) );") for i in range(n): - vector = f"[{','.join(map(str, np.random.uniform(size=dim)))}]" + vector = f"[{','.join(map(str, np.random.uniform(-1, 1, size=dim)))}]" print(f'INSERT INTO x VALUES ({i}, vector(\'{vector}\'));') print('---inserts') for i in range(q): - vector = f"[{','.join(map(str, np.random.uniform(size=dim)))}]" + vector = f"[{','.join(map(str, np.random.uniform(-1, 1, size=dim)))}]" print(f'SELECT id FROM vector_top_k(\'x_idx\', vector(\'{vector}\'), 1);') print('---search') From 96d5ca9235efea77ebd807e6241e3f9d1e9d8703 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Tue, 13 Aug 2024 11:11:49 +0400 Subject: [PATCH 15/20] fix formatting --- libsql-sqlite3/src/vector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsql-sqlite3/src/vector.c b/libsql-sqlite3/src/vector.c index 6c4a424343..c469fabdd7 100644 --- a/libsql-sqlite3/src/vector.c +++ b/libsql-sqlite3/src/vector.c @@ -312,7 +312,7 @@ int vectorParseSqliteBlobWithType( if( nDataSize != vectorDataSize(pVector->type, pVector->dims) ){ *pzErrMsg = sqlite3_mprintf( - "vector: unexpected data part size: type=%d, dims=%d, %ull != %ull", + "vector: unexpected data part size: type=%d, dims=%d, %u != %u", pVector->type, pVector->dims, nDataSize, From db154137ad51d6e6cbaedbe1ee7521738203088c Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Tue, 13 Aug 2024 11:13:46 +0400 Subject: [PATCH 16/20] fix format specifier + build bundles --- libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c | 2 +- libsql-ffi/bundled/src/sqlite3.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c index 3bac75359b..ad032de20e 100644 --- a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c +++ b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c @@ -211270,7 +211270,7 @@ int vectorParseSqliteBlobWithType( if( nDataSize != vectorDataSize(pVector->type, pVector->dims) ){ *pzErrMsg = sqlite3_mprintf( - "vector: unexpected data part size: type=%d, dims=%d, %ull != %ull", + "vector: unexpected data part size: type=%d, dims=%d, %u != %u", pVector->type, pVector->dims, nDataSize, diff --git a/libsql-ffi/bundled/src/sqlite3.c b/libsql-ffi/bundled/src/sqlite3.c index 3bac75359b..ad032de20e 100644 --- a/libsql-ffi/bundled/src/sqlite3.c +++ b/libsql-ffi/bundled/src/sqlite3.c @@ -211270,7 +211270,7 @@ int vectorParseSqliteBlobWithType( if( nDataSize != vectorDataSize(pVector->type, pVector->dims) ){ *pzErrMsg = sqlite3_mprintf( - "vector: unexpected data part size: type=%d, dims=%d, %ull != %ull", + "vector: unexpected data part size: type=%d, dims=%d, %u != %u", pVector->type, pVector->dims, nDataSize, From 7cafb80b461eb24724a95a29da9a5bfa107747de Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Tue, 13 Aug 2024 11:24:46 +0400 Subject: [PATCH 17/20] use float1bit instead of 1bit everywhere in the code in index settings --- libsql-sqlite3/src/vector.c | 30 ++++++++++---------- libsql-sqlite3/src/vector1bit.c | 10 +++---- libsql-sqlite3/src/vectorIndex.c | 15 +++++----- libsql-sqlite3/src/vectorInt.h | 6 ++-- libsql-sqlite3/src/vectordiskann.c | 4 +-- libsql-sqlite3/test/libsql_vector_index.test | 13 +++++++-- 6 files changed, 44 insertions(+), 34 deletions(-) diff --git a/libsql-sqlite3/src/vector.c b/libsql-sqlite3/src/vector.c index c469fabdd7..01bf402aa0 100644 --- a/libsql-sqlite3/src/vector.c +++ b/libsql-sqlite3/src/vector.c @@ -41,7 +41,7 @@ size_t vectorDataSize(VectorType type, VectorDims dims){ return dims * sizeof(float); case VECTOR_TYPE_FLOAT64: return dims * sizeof(double); - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: return (dims + 7) / 8; default: assert(0); @@ -114,7 +114,7 @@ float vectorDistanceCos(const Vector *pVector1, const Vector *pVector2){ return vectorF32DistanceCos(pVector1, pVector2); case VECTOR_TYPE_FLOAT64: return vectorF64DistanceCos(pVector1, pVector2); - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: return vector1BitDistanceHamming(pVector1, pVector2); default: assert(0); @@ -278,7 +278,7 @@ static int vectorParseMeta(const unsigned char *pBlob, size_t nBlobSize, int *pT } *pDims = nBlobSize / sizeof(double); *pDataSize = nBlobSize; - }else if( *pType == VECTOR_TYPE_1BIT ){ + }else if( *pType == VECTOR_TYPE_FLOAT1BIT ){ if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ *pzErrMsg = sqlite3_mprintf("vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; @@ -328,7 +328,7 @@ int vectorParseSqliteBlobWithType( case VECTOR_TYPE_FLOAT64: vectorF64DeserializeFromBlob(pVector, pBlob, nDataSize); return 0; - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: vector1BitDeserializeFromBlob(pVector, pBlob, nDataSize); return 0; default: @@ -426,7 +426,7 @@ void vectorDump(const Vector *pVector){ case VECTOR_TYPE_FLOAT64: vectorF64Dump(pVector); break; - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: vector1BitDump(pVector); break; default: @@ -457,7 +457,7 @@ static int vectorMetaSize(VectorType type, VectorDims dims){ return 0; }else if( type == VECTOR_TYPE_FLOAT64 ){ return 1; - }else if( type == VECTOR_TYPE_1BIT ){ + }else if( type == VECTOR_TYPE_FLOAT1BIT ){ nDataSize = vectorDataSize(type, dims); nMetaSize++; // one byte which specify amount of leftover bits if( nDataSize % 2 == 0 ){ @@ -477,10 +477,10 @@ static void vectorSerializeMeta(const Vector *pVector, size_t nDataSize, unsigne assert( nDataSize % 2 == 0 ); assert( nBlobSize == nDataSize + 1 ); pBlob[nBlobSize - 1] = VECTOR_TYPE_FLOAT64; - }else if( pVector->type == VECTOR_TYPE_1BIT ){ + }else if( pVector->type == VECTOR_TYPE_FLOAT1BIT ){ assert( nBlobSize % 2 == 1 ); assert( nBlobSize >= 3 ); - pBlob[nBlobSize - 1] = VECTOR_TYPE_1BIT; + pBlob[nBlobSize - 1] = VECTOR_TYPE_FLOAT1BIT; pBlob[nBlobSize - 2] = 8 * (nBlobSize - 1) - pVector->dims; }else{ assert( 0 ); @@ -517,7 +517,7 @@ void vectorSerializeWithMeta( case VECTOR_TYPE_FLOAT64: vectorF64SerializeToBlob(pVector, pBlob, nDataSize); break; - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: vector1BitSerializeToBlob(pVector, pBlob, nDataSize); break; default: @@ -533,7 +533,7 @@ size_t vectorSerializeToBlob(const Vector *pVector, unsigned char *pBlob, size_t return vectorF32SerializeToBlob(pVector, pBlob, nBlobSize); case VECTOR_TYPE_FLOAT64: return vectorF64SerializeToBlob(pVector, pBlob, nBlobSize); - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: return vector1BitSerializeToBlob(pVector, pBlob, nBlobSize); default: assert(0); @@ -562,7 +562,7 @@ static void vectorConvertFromF32(const Vector *pFrom, Vector *pTo){ for(i = 0; i < pFrom->dims; i++){ dstF64[i] = src[i]; } - }else if( pTo->type == VECTOR_TYPE_1BIT ){ + }else if( pTo->type == VECTOR_TYPE_FLOAT1BIT ){ dst1Bit = pTo->data; for(i = 0; i < pFrom->dims; i += 8){ dst1Bit[i / 8] = 0; @@ -594,7 +594,7 @@ static void vectorConvertFromF64(const Vector *pFrom, Vector *pTo){ for(i = 0; i < pFrom->dims; i++){ dstF32[i] = src[i]; } - }else if( pTo->type == VECTOR_TYPE_1BIT ){ + }else if( pTo->type == VECTOR_TYPE_FLOAT1BIT ){ dst1Bit = pTo->data; for(i = 0; i < pFrom->dims; i += 8){ dst1Bit[i / 8] = 0; @@ -618,7 +618,7 @@ static void vectorConvertFrom1Bit(const Vector *pFrom, Vector *pTo){ assert( pFrom->dims == pTo->dims ); assert( pFrom->type != pTo->type ); - assert( pFrom->type == VECTOR_TYPE_1BIT ); + assert( pFrom->type == VECTOR_TYPE_FLOAT1BIT ); src = pFrom->data; if( pTo->type == VECTOR_TYPE_FLOAT32 ){ @@ -656,7 +656,7 @@ void vectorConvert(const Vector *pFrom, Vector *pTo){ vectorConvertFromF32(pFrom, pTo); }else if( pFrom->type == VECTOR_TYPE_FLOAT64 ){ vectorConvertFromF64(pFrom, pTo); - }else if( pFrom->type == VECTOR_TYPE_1BIT ){ + }else if( pFrom->type == VECTOR_TYPE_FLOAT1BIT ){ vectorConvertFrom1Bit(pFrom, pTo); }else{ assert( 0 ); @@ -739,7 +739,7 @@ static void vector1BitFunc( int argc, sqlite3_value **argv ){ - vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_1BIT); + vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_FLOAT1BIT); } /* diff --git a/libsql-sqlite3/src/vector1bit.c b/libsql-sqlite3/src/vector1bit.c index b80c166522..86e367c2de 100644 --- a/libsql-sqlite3/src/vector1bit.c +++ b/libsql-sqlite3/src/vector1bit.c @@ -39,7 +39,7 @@ void vector1BitDump(const Vector *pVec){ u8 *elems = pVec->data; unsigned i; - assert( pVec->type == VECTOR_TYPE_1BIT ); + assert( pVec->type == VECTOR_TYPE_FLOAT1BIT ); printf("f1bit: ["); for(i = 0; i < pVec->dims; i++){ @@ -61,7 +61,7 @@ size_t vector1BitSerializeToBlob( u8 *pPtr = pBlob; unsigned i; - assert( pVector->type == VECTOR_TYPE_1BIT ); + assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); assert( pVector->dims <= MAX_VECTOR_SZ ); assert( nBlobSize >= (pVector->dims + 7) / 8 ); @@ -108,8 +108,8 @@ int vector1BitDistanceHamming(const Vector *v1, const Vector *v2){ int i, len8, len32, offset8; assert( v1->dims == v2->dims ); - assert( v1->type == VECTOR_TYPE_1BIT ); - assert( v2->type == VECTOR_TYPE_1BIT ); + assert( v1->type == VECTOR_TYPE_FLOAT1BIT ); + assert( v2->type == VECTOR_TYPE_FLOAT1BIT ); len8 = (v1->dims + 7) / 8; len32 = v1->dims / 32; @@ -131,7 +131,7 @@ void vector1BitDeserializeFromBlob( ){ u8 *elems = pVector->data; - assert( pVector->type == VECTOR_TYPE_1BIT ); + assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); assert( 0 <= pVector->dims && pVector->dims <= MAX_VECTOR_SZ ); assert( nBlobSize >= (pVector->dims + 7) / 8 ); diff --git a/libsql-sqlite3/src/vectorIndex.c b/libsql-sqlite3/src/vectorIndex.c index 6413bf0822..a9801c4e60 100644 --- a/libsql-sqlite3/src/vectorIndex.c +++ b/libsql-sqlite3/src/vectorIndex.c @@ -382,8 +382,8 @@ static struct VectorColumnType VECTOR_COLUMN_TYPES[] = { { "F32_BLOB", VECTOR_TYPE_FLOAT32 }, { "FLOAT64", VECTOR_TYPE_FLOAT64 }, { "F64_BLOB", VECTOR_TYPE_FLOAT64 }, - { "FLOAT1BIT", VECTOR_TYPE_1BIT }, - { "F1BIT_BLOB", VECTOR_TYPE_1BIT }, + { "FLOAT1BIT", VECTOR_TYPE_FLOAT1BIT }, + { "F1BIT_BLOB", VECTOR_TYPE_FLOAT1BIT }, }; /* @@ -399,10 +399,11 @@ struct VectorParamName { }; static struct VectorParamName VECTOR_PARAM_NAMES[] = { - { "type", VECTOR_INDEX_TYPE_PARAM_ID, 0, "diskann", VECTOR_INDEX_TYPE_DISKANN }, - { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "cosine", VECTOR_METRIC_TYPE_COS }, - { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "l2", VECTOR_METRIC_TYPE_L2 }, - { "compress_neighbors", VECTOR_COMPRESS_NEIGHBORS_PARAM_ID, 0, "1bit", VECTOR_TYPE_1BIT }, + { "type", VECTOR_INDEX_TYPE_PARAM_ID, 0, "diskann", VECTOR_INDEX_TYPE_DISKANN }, + { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "cosine", VECTOR_METRIC_TYPE_COS }, + { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "l2", VECTOR_METRIC_TYPE_L2 }, + { "compress_neighbors", VECTOR_COMPRESS_NEIGHBORS_PARAM_ID, 0, "float1bit", VECTOR_TYPE_FLOAT1BIT }, + { "compress_neighbors", VECTOR_COMPRESS_NEIGHBORS_PARAM_ID, 0, "float32", VECTOR_TYPE_FLOAT32 }, { "alpha", VECTOR_PRUNING_ALPHA_PARAM_ID, 2, 0, 0 }, { "search_l", VECTOR_SEARCH_L_PARAM_ID, 1, 0, 0 }, { "insert_l", VECTOR_INSERT_L_PARAM_ID, 1, 0, 0 }, @@ -962,7 +963,7 @@ int vectorIndexSearch( rc = SQLITE_ERROR; goto out; } - assert( type == VECTOR_TYPE_FLOAT32 || type == VECTOR_TYPE_FLOAT64 || type == VECTOR_TYPE_1BIT ); + assert( type == VECTOR_TYPE_FLOAT32 || type == VECTOR_TYPE_FLOAT64 || type == VECTOR_TYPE_FLOAT1BIT ); pVector = vectorAlloc(type, dims); if( pVector == NULL ){ diff --git a/libsql-sqlite3/src/vectorInt.h b/libsql-sqlite3/src/vectorInt.h index aaf219f52b..a17ff1d59a 100644 --- a/libsql-sqlite3/src/vectorInt.h +++ b/libsql-sqlite3/src/vectorInt.h @@ -42,9 +42,9 @@ typedef u32 VectorDims; /* * Enumerate of supported vector types (0 omitted intentionally as we can use zero as "undefined" value) */ -#define VECTOR_TYPE_FLOAT32 1 -#define VECTOR_TYPE_FLOAT64 2 -#define VECTOR_TYPE_1BIT 3 +#define VECTOR_TYPE_FLOAT32 1 +#define VECTOR_TYPE_FLOAT64 2 +#define VECTOR_TYPE_FLOAT1BIT 3 #define VECTOR_FLAGS_STATIC 1 diff --git a/libsql-sqlite3/src/vectordiskann.c b/libsql-sqlite3/src/vectordiskann.c index c28cf075e9..c6e2d5156f 100644 --- a/libsql-sqlite3/src/vectordiskann.c +++ b/libsql-sqlite3/src/vectordiskann.c @@ -505,7 +505,7 @@ int diskAnnCreateIndex( } } neighbours = vectorIdxParamsGetU64(pParams, VECTOR_COMPRESS_NEIGHBORS_PARAM_ID); - if( neighbours == VECTOR_TYPE_1BIT && metric != VECTOR_METRIC_TYPE_COS ){ + if( neighbours == VECTOR_TYPE_FLOAT1BIT && metric != VECTOR_METRIC_TYPE_COS ){ *pzErrMsg = "1-bit compression available only for cosine metric"; return SQLITE_ERROR; } @@ -1749,7 +1749,7 @@ int diskAnnOpenIndex( if( compressNeighbours == 0 ){ pIndex->nEdgeVectorType = pIndex->nNodeVectorType; pIndex->nEdgeVectorSize = pIndex->nNodeVectorSize; - }else if( compressNeighbours == VECTOR_TYPE_1BIT ){ + }else if( compressNeighbours == VECTOR_TYPE_FLOAT1BIT ){ pIndex->nEdgeVectorType = compressNeighbours; pIndex->nEdgeVectorSize = vectorDataSize(compressNeighbours, pIndex->nVectorDims); }else{ diff --git a/libsql-sqlite3/test/libsql_vector_index.test b/libsql-sqlite3/test/libsql_vector_index.test index 242383e376..f066275833 100644 --- a/libsql-sqlite3/test/libsql_vector_index.test +++ b/libsql-sqlite3/test/libsql_vector_index.test @@ -275,7 +275,7 @@ do_execsql_test vector-transaction { do_execsql_test vector-1bit { CREATE TABLE t_1bit( v FLOAT32(3) ); - CREATE INDEX t_1bit_idx ON t_1bit( libsql_vector_idx(v, 'compress_neighbors=1bit') ); + CREATE INDEX t_1bit_idx ON t_1bit( libsql_vector_idx(v, 'compress_neighbors=float1bit') ); INSERT INTO t_1bit VALUES (vector('[-1,-1,1]')); INSERT INTO t_1bit VALUES (vector('[-1,1,-1.5]')); INSERT INTO t_1bit VALUES (vector('[1,-1,-1]')); @@ -285,7 +285,7 @@ do_execsql_test vector-1bit { do_execsql_test vector-all-params { CREATE TABLE t_all_params ( emb FLOAT32(2) ); - CREATE INDEX t_all_params_idx ON t_all_params(libsql_vector_idx(emb, 'type=diskann', 'metric=cos', 'alpha=1.2', 'search_l=200', 'insert_l=70', 'max_neighbors=6', 'compress_neighbors=1bit')); + CREATE INDEX t_all_params_idx ON t_all_params(libsql_vector_idx(emb, 'type=diskann', 'metric=cos', 'alpha=1.2', 'search_l=200', 'insert_l=70', 'max_neighbors=6', 'compress_neighbors=float1bit')); INSERT INTO t_all_params VALUES (vector('[1,2]')), (vector('[3,4]')); SELECT * FROM vector_top_k('t_all_params_idx', vector('[1,2]'), 2); } {1 2} @@ -336,6 +336,15 @@ do_execsql_test vector-1bit-index { SELECT * FROM vector_top_k('t_1bit_table_idx', vector1bit('[10,-10,-20,20]'), 4); } {3 1 2} +do_execsql_test vector-f64-compress-f32 { + CREATE TABLE t_f64_f32( v FLOAT64(4) ); + CREATE INDEX t_f64_f32_idx ON t_f64_f32( libsql_vector_idx(v, 'compress_neighbors=float32') ); + INSERT INTO t_f64_f32 VALUES ( vector64('[1,-1,1,-1]') ); + INSERT INTO t_f64_f32 VALUES ( vector64('[-1,1,1,-1]') ); + INSERT INTO t_f64_f32 VALUES ( vector64('[1,-1,-1,1]') ); + SELECT * FROM vector_top_k('t_f64_f32_idx', vector64('[10,-10,-20,20]'), 4); +} {3 1 2} + proc error_messages {sql} { set ret "" catch { From acafcc8277958f6d08674ec32c858a5b4eb94eae Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Tue, 13 Aug 2024 11:26:32 +0400 Subject: [PATCH 18/20] build bundles --- .../SQLite3MultipleCiphers/src/sqlite3.c | 65 ++++++++++--------- libsql-ffi/bundled/src/sqlite3.c | 65 ++++++++++--------- 2 files changed, 66 insertions(+), 64 deletions(-) diff --git a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c index ad032de20e..8895733cb8 100644 --- a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c +++ b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c @@ -85261,9 +85261,9 @@ typedef u32 VectorDims; /* * Enumerate of supported vector types (0 omitted intentionally as we can use zero as "undefined" value) */ -#define VECTOR_TYPE_FLOAT32 1 -#define VECTOR_TYPE_FLOAT64 2 -#define VECTOR_TYPE_1BIT 3 +#define VECTOR_TYPE_FLOAT32 1 +#define VECTOR_TYPE_FLOAT64 2 +#define VECTOR_TYPE_FLOAT1BIT 3 #define VECTOR_FLAGS_STATIC 1 @@ -210999,7 +210999,7 @@ size_t vectorDataSize(VectorType type, VectorDims dims){ return dims * sizeof(float); case VECTOR_TYPE_FLOAT64: return dims * sizeof(double); - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: return (dims + 7) / 8; default: assert(0); @@ -211072,7 +211072,7 @@ float vectorDistanceCos(const Vector *pVector1, const Vector *pVector2){ return vectorF32DistanceCos(pVector1, pVector2); case VECTOR_TYPE_FLOAT64: return vectorF64DistanceCos(pVector1, pVector2); - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: return vector1BitDistanceHamming(pVector1, pVector2); default: assert(0); @@ -211236,7 +211236,7 @@ static int vectorParseMeta(const unsigned char *pBlob, size_t nBlobSize, int *pT } *pDims = nBlobSize / sizeof(double); *pDataSize = nBlobSize; - }else if( *pType == VECTOR_TYPE_1BIT ){ + }else if( *pType == VECTOR_TYPE_FLOAT1BIT ){ if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ *pzErrMsg = sqlite3_mprintf("vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; @@ -211286,7 +211286,7 @@ int vectorParseSqliteBlobWithType( case VECTOR_TYPE_FLOAT64: vectorF64DeserializeFromBlob(pVector, pBlob, nDataSize); return 0; - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: vector1BitDeserializeFromBlob(pVector, pBlob, nDataSize); return 0; default: @@ -211384,7 +211384,7 @@ void vectorDump(const Vector *pVector){ case VECTOR_TYPE_FLOAT64: vectorF64Dump(pVector); break; - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: vector1BitDump(pVector); break; default: @@ -211415,7 +211415,7 @@ static int vectorMetaSize(VectorType type, VectorDims dims){ return 0; }else if( type == VECTOR_TYPE_FLOAT64 ){ return 1; - }else if( type == VECTOR_TYPE_1BIT ){ + }else if( type == VECTOR_TYPE_FLOAT1BIT ){ nDataSize = vectorDataSize(type, dims); nMetaSize++; // one byte which specify amount of leftover bits if( nDataSize % 2 == 0 ){ @@ -211435,10 +211435,10 @@ static void vectorSerializeMeta(const Vector *pVector, size_t nDataSize, unsigne assert( nDataSize % 2 == 0 ); assert( nBlobSize == nDataSize + 1 ); pBlob[nBlobSize - 1] = VECTOR_TYPE_FLOAT64; - }else if( pVector->type == VECTOR_TYPE_1BIT ){ + }else if( pVector->type == VECTOR_TYPE_FLOAT1BIT ){ assert( nBlobSize % 2 == 1 ); assert( nBlobSize >= 3 ); - pBlob[nBlobSize - 1] = VECTOR_TYPE_1BIT; + pBlob[nBlobSize - 1] = VECTOR_TYPE_FLOAT1BIT; pBlob[nBlobSize - 2] = 8 * (nBlobSize - 1) - pVector->dims; }else{ assert( 0 ); @@ -211475,7 +211475,7 @@ void vectorSerializeWithMeta( case VECTOR_TYPE_FLOAT64: vectorF64SerializeToBlob(pVector, pBlob, nDataSize); break; - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: vector1BitSerializeToBlob(pVector, pBlob, nDataSize); break; default: @@ -211491,7 +211491,7 @@ size_t vectorSerializeToBlob(const Vector *pVector, unsigned char *pBlob, size_t return vectorF32SerializeToBlob(pVector, pBlob, nBlobSize); case VECTOR_TYPE_FLOAT64: return vectorF64SerializeToBlob(pVector, pBlob, nBlobSize); - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: return vector1BitSerializeToBlob(pVector, pBlob, nBlobSize); default: assert(0); @@ -211520,7 +211520,7 @@ static void vectorConvertFromF32(const Vector *pFrom, Vector *pTo){ for(i = 0; i < pFrom->dims; i++){ dstF64[i] = src[i]; } - }else if( pTo->type == VECTOR_TYPE_1BIT ){ + }else if( pTo->type == VECTOR_TYPE_FLOAT1BIT ){ dst1Bit = pTo->data; for(i = 0; i < pFrom->dims; i += 8){ dst1Bit[i / 8] = 0; @@ -211552,7 +211552,7 @@ static void vectorConvertFromF64(const Vector *pFrom, Vector *pTo){ for(i = 0; i < pFrom->dims; i++){ dstF32[i] = src[i]; } - }else if( pTo->type == VECTOR_TYPE_1BIT ){ + }else if( pTo->type == VECTOR_TYPE_FLOAT1BIT ){ dst1Bit = pTo->data; for(i = 0; i < pFrom->dims; i += 8){ dst1Bit[i / 8] = 0; @@ -211576,7 +211576,7 @@ static void vectorConvertFrom1Bit(const Vector *pFrom, Vector *pTo){ assert( pFrom->dims == pTo->dims ); assert( pFrom->type != pTo->type ); - assert( pFrom->type == VECTOR_TYPE_1BIT ); + assert( pFrom->type == VECTOR_TYPE_FLOAT1BIT ); src = pFrom->data; if( pTo->type == VECTOR_TYPE_FLOAT32 ){ @@ -211614,7 +211614,7 @@ void vectorConvert(const Vector *pFrom, Vector *pTo){ vectorConvertFromF32(pFrom, pTo); }else if( pFrom->type == VECTOR_TYPE_FLOAT64 ){ vectorConvertFromF64(pFrom, pTo); - }else if( pFrom->type == VECTOR_TYPE_1BIT ){ + }else if( pFrom->type == VECTOR_TYPE_FLOAT1BIT ){ vectorConvertFrom1Bit(pFrom, pTo); }else{ assert( 0 ); @@ -211697,7 +211697,7 @@ static void vector1BitFunc( int argc, sqlite3_value **argv ){ - vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_1BIT); + vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_FLOAT1BIT); } /* @@ -211884,7 +211884,7 @@ void vector1BitDump(const Vector *pVec){ u8 *elems = pVec->data; unsigned i; - assert( pVec->type == VECTOR_TYPE_1BIT ); + assert( pVec->type == VECTOR_TYPE_FLOAT1BIT ); printf("f1bit: ["); for(i = 0; i < pVec->dims; i++){ @@ -211906,7 +211906,7 @@ size_t vector1BitSerializeToBlob( u8 *pPtr = pBlob; unsigned i; - assert( pVector->type == VECTOR_TYPE_1BIT ); + assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); assert( pVector->dims <= MAX_VECTOR_SZ ); assert( nBlobSize >= (pVector->dims + 7) / 8 ); @@ -211953,8 +211953,8 @@ int vector1BitDistanceHamming(const Vector *v1, const Vector *v2){ int i, len8, len32, offset8; assert( v1->dims == v2->dims ); - assert( v1->type == VECTOR_TYPE_1BIT ); - assert( v2->type == VECTOR_TYPE_1BIT ); + assert( v1->type == VECTOR_TYPE_FLOAT1BIT ); + assert( v2->type == VECTOR_TYPE_FLOAT1BIT ); len8 = (v1->dims + 7) / 8; len32 = v1->dims / 32; @@ -211976,7 +211976,7 @@ void vector1BitDeserializeFromBlob( ){ u8 *elems = pVector->data; - assert( pVector->type == VECTOR_TYPE_1BIT ); + assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); assert( 0 <= pVector->dims && pVector->dims <= MAX_VECTOR_SZ ); assert( nBlobSize >= (pVector->dims + 7) / 8 ); @@ -212494,7 +212494,7 @@ int diskAnnCreateIndex( } } neighbours = vectorIdxParamsGetU64(pParams, VECTOR_COMPRESS_NEIGHBORS_PARAM_ID); - if( neighbours == VECTOR_TYPE_1BIT && metric != VECTOR_METRIC_TYPE_COS ){ + if( neighbours == VECTOR_TYPE_FLOAT1BIT && metric != VECTOR_METRIC_TYPE_COS ){ *pzErrMsg = "1-bit compression available only for cosine metric"; return SQLITE_ERROR; } @@ -213738,7 +213738,7 @@ int diskAnnOpenIndex( if( compressNeighbours == 0 ){ pIndex->nEdgeVectorType = pIndex->nNodeVectorType; pIndex->nEdgeVectorSize = pIndex->nNodeVectorSize; - }else if( compressNeighbours == VECTOR_TYPE_1BIT ){ + }else if( compressNeighbours == VECTOR_TYPE_FLOAT1BIT ){ pIndex->nEdgeVectorType = compressNeighbours; pIndex->nEdgeVectorSize = vectorDataSize(compressNeighbours, pIndex->nVectorDims); }else{ @@ -214541,8 +214541,8 @@ static struct VectorColumnType VECTOR_COLUMN_TYPES[] = { { "F32_BLOB", VECTOR_TYPE_FLOAT32 }, { "FLOAT64", VECTOR_TYPE_FLOAT64 }, { "F64_BLOB", VECTOR_TYPE_FLOAT64 }, - { "FLOAT1BIT", VECTOR_TYPE_1BIT }, - { "F1BIT_BLOB", VECTOR_TYPE_1BIT }, + { "FLOAT1BIT", VECTOR_TYPE_FLOAT1BIT }, + { "F1BIT_BLOB", VECTOR_TYPE_FLOAT1BIT }, }; /* @@ -214558,10 +214558,11 @@ struct VectorParamName { }; static struct VectorParamName VECTOR_PARAM_NAMES[] = { - { "type", VECTOR_INDEX_TYPE_PARAM_ID, 0, "diskann", VECTOR_INDEX_TYPE_DISKANN }, - { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "cosine", VECTOR_METRIC_TYPE_COS }, - { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "l2", VECTOR_METRIC_TYPE_L2 }, - { "compress_neighbors", VECTOR_COMPRESS_NEIGHBORS_PARAM_ID, 0, "1bit", VECTOR_TYPE_1BIT }, + { "type", VECTOR_INDEX_TYPE_PARAM_ID, 0, "diskann", VECTOR_INDEX_TYPE_DISKANN }, + { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "cosine", VECTOR_METRIC_TYPE_COS }, + { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "l2", VECTOR_METRIC_TYPE_L2 }, + { "compress_neighbors", VECTOR_COMPRESS_NEIGHBORS_PARAM_ID, 0, "float1bit", VECTOR_TYPE_FLOAT1BIT }, + { "compress_neighbors", VECTOR_COMPRESS_NEIGHBORS_PARAM_ID, 0, "float32", VECTOR_TYPE_FLOAT32 }, { "alpha", VECTOR_PRUNING_ALPHA_PARAM_ID, 2, 0, 0 }, { "search_l", VECTOR_SEARCH_L_PARAM_ID, 1, 0, 0 }, { "insert_l", VECTOR_INSERT_L_PARAM_ID, 1, 0, 0 }, @@ -215121,7 +215122,7 @@ int vectorIndexSearch( rc = SQLITE_ERROR; goto out; } - assert( type == VECTOR_TYPE_FLOAT32 || type == VECTOR_TYPE_FLOAT64 || type == VECTOR_TYPE_1BIT ); + assert( type == VECTOR_TYPE_FLOAT32 || type == VECTOR_TYPE_FLOAT64 || type == VECTOR_TYPE_FLOAT1BIT ); pVector = vectorAlloc(type, dims); if( pVector == NULL ){ diff --git a/libsql-ffi/bundled/src/sqlite3.c b/libsql-ffi/bundled/src/sqlite3.c index ad032de20e..8895733cb8 100644 --- a/libsql-ffi/bundled/src/sqlite3.c +++ b/libsql-ffi/bundled/src/sqlite3.c @@ -85261,9 +85261,9 @@ typedef u32 VectorDims; /* * Enumerate of supported vector types (0 omitted intentionally as we can use zero as "undefined" value) */ -#define VECTOR_TYPE_FLOAT32 1 -#define VECTOR_TYPE_FLOAT64 2 -#define VECTOR_TYPE_1BIT 3 +#define VECTOR_TYPE_FLOAT32 1 +#define VECTOR_TYPE_FLOAT64 2 +#define VECTOR_TYPE_FLOAT1BIT 3 #define VECTOR_FLAGS_STATIC 1 @@ -210999,7 +210999,7 @@ size_t vectorDataSize(VectorType type, VectorDims dims){ return dims * sizeof(float); case VECTOR_TYPE_FLOAT64: return dims * sizeof(double); - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: return (dims + 7) / 8; default: assert(0); @@ -211072,7 +211072,7 @@ float vectorDistanceCos(const Vector *pVector1, const Vector *pVector2){ return vectorF32DistanceCos(pVector1, pVector2); case VECTOR_TYPE_FLOAT64: return vectorF64DistanceCos(pVector1, pVector2); - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: return vector1BitDistanceHamming(pVector1, pVector2); default: assert(0); @@ -211236,7 +211236,7 @@ static int vectorParseMeta(const unsigned char *pBlob, size_t nBlobSize, int *pT } *pDims = nBlobSize / sizeof(double); *pDataSize = nBlobSize; - }else if( *pType == VECTOR_TYPE_1BIT ){ + }else if( *pType == VECTOR_TYPE_FLOAT1BIT ){ if( nBlobSize == 0 || nBlobSize % 2 != 0 ){ *pzErrMsg = sqlite3_mprintf("vector: 1bit vector blob length must be divisible by 2 and not be empty (excluding 'type'-byte): length=%d", nBlobSize); return SQLITE_ERROR; @@ -211286,7 +211286,7 @@ int vectorParseSqliteBlobWithType( case VECTOR_TYPE_FLOAT64: vectorF64DeserializeFromBlob(pVector, pBlob, nDataSize); return 0; - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: vector1BitDeserializeFromBlob(pVector, pBlob, nDataSize); return 0; default: @@ -211384,7 +211384,7 @@ void vectorDump(const Vector *pVector){ case VECTOR_TYPE_FLOAT64: vectorF64Dump(pVector); break; - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: vector1BitDump(pVector); break; default: @@ -211415,7 +211415,7 @@ static int vectorMetaSize(VectorType type, VectorDims dims){ return 0; }else if( type == VECTOR_TYPE_FLOAT64 ){ return 1; - }else if( type == VECTOR_TYPE_1BIT ){ + }else if( type == VECTOR_TYPE_FLOAT1BIT ){ nDataSize = vectorDataSize(type, dims); nMetaSize++; // one byte which specify amount of leftover bits if( nDataSize % 2 == 0 ){ @@ -211435,10 +211435,10 @@ static void vectorSerializeMeta(const Vector *pVector, size_t nDataSize, unsigne assert( nDataSize % 2 == 0 ); assert( nBlobSize == nDataSize + 1 ); pBlob[nBlobSize - 1] = VECTOR_TYPE_FLOAT64; - }else if( pVector->type == VECTOR_TYPE_1BIT ){ + }else if( pVector->type == VECTOR_TYPE_FLOAT1BIT ){ assert( nBlobSize % 2 == 1 ); assert( nBlobSize >= 3 ); - pBlob[nBlobSize - 1] = VECTOR_TYPE_1BIT; + pBlob[nBlobSize - 1] = VECTOR_TYPE_FLOAT1BIT; pBlob[nBlobSize - 2] = 8 * (nBlobSize - 1) - pVector->dims; }else{ assert( 0 ); @@ -211475,7 +211475,7 @@ void vectorSerializeWithMeta( case VECTOR_TYPE_FLOAT64: vectorF64SerializeToBlob(pVector, pBlob, nDataSize); break; - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: vector1BitSerializeToBlob(pVector, pBlob, nDataSize); break; default: @@ -211491,7 +211491,7 @@ size_t vectorSerializeToBlob(const Vector *pVector, unsigned char *pBlob, size_t return vectorF32SerializeToBlob(pVector, pBlob, nBlobSize); case VECTOR_TYPE_FLOAT64: return vectorF64SerializeToBlob(pVector, pBlob, nBlobSize); - case VECTOR_TYPE_1BIT: + case VECTOR_TYPE_FLOAT1BIT: return vector1BitSerializeToBlob(pVector, pBlob, nBlobSize); default: assert(0); @@ -211520,7 +211520,7 @@ static void vectorConvertFromF32(const Vector *pFrom, Vector *pTo){ for(i = 0; i < pFrom->dims; i++){ dstF64[i] = src[i]; } - }else if( pTo->type == VECTOR_TYPE_1BIT ){ + }else if( pTo->type == VECTOR_TYPE_FLOAT1BIT ){ dst1Bit = pTo->data; for(i = 0; i < pFrom->dims; i += 8){ dst1Bit[i / 8] = 0; @@ -211552,7 +211552,7 @@ static void vectorConvertFromF64(const Vector *pFrom, Vector *pTo){ for(i = 0; i < pFrom->dims; i++){ dstF32[i] = src[i]; } - }else if( pTo->type == VECTOR_TYPE_1BIT ){ + }else if( pTo->type == VECTOR_TYPE_FLOAT1BIT ){ dst1Bit = pTo->data; for(i = 0; i < pFrom->dims; i += 8){ dst1Bit[i / 8] = 0; @@ -211576,7 +211576,7 @@ static void vectorConvertFrom1Bit(const Vector *pFrom, Vector *pTo){ assert( pFrom->dims == pTo->dims ); assert( pFrom->type != pTo->type ); - assert( pFrom->type == VECTOR_TYPE_1BIT ); + assert( pFrom->type == VECTOR_TYPE_FLOAT1BIT ); src = pFrom->data; if( pTo->type == VECTOR_TYPE_FLOAT32 ){ @@ -211614,7 +211614,7 @@ void vectorConvert(const Vector *pFrom, Vector *pTo){ vectorConvertFromF32(pFrom, pTo); }else if( pFrom->type == VECTOR_TYPE_FLOAT64 ){ vectorConvertFromF64(pFrom, pTo); - }else if( pFrom->type == VECTOR_TYPE_1BIT ){ + }else if( pFrom->type == VECTOR_TYPE_FLOAT1BIT ){ vectorConvertFrom1Bit(pFrom, pTo); }else{ assert( 0 ); @@ -211697,7 +211697,7 @@ static void vector1BitFunc( int argc, sqlite3_value **argv ){ - vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_1BIT); + vectorFuncHintedType(context, argc, argv, VECTOR_TYPE_FLOAT1BIT); } /* @@ -211884,7 +211884,7 @@ void vector1BitDump(const Vector *pVec){ u8 *elems = pVec->data; unsigned i; - assert( pVec->type == VECTOR_TYPE_1BIT ); + assert( pVec->type == VECTOR_TYPE_FLOAT1BIT ); printf("f1bit: ["); for(i = 0; i < pVec->dims; i++){ @@ -211906,7 +211906,7 @@ size_t vector1BitSerializeToBlob( u8 *pPtr = pBlob; unsigned i; - assert( pVector->type == VECTOR_TYPE_1BIT ); + assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); assert( pVector->dims <= MAX_VECTOR_SZ ); assert( nBlobSize >= (pVector->dims + 7) / 8 ); @@ -211953,8 +211953,8 @@ int vector1BitDistanceHamming(const Vector *v1, const Vector *v2){ int i, len8, len32, offset8; assert( v1->dims == v2->dims ); - assert( v1->type == VECTOR_TYPE_1BIT ); - assert( v2->type == VECTOR_TYPE_1BIT ); + assert( v1->type == VECTOR_TYPE_FLOAT1BIT ); + assert( v2->type == VECTOR_TYPE_FLOAT1BIT ); len8 = (v1->dims + 7) / 8; len32 = v1->dims / 32; @@ -211976,7 +211976,7 @@ void vector1BitDeserializeFromBlob( ){ u8 *elems = pVector->data; - assert( pVector->type == VECTOR_TYPE_1BIT ); + assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); assert( 0 <= pVector->dims && pVector->dims <= MAX_VECTOR_SZ ); assert( nBlobSize >= (pVector->dims + 7) / 8 ); @@ -212494,7 +212494,7 @@ int diskAnnCreateIndex( } } neighbours = vectorIdxParamsGetU64(pParams, VECTOR_COMPRESS_NEIGHBORS_PARAM_ID); - if( neighbours == VECTOR_TYPE_1BIT && metric != VECTOR_METRIC_TYPE_COS ){ + if( neighbours == VECTOR_TYPE_FLOAT1BIT && metric != VECTOR_METRIC_TYPE_COS ){ *pzErrMsg = "1-bit compression available only for cosine metric"; return SQLITE_ERROR; } @@ -213738,7 +213738,7 @@ int diskAnnOpenIndex( if( compressNeighbours == 0 ){ pIndex->nEdgeVectorType = pIndex->nNodeVectorType; pIndex->nEdgeVectorSize = pIndex->nNodeVectorSize; - }else if( compressNeighbours == VECTOR_TYPE_1BIT ){ + }else if( compressNeighbours == VECTOR_TYPE_FLOAT1BIT ){ pIndex->nEdgeVectorType = compressNeighbours; pIndex->nEdgeVectorSize = vectorDataSize(compressNeighbours, pIndex->nVectorDims); }else{ @@ -214541,8 +214541,8 @@ static struct VectorColumnType VECTOR_COLUMN_TYPES[] = { { "F32_BLOB", VECTOR_TYPE_FLOAT32 }, { "FLOAT64", VECTOR_TYPE_FLOAT64 }, { "F64_BLOB", VECTOR_TYPE_FLOAT64 }, - { "FLOAT1BIT", VECTOR_TYPE_1BIT }, - { "F1BIT_BLOB", VECTOR_TYPE_1BIT }, + { "FLOAT1BIT", VECTOR_TYPE_FLOAT1BIT }, + { "F1BIT_BLOB", VECTOR_TYPE_FLOAT1BIT }, }; /* @@ -214558,10 +214558,11 @@ struct VectorParamName { }; static struct VectorParamName VECTOR_PARAM_NAMES[] = { - { "type", VECTOR_INDEX_TYPE_PARAM_ID, 0, "diskann", VECTOR_INDEX_TYPE_DISKANN }, - { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "cosine", VECTOR_METRIC_TYPE_COS }, - { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "l2", VECTOR_METRIC_TYPE_L2 }, - { "compress_neighbors", VECTOR_COMPRESS_NEIGHBORS_PARAM_ID, 0, "1bit", VECTOR_TYPE_1BIT }, + { "type", VECTOR_INDEX_TYPE_PARAM_ID, 0, "diskann", VECTOR_INDEX_TYPE_DISKANN }, + { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "cosine", VECTOR_METRIC_TYPE_COS }, + { "metric", VECTOR_METRIC_TYPE_PARAM_ID, 0, "l2", VECTOR_METRIC_TYPE_L2 }, + { "compress_neighbors", VECTOR_COMPRESS_NEIGHBORS_PARAM_ID, 0, "float1bit", VECTOR_TYPE_FLOAT1BIT }, + { "compress_neighbors", VECTOR_COMPRESS_NEIGHBORS_PARAM_ID, 0, "float32", VECTOR_TYPE_FLOAT32 }, { "alpha", VECTOR_PRUNING_ALPHA_PARAM_ID, 2, 0, 0 }, { "search_l", VECTOR_SEARCH_L_PARAM_ID, 1, 0, 0 }, { "insert_l", VECTOR_INSERT_L_PARAM_ID, 1, 0, 0 }, @@ -215121,7 +215122,7 @@ int vectorIndexSearch( rc = SQLITE_ERROR; goto out; } - assert( type == VECTOR_TYPE_FLOAT32 || type == VECTOR_TYPE_FLOAT64 || type == VECTOR_TYPE_1BIT ); + assert( type == VECTOR_TYPE_FLOAT32 || type == VECTOR_TYPE_FLOAT64 || type == VECTOR_TYPE_FLOAT1BIT ); pVector = vectorAlloc(type, dims); if( pVector == NULL ){ From 7a0fa8c19fd4d0349cf970efb09773f93bd0b021 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Tue, 13 Aug 2024 11:33:58 +0400 Subject: [PATCH 19/20] rename vector1bit.c -> vectorfloat1bit.c --- .../SQLite3MultipleCiphers/src/sqlite3.c | 289 +++++++++--------- libsql-ffi/bundled/src/sqlite3.c | 289 +++++++++--------- libsql-sqlite3/Makefile.in | 8 +- libsql-sqlite3/src/vectorIndex.c | 1 - .../src/{vector1bit.c => vectorfloat1bit.c} | 0 libsql-sqlite3/tool/mksqlite3c.tcl | 2 +- libsql-sqlite3/tool/showwal | Bin 0 -> 54760 bytes 7 files changed, 293 insertions(+), 296 deletions(-) rename libsql-sqlite3/src/{vector1bit.c => vectorfloat1bit.c} (100%) create mode 100755 libsql-sqlite3/tool/showwal diff --git a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c index 8895733cb8..477758b4cc 100644 --- a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c +++ b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c @@ -211842,150 +211842,6 @@ SQLITE_PRIVATE void sqlite3RegisterVectorFunctions(void){ #endif /* !defined(SQLITE_OMIT_VECTOR) */ /************** End of vector.c **********************************************/ -/************** Begin file vector1bit.c **************************************/ -/* -** 2024-07-04 -** -** Copyright 2024 the libSQL authors -** -** Permission is hereby granted, free of charge, to any person obtaining a copy of -** this software and associated documentation files (the "Software"), to deal in -** the Software without restriction, including without limitation the rights to -** use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -** the Software, and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in all -** copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -** FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -** COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -** IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -** -****************************************************************************** -** -** 1-bit vector format utilities. -*/ -#ifndef SQLITE_OMIT_VECTOR -/* #include "sqliteInt.h" */ - -/* #include "vectorInt.h" */ - -/* #include */ - -/************************************************************************** -** Utility routines for debugging -**************************************************************************/ - -void vector1BitDump(const Vector *pVec){ - u8 *elems = pVec->data; - unsigned i; - - assert( pVec->type == VECTOR_TYPE_FLOAT1BIT ); - - printf("f1bit: ["); - for(i = 0; i < pVec->dims; i++){ - printf("%s%d", i == 0 ? "" : ", ", ((elems[i / 8] >> (i & 7)) & 1) ? +1 : -1); - } - printf("]\n"); -} - -/************************************************************************** -** Utility routines for vector serialization and deserialization -**************************************************************************/ - -size_t vector1BitSerializeToBlob( - const Vector *pVector, - unsigned char *pBlob, - size_t nBlobSize -){ - u8 *elems = pVector->data; - u8 *pPtr = pBlob; - unsigned i; - - assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); - assert( pVector->dims <= MAX_VECTOR_SZ ); - assert( nBlobSize >= (pVector->dims + 7) / 8 ); - - for(i = 0; i < (pVector->dims + 7) / 8; i++){ - pPtr[i] = elems[i]; - } - return (pVector->dims + 7) / 8; -} - -// [sum(map(int, bin(i)[2:])) for i in range(256)] -static int BitsCount[256] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, -}; - -static inline int sqlite3PopCount32(u32 a){ -#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) - return __builtin_popcount(a); -#else - return BitsCount[a >> 24] + BitsCount[(a >> 16) & 0xff] + BitsCount[(a >> 8) & 0xff] + BitsCount[a & 0xff]; -#endif -} - -int vector1BitDistanceHamming(const Vector *v1, const Vector *v2){ - int diff = 0; - u8 *e1U8 = v1->data; - u32 *e1U32 = v1->data; - u8 *e2U8 = v2->data; - u32 *e2U32 = v2->data; - int i, len8, len32, offset8; - - assert( v1->dims == v2->dims ); - assert( v1->type == VECTOR_TYPE_FLOAT1BIT ); - assert( v2->type == VECTOR_TYPE_FLOAT1BIT ); - - len8 = (v1->dims + 7) / 8; - len32 = v1->dims / 32; - offset8 = len32 * 4; - - for(i = 0; i < len32; i++){ - diff += sqlite3PopCount32(e1U32[i] ^ e2U32[i]); - } - for(i = offset8; i < len8; i++){ - diff += sqlite3PopCount32(e1U8[i] ^ e2U8[i]); - } - return diff; -} - -void vector1BitDeserializeFromBlob( - Vector *pVector, - const unsigned char *pBlob, - size_t nBlobSize -){ - u8 *elems = pVector->data; - - assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); - assert( 0 <= pVector->dims && pVector->dims <= MAX_VECTOR_SZ ); - assert( nBlobSize >= (pVector->dims + 7) / 8 ); - - memcpy(elems, pBlob, (pVector->dims + 7) / 8); -} - -#endif /* !defined(SQLITE_OMIT_VECTOR) */ - -/************** End of vector1bit.c ******************************************/ /************** Begin file vectordiskann.c ***********************************/ /* ** 2024-03-23 @@ -213765,6 +213621,150 @@ void diskAnnCloseIndex(DiskAnnIndex *pIndex){ #endif /* !defined(SQLITE_OMIT_VECTOR) */ /************** End of vectordiskann.c ***************************************/ +/************** Begin file vectorfloat1bit.c *********************************/ +/* +** 2024-07-04 +** +** Copyright 2024 the libSQL authors +** +** Permission is hereby granted, free of charge, to any person obtaining a copy of +** this software and associated documentation files (the "Software"), to deal in +** the Software without restriction, including without limitation the rights to +** use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +** the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in all +** copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +** FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +** COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +** IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************** +** +** 1-bit vector format utilities. +*/ +#ifndef SQLITE_OMIT_VECTOR +/* #include "sqliteInt.h" */ + +/* #include "vectorInt.h" */ + +/* #include */ + +/************************************************************************** +** Utility routines for debugging +**************************************************************************/ + +void vector1BitDump(const Vector *pVec){ + u8 *elems = pVec->data; + unsigned i; + + assert( pVec->type == VECTOR_TYPE_FLOAT1BIT ); + + printf("f1bit: ["); + for(i = 0; i < pVec->dims; i++){ + printf("%s%d", i == 0 ? "" : ", ", ((elems[i / 8] >> (i & 7)) & 1) ? +1 : -1); + } + printf("]\n"); +} + +/************************************************************************** +** Utility routines for vector serialization and deserialization +**************************************************************************/ + +size_t vector1BitSerializeToBlob( + const Vector *pVector, + unsigned char *pBlob, + size_t nBlobSize +){ + u8 *elems = pVector->data; + u8 *pPtr = pBlob; + unsigned i; + + assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); + assert( pVector->dims <= MAX_VECTOR_SZ ); + assert( nBlobSize >= (pVector->dims + 7) / 8 ); + + for(i = 0; i < (pVector->dims + 7) / 8; i++){ + pPtr[i] = elems[i]; + } + return (pVector->dims + 7) / 8; +} + +// [sum(map(int, bin(i)[2:])) for i in range(256)] +static int BitsCount[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; + +static inline int sqlite3PopCount32(u32 a){ +#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) + return __builtin_popcount(a); +#else + return BitsCount[a >> 24] + BitsCount[(a >> 16) & 0xff] + BitsCount[(a >> 8) & 0xff] + BitsCount[a & 0xff]; +#endif +} + +int vector1BitDistanceHamming(const Vector *v1, const Vector *v2){ + int diff = 0; + u8 *e1U8 = v1->data; + u32 *e1U32 = v1->data; + u8 *e2U8 = v2->data; + u32 *e2U32 = v2->data; + int i, len8, len32, offset8; + + assert( v1->dims == v2->dims ); + assert( v1->type == VECTOR_TYPE_FLOAT1BIT ); + assert( v2->type == VECTOR_TYPE_FLOAT1BIT ); + + len8 = (v1->dims + 7) / 8; + len32 = v1->dims / 32; + offset8 = len32 * 4; + + for(i = 0; i < len32; i++){ + diff += sqlite3PopCount32(e1U32[i] ^ e2U32[i]); + } + for(i = offset8; i < len8; i++){ + diff += sqlite3PopCount32(e1U8[i] ^ e2U8[i]); + } + return diff; +} + +void vector1BitDeserializeFromBlob( + Vector *pVector, + const unsigned char *pBlob, + size_t nBlobSize +){ + u8 *elems = pVector->data; + + assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); + assert( 0 <= pVector->dims && pVector->dims <= MAX_VECTOR_SZ ); + assert( nBlobSize >= (pVector->dims + 7) / 8 ); + + memcpy(elems, pBlob, (pVector->dims + 7) / 8); +} + +#endif /* !defined(SQLITE_OMIT_VECTOR) */ + +/************** End of vectorfloat1bit.c *************************************/ /************** Begin file vectorfloat32.c ***********************************/ /* ** 2024-07-04 @@ -214183,7 +214183,6 @@ void vectorF64DeserializeFromBlob( ** ** libSQL vector search. */ -/* #include "vectorInt.h" */ #ifndef SQLITE_OMIT_VECTOR /* #include "sqlite3.h" */ /* #include "vdbeInt.h" */ diff --git a/libsql-ffi/bundled/src/sqlite3.c b/libsql-ffi/bundled/src/sqlite3.c index 8895733cb8..477758b4cc 100644 --- a/libsql-ffi/bundled/src/sqlite3.c +++ b/libsql-ffi/bundled/src/sqlite3.c @@ -211842,150 +211842,6 @@ SQLITE_PRIVATE void sqlite3RegisterVectorFunctions(void){ #endif /* !defined(SQLITE_OMIT_VECTOR) */ /************** End of vector.c **********************************************/ -/************** Begin file vector1bit.c **************************************/ -/* -** 2024-07-04 -** -** Copyright 2024 the libSQL authors -** -** Permission is hereby granted, free of charge, to any person obtaining a copy of -** this software and associated documentation files (the "Software"), to deal in -** the Software without restriction, including without limitation the rights to -** use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -** the Software, and to permit persons to whom the Software is furnished to do so, -** subject to the following conditions: -** -** The above copyright notice and this permission notice shall be included in all -** copies or substantial portions of the Software. -** -** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -** FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -** COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -** IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -** -****************************************************************************** -** -** 1-bit vector format utilities. -*/ -#ifndef SQLITE_OMIT_VECTOR -/* #include "sqliteInt.h" */ - -/* #include "vectorInt.h" */ - -/* #include */ - -/************************************************************************** -** Utility routines for debugging -**************************************************************************/ - -void vector1BitDump(const Vector *pVec){ - u8 *elems = pVec->data; - unsigned i; - - assert( pVec->type == VECTOR_TYPE_FLOAT1BIT ); - - printf("f1bit: ["); - for(i = 0; i < pVec->dims; i++){ - printf("%s%d", i == 0 ? "" : ", ", ((elems[i / 8] >> (i & 7)) & 1) ? +1 : -1); - } - printf("]\n"); -} - -/************************************************************************** -** Utility routines for vector serialization and deserialization -**************************************************************************/ - -size_t vector1BitSerializeToBlob( - const Vector *pVector, - unsigned char *pBlob, - size_t nBlobSize -){ - u8 *elems = pVector->data; - u8 *pPtr = pBlob; - unsigned i; - - assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); - assert( pVector->dims <= MAX_VECTOR_SZ ); - assert( nBlobSize >= (pVector->dims + 7) / 8 ); - - for(i = 0; i < (pVector->dims + 7) / 8; i++){ - pPtr[i] = elems[i]; - } - return (pVector->dims + 7) / 8; -} - -// [sum(map(int, bin(i)[2:])) for i in range(256)] -static int BitsCount[256] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, -}; - -static inline int sqlite3PopCount32(u32 a){ -#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) - return __builtin_popcount(a); -#else - return BitsCount[a >> 24] + BitsCount[(a >> 16) & 0xff] + BitsCount[(a >> 8) & 0xff] + BitsCount[a & 0xff]; -#endif -} - -int vector1BitDistanceHamming(const Vector *v1, const Vector *v2){ - int diff = 0; - u8 *e1U8 = v1->data; - u32 *e1U32 = v1->data; - u8 *e2U8 = v2->data; - u32 *e2U32 = v2->data; - int i, len8, len32, offset8; - - assert( v1->dims == v2->dims ); - assert( v1->type == VECTOR_TYPE_FLOAT1BIT ); - assert( v2->type == VECTOR_TYPE_FLOAT1BIT ); - - len8 = (v1->dims + 7) / 8; - len32 = v1->dims / 32; - offset8 = len32 * 4; - - for(i = 0; i < len32; i++){ - diff += sqlite3PopCount32(e1U32[i] ^ e2U32[i]); - } - for(i = offset8; i < len8; i++){ - diff += sqlite3PopCount32(e1U8[i] ^ e2U8[i]); - } - return diff; -} - -void vector1BitDeserializeFromBlob( - Vector *pVector, - const unsigned char *pBlob, - size_t nBlobSize -){ - u8 *elems = pVector->data; - - assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); - assert( 0 <= pVector->dims && pVector->dims <= MAX_VECTOR_SZ ); - assert( nBlobSize >= (pVector->dims + 7) / 8 ); - - memcpy(elems, pBlob, (pVector->dims + 7) / 8); -} - -#endif /* !defined(SQLITE_OMIT_VECTOR) */ - -/************** End of vector1bit.c ******************************************/ /************** Begin file vectordiskann.c ***********************************/ /* ** 2024-03-23 @@ -213765,6 +213621,150 @@ void diskAnnCloseIndex(DiskAnnIndex *pIndex){ #endif /* !defined(SQLITE_OMIT_VECTOR) */ /************** End of vectordiskann.c ***************************************/ +/************** Begin file vectorfloat1bit.c *********************************/ +/* +** 2024-07-04 +** +** Copyright 2024 the libSQL authors +** +** Permission is hereby granted, free of charge, to any person obtaining a copy of +** this software and associated documentation files (the "Software"), to deal in +** the Software without restriction, including without limitation the rights to +** use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +** the Software, and to permit persons to whom the Software is furnished to do so, +** subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in all +** copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +** FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +** COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +** IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +** +****************************************************************************** +** +** 1-bit vector format utilities. +*/ +#ifndef SQLITE_OMIT_VECTOR +/* #include "sqliteInt.h" */ + +/* #include "vectorInt.h" */ + +/* #include */ + +/************************************************************************** +** Utility routines for debugging +**************************************************************************/ + +void vector1BitDump(const Vector *pVec){ + u8 *elems = pVec->data; + unsigned i; + + assert( pVec->type == VECTOR_TYPE_FLOAT1BIT ); + + printf("f1bit: ["); + for(i = 0; i < pVec->dims; i++){ + printf("%s%d", i == 0 ? "" : ", ", ((elems[i / 8] >> (i & 7)) & 1) ? +1 : -1); + } + printf("]\n"); +} + +/************************************************************************** +** Utility routines for vector serialization and deserialization +**************************************************************************/ + +size_t vector1BitSerializeToBlob( + const Vector *pVector, + unsigned char *pBlob, + size_t nBlobSize +){ + u8 *elems = pVector->data; + u8 *pPtr = pBlob; + unsigned i; + + assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); + assert( pVector->dims <= MAX_VECTOR_SZ ); + assert( nBlobSize >= (pVector->dims + 7) / 8 ); + + for(i = 0; i < (pVector->dims + 7) / 8; i++){ + pPtr[i] = elems[i]; + } + return (pVector->dims + 7) / 8; +} + +// [sum(map(int, bin(i)[2:])) for i in range(256)] +static int BitsCount[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; + +static inline int sqlite3PopCount32(u32 a){ +#if GCC_VERSION>=5004000 && !defined(__INTEL_COMPILER) + return __builtin_popcount(a); +#else + return BitsCount[a >> 24] + BitsCount[(a >> 16) & 0xff] + BitsCount[(a >> 8) & 0xff] + BitsCount[a & 0xff]; +#endif +} + +int vector1BitDistanceHamming(const Vector *v1, const Vector *v2){ + int diff = 0; + u8 *e1U8 = v1->data; + u32 *e1U32 = v1->data; + u8 *e2U8 = v2->data; + u32 *e2U32 = v2->data; + int i, len8, len32, offset8; + + assert( v1->dims == v2->dims ); + assert( v1->type == VECTOR_TYPE_FLOAT1BIT ); + assert( v2->type == VECTOR_TYPE_FLOAT1BIT ); + + len8 = (v1->dims + 7) / 8; + len32 = v1->dims / 32; + offset8 = len32 * 4; + + for(i = 0; i < len32; i++){ + diff += sqlite3PopCount32(e1U32[i] ^ e2U32[i]); + } + for(i = offset8; i < len8; i++){ + diff += sqlite3PopCount32(e1U8[i] ^ e2U8[i]); + } + return diff; +} + +void vector1BitDeserializeFromBlob( + Vector *pVector, + const unsigned char *pBlob, + size_t nBlobSize +){ + u8 *elems = pVector->data; + + assert( pVector->type == VECTOR_TYPE_FLOAT1BIT ); + assert( 0 <= pVector->dims && pVector->dims <= MAX_VECTOR_SZ ); + assert( nBlobSize >= (pVector->dims + 7) / 8 ); + + memcpy(elems, pBlob, (pVector->dims + 7) / 8); +} + +#endif /* !defined(SQLITE_OMIT_VECTOR) */ + +/************** End of vectorfloat1bit.c *************************************/ /************** Begin file vectorfloat32.c ***********************************/ /* ** 2024-07-04 @@ -214183,7 +214183,6 @@ void vectorF64DeserializeFromBlob( ** ** libSQL vector search. */ -/* #include "vectorInt.h" */ #ifndef SQLITE_OMIT_VECTOR /* #include "sqlite3.h" */ /* #include "vdbeInt.h" */ diff --git a/libsql-sqlite3/Makefile.in b/libsql-sqlite3/Makefile.in index 0afadd458f..db1e2c55ce 100644 --- a/libsql-sqlite3/Makefile.in +++ b/libsql-sqlite3/Makefile.in @@ -195,7 +195,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \ sqlite3session.lo select.lo sqlite3rbu.lo status.lo stmt.lo \ table.lo threads.lo tokenize.lo treeview.lo trigger.lo \ update.lo userauth.lo upsert.lo util.lo vacuum.lo \ - vector.lo vectorfloat32.lo vectorfloat64.lo vector1bit.lo \ + vector.lo vectorfloat32.lo vectorfloat64.lo vectorfloat1bit.lo \ vectorIndex.lo vectordiskann.lo vectorvtab.lo \ vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \ vdbetrace.lo vdbevtab.lo \ @@ -302,8 +302,8 @@ SRC = \ $(TOP)/src/util.c \ $(TOP)/src/vacuum.c \ $(TOP)/src/vector.c \ - $(TOP)/src/vector1bit.c \ $(TOP)/src/vectorInt.h \ + $(TOP)/src/vectorfloat1bit.c \ $(TOP)/src/vectorfloat32.c \ $(TOP)/src/vectorfloat64.c \ $(TOP)/src/vectorIndexInt.h \ @@ -1139,8 +1139,8 @@ vacuum.lo: $(TOP)/src/vacuum.c $(HDR) vector.lo: $(TOP)/src/vector.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vector.c -vector1bit.lo: $(TOP)/src/vector1bit.c $(HDR) - $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vector1bit.c +vectorfloat1bit.lo: $(TOP)/src/vectorfloat1bit.c $(HDR) + $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vectorfloat1bit.c vectorfloat32.lo: $(TOP)/src/vectorfloat32.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vectorfloat32.c diff --git a/libsql-sqlite3/src/vectorIndex.c b/libsql-sqlite3/src/vectorIndex.c index a9801c4e60..a253d0d12b 100644 --- a/libsql-sqlite3/src/vectorIndex.c +++ b/libsql-sqlite3/src/vectorIndex.c @@ -24,7 +24,6 @@ ** ** libSQL vector search. */ -#include "vectorInt.h" #ifndef SQLITE_OMIT_VECTOR #include "sqlite3.h" #include "vdbeInt.h" diff --git a/libsql-sqlite3/src/vector1bit.c b/libsql-sqlite3/src/vectorfloat1bit.c similarity index 100% rename from libsql-sqlite3/src/vector1bit.c rename to libsql-sqlite3/src/vectorfloat1bit.c diff --git a/libsql-sqlite3/tool/mksqlite3c.tcl b/libsql-sqlite3/tool/mksqlite3c.tcl index 3a04459e31..fe76abc0a8 100644 --- a/libsql-sqlite3/tool/mksqlite3c.tcl +++ b/libsql-sqlite3/tool/mksqlite3c.tcl @@ -468,8 +468,8 @@ set flist { json.c vector.c - vector1bit.c vectordiskann.c + vectorfloat1bit.c vectorfloat32.c vectorfloat64.c vectorIndex.c diff --git a/libsql-sqlite3/tool/showwal b/libsql-sqlite3/tool/showwal new file mode 100755 index 0000000000000000000000000000000000000000..0687a4159570659c43bc62bd066c82c673c18e26 GIT binary patch literal 54760 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 EKTKO&M*si- literal 0 HcmV?d00001 From 8604065adb101a44043d73b70e4c838788236a93 Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Tue, 13 Aug 2024 12:11:58 +0400 Subject: [PATCH 20/20] allow any neighbor compression types --- libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c | 4 +--- libsql-ffi/bundled/src/sqlite3.c | 4 +--- libsql-sqlite3/src/vectordiskann.c | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c index 477758b4cc..e48ad61292 100644 --- a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c +++ b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c @@ -213594,11 +213594,9 @@ int diskAnnOpenIndex( if( compressNeighbours == 0 ){ pIndex->nEdgeVectorType = pIndex->nNodeVectorType; pIndex->nEdgeVectorSize = pIndex->nNodeVectorSize; - }else if( compressNeighbours == VECTOR_TYPE_FLOAT1BIT ){ + }else{ pIndex->nEdgeVectorType = compressNeighbours; pIndex->nEdgeVectorSize = vectorDataSize(compressNeighbours, pIndex->nVectorDims); - }else{ - return SQLITE_ERROR; } *ppIndex = pIndex; diff --git a/libsql-ffi/bundled/src/sqlite3.c b/libsql-ffi/bundled/src/sqlite3.c index 477758b4cc..e48ad61292 100644 --- a/libsql-ffi/bundled/src/sqlite3.c +++ b/libsql-ffi/bundled/src/sqlite3.c @@ -213594,11 +213594,9 @@ int diskAnnOpenIndex( if( compressNeighbours == 0 ){ pIndex->nEdgeVectorType = pIndex->nNodeVectorType; pIndex->nEdgeVectorSize = pIndex->nNodeVectorSize; - }else if( compressNeighbours == VECTOR_TYPE_FLOAT1BIT ){ + }else{ pIndex->nEdgeVectorType = compressNeighbours; pIndex->nEdgeVectorSize = vectorDataSize(compressNeighbours, pIndex->nVectorDims); - }else{ - return SQLITE_ERROR; } *ppIndex = pIndex; diff --git a/libsql-sqlite3/src/vectordiskann.c b/libsql-sqlite3/src/vectordiskann.c index c6e2d5156f..5f30806db3 100644 --- a/libsql-sqlite3/src/vectordiskann.c +++ b/libsql-sqlite3/src/vectordiskann.c @@ -1749,11 +1749,9 @@ int diskAnnOpenIndex( if( compressNeighbours == 0 ){ pIndex->nEdgeVectorType = pIndex->nNodeVectorType; pIndex->nEdgeVectorSize = pIndex->nNodeVectorSize; - }else if( compressNeighbours == VECTOR_TYPE_FLOAT1BIT ){ + }else{ pIndex->nEdgeVectorType = compressNeighbours; pIndex->nEdgeVectorSize = vectorDataSize(compressNeighbours, pIndex->nVectorDims); - }else{ - return SQLITE_ERROR; } *ppIndex = pIndex;