Moving functions into impl for Vector<N,D,S>

This commit is contained in:
Nathan 2019-03-02 15:00:40 -06:00
parent 28525bfc20
commit 36feddb8c2
2 changed files with 122 additions and 136 deletions

View File

@ -5,37 +5,35 @@ use std::cmp;
use storage::Storage; use storage::Storage;
use {zero, Real, Vector, VectorN, U1}; use {zero, Real, Vector, VectorN, U1};
/// Returns the convolution of the target vector and a kernel impl<N: Real, D1: Dim, S1: Storage<N, D1>> Vector<N, D1, S1> {
/// /// Returns the convolution of the target vector and a kernel
/// # Arguments ///
/// /// # Arguments
/// * `vector` - A Vector with size > 0 ///
/// * `kernel` - A Vector with size > 0 /// * `kernel` - A Vector with size > 0
/// ///
/// # Errors /// # Errors
/// Inputs must statisfy `vector.len() >= kernel.len() > 0`. /// Inputs must statisfy `vector.len() >= kernel.len() > 0`.
/// ///
pub fn convolve_full<N, D1, D2, S1, S2>( pub fn convolve_full<D2, S2>(
vector: Vector<N, D1, S1>, &self,
kernel: Vector<N, D2, S2>, kernel: Vector<N, D2, S2>,
) -> VectorN<N, DimDiff<DimSum<D1, D2>, U1>> ) -> VectorN<N, DimDiff<DimSum<D1, D2>, U1>>
where where
N: Real,
D1: DimAdd<D2>, D1: DimAdd<D2>,
D2: DimAdd<D1, Output = DimSum<D1, D2>>, D2: DimAdd<D1, Output = DimSum<D1, D2>>,
DimSum<D1, D2>: DimSub<U1>, DimSum<D1, D2>: DimSub<U1>,
S1: Storage<N, D1>,
S2: Storage<N, D2>, S2: Storage<N, D2>,
DefaultAllocator: Allocator<N, DimDiff<DimSum<D1, D2>, U1>>, DefaultAllocator: Allocator<N, DimDiff<DimSum<D1, D2>, U1>>,
{ {
let vec = vector.len(); let vec = self.len();
let ker = kernel.len(); let ker = kernel.len();
if ker == 0 || ker > vec { if ker == 0 || ker > vec {
panic!("convolve_full expects `vector.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker); panic!("convolve_full expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker);
} }
let result_len = vector.data.shape().0.add(kernel.data.shape().0).sub(U1); let result_len = self.data.shape().0.add(kernel.data.shape().0).sub(U1);
let mut conv = VectorN::zeros_generic(result_len, U1); let mut conv = VectorN::zeros_generic(result_len, U1);
for i in 0..(vec + ker - 1) { for i in 0..(vec + ker - 1) {
@ -43,89 +41,77 @@ where
let u_f = cmp::min(i, vec - 1); let u_f = cmp::min(i, vec - 1);
if u_i == u_f { if u_i == u_f {
conv[i] += vector[u_i] * kernel[(i - u_i)]; conv[i] += self[u_i] * kernel[(i - u_i)];
} else { } else {
for u in u_i..(u_f + 1) { for u in u_i..(u_f + 1) {
if i - u < ker { if i - u < ker {
conv[i] += vector[u] * kernel[(i - u)]; conv[i] += self[u] * kernel[(i - u)];
} }
} }
} }
} }
conv conv
} }
/// Returns the convolution of the target vector and a kernel
/// Returns the convolution of the vector and a kernel /// The output convolution consists only of those elements that do not rely on the zero-padding.
/// The output convolution consists only of those elements that do not rely on the zero-padding. /// # Arguments
/// # Arguments ///
/// /// * `kernel` - A Vector with size > 0
/// * `vector` - A Vector with size > 0 ///
/// * `kernel` - A Vector with size > 0 ///
/// /// # Errors
/// /// Inputs must statisfy `self.len() >= kernel.len() > 0`.
/// # Errors ///
/// Inputs must statisfy `vector.len() >= kernel.len() > 0`. pub fn convolve_valid<D2, S2>(&self, kernel: Vector<N, D2, S2>,
/// ) -> VectorN<N, DimDiff<DimSum<D1, U1>, D2>>
pub fn convolve_valid<N, D1, D2, S1, S2>( where
vector: Vector<N, D1, S1>,
kernel: Vector<N, D2, S2>,
) -> VectorN<N, DimDiff<DimSum<D1, U1>, D2>>
where
N: Real,
D1: DimAdd<U1>, D1: DimAdd<U1>,
D2: Dim, D2: Dim,
DimSum<D1, U1>: DimSub<D2>, DimSum<D1, U1>: DimSub<D2>,
S1: Storage<N, D1>,
S2: Storage<N, D2>, S2: Storage<N, D2>,
DefaultAllocator: Allocator<N, DimDiff<DimSum<D1, U1>, D2>>, DefaultAllocator: Allocator<N, DimDiff<DimSum<D1, U1>, D2>>,
{ {
let vec = vector.len(); let vec = self.len();
let ker = kernel.len(); let ker = kernel.len();
if ker == 0 || ker > vec { if ker == 0 || ker > vec {
panic!("convolve_valid expects `vector.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker); panic!("convolve_valid expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker);
} }
let result_len = vector.data.shape().0.add(U1).sub(kernel.data.shape().0); let result_len = self.data.shape().0.add(U1).sub(kernel.data.shape().0);
let mut conv = VectorN::zeros_generic(result_len, U1); let mut conv = VectorN::zeros_generic(result_len, U1);
for i in 0..(vec - ker + 1) { for i in 0..(vec - ker + 1) {
for j in 0..ker { for j in 0..ker {
conv[i] += vector[i + j] * kernel[ker - j - 1]; conv[i] += self[i + j] * kernel[ker - j - 1];
} }
} }
conv conv
} }
/// Returns the convolution of the vector and a kernel /// Returns the convolution of the targetvector and a kernel
/// The output convolution is the same size as vector, centered with respect to the full output. /// The output convolution is the same size as vector, centered with respect to the full output.
/// # Arguments /// # Arguments
/// ///
/// * `vector` - A Vector with size > 0 /// * `kernel` - A Vector with size > 0
/// * `kernel` - A Vector with size > 0 ///
/// /// # Errors
/// # Errors /// Inputs must statisfy `self.len() >= kernel.len() > 0`.
/// Inputs must statisfy `vector.len() >= kernel.len() > 0`. pub fn convolve_same<D2, S2>(&self, kernel: Vector<N, D2, S2>) -> VectorN<N, DimMaximum<D1, D2>>
pub fn convolve_same<N, D1, D2, S1, S2>( where
vector: Vector<N, D1, S1>,
kernel: Vector<N, D2, S2>,
) -> VectorN<N, DimMaximum<D1, D2>>
where
N: Real,
D1: DimMax<D2>, D1: DimMax<D2>,
D2: DimMax<D1, Output = DimMaximum<D1, D2>>, D2: DimMax<D1, Output = DimMaximum<D1, D2>>,
S1: Storage<N, D1>,
S2: Storage<N, D2>, S2: Storage<N, D2>,
DefaultAllocator: Allocator<N, DimMaximum<D1, D2>>, DefaultAllocator: Allocator<N, DimMaximum<D1, D2>>,
{ {
let vec = vector.len(); let vec = self.len();
let ker = kernel.len(); let ker = kernel.len();
if ker == 0 || ker > vec { if ker == 0 || ker > vec {
panic!("convolve_same expects `vector.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker); panic!("convolve_same expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker);
} }
let result_len = vector.data.shape().0.max(kernel.data.shape().0); let result_len = self.data.shape().0.max(kernel.data.shape().0);
let mut conv = VectorN::zeros_generic(result_len, U1); let mut conv = VectorN::zeros_generic(result_len, U1);
for i in 0..vec { for i in 0..vec {
@ -133,10 +119,11 @@ where
let val = if i + j < 1 || i + j >= vec + 1 { let val = if i + j < 1 || i + j >= vec + 1 {
zero::<N>() zero::<N>()
} else { } else {
vector[i + j - 1] self[i + j - 1]
}; };
conv[i] += val * kernel[ker - j - 1]; conv[i] += val * kernel[ker - j - 1];
} }
} }
conv conv
}
} }

