diff --git a/README.md b/README.md index 42cba82..c4ce67e 100644 --- a/README.md +++ b/README.md @@ -882,6 +882,9 @@ Each half vector takes `2 * dimensions + 8` bytes of storage. Each element is a Operator | Description | Added --- | --- | --- +\+ | element-wise addition | unreleased +\- | element-wise subtraction | unreleased +\* | element-wise multiplication | unreleased <-> | Euclidean distance | unreleased <#> | negative inner product | unreleased <=> | cosine distance | unreleased @@ -891,6 +894,8 @@ Operator | Description | Added Function | Description | Added --- | --- | --- cosine_distance(halfvec, halfvec) → double precision | cosine distance | unreleased +halfvec_dims(halfvec) → integer | number of dimensions | unreleased +halfvec_norm(halfvec) → double precision | Euclidean norm | unreleased inner_product(halfvec, halfvec) → double precision | inner product | unreleased l2_distance(halfvec, halfvec) → double precision | Euclidean distance | unreleased l1_distance(halfvec, halfvec) → double precision | taxicab distance | unreleased diff --git a/sql/vector--0.6.2--0.7.0.sql b/sql/vector--0.6.2--0.7.0.sql index cc641ed..d5b4e6b 100644 --- a/sql/vector--0.6.2--0.7.0.sql +++ b/sql/vector--0.6.2--0.7.0.sql @@ -71,15 +71,48 @@ CREATE FUNCTION cosine_distance(halfvec, halfvec) RETURNS float8 CREATE FUNCTION l1_distance(halfvec, halfvec) RETURNS float8 AS 'MODULE_PATHNAME', 'halfvec_l1_distance' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE FUNCTION halfvec_dims(halfvec) RETURNS integer + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + CREATE FUNCTION halfvec_norm(halfvec) RETURNS float8 AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE FUNCTION halfvec_add(halfvec, halfvec) RETURNS halfvec + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_sub(halfvec, halfvec) RETURNS halfvec + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_mul(halfvec, halfvec) RETURNS halfvec + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + CREATE FUNCTION quantize_binary(halfvec) RETURNS bit AS 'MODULE_PATHNAME', 'halfvec_quantize_binary' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE FUNCTION subvector(halfvec, int, int) RETURNS halfvec AS 'MODULE_PATHNAME', 'halfvec_subvector' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE FUNCTION halfvec_lt(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_le(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_eq(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_ne(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_ge(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_gt(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_cmp(halfvec, halfvec) RETURNS int4 + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + CREATE FUNCTION halfvec_l2_squared_distance(halfvec, halfvec) RETURNS float8 AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; @@ -140,6 +173,56 @@ CREATE OPERATOR <=> ( COMMUTATOR = '<=>' ); +CREATE OPERATOR + ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_add, + COMMUTATOR = + +); + +CREATE OPERATOR - ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_sub +); + +CREATE OPERATOR * ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_mul, + COMMUTATOR = * +); + +CREATE OPERATOR < ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_lt, + COMMUTATOR = > , NEGATOR = >= , + RESTRICT = scalarltsel, JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_le, + COMMUTATOR = >= , NEGATOR = > , + RESTRICT = scalarlesel, JOIN = scalarlejoinsel +); + +CREATE OPERATOR = ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_eq, + COMMUTATOR = = , NEGATOR = <> , + RESTRICT = eqsel, JOIN = eqjoinsel +); + +CREATE OPERATOR <> ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_ne, + COMMUTATOR = <> , NEGATOR = = , + RESTRICT = eqsel, JOIN = eqjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_ge, + COMMUTATOR = <= , NEGATOR = < , + RESTRICT = scalargesel, JOIN = scalargejoinsel +); + +CREATE OPERATOR > ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_gt, + COMMUTATOR = < , NEGATOR = <= , + RESTRICT = scalargtsel, JOIN = scalargtjoinsel +); + CREATE OPERATOR CLASS halfvec_l2_ops FOR TYPE halfvec USING ivfflat AS OPERATOR 1 <-> (halfvec, halfvec) FOR ORDER BY float_ops, @@ -184,7 +267,7 @@ CREATE FUNCTION vector_to_halfvec(vector, integer, boolean) RETURNS halfvec AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE CAST (halfvec AS vector) - WITH FUNCTION halfvec_to_vector(halfvec, integer, boolean) AS IMPLICIT; + WITH FUNCTION halfvec_to_vector(halfvec, integer, boolean) AS ASSIGNMENT; CREATE CAST (vector AS halfvec) WITH FUNCTION vector_to_halfvec(vector, integer, boolean) AS IMPLICIT; diff --git a/sql/vector.sql b/sql/vector.sql index a0d59dd..397c839 100644 --- a/sql/vector.sql +++ b/sql/vector.sql @@ -364,9 +364,21 @@ CREATE FUNCTION cosine_distance(halfvec, halfvec) RETURNS float8 CREATE FUNCTION l1_distance(halfvec, halfvec) RETURNS float8 AS 'MODULE_PATHNAME', 'halfvec_l1_distance' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE FUNCTION halfvec_dims(halfvec) RETURNS integer + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + CREATE FUNCTION halfvec_norm(halfvec) RETURNS float8 AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE FUNCTION halfvec_add(halfvec, halfvec) RETURNS halfvec + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_sub(halfvec, halfvec) RETURNS halfvec + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_mul(halfvec, halfvec) RETURNS halfvec + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + CREATE FUNCTION quantize_binary(halfvec) RETURNS bit AS 'MODULE_PATHNAME', 'halfvec_quantize_binary' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; @@ -375,6 +387,27 @@ CREATE FUNCTION subvector(halfvec, int, int) RETURNS halfvec -- halfvec private functions +CREATE FUNCTION halfvec_lt(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_le(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_eq(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_ne(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_ge(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_gt(halfvec, halfvec) RETURNS bool + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION halfvec_cmp(halfvec, halfvec) RETURNS int4 + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + CREATE FUNCTION halfvec_l2_squared_distance(halfvec, halfvec) RETURNS float8 AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; @@ -441,6 +474,56 @@ CREATE OPERATOR <=> ( COMMUTATOR = '<=>' ); +CREATE OPERATOR + ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_add, + COMMUTATOR = + +); + +CREATE OPERATOR - ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_sub +); + +CREATE OPERATOR * ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_mul, + COMMUTATOR = * +); + +CREATE OPERATOR < ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_lt, + COMMUTATOR = > , NEGATOR = >= , + RESTRICT = scalarltsel, JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_le, + COMMUTATOR = >= , NEGATOR = > , + RESTRICT = scalarlesel, JOIN = scalarlejoinsel +); + +CREATE OPERATOR = ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_eq, + COMMUTATOR = = , NEGATOR = <> , + RESTRICT = eqsel, JOIN = eqjoinsel +); + +CREATE OPERATOR <> ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_ne, + COMMUTATOR = <> , NEGATOR = = , + RESTRICT = eqsel, JOIN = eqjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_ge, + COMMUTATOR = <= , NEGATOR = < , + RESTRICT = scalargesel, JOIN = scalargejoinsel +); + +CREATE OPERATOR > ( + LEFTARG = halfvec, RIGHTARG = halfvec, PROCEDURE = halfvec_gt, + COMMUTATOR = < , NEGATOR = <= , + RESTRICT = scalargtsel, JOIN = scalargtjoinsel +); + -- halfvec opclasses CREATE OPERATOR CLASS halfvec_l2_ops @@ -489,7 +572,7 @@ CREATE FUNCTION vector_to_halfvec(vector, integer, boolean) RETURNS halfvec AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE CAST (halfvec AS vector) - WITH FUNCTION halfvec_to_vector(halfvec, integer, boolean) AS IMPLICIT; + WITH FUNCTION halfvec_to_vector(halfvec, integer, boolean) AS ASSIGNMENT; CREATE CAST (vector AS halfvec) WITH FUNCTION vector_to_halfvec(vector, integer, boolean) AS IMPLICIT; diff --git a/src/halfutils.h b/src/halfutils.h index 66ad23d..5881315 100644 --- a/src/halfutils.h +++ b/src/halfutils.h @@ -41,6 +41,19 @@ HalfIsInf(half num) #endif } +/* + * Check if half is zero + */ +static inline bool +HalfIsZero(half num) +{ +#ifdef FLT16_SUPPORT + return num == 0; +#else + return (num & 0x7FFF) == 0x0000; +#endif +} + /* * Convert a half to a float4 */ diff --git a/src/halfvec.c b/src/halfvec.c index cb4c8bf..725960e 100644 --- a/src/halfvec.c +++ b/src/halfvec.c @@ -146,6 +146,24 @@ halfvec_isspace(char ch) return false; } +#if PG_VERSION_NUM < 120003 +static pg_noinline void +float_overflow_error(void) +{ + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value out of range: overflow"))); +} + +static pg_noinline void +float_underflow_error(void) +{ + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value out of range: underflow"))); +} +#endif + /* * Convert textual representation to internal representation */ @@ -677,6 +695,18 @@ halfvec_l1_distance(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8((double) distance); } +/* + * Get the dimensions of a half vector + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_dims); +Datum +halfvec_dims(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + + PG_RETURN_INT32(a->dim); +} + /* * Get the L2 norm of a half vector */ @@ -699,6 +729,126 @@ halfvec_norm(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(sqrt(norm)); } +/* + * Add half vectors + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_add); +Datum +halfvec_add(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + HalfVector *b = PG_GETARG_HALFVEC_P(1); + half *ax = a->x; + half *bx = b->x; + HalfVector *result; + half *rx; + + CheckDims(a, b); + + result = InitHalfVector(a->dim); + rx = result->x; + + /* Auto-vectorized */ + for (int i = 0, imax = a->dim; i < imax; i++) + { +#ifdef FLT16_SUPPORT + rx[i] = ax[i] + bx[i]; +#else + rx[i] = Float4ToHalfUnchecked(HalfToFloat4(ax[i]) + HalfToFloat4(bx[i])); +#endif + } + + /* Check for overflow */ + for (int i = 0, imax = a->dim; i < imax; i++) + { + if (HalfIsInf(rx[i])) + float_overflow_error(); + } + + PG_RETURN_POINTER(result); +} + +/* + * Subtract half vectors + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_sub); +Datum +halfvec_sub(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + HalfVector *b = PG_GETARG_HALFVEC_P(1); + half *ax = a->x; + half *bx = b->x; + HalfVector *result; + half *rx; + + CheckDims(a, b); + + result = InitHalfVector(a->dim); + rx = result->x; + + /* Auto-vectorized */ + for (int i = 0, imax = a->dim; i < imax; i++) + { +#ifdef FLT16_SUPPORT + rx[i] = ax[i] - bx[i]; +#else + rx[i] = Float4ToHalfUnchecked(HalfToFloat4(ax[i]) - HalfToFloat4(bx[i])); +#endif + } + + /* Check for overflow */ + for (int i = 0, imax = a->dim; i < imax; i++) + { + if (HalfIsInf(rx[i])) + float_overflow_error(); + } + + PG_RETURN_POINTER(result); +} + +/* + * Multiply half vectors + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_mul); +Datum +halfvec_mul(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + HalfVector *b = PG_GETARG_HALFVEC_P(1); + half *ax = a->x; + half *bx = b->x; + HalfVector *result; + half *rx; + + CheckDims(a, b); + + result = InitHalfVector(a->dim); + rx = result->x; + + /* Auto-vectorized */ + for (int i = 0, imax = a->dim; i < imax; i++) + { +#ifdef FLT16_SUPPORT + rx[i] = ax[i] * bx[i]; +#else + rx[i] = Float4ToHalfUnchecked(HalfToFloat4(ax[i]) * HalfToFloat4(bx[i])); +#endif + } + + /* Check for overflow and underflow */ + for (int i = 0, imax = a->dim; i < imax; i++) + { + if (HalfIsInf(rx[i])) + float_overflow_error(); + + if (HalfIsZero(rx[i]) && !(HalfIsZero(ax[i]) || HalfIsZero(bx[i]))) + float_underflow_error(); + } + + PG_RETURN_POINTER(result); +} + /* * Quantize a half vector */ @@ -775,3 +925,94 @@ halfvec_cmp_internal(HalfVector * a, HalfVector * b) return 0; } + +/* + * Less than + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_lt); +Datum +halfvec_lt(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + HalfVector *b = PG_GETARG_HALFVEC_P(1); + + PG_RETURN_BOOL(halfvec_cmp_internal(a, b) < 0); +} + +/* + * Less than or equal + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_le); +Datum +halfvec_le(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + HalfVector *b = PG_GETARG_HALFVEC_P(1); + + PG_RETURN_BOOL(halfvec_cmp_internal(a, b) <= 0); +} + +/* + * Equal + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_eq); +Datum +halfvec_eq(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + HalfVector *b = PG_GETARG_HALFVEC_P(1); + + PG_RETURN_BOOL(halfvec_cmp_internal(a, b) == 0); +} + +/* + * Not equal + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_ne); +Datum +halfvec_ne(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + HalfVector *b = PG_GETARG_HALFVEC_P(1); + + PG_RETURN_BOOL(halfvec_cmp_internal(a, b) != 0); +} + +/* + * Greater than or equal + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_ge); +Datum +halfvec_ge(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + HalfVector *b = PG_GETARG_HALFVEC_P(1); + + PG_RETURN_BOOL(halfvec_cmp_internal(a, b) >= 0); +} + +/* + * Greater than + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_gt); +Datum +halfvec_gt(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + HalfVector *b = PG_GETARG_HALFVEC_P(1); + + PG_RETURN_BOOL(halfvec_cmp_internal(a, b) > 0); +} + +/* + * Compare half vectors + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(halfvec_cmp); +Datum +halfvec_cmp(PG_FUNCTION_ARGS) +{ + HalfVector *a = PG_GETARG_HALFVEC_P(0); + HalfVector *b = PG_GETARG_HALFVEC_P(1); + + PG_RETURN_INT32(halfvec_cmp_internal(a, b)); +} diff --git a/test/expected/halfvec_functions.out b/test/expected/halfvec_functions.out index 7bd76e5..70d904a 100644 --- a/test/expected/halfvec_functions.out +++ b/test/expected/halfvec_functions.out @@ -1,3 +1,149 @@ +SELECT '[1,2,3]'::halfvec + '[4,5,6]'; + ?column? +---------- + [5,7,9] +(1 row) + +SELECT '[65519]'::halfvec + '[65519]'; +ERROR: value out of range: overflow +SELECT '[1,2,3]'::halfvec - '[4,5,6]'; + ?column? +------------ + [-3,-3,-3] +(1 row) + +SELECT '[-65519]'::halfvec - '[65519]'; +ERROR: value out of range: overflow +SELECT '[1,2,3]'::halfvec * '[4,5,6]'; + ?column? +----------- + [4,10,18] +(1 row) + +SELECT '[65519]'::halfvec * '[65519]'; +ERROR: value out of range: overflow +SELECT '[1e-7]'::halfvec * '[1e-7]'; +ERROR: value out of range: underflow +SELECT '[1,2,3]'::halfvec < '[1,2,3]'; + ?column? +---------- + f +(1 row) + +SELECT '[1,2,3]'::halfvec < '[1,2]'; + ?column? +---------- + f +(1 row) + +SELECT '[1,2,3]'::halfvec <= '[1,2,3]'; + ?column? +---------- + t +(1 row) + +SELECT '[1,2,3]'::halfvec <= '[1,2]'; + ?column? +---------- + f +(1 row) + +SELECT '[1,2,3]'::halfvec = '[1,2,3]'; + ?column? +---------- + t +(1 row) + +SELECT '[1,2,3]'::halfvec = '[1,2]'; + ?column? +---------- + f +(1 row) + +SELECT '[1,2,3]'::halfvec != '[1,2,3]'; + ?column? +---------- + f +(1 row) + +SELECT '[1,2,3]'::halfvec != '[1,2]'; + ?column? +---------- + t +(1 row) + +SELECT '[1,2,3]'::halfvec >= '[1,2,3]'; + ?column? +---------- + t +(1 row) + +SELECT '[1,2,3]'::halfvec >= '[1,2]'; + ?column? +---------- + t +(1 row) + +SELECT '[1,2,3]'::halfvec > '[1,2,3]'; + ?column? +---------- + f +(1 row) + +SELECT '[1,2,3]'::halfvec > '[1,2]'; + ?column? +---------- + t +(1 row) + +SELECT halfvec_cmp('[1,2,3]', '[1,2,3]'); + halfvec_cmp +------------- + 0 +(1 row) + +SELECT halfvec_cmp('[1,2,3]', '[0,0,0]'); + halfvec_cmp +------------- + 1 +(1 row) + +SELECT halfvec_cmp('[0,0,0]', '[1,2,3]'); + halfvec_cmp +------------- + -1 +(1 row) + +SELECT halfvec_cmp('[1,2]', '[1,2,3]'); + halfvec_cmp +------------- + -1 +(1 row) + +SELECT halfvec_cmp('[1,2,3]', '[1,2]'); + halfvec_cmp +------------- + 1 +(1 row) + +SELECT halfvec_cmp('[1,2]', '[2,3,4]'); + halfvec_cmp +------------- + -1 +(1 row) + +SELECT halfvec_cmp('[2,3]', '[1,2,3]'); + halfvec_cmp +------------- + 1 +(1 row) + +SELECT halfvec_dims('[1,2,3]'::halfvec); + halfvec_dims +-------------- + 3 +(1 row) + SELECT round(halfvec_norm('[1,1]')::numeric, 5); round --------- diff --git a/test/sql/halfvec_functions.sql b/test/sql/halfvec_functions.sql index d35bc87..9f4943b 100644 --- a/test/sql/halfvec_functions.sql +++ b/test/sql/halfvec_functions.sql @@ -1,3 +1,34 @@ +SELECT '[1,2,3]'::halfvec + '[4,5,6]'; +SELECT '[65519]'::halfvec + '[65519]'; +SELECT '[1,2,3]'::halfvec - '[4,5,6]'; +SELECT '[-65519]'::halfvec - '[65519]'; +SELECT '[1,2,3]'::halfvec * '[4,5,6]'; +SELECT '[65519]'::halfvec * '[65519]'; +SELECT '[1e-7]'::halfvec * '[1e-7]'; + +SELECT '[1,2,3]'::halfvec < '[1,2,3]'; +SELECT '[1,2,3]'::halfvec < '[1,2]'; +SELECT '[1,2,3]'::halfvec <= '[1,2,3]'; +SELECT '[1,2,3]'::halfvec <= '[1,2]'; +SELECT '[1,2,3]'::halfvec = '[1,2,3]'; +SELECT '[1,2,3]'::halfvec = '[1,2]'; +SELECT '[1,2,3]'::halfvec != '[1,2,3]'; +SELECT '[1,2,3]'::halfvec != '[1,2]'; +SELECT '[1,2,3]'::halfvec >= '[1,2,3]'; +SELECT '[1,2,3]'::halfvec >= '[1,2]'; +SELECT '[1,2,3]'::halfvec > '[1,2,3]'; +SELECT '[1,2,3]'::halfvec > '[1,2]'; + +SELECT halfvec_cmp('[1,2,3]', '[1,2,3]'); +SELECT halfvec_cmp('[1,2,3]', '[0,0,0]'); +SELECT halfvec_cmp('[0,0,0]', '[1,2,3]'); +SELECT halfvec_cmp('[1,2]', '[1,2,3]'); +SELECT halfvec_cmp('[1,2,3]', '[1,2]'); +SELECT halfvec_cmp('[1,2]', '[2,3,4]'); +SELECT halfvec_cmp('[2,3]', '[1,2,3]'); + +SELECT halfvec_dims('[1,2,3]'::halfvec); + SELECT round(halfvec_norm('[1,1]')::numeric, 5); SELECT halfvec_norm('[3,4]'); SELECT halfvec_norm('[0,1]');