hpt 0.1.3

High Performance Tensor (HPT) - A fast, efficient, and user-friendly tensor computation library for Rust
Documentation
use hpt_allocator::{
    traits::{Allocator, AllocatorOutputRetrive},
    Cpu,
};
use hpt_common::error::base::TensorError;
use hpt_traits::ops::creation::TensorCreator;
use hpt_traits::{
    ops::windows::WindowOps,
    tensor::{CommonBounds, TensorLike},
};
use hpt_types::{
    dtype::{FloatConst, TypeCommon},
    into_scalar::Cast,
    traits::VecTrait,
    type_promote::{FloatOutBinary, FloatOutUnary, NormalOut},
};
use rayon::{
    iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator},
    slice::ParallelSliceMut,
};

use crate::tensor_base::_Tensor;

pub(crate) type Simd<T> = <T as TypeCommon>::Vec;

impl<T, A2, const DEVICE: usize> WindowOps for _Tensor<T, Cpu, DEVICE, A2>
where
    f64: Cast<T>,
    T: CommonBounds + FloatOutBinary<Output = T> + FloatOutUnary<Output = T> + FloatConst,
    Simd<T>: FloatOutBinary<Simd<T>, Output = Simd<T>> + FloatOutUnary<Output = Simd<T>>,
    usize: Cast<T>,
    i64: Cast<T>,
    A2: Allocator,
    A2::Output: AllocatorOutputRetrive,
{
    type Output = _Tensor<T, Cpu, DEVICE, A2>;
    type Meta = T;

    #[track_caller]
    fn hamming_window(window_length: i64, periodic: bool) -> Result<Self::Output, TensorError> {
        __hamming_window(window_length, (0.54).cast(), (0.46).cast(), periodic)
    }

    #[track_caller]
    fn hann_window(window_length: i64, periodic: bool) -> Result<Self::Output, TensorError> {
        __hamming_window(window_length, (0.5).cast(), (0.5).cast(), periodic)
    }

    #[track_caller]
    fn blackman_window(window_length: i64, periodic: bool) -> Result<Self::Output, TensorError> {
        let a0: T = (0.42).cast();
        let a1: T = (0.5).cast();
        let a2: T = (0.08).cast();
        let two_pi = f64::TWOPI.cast();
        let four_pi = f64::FOURPI.cast();
        let length_usize = if periodic {
            window_length
        } else {
            window_length - 1
        };
        let length: T = length_usize.cast();
        let mut ret = Self::Output::empty(&[length_usize])?;
        ret.as_raw_mut()
            .par_iter_mut()
            .enumerate()
            .for_each(|(idx, x)| {
                let idx: T = idx.cast();
                let a = a1._mul(two_pi._mul(idx)._div(length)._cos());
                let b = a2._mul(four_pi._mul(idx)._div(length)._cos());
                *x = a0._sub(a)._add(b);
            });
        Ok(ret)
    }
}

#[track_caller]
fn __hamming_window<T, A2, const DEVICE: usize>(
    window_length: i64,
    alpha: T,
    beta: T,
    periodic: bool,
) -> Result<_Tensor<T, Cpu, DEVICE, A2>, TensorError>
where
    f64: Cast<T>,
    T: CommonBounds + FloatOutUnary<Output = T> + FloatConst + FloatOutBinary<Output = T>,
    Simd<T>: FloatOutBinary<Simd<T>, Output = Simd<T>> + FloatOutUnary<Output = Simd<T>>,
    usize: Cast<T>,
    i64: Cast<T>,
    A2: Allocator,
    A2::Output: AllocatorOutputRetrive,
{
    let length_usize = (if periodic {
        window_length
    } else {
        window_length - 1
    }) as usize;
    let length: T = length_usize.cast();
    let mut ret = _Tensor::<T, Cpu, DEVICE, A2>::empty(&[length_usize as i64])?;
    let mut chunk_exact = ret.as_raw_mut().par_chunks_exact_mut(Simd::<T>::SIZE);
    let two_pi = Simd::<T>::splat(T::TWOPI);
    let length_vec = Simd::<T>::splat(length);
    let alpha_vec = Simd::<T>::splat(alpha);
    let beta_vec = Simd::<T>::splat(beta._neg());
    let remainder = chunk_exact.remainder();
    remainder.iter_mut().enumerate().for_each(|(idx, x)| {
        let idx: T = idx.cast();
        *x = idx
            ._mul(T::TWOPI._div(length))
            ._cos()
            ._mul_add(beta._neg(), alpha);
    });
    chunk_exact.enumerate().for_each(|(x, vec)| {
        let idx = x * Simd::<T>::SIZE;
        let mut idxes = Simd::<T>::splat(T::ZERO);
        for i in 0..Simd::<T>::SIZE {
            idxes[i] = (idx + i).cast();
        }
        let ptr = vec as *mut _ as *mut Simd<T>;

        let res = hpt_types::traits::VecTrait::mul_add(
            idxes._mul(two_pi._div(length_vec))._cos(),
            beta_vec,
            alpha_vec,
        );
        unsafe {
            ptr.write_unaligned(res);
        }
    });
    Ok(ret)
}