use super::distance::{sparse_bm25, sparse_cosine, sparse_dot, sparse_euclidean, sparse_manhattan};
use super::types::SparseVec;
use pgrx::prelude::*;
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_dot")]
fn pg_sparse_dot(a: SparseVec, b: SparseVec) -> f32 {
sparse_dot(&a, &b)
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_cosine")]
fn pg_sparse_cosine(a: SparseVec, b: SparseVec) -> f32 {
sparse_cosine(&a, &b)
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_euclidean")]
fn pg_sparse_euclidean(a: SparseVec, b: SparseVec) -> f32 {
sparse_euclidean(&a, &b)
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_manhattan")]
fn pg_sparse_manhattan(a: SparseVec, b: SparseVec) -> f32 {
sparse_manhattan(&a, &b)
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_to_sparse")]
fn pg_to_sparse(indices: Vec<i32>, values: Vec<f32>, dim: i32) -> SparseVec {
let indices: Vec<u32> = indices.into_iter().map(|i| i as u32).collect();
SparseVec::new(indices, values, dim as u32)
.unwrap_or_else(|e| panic!("Failed to create sparse vector: {}", e))
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_nnz")]
fn pg_sparse_nnz(sparse: SparseVec) -> i32 {
sparse.nnz() as i32
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_dim")]
fn pg_sparse_dim(sparse: SparseVec) -> i32 {
sparse.dim() as i32
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_norm")]
fn pg_sparse_norm(sparse: SparseVec) -> f32 {
sparse.norm()
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_top_k")]
fn pg_sparse_top_k(sparse: SparseVec, k: i32) -> SparseVec {
sparse.top_k(k as usize)
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_prune")]
fn pg_sparse_prune(sparse: SparseVec, threshold: f32) -> SparseVec {
let mut result = sparse;
result.prune(threshold);
result
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_dense_to_sparse")]
fn pg_dense_to_sparse(dense: Vec<f32>) -> SparseVec {
let mut indices = Vec::new();
let mut values = Vec::new();
for (i, &val) in dense.iter().enumerate() {
if val != 0.0 {
indices.push(i as u32);
values.push(val);
}
}
let dim = dense.len() as u32;
SparseVec::new(indices, values, dim)
.unwrap_or_else(|e| panic!("Failed to create sparse vector: {}", e))
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_to_dense")]
fn pg_sparse_to_dense(sparse: SparseVec) -> Vec<f32> {
sparse.to_dense()
}
#[pg_extern(immutable, parallel_safe, name = "ruvector_sparse_bm25")]
fn pg_sparse_bm25(
query: SparseVec,
doc: SparseVec,
doc_len: f32,
avg_doc_len: f32,
k1: default!(f32, 1.2),
b: default!(f32, 0.75),
) -> f32 {
sparse_bm25(&query, &doc, doc_len, avg_doc_len, k1, b)
}
#[cfg(feature = "pg_test")]
#[pg_schema]
mod tests {
use super::*;
#[pg_test]
fn test_pg_sparse_dot() {
let a = SparseVec::new(vec![0, 2, 5], vec![1.0, 2.0, 3.0], 10).unwrap();
let b = SparseVec::new(vec![2, 3, 5], vec![4.0, 5.0, 6.0], 10).unwrap();
let result = pg_sparse_dot(a, b);
assert!((result - 26.0).abs() < 1e-5);
}
#[pg_test]
fn test_pg_sparse_cosine() {
let a = SparseVec::new(vec![0, 1], vec![3.0, 4.0], 10).unwrap();
let b = SparseVec::new(vec![0, 1], vec![3.0, 4.0], 10).unwrap();
let result = pg_sparse_cosine(a, b);
assert!((result - 1.0).abs() < 1e-5);
}
#[pg_test]
fn test_pg_to_sparse() {
let indices = vec![1, 2, 5];
let values = vec![0.5, 0.3, 0.8];
let dim = 10;
let sparse = pg_to_sparse(indices, values, dim);
assert_eq!(sparse.nnz(), 3);
assert_eq!(sparse.dim(), 10);
}
#[pg_test]
fn test_pg_sparse_top_k() {
let sparse = SparseVec::new(vec![0, 1, 2, 3], vec![0.1, 0.5, 0.05, 0.8], 10).unwrap();
let top2 = pg_sparse_top_k(sparse, 2);
assert_eq!(top2.nnz(), 2);
}
#[pg_test]
fn test_pg_dense_to_sparse() {
let dense = vec![0.0, 0.5, 0.0, 0.3, 0.0];
let sparse = pg_dense_to_sparse(dense);
assert_eq!(sparse.nnz(), 2);
assert_eq!(sparse.get(1), 0.5);
assert_eq!(sparse.get(3), 0.3);
}
}