Moved test file to lingal folder, wrote tests based on github ticket request (scipy reference)
This commit is contained in:
parent
645ca8ad52
commit
b3c6492530
|
@ -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 {
|
||||||
|
@ -75,23 +103,3 @@ 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() {
|
|
||||||
|
|
||||||
}
|
|
|
@ -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::*;
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
|
@ -11,3 +11,4 @@ mod real_schur;
|
||||||
mod solve;
|
mod solve;
|
||||||
mod svd;
|
mod svd;
|
||||||
mod tridiagonal;
|
mod tridiagonal;
|
||||||
|
mod convolution;
|
Loading…
Reference in New Issue