///|
/// Compute squared L2 distance without the final square root.
pub fn squared_euclidean_distance(
a : Array[Double],
b : Array[Double],
) -> Double raise VectorError {
if a.length() != b.length() {
raise DimensionMismatch("Squared distance dimensions do not match")
}
if a.length() == 0 {
raise EmptyVector
}
let mut total = 0.0
for i = 0; i < a.length(); i = i + 1 {
let delta = a[i] - b[i]
total = total + delta * delta
}
total
}
///|
/// Convert cosine similarity to cosine distance in [0, 2] for finite vectors.
pub fn cosine_distance(
a : Array[Double],
b : Array[Double],
) -> Double raise VectorError {
1.0 - cosine_similarity(a, b)
}
///|
/// Return whether every coordinate is exactly zero.
pub fn is_zero_vector(vector : Array[Double]) -> Bool {
for value in vector {
if value != 0.0 {
return false
}
}
true
}
///|
/// Sum coordinates across a non-empty vector set.
pub fn vector_sum(
vectors : Array[Array[Double]],
) -> Array[Double] raise VectorError {
if vectors.length() == 0 {
raise EmptyVector
}
let dimension = vectors[0].length()
if dimension == 0 {
raise EmptyVector
}
let sum = Array::make(dimension, 0.0)
for vector in vectors {
if vector.length() != dimension {
raise DimensionMismatch("Vector dimensions differ in sum")
}
for i = 0; i < dimension; i = i + 1 {
sum[i] = sum[i] + vector[i]
}
}
sum
}
///|
/// Center each vector by subtracting the corpus mean.
pub fn center_vectors(
vectors : Array[Array[Double]],
) -> Array[Array[Double]] raise VectorError {
let mean = vector_mean(vectors)
let centered = []
for vector in vectors {
centered.push(vector_subtract(vector, mean))
}
centered
}