use std::cmp; use crate::base::allocator::Allocator; use crate::base::default_allocator::DefaultAllocator; use crate::base::dimension::{Const, Dim, DimAdd, DimDiff, DimSub, DimSum}; use crate::storage::Storage; use crate::{OVector, RealField, U1, Vector, zero}; 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, ) -> OVector, 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 {vec} and {ker} respectively." ); } let result_len = self .data .shape() .0 .add(kernel.shape_generic().0) .sub(Const::<1>); let mut conv = OVector::zeros_generic(result_len, Const::<1>); 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].clone() * kernel[i - u_i].clone(); } else { for u in u_i..(u_f + 1) { if i - u < ker { conv[i] += self[u].clone() * kernel[i - u].clone(); } } } } 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, ) -> OVector, 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 {vec} and {ker} respectively." ); } let result_len = self .data .shape() .0 .add(Const::<1>) .sub(kernel.shape_generic().0); let mut conv = OVector::zeros_generic(result_len, Const::<1>); for i in 0..(vec - ker + 1) { for j in 0..ker { conv[i] += self[i + j].clone() * kernel[ker - j - 1].clone(); } } 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`. #[must_use] pub fn convolve_same(&self, kernel: Vector) -> OVector 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 {vec} and {ker} respectively." ); } let mut conv = OVector::zeros_generic(self.shape_generic().0, Const::<1>); 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].clone() }; conv[i] += val * kernel[ker - j - 1].clone(); } } conv } }