use std::ops::{Add, Sub, Neg, Mul, Index, IndexMut};
use super::kernels;
use crate::fixed_point::fixed_num::{Fixed, FixedNum};
use crate::fixed_point::width::Storage;
#[inline]
fn rotated<S: Storage, const F: u32>(a: Fixed<S, F>, b: Fixed<S, F>, c: Fixed<S, F>, d: Fixed<S, F>, subtract: bool) -> Fixed<S, F>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
let (p, q) = (a.raw().mul_wide(b.raw()), c.raw().mul_wide(d.raw()));
let sum = if subtract { Fixed::<S, F>::compute_checked_subtract(p, q) } else { Fixed::<S, F>::compute_checked_add(p, q) };
Fixed::from_raw(kernels::round_to_storage::<Fixed<S, F>>(sum.expect("FixedVector::rotate_pairs: overflow")))
}
#[derive(Clone, Debug, PartialEq)]
pub struct FixedVector<T> {
data: Vec<T>,
}
impl<S: Storage, const F: u32> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
pub fn new(dim: usize) -> Self {
Self {
data: vec![Fixed::ZERO; dim],
}
}
pub fn from_f32_slice(values: &[f32]) -> Self {
Self {
data: values.iter().map(|&v| Fixed::from_f32(v)).collect(),
}
}
pub fn from_slice(values: &[Fixed<S, F>]) -> Self {
Self {
data: values.to_vec(),
}
}
#[inline]
pub fn len(&self) -> usize {
self.data.len()
}
#[inline]
pub fn dimension(&self) -> usize {
self.data.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn dot(&self, other: &Self) -> Fixed<S, F> {
assert_eq!(self.len(), other.len(), "FixedVector::dot: dimension mismatch");
kernels::dot(&self.data, &other.data)
}
pub fn length_squared(&self) -> Fixed<S, F> {
self.dot(self)
}
pub fn length(&self) -> Fixed<S, F> {
let raw = Fixed::raw_slice(&self.data);
Fixed::from_raw(kernels::sqrt_dot::<Fixed<S, F>>(raw, raw).expect("FixedVector::length exceeds storage"))
}
pub fn normalize(&mut self) {
let raw = Fixed::raw_slice(&self.data);
let sum_sq = kernels::exact_dot::<Fixed<S, F>>(raw, raw).expect("FixedVector::normalize: squared length exceeds the compute tier");
assert!(!Fixed::<S, F>::compute_is_zero(&sum_sq), "FixedVector::normalize: zero vector");
let len = Fixed::<S, F>::sqrt_at_compute_tier(sum_sq);
let one = Fixed::<S, F>::one().raw().widen();
for v in &mut self.data {
let numer = S::widen_product(Fixed::<S, F>::upscale_to_compute(v.raw()), one);
*v = Fixed::from_raw(kernels::divide_to_storage_nearest::<Fixed<S, F>>(numer, len).expect("FixedVector::normalize: zero length"));
}
}
pub fn normalized(&self) -> Self {
let mut result = self.clone();
result.normalize();
result
}
pub fn map(&self, f: impl Fn(Fixed<S, F>) -> Fixed<S, F>) -> Self {
Self {
data: self.data.iter().map(|&v| f(v)).collect(),
}
}
pub fn iter(&self) -> std::slice::Iter<'_, Fixed<S, F>> {
self.data.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Fixed<S, F>> {
self.data.iter_mut()
}
pub fn metric_distance_safe(&self, other: &Self) -> Fixed<S, F> {
assert_eq!(self.len(), other.len(), "FixedVector::metric_distance_safe: dimension mismatch");
let diff_raw: Vec<S> = (0..self.len())
.map(|i| (self.data[i] - other.data[i]).raw())
.collect();
Fixed::from_raw(kernels::sqrt_dot::<Fixed<S, F>>(&diff_raw, &diff_raw).expect("metric distance exceeds storage"))
}
}
impl<S: Storage, const F: u32> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
pub fn length_fused(&self) -> Fixed<S, F> {
super::fused::sqrt_sum_sq(&self.data)
}
pub fn distance_to(&self, other: &Self) -> Fixed<S, F> {
assert_eq!(self.len(), other.len(), "FixedVector::distance_to: dimension mismatch");
super::fused::euclidean_distance(&self.data, &other.data)
}
}
impl<T> Index<usize> for FixedVector<T> {
type Output = T;
#[inline]
fn index(&self, idx: usize) -> &T {
&self.data[idx]
}
}
impl<T> IndexMut<usize> for FixedVector<T> {
#[inline]
fn index_mut(&mut self, idx: usize) -> &mut T {
&mut self.data[idx]
}
}
impl<T> Default for FixedVector<T> {
fn default() -> Self {
Self { data: Vec::new() }
}
}
impl<S: Storage, const F: u32> Add for FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Output = Self;
fn add(self, rhs: Self) -> Self {
assert_eq!(self.len(), rhs.len(), "FixedVector::add: dimension mismatch");
Self {
data: self.data.iter().zip(rhs.data.iter())
.map(|(&a, &b)| a + b).collect(),
}
}
}
impl<'a, 'b, S: Storage, const F: u32> Add<&'b FixedVector<Fixed<S, F>>> for &'a FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Output = FixedVector<Fixed<S, F>>;
fn add(self, rhs: &'b FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
assert_eq!(self.len(), rhs.len(), "FixedVector::add: dimension mismatch");
FixedVector {
data: self.data.iter().zip(rhs.data.iter())
.map(|(&a, &b)| a + b).collect(),
}
}
}
impl<S: Storage, const F: u32> Sub for FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Output = Self;
fn sub(self, rhs: Self) -> Self {
assert_eq!(self.len(), rhs.len(), "FixedVector::sub: dimension mismatch");
Self {
data: self.data.iter().zip(rhs.data.iter())
.map(|(&a, &b)| a - b).collect(),
}
}
}
impl<'a, 'b, S: Storage, const F: u32> Sub<&'b FixedVector<Fixed<S, F>>> for &'a FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Output = FixedVector<Fixed<S, F>>;
fn sub(self, rhs: &'b FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
assert_eq!(self.len(), rhs.len(), "FixedVector::sub: dimension mismatch");
FixedVector {
data: self.data.iter().zip(rhs.data.iter())
.map(|(&a, &b)| a - b).collect(),
}
}
}
impl<S: Storage, const F: u32> Neg for FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Output = Self;
fn neg(self) -> Self {
Self {
data: self.data.iter().map(|&v| -v).collect(),
}
}
}
impl<S: Storage, const F: u32> Neg for &FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Output = FixedVector<Fixed<S, F>>;
fn neg(self) -> FixedVector<Fixed<S, F>> {
FixedVector {
data: self.data.iter().map(|&v| -v).collect(),
}
}
}
impl<S: Storage, const F: u32> Mul<FixedVector<Fixed<S, F>>> for Fixed<S, F>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Output = FixedVector<Fixed<S, F>>;
fn mul(self, rhs: FixedVector<Fixed<S, F>>) -> FixedVector<Fixed<S, F>> {
FixedVector {
data: rhs.data.iter().map(|&v| self * v).collect(),
}
}
}
impl<S: Storage, const F: u32> Mul<Fixed<S, F>> for FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Output = Self;
fn mul(self, rhs: Fixed<S, F>) -> Self {
Self {
data: self.data.iter().map(|&v| v * rhs).collect(),
}
}
}
impl<S: Storage, const F: u32> Mul<Fixed<S, F>> for &FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
type Output = FixedVector<Fixed<S, F>>;
fn mul(self, rhs: Fixed<S, F>) -> FixedVector<Fixed<S, F>> {
FixedVector {
data: self.data.iter().map(|&v| v * rhs).collect(),
}
}
}
impl<S: Storage, const F: u32> FixedVector<Fixed<S, F>>
where
Fixed<S, F>: FixedNum<Storage = S>,
{
pub fn dot_precise(&self, other: &Self) -> Fixed<S, F> {
assert_eq!(self.len(), other.len(), "FixedVector::dot_precise: dimension mismatch");
kernels::dot(&self.data, &other.data)
}
pub fn cross(&self, other: &Self) -> Self {
assert_eq!(self.len(), 3, "FixedVector::cross: self must be 3D");
assert_eq!(other.len(), 3, "FixedVector::cross: other must be 3D");
let (u, v) = (&self.data, &other.data);
let component = |i: usize, j: usize| {
let first = kernels::exact_dot::<Fixed<S, F>>(&[u[i].raw()], &[v[j].raw()]).expect("FixedVector::cross: product");
let second = kernels::exact_dot::<Fixed<S, F>>(&[u[j].raw()], &[v[i].raw()]).expect("FixedVector::cross: product");
Fixed::from_raw(kernels::round_to_storage::<Fixed<S, F>>(Fixed::<S, F>::compute_subtract(first, second)))
};
Self::from_slice(&[component(1, 2), component(2, 0), component(0, 1)])
}
pub fn outer_product(&self, other: &Self) -> super::FixedMatrix<Fixed<S, F>> {
let mut m = super::FixedMatrix::<Fixed<S, F>>::new(self.len(), other.len());
for i in 0..self.len() {
for j in 0..other.len() {
m.set(i, j, self.data[i] * other.data[j]);
}
}
m
}
#[inline]
pub fn as_slice(&self) -> &[Fixed<S, F>] {
&self.data
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [Fixed<S, F>] {
&mut self.data
}
pub fn rotate_pairs(&mut self, sin: &[Fixed<S, F>], cos: &[Fixed<S, F>], rotary_dim: usize) {
let half = rotary_dim / 2;
assert!(rotary_dim <= self.data.len(), "FixedVector::rotate_pairs: rotary_dim exceeds the vector length");
assert!(sin.len() >= half && cos.len() >= half, "FixedVector::rotate_pairs: sin/cos shorter than rotary_dim / 2");
let (lo, hi) = self.data.split_at_mut(half);
for i in 0..half {
let (x0, x1) = (lo[i], hi[i]);
lo[i] = rotated(x0, cos[i], x1, sin[i], true);
hi[i] = rotated(x0, sin[i], x1, cos[i], false);
}
}
}