use std::cmp; use crate::base::allocator::Allocator; use crate::base::default_allocator::DefaultAllocator; use crate::base::dimension::{Dim, DimAdd, DimDiff, DimSub, DimSum}; use crate::storage::Storage; use crate::{zero, RealField, Vector, VectorN, U1}; impl> Vector { /// Returns the convolution of the target vector and a kernel. /// /// # Arguments /// /// * `kernel` - A Vector with size > 0 /// /// # Errors /// Inputs must satisfy `vector.len() >= kernel.len() > 0`. /// pub fn convolve_full( &self, kernel: Vector, ) -> VectorN, U1>> where D1: DimAdd, D2: DimAdd>, DimSum: DimSub, S2: Storage, DefaultAllocator: Allocator, U1>>, { let vec = self.len(); let ker = kernel.len(); if ker == 0 || ker > vec { panic!("convolve_full expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker); } let result_len = self.data.shape().0.add(kernel.data.shape().0).sub(U1); let mut conv = VectorN::zeros_generic(result_len, U1); for i in 0..(vec + ker - 1) { let u_i = if i > vec { i - ker } else { 0 }; let u_f = cmp::min(i, vec - 1); if u_i == u_f { conv[i] += self[u_i] * kernel[(i - u_i)]; } else { for u in u_i..(u_f + 1) { if i - u < ker { conv[i] += self[u] * kernel[(i - u)]; } } } } conv } /// Returns the convolution of the target vector and a kernel. /// /// The output convolution consists only of those elements that do not rely on the zero-padding. /// # Arguments /// /// * `kernel` - A Vector with size > 0 /// /// /// # Errors /// Inputs must satisfy `self.len() >= kernel.len() > 0`. /// pub fn convolve_valid( &self, kernel: Vector, ) -> VectorN, D2>> where D1: DimAdd, D2: Dim, DimSum: DimSub, S2: Storage, DefaultAllocator: Allocator, D2>>, { let vec = self.len(); let ker = kernel.len(); if ker == 0 || ker > vec { panic!("convolve_valid expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker); } let result_len = self.data.shape().0.add(U1).sub(kernel.data.shape().0); let mut conv = VectorN::zeros_generic(result_len, U1); for i in 0..(vec - ker + 1) { for j in 0..ker { conv[i] += self[i + j] * kernel[ker - j - 1]; } } conv } /// Returns the convolution of the target vector and a kernel. /// /// The output convolution is the same size as vector, centered with respect to the ‘full’ output. /// # Arguments /// /// * `kernel` - A Vector with size > 0 /// /// # Errors /// Inputs must satisfy `self.len() >= kernel.len() > 0`. pub fn convolve_same(&self, kernel: Vector) -> VectorN where D2: Dim, S2: Storage, DefaultAllocator: Allocator, { let vec = self.len(); let ker = kernel.len(); if ker == 0 || ker > vec { panic!("convolve_same expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker); } let mut conv = VectorN::zeros_generic(self.data.shape().0, U1); for i in 0..vec { for j in 0..ker { let val = if i + j < 1 || i + j >= vec + 1 { zero::() } else { self[i + j - 1] }; conv[i] += val * kernel[ker - j - 1]; } } conv } }