| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2026 Tiger Data, Inc. | ||
| 3 | * Licensed under the PostgreSQL License. See LICENSE for details. | ||
| 4 | * | ||
| 5 | * vec32.h - Vector type compatible with pgvector | ||
| 6 | * | ||
| 7 | * The struct layout is identical to pgvector's Vector type, enabling | ||
| 8 | * zero-copy interoperability when running inside PostgreSQL. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef VEC32_H | ||
| 12 | #define VEC32_H | ||
| 13 | |||
| 14 | #include <stdint.h> | ||
| 15 | #include <string.h> | ||
| 16 | |||
| 17 | #include "core/types.h" | ||
| 18 | |||
| 19 | #define VEC32_MAX_DIM 16000 | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Vec32: Binary-compatible with pgvector's Vector type. | ||
| 23 | * | ||
| 24 | * The struct layout is identical in both standalone and PostgreSQL modes. | ||
| 25 | * In standalone mode, vl_len_ stores the total size (not used as varlena). | ||
| 26 | * In PostgreSQL mode, vl_len_ is managed by SET_VARSIZE/VARSIZE macros. | ||
| 27 | */ | ||
| 28 | typedef struct Vec32 | ||
| 29 | { | ||
| 30 | int32_t vl_len_; /* varlena header / size in standalone mode */ | ||
| 31 | int16_t dim; /* number of dimensions */ | ||
| 32 | int16_t unused; /* reserved for future use, always zero */ | ||
| 33 | float x[]; /* flexible array member */ | ||
| 34 | } Vec32; | ||
| 35 | |||
| 36 | #define VEC32_SIZE(dim) (offsetof(Vec32, x) + sizeof(float) * (dim)) | ||
| 37 | #define VEC32_DIM(v) ((v)->dim) | ||
| 38 | #define VEC32_DATA(v) ((v)->x) | ||
| 39 | |||
| 40 | /* Convert to Vec32Ref for internal operations */ | ||
| 41 | static inline Vec32Ref | ||
| 42 | 136540 | Vec32ToRef(const Vec32 *v) | |
| 43 | { | ||
| 44 | 136540 | return (Vec32Ref){.data = v->x, .dim = (Dimension)v->dim}; | |
| 45 | } | ||
| 46 | |||
| 47 | /* Convert to VectorMut for mutable operations */ | ||
| 48 | static inline VectorMut | ||
| 49 | Vec32ToMut(Vec32 *v) | ||
| 50 | { | ||
| 51 | return (VectorMut){.data = v->x, .dim = (Dimension)v->dim}; | ||
| 52 | } | ||
| 53 | |||
| 54 | /* Allocation and lifecycle */ | ||
| 55 | Vec32 *vec32_create(Dimension dim); | ||
| 56 | Vec32 *vec32_copy(const Vec32 *src); | ||
| 57 | void vec32_free(Vec32 *v); | ||
| 58 | |||
| 59 | /* Initialization */ | ||
| 60 | void vec32_set(Vec32 *v, const float *values); | ||
| 61 | void vec32_zero(Vec32 *v); | ||
| 62 | void vec32_fill(Vec32 *v, float value); | ||
| 63 | |||
| 64 | /* Operations */ | ||
| 65 | float vec32_dot(const Vec32 *a, const Vec32 *b); | ||
| 66 | float vec32_norm(const Vec32 *v); | ||
| 67 | void vec32_normalize(Vec32 *v); | ||
| 68 | |||
| 69 | /* ---------------------------------------------------------------- | ||
| 70 | * Inline vtable for compile-time specialization | ||
| 71 | * | ||
| 72 | * These inline functions + static const vtable enable the | ||
| 73 | * compiler to inline through vtable function pointers when the | ||
| 74 | * pointer target is known at compile time. Used by k-means and | ||
| 75 | * other hot loops that dispatch once at the entry point. | ||
| 76 | * ---------------------------------------------------------------- */ | ||
| 77 | |||
| 78 | VS_VTABLE_INLINE float | ||
| 79 | 359024 | vs_f32_dot_product(const void *vec, const float *centroid, Dimension dim) | |
| 80 | { | ||
| 81 | 359024 | const float *v = (const float *)vec; | |
| 82 | 359024 | float sum = 0.0f; | |
| 83 |
2/8✓ Branch 0 taken 2890057 times.
✓ Branch 1 taken 359024 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
3249081 | for (Dimension d = 0; d < dim; d++) |
| 84 | 2890057 | sum += v[d] * centroid[d]; | |
| 85 |
0/6✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
359024 | return sum; |
| 86 | } | ||
| 87 | |||
| 88 | VS_VTABLE_INLINE float | ||
| 89 | 8002156 | vs_f32_l2_squared(const void *vec, const float *centroid, Dimension dim) | |
| 90 | { | ||
| 91 | 8002156 | const float *v = (const float *)vec; | |
| 92 | 8002156 | float sum = 0.0f; | |
| 93 |
2/2✓ Branch 0 taken 579590697 times.
✓ Branch 1 taken 8002156 times.
|
587592853 | for (Dimension d = 0; d < dim; d++) |
| 94 | { | ||
| 95 | 579590697 | float diff = v[d] - centroid[d]; | |
| 96 | 579590697 | sum += diff * diff; | |
| 97 | } | ||
| 98 | 8002156 | return sum; | |
| 99 | } | ||
| 100 | |||
| 101 | VS_VTABLE_INLINE float | ||
| 102 | 778198 | vs_f32_norm_sq(const void *vec, Dimension dim) | |
| 103 | { | ||
| 104 | 778198 | const float *v = (const float *)vec; | |
| 105 | 778198 | float sum = 0.0f; | |
| 106 |
2/2✓ Branch 0 taken 48007104 times.
✓ Branch 1 taken 778198 times.
|
48785302 | for (Dimension d = 0; d < dim; d++) |
| 107 | 48007104 | sum += v[d] * v[d]; | |
| 108 | 778198 | return sum; | |
| 109 | } | ||
| 110 | |||
| 111 | VS_VTABLE_INLINE void | ||
| 112 | 22800 | vs_f32_sum_to_float(const void *vec, float *accum, Dimension dim) | |
| 113 | { | ||
| 114 | 22800 | const float *v = (const float *)vec; | |
| 115 |
2/2✓ Branch 0 taken 136960 times.
✓ Branch 1 taken 22800 times.
|
159760 | for (Dimension d = 0; d < dim; d++) |
| 116 | 136960 | accum[d] += v[d]; | |
| 117 | 22800 | } | |
| 118 | |||
| 119 | VS_VTABLE_INLINE void | ||
| 120 | 16777 | vs_f32_to_float_one(const void *src, float *dst, Dimension dim) | |
| 121 | { | ||
| 122 | 16777 | memcpy(dst, src, (size_t)dim * sizeof(float)); | |
| 123 | 16777 | } | |
| 124 | |||
| 125 | VS_VTABLE_INLINE const float * | ||
| 126 | 780431 | vs_f32_to_float_block( | |
| 127 | const void *src, float *dst, uint32_t count, Dimension dim) | ||
| 128 | { | ||
| 129 | 780389 | (void)dst; | |
| 130 | 780389 | (void)count; | |
| 131 | 780389 | (void)dim; | |
| 132 | 780431 | return (const float *)src; | |
| 133 | } | ||
| 134 | |||
| 135 | static const Vec32TypeOps vs_f32_type_ops = { | ||
| 136 | .name = "float32", | ||
| 137 | .element_size = sizeof(float), | ||
| 138 | .dot_product = vs_f32_dot_product, | ||
| 139 | .l2_squared = vs_f32_l2_squared, | ||
| 140 | .norm_sq = vs_f32_norm_sq, | ||
| 141 | .sum_to_float = vs_f32_sum_to_float, | ||
| 142 | .to_float_one = vs_f32_to_float_one, | ||
| 143 | .to_float_block = vs_f32_to_float_block, | ||
| 144 | }; | ||
| 145 | |||
| 146 | #endif /* VEC32_H */ | ||
| 147 |