View File

@ -1,4 +1,3 @@
use na::linalg::{convolve_full,convolve_valid,convolve_same};
use na::{Vector2,Vector3,Vector4,Vector5,DVector}; use na::{Vector2,Vector3,Vector4,Vector5,DVector};
use std::panic; use std::panic;
@ -13,13 +12,13 @@ use std::panic;
fn convolve_same_check(){ fn convolve_same_check(){
// Static Tests // Static Tests
let actual_s = Vector4::from_vec(vec![1.0,4.0,7.0,10.0]); let actual_s = Vector4::from_vec(vec![1.0,4.0,7.0,10.0]);
let expected_s = convolve_same(Vector4::new(1.0,2.0,3.0,4.0), Vector2::new(1.0,2.0)); let expected_s = Vector4::new(1.0,2.0,3.0,4.0).convolve_same(Vector2::new(1.0,2.0));
assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7)); assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7));
// Dynamic Tests // Dynamic Tests
let actual_d = DVector::from_vec(vec![1.0,4.0,7.0,10.0]); let actual_d = DVector::from_vec(vec![1.0,4.0,7.0,10.0]);
let expected_d = convolve_same(DVector::from_vec(vec![1.0,2.0,3.0,4.0]),DVector::from_vec(vec![1.0,2.0])); let expected_d = DVector::from_vec(vec![1.0,2.0,3.0,4.0]).convolve_same(DVector::from_vec(vec![1.0,2.0]));
assert!(relative_eq!(actual_d, expected_d, epsilon = 1.0e-7)); assert!(relative_eq!(actual_d, expected_d, epsilon = 1.0e-7));
@ -27,19 +26,19 @@ fn convolve_same_check(){
// These really only apply to dynamic sized vectors // These really only apply to dynamic sized vectors
assert!( assert!(
panic::catch_unwind(|| { panic::catch_unwind(|| {
convolve_same(DVector::from_vec(vec![1.0,2.0]), DVector::from_vec(vec![1.0,2.0,3.0,4.0])); DVector::from_vec(vec![1.0,2.0]).convolve_same(DVector::from_vec(vec![1.0,2.0,3.0,4.0]));
}).is_err() }).is_err()
); );
assert!( assert!(
panic::catch_unwind(|| { panic::catch_unwind(|| {
convolve_same(DVector::<f32>::from_vec(vec![]), DVector::from_vec(vec![1.0,2.0,3.0,4.0])); DVector::<f32>::from_vec(vec![]).convolve_same(DVector::from_vec(vec![1.0,2.0,3.0,4.0]));
}).is_err() }).is_err()
); );
assert!( assert!(
panic::catch_unwind(|| { panic::catch_unwind(|| {
convolve_same(DVector::from_vec(vec![1.0,2.0,3.0,4.0]),DVector::<f32>::from_vec(vec![])); DVector::from_vec(vec![1.0,2.0,3.0,4.0]).convolve_same(DVector::<f32>::from_vec(vec![]));
}).is_err() }).is_err()
); );
} }
@ -50,13 +49,13 @@ fn convolve_same_check(){
fn convolve_full_check(){ fn convolve_full_check(){
// Static Tests // Static Tests
let actual_s = Vector5::new(1.0,4.0,7.0,10.0,8.0); let actual_s = Vector5::new(1.0,4.0,7.0,10.0,8.0);
let expected_s = convolve_full(Vector4::new(1.0,2.0,3.0,4.0), Vector2::new(1.0,2.0)); let expected_s = Vector4::new(1.0,2.0,3.0,4.0).convolve_full(Vector2::new(1.0,2.0));
assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7)); assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7));
// Dynamic Tests // Dynamic Tests
let actual_d = DVector::from_vec(vec![1.0,4.0,7.0,10.0,8.0]); let actual_d = DVector::from_vec(vec![1.0,4.0,7.0,10.0,8.0]);
let expected_d = convolve_full(DVector::from_vec(vec![1.0,2.0,3.0,4.0]), DVector::from_vec(vec![1.0,2.0])); let expected_d = DVector::from_vec(vec![1.0,2.0,3.0,4.0]).convolve_full(DVector::from_vec(vec![1.0,2.0]));
assert!(relative_eq!(actual_d, expected_d, epsilon = 1.0e-7)); assert!(relative_eq!(actual_d, expected_d, epsilon = 1.0e-7));
@ -64,19 +63,19 @@ fn convolve_full_check(){
// These really only apply to dynamic sized vectors // These really only apply to dynamic sized vectors
assert!( assert!(
panic::catch_unwind(|| { panic::catch_unwind(|| {
convolve_full(DVector::from_vec(vec![1.0,2.0]), DVector::from_vec(vec![1.0,2.0,3.0,4.0])); DVector::from_vec(vec![1.0,2.0]).convolve_full(DVector::from_vec(vec![1.0,2.0,3.0,4.0]));
}).is_err() }).is_err()
); );
assert!( assert!(
panic::catch_unwind(|| { panic::catch_unwind(|| {
convolve_full(DVector::<f32>::from_vec(vec![]), DVector::from_vec(vec![1.0,2.0,3.0,4.0])); DVector::<f32>::from_vec(vec![]).convolve_full(DVector::from_vec(vec![1.0,2.0,3.0,4.0]));
}).is_err() }).is_err()
); );
assert!( assert!(
panic::catch_unwind(|| { panic::catch_unwind(|| {
convolve_full(DVector::from_vec(vec![1.0,2.0,3.0,4.0]),DVector::<f32>::from_vec(vec![])); DVector::from_vec(vec![1.0,2.0,3.0,4.0]).convolve_full(DVector::<f32>::from_vec(vec![]));
}).is_err() }).is_err()
); );
} }
@ -87,13 +86,13 @@ fn convolve_full_check(){
fn convolve_valid_check(){ fn convolve_valid_check(){
// Static Tests // Static Tests
let actual_s = Vector3::from_vec(vec![4.0,7.0,10.0]); let actual_s = Vector3::from_vec(vec![4.0,7.0,10.0]);
let expected_s = convolve_valid( Vector4::new(1.0,2.0,3.0,4.0), Vector2::new(1.0,2.0)); let expected_s = Vector4::new(1.0,2.0,3.0,4.0).convolve_valid( Vector2::new(1.0,2.0));
assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7)); assert!(relative_eq!(actual_s, expected_s, epsilon = 1.0e-7));
// Dynamic Tests // Dynamic Tests
let actual_d = DVector::from_vec(vec![4.0,7.0,10.0]); let actual_d = DVector::from_vec(vec![4.0,7.0,10.0]);
let expected_d = convolve_valid(DVector::from_vec(vec![1.0,2.0,3.0,4.0]), DVector::from_vec(vec![1.0,2.0])); let expected_d = DVector::from_vec(vec![1.0,2.0,3.0,4.0]).convolve_valid(DVector::from_vec(vec![1.0,2.0]));
assert!(relative_eq!(actual_d, expected_d, epsilon = 1.0e-7)); assert!(relative_eq!(actual_d, expected_d, epsilon = 1.0e-7));
@ -101,19 +100,19 @@ fn convolve_valid_check(){
// These really only apply to dynamic sized vectors // These really only apply to dynamic sized vectors
assert!( assert!(
panic::catch_unwind(|| { panic::catch_unwind(|| {
convolve_valid(DVector::from_vec(vec![1.0,2.0]), DVector::from_vec(vec![1.0,2.0,3.0,4.0])); DVector::from_vec(vec![1.0,2.0]).convolve_valid(DVector::from_vec(vec![1.0,2.0,3.0,4.0]));
}).is_err() }).is_err()
); );
assert!( assert!(
panic::catch_unwind(|| { panic::catch_unwind(|| {
convolve_valid(DVector::<f32>::from_vec(vec![]), DVector::from_vec(vec![1.0,2.0,3.0,4.0])); DVector::<f32>::from_vec(vec![]).convolve_valid(DVector::from_vec(vec![1.0,2.0,3.0,4.0]));
}).is_err() }).is_err()
); );
assert!( assert!(
panic::catch_unwind(|| { panic::catch_unwind(|| {
convolve_valid(DVector::from_vec(vec![1.0,2.0,3.0,4.0]),DVector::<f32>::from_vec(vec![])); DVector::from_vec(vec![1.0,2.0,3.0,4.0]).convolve_valid(DVector::<f32>::from_vec(vec![]));
}).is_err() }).is_err()
); );