diff --git a/CHANGELOG.md b/CHANGELOG.md index 79f4eb3..f07f466 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 0.5.0 (unreleased) - Added support for parallel index builds +- Added `l1_distance` function ## 0.4.4 (2023-06-12) diff --git a/README.md b/README.md index 99daf12..a1d9f6a 100644 --- a/README.md +++ b/README.md @@ -354,6 +354,7 @@ Function | Description cosine_distance(vector, vector) → double precision | cosine distance inner_product(vector, vector) → double precision | inner product l2_distance(vector, vector) → double precision | Euclidean distance +l1_distance(vector, vector) → double precision | Taxicab distance [unreleased] vector_dims(vector) → integer | number of dimensions vector_norm(vector) → double precision | Euclidean norm diff --git a/sql/vector--0.4.4--0.5.0.sql b/sql/vector--0.4.4--0.5.0.sql new file mode 100644 index 0000000..25a38f8 --- /dev/null +++ b/sql/vector--0.4.4--0.5.0.sql @@ -0,0 +1,5 @@ +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "ALTER EXTENSION vector UPDATE TO '0.5.0'" to load this file. \quit + +CREATE FUNCTION l1_distance(vector, vector) RETURNS float8 + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; diff --git a/sql/vector.sql b/sql/vector.sql index 6188e2e..d4cf04d 100644 --- a/sql/vector.sql +++ b/sql/vector.sql @@ -40,6 +40,9 @@ CREATE FUNCTION inner_product(vector, vector) RETURNS float8 CREATE FUNCTION cosine_distance(vector, vector) RETURNS float8 AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE FUNCTION l1_distance(vector, vector) RETURNS float8 + AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + CREATE FUNCTION vector_dims(vector) RETURNS integer AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; diff --git a/src/vector.c b/src/vector.c index 2bdd3fa..3b383be 100644 --- a/src/vector.c +++ b/src/vector.c @@ -641,6 +641,28 @@ vector_spherical_distance(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(acos(distance) / M_PI); } +/* + * Get the L1 distance between vectors + */ +PGDLLEXPORT PG_FUNCTION_INFO_V1(l1_distance); +Datum +l1_distance(PG_FUNCTION_ARGS) +{ + Vector *a = PG_GETARG_VECTOR_P(0); + Vector *b = PG_GETARG_VECTOR_P(1); + float *ax = a->x; + float *bx = b->x; + float distance = 0.0; + + CheckDims(a, b); + + /* Auto-vectorized */ + for (int i = 0; i < a->dim; i++) + distance += fabsf(ax[i] - bx[i]); + + PG_RETURN_FLOAT8((double) distance); +} + /* * Get the dimensions of a vector */ diff --git a/test/expected/functions.out b/test/expected/functions.out index 0272282..1a8a471 100644 --- a/test/expected/functions.out +++ b/test/expected/functions.out @@ -86,6 +86,20 @@ SELECT cosine_distance('[1,1]', '[-1,-1]'); SELECT cosine_distance('[1,2]', '[3]'); ERROR: different vector dimensions 2 and 1 +SELECT l1_distance('[0,0]', '[3,4]'); + l1_distance +------------- + 7 +(1 row) + +SELECT l1_distance('[0,0]', '[0,1]'); + l1_distance +------------- + 1 +(1 row) + +SELECT l1_distance('[1,2]', '[3]'); +ERROR: different vector dimensions 2 and 1 SELECT avg(v) FROM unnest(ARRAY['[1,2,3]'::vector, '[3,5,7]']) v; avg ----------- diff --git a/test/sql/functions.sql b/test/sql/functions.sql index e4d3317..324debb 100644 --- a/test/sql/functions.sql +++ b/test/sql/functions.sql @@ -22,6 +22,10 @@ SELECT cosine_distance('[1,1]', '[1,1]'); SELECT cosine_distance('[1,1]', '[-1,-1]'); SELECT cosine_distance('[1,2]', '[3]'); +SELECT l1_distance('[0,0]', '[3,4]'); +SELECT l1_distance('[0,0]', '[0,1]'); +SELECT l1_distance('[1,2]', '[3]'); + SELECT avg(v) FROM unnest(ARRAY['[1,2,3]'::vector, '[3,5,7]']) v; SELECT avg(v) FROM unnest(ARRAY['[1,2,3]'::vector, '[3,5,7]', NULL]) v; SELECT avg(v) FROM unnest(ARRAY[]::vector[]) v;