use std::ops::{Add, Sub, Neg, Mul, Index, IndexMut};
use super::FixedPoint;
use super::interval::exact_product;
use super::linalg::{compute_tier_dot, compute_tier_sqrt_dot, round_to_storage};
use crate::fixed_point::universal::fasc::stack_evaluator::compute::{compute_checked_add, compute_checked_subtract};
use crate::fixed_point::universal::fasc::stack_evaluator::BinaryStorage;
#[inline]
fn rotated(a: FixedPoint, b: FixedPoint, c: FixedPoint, d: FixedPoint, subtract: bool) -> FixedPoint {
let (p, q) = (exact_product(a.raw(), b.raw()), exact_product(c.raw(), d.raw()));
let sum = if subtract { compute_checked_subtract(p, q) } else { compute_checked_add(p, q) };
FixedPoint::from_raw(round_to_storage(sum.expect("FixedVector::rotate_pairs: overflow")))
}
#[derive(Clone, Debug, PartialEq)]
pub struct FixedVector {
data: Vec<FixedPoint>,
}
impl FixedVector {
pub fn new(dim: usize) -> Self {
Self {
data: vec![FixedPoint::ZERO; dim],
}
}
pub fn from_f32_slice(values: &[f32]) -> Self {
Self {
data: values.iter().map(|&v| FixedPoint::from_f32(v)).collect(),
}
}
pub fn from_slice(values: &[FixedPoint]) -> 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: &FixedVector) -> FixedPoint {
assert_eq!(self.len(), other.len(), "FixedVector::dot: dimension mismatch");
compute_tier_dot(&self.data, &other.data)
}
pub fn length_squared(&self) -> FixedPoint {
self.dot(self)
}
pub fn length(&self) -> FixedPoint {
let raw: Vec<BinaryStorage> = self.data.iter().map(|x| x.raw()).collect();
FixedPoint::from_raw(compute_tier_sqrt_dot(&raw, &raw).expect("FixedVector::length exceeds storage"))
}
pub fn length_fused(&self) -> FixedPoint {
super::fused::sqrt_sum_sq(&self.data)
}
pub fn distance_to(&self, other: &FixedVector) -> FixedPoint {
assert_eq!(self.len(), other.len(), "FixedVector::distance_to: dimension mismatch");
super::fused::euclidean_distance(&self.data, &other.data)
}
pub fn normalize(&mut self) {
use super::linalg::{exact_dot, upscale_to_compute};
use super::wide_acc::{divide_to_storage_nearest, widen_product, widen_storage};
use crate::fixed_point::universal::fasc::stack_evaluator::compute::{compute_is_zero, sqrt_at_compute_tier};
let raw: Vec<BinaryStorage> = self.data.iter().map(|x| x.raw()).collect();
let sum_sq = exact_dot(&raw, &raw).expect("FixedVector::normalize: squared length exceeds the compute tier");
assert!(!compute_is_zero(&sum_sq), "FixedVector::normalize: zero vector");
let len = sqrt_at_compute_tier(sum_sq);
let one = widen_storage(FixedPoint::one().raw());
for v in &mut self.data {
let numer = widen_product(upscale_to_compute(v.raw()), one);
*v = FixedPoint::from_raw(divide_to_storage_nearest(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(FixedPoint) -> FixedPoint) -> Self {
Self {
data: self.data.iter().map(|&v| f(v)).collect(),
}
}
pub fn iter(&self) -> std::slice::Iter<'_, FixedPoint> {
self.data.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, FixedPoint> {
self.data.iter_mut()
}
pub fn metric_distance_safe(&self, other: &FixedVector) -> FixedPoint {
assert_eq!(self.len(), other.len(), "FixedVector::metric_distance_safe: dimension mismatch");
let diff_raw: Vec<BinaryStorage> = (0..self.len())
.map(|i| (self.data[i] - other.data[i]).raw())
.collect();
FixedPoint::from_raw(compute_tier_sqrt_dot(&diff_raw, &diff_raw).expect("metric distance exceeds storage"))
}
}
impl Index<usize> for FixedVector {
type Output = FixedPoint;
#[inline]
fn index(&self, idx: usize) -> &FixedPoint {
&self.data[idx]
}
}
impl IndexMut<usize> for FixedVector {
#[inline]
fn index_mut(&mut self, idx: usize) -> &mut FixedPoint {
&mut self.data[idx]
}
}
impl Default for FixedVector {
fn default() -> Self {
Self { data: Vec::new() }
}
}
impl Add for FixedVector {
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> Add<&'b FixedVector> for &'a FixedVector {
type Output = FixedVector;
fn add(self, rhs: &'b FixedVector) -> FixedVector {
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 Sub for FixedVector {
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> Sub<&'b FixedVector> for &'a FixedVector {
type Output = FixedVector;
fn sub(self, rhs: &'b FixedVector) -> FixedVector {
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 Neg for FixedVector {
type Output = Self;
fn neg(self) -> Self {
Self {
data: self.data.iter().map(|&v| -v).collect(),
}
}
}
impl Neg for &FixedVector {
type Output = FixedVector;
fn neg(self) -> FixedVector {
FixedVector {
data: self.data.iter().map(|&v| -v).collect(),
}
}
}
impl Mul<FixedVector> for FixedPoint {
type Output = FixedVector;
fn mul(self, rhs: FixedVector) -> FixedVector {
FixedVector {
data: rhs.data.iter().map(|&v| self * v).collect(),
}
}
}
impl Mul<FixedPoint> for FixedVector {
type Output = Self;
fn mul(self, rhs: FixedPoint) -> Self {
Self {
data: self.data.iter().map(|&v| v * rhs).collect(),
}
}
}
impl Mul<FixedPoint> for &FixedVector {
type Output = FixedVector;
fn mul(self, rhs: FixedPoint) -> FixedVector {
FixedVector {
data: self.data.iter().map(|&v| v * rhs).collect(),
}
}
}
impl FixedVector {
pub fn dot_precise(&self, other: &FixedVector) -> FixedPoint {
assert_eq!(self.len(), other.len(), "FixedVector::dot_precise: dimension mismatch");
compute_tier_dot(&self.data, &other.data)
}
pub fn cross(&self, other: &FixedVector) -> FixedVector {
use super::linalg::{exact_dot, round_to_storage};
use crate::fixed_point::universal::fasc::stack_evaluator::compute::compute_subtract;
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 = exact_dot(&[u[i].raw()], &[v[j].raw()]).expect("FixedVector::cross: product");
let second = exact_dot(&[u[j].raw()], &[v[i].raw()]).expect("FixedVector::cross: product");
FixedPoint::from_raw(round_to_storage(compute_subtract(first, second)))
};
FixedVector::from_slice(&[component(1, 2), component(2, 0), component(0, 1)])
}
pub fn outer_product(&self, other: &FixedVector) -> super::FixedMatrix {
let mut m = super::FixedMatrix::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) -> &[FixedPoint] {
&self.data
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [FixedPoint] {
&mut self.data
}
pub fn rotate_pairs(&mut self, sin: &[FixedPoint], cos: &[FixedPoint], 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);
}
}
}