Compare commits

..

2 Commits

Author SHA1 Message Date
Andrew Kane
cd8d04359a fp16 2024-03-30 16:15:11 -07:00
Andrew Kane
eeeacc771b Test 2024-03-30 16:00:19 -07:00
8 changed files with 33 additions and 160 deletions

View File

@@ -8,16 +8,8 @@ jobs:
fail-fast: false
matrix:
include:
- postgres: 17
os: ubuntu-22.04
- postgres: 16
os: ubuntu-22.04
- postgres: 15
os: ubuntu-22.04
- postgres: 14
os: ubuntu-22.04
- postgres: 13
os: ubuntu-20.04
- postgres: 12
os: ubuntu-20.04
steps:
@@ -32,37 +24,6 @@ jobs:
- run: |
export PG_CONFIG=`which pg_config`
sudo --preserve-env=PG_CONFIG make install
- run: make installcheck
- if: ${{ failure() }}
run: cat regression.diffs
- run: |
sudo apt-get update
sudo apt-get install libipc-run-perl
- run: make prove_installcheck
mac:
runs-on: macos-latest
if: ${{ !startsWith(github.ref_name, 'windows') }}
steps:
- uses: actions/checkout@v4
- uses: ankane/setup-postgres@v1
with:
postgres-version: 14
- run: make
env:
PG_CFLAGS: -DUSE_ASSERT_CHECKING -Wall -Wextra -Werror -Wno-unused-parameter
- run: make install
- run: make installcheck
- if: ${{ failure() }}
run: cat regression.diffs
- run: |
brew install cpanm
cpanm --notest IPC::Run
wget -q https://github.com/postgres/postgres/archive/refs/tags/REL_14_10.tar.gz
tar xf REL_14_10.tar.gz
- run: make prove_installcheck PROVE_FLAGS="-I ./postgres-REL_14_10/src/test/perl" PERL5LIB="/Users/runner/perl5/lib/perl5"
- run: make clean && /usr/local/opt/llvm@15/bin/scan-build --status-bugs make
env:
PG_CFLAGS: -DUSE_ASSERT_CHECKING
windows:
runs-on: windows-latest
if: ${{ !startsWith(github.ref_name, 'mac') }}
@@ -95,20 +56,5 @@ jobs:
git fetch origin ${{ github.ref }}
git reset --hard FETCH_HEAD
make
make install
chown -R postgres .
sudo -u postgres make installcheck
sudo -u postgres make prove_installcheck
env:
PG_CFLAGS: -DUSE_ASSERT_CHECKING -Wall -Wextra -Werror -Wno-unused-parameter -Wno-sign-compare
valgrind:
if: ${{ !startsWith(github.ref_name, 'mac') && !startsWith(github.ref_name, 'windows') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ankane/setup-postgres-valgrind@v1
with:
postgres-version: 16
- run: make
- run: sudo --preserve-env=PG_CONFIG make install
- run: make installcheck

View File

@@ -400,29 +400,6 @@ Use [partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html
CREATE TABLE items (embedding vector(3), category_id int) PARTITION BY LIST(category_id);
```
## Types
- `vector`
- `halfvec`
## Half-Precision
```sql
CREATE TABLE items (id bigserial PRIMARY KEY, embedding halfvec(3));
INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');
CREATE INDEX ON items USING hnsw ((embedding::halfvec(3)) halfvec_l2_ops);
```
```sql
SELECT id FROM items ORDER BY embedding::halfvec(3) <-> '[1,2,3]' LIMIT 5;
```
```sql
SELECT id FROM (
SELECT * FROM items ORDER BY embedding::halfvec(3) <-> '[1,2,3]' LIMIT 20
) ORDER BY embedding <-> '[1,2,3]' LIMIT 5;
```
## Hybrid Search
Use together with Postgres [full-text search](https://www.postgresql.org/docs/current/textsearch-intro.html) for hybrid search.

View File

@@ -104,30 +104,13 @@ HalfToFloat4(half num)
/* TODO Improve performance */
/* Assumes same endianness for floats and integers */
union
{
float f;
uint32 i;
} swapfloat;
union
{
half h;
uint16 i;
} swaphalf;
uint16 bin;
uint32 exponent;
uint32 mantissa;
uint32 result;
swaphalf.h = num;
bin = swaphalf.i;
exponent = (bin & 0x7C00) >> 10;
mantissa = bin & 0x03FF;
/* TODO Use union to swap */
uint16 bin = *((uint16 *) &num);
uint32 exponent = (bin & 0x7C00) >> 10;
uint32 mantissa = bin & 0x03FF;
/* Sign */
result = (bin & 0x8000) << 16;
uint32 result = (bin & 0x8000) << 16;
if (exponent == 31)
{
@@ -173,8 +156,8 @@ HalfToFloat4(half num)
result |= mantissa << 13;
}
swapfloat.i = result;
return swapfloat.f;
/* TODO Use union to swap */
return *((float *) &result);
#endif
}
@@ -190,30 +173,13 @@ Float4ToHalfUnchecked(float num)
/* TODO Improve performance */
/* Assumes same endianness for floats and integers */
union
{
float f;
uint32 i;
} swapfloat;
union
{
half h;
uint16 i;
} swaphalf;
uint32 bin;
int exponent;
int mantissa;
uint16 result;
swapfloat.f = num;
bin = swapfloat.i;
exponent = (bin & 0x7F800000) >> 23;
mantissa = bin & 0x007FFFFF;
/* TODO Use union to swap */
uint32 bin = *((uint32 *) &num);
int exponent = (bin & 0x7F800000) >> 23;
int mantissa = bin & 0x007FFFFF;
/* Sign */
result = (bin & 0x80000000) >> 16;
uint16 result = (bin & 0x80000000) >> 16;
if (isinf(num))
{
@@ -272,8 +238,8 @@ Float4ToHalfUnchecked(float num)
}
}
swaphalf.i = result;
return swaphalf.h;
/* TODO Use union to swap */
return *((half *) & result);
#endif
}
@@ -512,9 +478,6 @@ halfvec_in(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(result);
}
#define AppendChar(ptr, c) (*(ptr)++ = (c))
#define AppendFloat(ptr, f) ((ptr) += float_to_shortest_decimal_bufn((f), (ptr)))
/*
* Convert internal representation to textual representation
*/
@@ -526,6 +489,7 @@ halfvec_out(PG_FUNCTION_ARGS)
int dim = vector->dim;
char *buf;
char *ptr;
int n;
/*
* Need:
@@ -540,17 +504,21 @@ halfvec_out(PG_FUNCTION_ARGS)
buf = (char *) palloc(FLOAT_SHORTEST_DECIMAL_LEN * dim + 2);
ptr = buf;
AppendChar(ptr, '[');
*ptr = '[';
ptr++;
for (int i = 0; i < dim; i++)
{
if (i > 0)
AppendChar(ptr, ',');
AppendFloat(ptr, HalfToFloat4(vector->x[i]));
{
*ptr = ',';
ptr++;
}
AppendChar(ptr, ']');
n = float_to_shortest_decimal_bufn(HalfToFloat4(vector->x[i]), ptr);
ptr += n;
}
*ptr = ']';
ptr++;
*ptr = '\0';
PG_FREE_IF_COPY(vector, 0);
@@ -763,18 +731,15 @@ Datum
vector_to_halfvec(PG_FUNCTION_ARGS)
{
Vector *vec = PG_GETARG_VECTOR_P(0);
int32 typmod = PG_GETARG_INT32(1);
HalfVector *result;
CheckDim(vec->dim);
CheckExpectedDim(typmod, vec->dim);
result = InitHalfVector(vec->dim);
for (int i = 0; i < vec->dim; i++)
{
result->x[i] = Float4ToHalfUnchecked(vec->x[i]);
/* TODO Better error for overflow */
CheckElement(result->x[i]);
}

View File

@@ -14,7 +14,7 @@
#define HALF_MAX FLT16_MAX
#else
/* TODO #pragma message("")? */
#define half uint16
#define half __fp16
#define HALF_MAX 65504
#endif

View File

@@ -541,11 +541,9 @@ Datum
halfvec_to_vector(PG_FUNCTION_ARGS)
{
HalfVector *vec = PG_GETARG_HALFVEC_P(0);
int32 typmod = PG_GETARG_INT32(1);
Vector *result;
CheckDim(vec->dim);
CheckExpectedDim(typmod, vec->dim);
result = InitVector(vec->dim);

View File

@@ -58,12 +58,6 @@ SELECT '[1,2,3]'::halfvec::vector;
[1,2,3]
(1 row)
SELECT '[1,2,3]'::vector::halfvec(2);
ERROR: expected 2 dimensions, not 3
SELECT '[1,2,3]'::halfvec::vector(2);
ERROR: expected 2 dimensions, not 3
SELECT '[65520]'::vector::halfvec;
ERROR: infinite value not allowed in halfvec
SELECT '[1e-8]'::vector::halfvec;
halfvec
---------

View File

@@ -12,9 +12,6 @@ SELECT '{{1}}'::real[]::vector;
SELECT '[1,2,3]'::vector::real[];
SELECT '[1,2,3]'::vector::halfvec;
SELECT '[1,2,3]'::halfvec::vector;
SELECT '[1,2,3]'::vector::halfvec(2);
SELECT '[1,2,3]'::halfvec::vector(2);
SELECT '[65520]'::vector::halfvec;
SELECT '[1e-8]'::vector::halfvec;
SELECT array_agg(n)::vector FROM generate_series(1, 16001) n;
SELECT array_to_vector(array_agg(n), 16001, false) FROM generate_series(1, 16001) n;

View File

@@ -8,8 +8,6 @@ my $node;
my @queries = ();
my @expected;
my $limit = 20;
my $dim = 10;
my $array_sql = join(",", ('random()') x $dim);
sub test_recall
{
@@ -54,20 +52,18 @@ $node->start;
# Create table
$node->safe_psql("postgres", "CREATE EXTENSION vector;");
$node->safe_psql("postgres", "CREATE TABLE tst (i int4, v halfvec($dim));");
$node->safe_psql("postgres", "CREATE TABLE tst (i int4, v halfvec(3));");
$node->safe_psql("postgres",
"INSERT INTO tst SELECT i, ARRAY[$array_sql] FROM generate_series(1, 10000) i;"
"INSERT INTO tst SELECT i, ARRAY[random(), random(), random()] FROM generate_series(1, 10000) i;"
);
# Generate queries
for (1 .. 20)
{
my @r = ();
for (1 .. $dim)
{
push(@r, rand());
}
push(@queries, "[" . join(",", @r) . "]");
my $r1 = rand();
my $r2 = rand();
my $r3 = rand();
push(@queries, "[$r1,$r2,$r3]");
}
# Check each index type
@@ -94,7 +90,7 @@ for my $i (0 .. $#operators)
));
# Test approximate results
my $min = $operator eq "<#>" ? 0.95 : 0.99;
my $min = $operator eq "<#>" ? 0.80 : ($operator eq "<=>" ? 0.80 : 0.99);
test_recall($min, $operator);
$node->safe_psql("postgres", "DROP INDEX idx;");