Moved test file to lingal folder, wrote tests based on github ticket request (scipy reference)

This commit is contained in:
Nathan 2019-02-10 13:40:32 -06:00
parent 645ca8ad52
commit b3c6492530
4 changed files with 93 additions and 33 deletions

View File

@ -1,20 +1,25 @@
extern crate nalgebra as na; use storage::Storage;
use na::storage::Storage; use {zero, DVector, Dim, Dynamic, Matrix, Real, VecStorage, Vector, U1};
use na::{zero, DVector, Dim, Dynamic, Matrix, Real, VecStorage, Vector, U1};
use std::cmp; use std::cmp;
enum ConvolveMode { ///
Full, /// The output is the full discrete linear convolution of the inputs
Valid, ///
Same, pub fn convolve_full<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
}
fn convolve_full<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
vector: Vector<R, D, S>, vector: Vector<R, D, S>,
kernel: Vector<R, E, Q>, kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> { ) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
let vec = vector.len(); let vec = vector.len();
let ker = kernel.len(); let ker = kernel.len();
if vec == 0 || ker == 0 {
panic!("Convolve's inputs must not be 0-sized. ");
}
if ker > vec {
return convolve_full(kernel, vector);
}
let newlen = vec + ker - 1; let newlen = vec + ker - 1;
let mut conv = DVector::<R>::zeros(newlen); let mut conv = DVector::<R>::zeros(newlen);
@ -36,12 +41,24 @@ fn convolve_full<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
conv conv
} }
fn convolve_valid<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>( ///
/// The output consists only of those elements that do not rely on the zero-padding.
///
pub fn convolve_valid<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
vector: Vector<R, D, S>, vector: Vector<R, D, S>,
kernel: Vector<R, E, Q>, kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> { ) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
let vec = vector.len(); let vec = vector.len();
let ker = kernel.len(); let ker = kernel.len();
if vec == 0 || ker == 0 {
panic!("Convolve's inputs must not be 0-sized. ");
}
if ker > vec {
return convolve_valid(kernel, vector);
}
let newlen = vec - ker + 1; let newlen = vec - ker + 1;
let mut conv = DVector::<R>::zeros(newlen); let mut conv = DVector::<R>::zeros(newlen);
@ -54,13 +71,24 @@ fn convolve_valid<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
conv conv
} }
fn convolve_same<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>( ///
/// The output is the same size as in1, centered with respect to the full output.
///
pub fn convolve_same<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
vector: Vector<R, D, S>, vector: Vector<R, D, S>,
kernel: Vector<R, E, Q>, kernel: Vector<R, E, Q>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> { ) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
let vec = vector.len(); let vec = vector.len();
let ker = kernel.len(); let ker = kernel.len();
if vec == 0 || ker == 0 {
panic!("Convolve's inputs must not be 0-sized. ");
}
if ker > vec {
return convolve_same(kernel, vector);
}
let mut conv = DVector::<R>::zeros(vec); let mut conv = DVector::<R>::zeros(vec);
for i in 0..vec { for i in 0..vec {
@ -74,24 +102,4 @@ fn convolve_same<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
} }
} }
conv conv
} }
fn convolve<R: Real, D: Dim, E: Dim, S: Storage<R, D>, Q: Storage<R, E>>(
vector: Vector<R, D, S>,
kernel: Vector<R, E, Q>,
mode: Option<ConvolveMode>,
) -> Matrix<R, Dynamic, U1, VecStorage<R, Dynamic, U1>> {
if kernel.len() > vector.len() {
return convolve(kernel, vector, mode);
}
match mode.unwrap_or(ConvolveMode::Full) {
ConvolveMode::Full => return convolve_full(vector, kernel),
ConvolveMode::Valid => return convolve_valid(vector, kernel),
ConvolveMode::Same => return convolve_same(vector, kernel),
}
}
fn main() {
}

View File

@ -17,6 +17,7 @@ mod solve;
mod svd; mod svd;
mod symmetric_eigen; mod symmetric_eigen;
mod symmetric_tridiagonal; mod symmetric_tridiagonal;
mod convolution;
//// FIXME: Not complete enough for publishing. //// FIXME: Not complete enough for publishing.
//// This handles only cases where each eigenvalue has multiplicity one. //// This handles only cases where each eigenvalue has multiplicity one.
@ -33,3 +34,4 @@ pub use self::schur::*;
pub use self::svd::*; pub use self::svd::*;
pub use self::symmetric_eigen::*; pub use self::symmetric_eigen::*;
pub use self::symmetric_tridiagonal::*; pub use self::symmetric_tridiagonal::*;
pub use self::convolution::*;

View File

@ -0,0 +1,49 @@
use na::linalg::{convolve_full,convolve_valid,convolve_same};
use na::{Vector2,Vector4,DVector};
//
// Should mimic calculations in Python's scipy library
// >>>from scipy.signal import convolve
//
// >>> convolve([1,2,3,4],[1,2],"same")
// array([ 1, 4, 7, 10])
#[test]
fn convolve_same_check(){
let vec = Vector4::new(1.0,2.0,3.0,4.0);
let ker = Vector2::new(1.0,2.0);
let actual = DVector::from_vec(4, vec![1.0,4.0,7.0,10.0]);
let expected = convolve_same(vec,ker);
assert!(relative_eq!(actual, expected, epsilon = 1.0e-7));
}
// >>> convolve([1,2,3,4],[1,2],"valid")
// array([ 1, 4, 7, 10, 8])
#[test]
fn convolve_full_check(){
let vec = Vector4::new(1.0,2.0,3.0,4.0);
let ker = Vector2::new(1.0,2.0);
let actual = DVector::from_vec(5, vec![1.0,4.0,7.0,10.0,8.0]);
let expected = convolve_full(vec,ker);
assert!(relative_eq!(actual, expected, epsilon = 1.0e-7));
}
// >>> convolve([1,2,3,4],[1,2],"valid")
// array([ 4, 7, 10])
#[test]
fn convolve_valid_check(){
let vec = Vector4::new(1.0,2.0,3.0,4.0);
let ker = Vector2::new(1.0,2.0);
let actual = DVector::from_vec(3, vec![4.0,7.0,10.0]);
let expected = convolve_valid(vec,ker);
assert!(relative_eq!(actual, expected, epsilon = 1.0e-7));
}

View File

@ -11,3 +11,4 @@ mod real_schur;
mod solve; mod solve;
mod svd; mod svd;
mod tridiagonal; mod tridiagonal;
mod convolution;