2019-02-07 11:15:33 +08:00
|
|
|
|
use std::cmp;
|
|
|
|
|
|
2019-03-31 16:53:11 +08:00
|
|
|
|
use crate::base::allocator::Allocator;
|
|
|
|
|
use crate::base::default_allocator::DefaultAllocator;
|
2019-03-31 23:30:32 +08:00
|
|
|
|
use crate::base::dimension::{Dim, DimAdd, DimDiff, DimSub, DimSum};
|
2019-03-31 16:53:11 +08:00
|
|
|
|
use crate::storage::Storage;
|
|
|
|
|
use crate::{zero, RealField, Vector, VectorN, U1};
|
|
|
|
|
|
|
|
|
|
impl<N: RealField, D1: Dim, S1: Storage<N, D1>> Vector<N, D1, S1> {
|
2019-03-31 23:03:02 +08:00
|
|
|
|
/// Returns the convolution of the target vector and a kernel.
|
2019-03-03 05:00:40 +08:00
|
|
|
|
///
|
|
|
|
|
/// # Arguments
|
|
|
|
|
///
|
|
|
|
|
/// * `kernel` - A Vector with size > 0
|
|
|
|
|
///
|
|
|
|
|
/// # Errors
|
2019-03-31 23:03:02 +08:00
|
|
|
|
/// Inputs must satisfy `vector.len() >= kernel.len() > 0`.
|
2019-03-03 05:00:40 +08:00
|
|
|
|
///
|
|
|
|
|
pub fn convolve_full<D2, S2>(
|
|
|
|
|
&self,
|
|
|
|
|
kernel: Vector<N, D2, S2>,
|
|
|
|
|
) -> VectorN<N, DimDiff<DimSum<D1, D2>, U1>>
|
|
|
|
|
where
|
|
|
|
|
D1: DimAdd<D2>,
|
|
|
|
|
D2: DimAdd<D1, Output = DimSum<D1, D2>>,
|
|
|
|
|
DimSum<D1, D2>: DimSub<U1>,
|
|
|
|
|
S2: Storage<N, D2>,
|
|
|
|
|
DefaultAllocator: Allocator<N, DimDiff<DimSum<D1, D2>, U1>>,
|
|
|
|
|
{
|
|
|
|
|
let vec = self.len();
|
|
|
|
|
let ker = kernel.len();
|
2019-02-19 09:01:18 +08:00
|
|
|
|
|
2019-03-03 05:00:40 +08:00
|
|
|
|
if ker == 0 || ker > vec {
|
|
|
|
|
panic!("convolve_full expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker);
|
|
|
|
|
}
|
2019-02-19 09:01:18 +08:00
|
|
|
|
|
2019-03-03 05:00:40 +08:00
|
|
|
|
let result_len = self.data.shape().0.add(kernel.data.shape().0).sub(U1);
|
|
|
|
|
let mut conv = VectorN::zeros_generic(result_len, U1);
|
2019-02-19 09:01:18 +08:00
|
|
|
|
|
2019-03-03 05:00:40 +08:00
|
|
|
|
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);
|
2019-02-19 09:01:18 +08:00
|
|
|
|
|
2019-03-03 05:00:40 +08:00
|
|
|
|
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)];
|
|
|
|
|
}
|
2019-02-08 09:58:09 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-03 05:00:40 +08:00
|
|
|
|
conv
|
2019-02-08 09:58:09 +08:00
|
|
|
|
}
|
2019-03-31 23:03:02 +08:00
|
|
|
|
/// Returns the convolution of the target vector and a kernel.
|
|
|
|
|
///
|
2019-03-03 05:00:40 +08:00
|
|
|
|
/// The output convolution consists only of those elements that do not rely on the zero-padding.
|
|
|
|
|
/// # Arguments
|
|
|
|
|
///
|
|
|
|
|
/// * `kernel` - A Vector with size > 0
|
|
|
|
|
///
|
|
|
|
|
///
|
|
|
|
|
/// # Errors
|
2019-03-31 23:03:02 +08:00
|
|
|
|
/// Inputs must satisfy `self.len() >= kernel.len() > 0`.
|
2019-03-03 05:00:40 +08:00
|
|
|
|
///
|
2020-04-06 00:49:48 +08:00
|
|
|
|
pub fn convolve_valid<D2, S2>(
|
|
|
|
|
&self,
|
|
|
|
|
kernel: Vector<N, D2, S2>,
|
|
|
|
|
) -> VectorN<N, DimDiff<DimSum<D1, U1>, D2>>
|
2019-03-03 05:00:40 +08:00
|
|
|
|
where
|
|
|
|
|
D1: DimAdd<U1>,
|
|
|
|
|
D2: Dim,
|
|
|
|
|
DimSum<D1, U1>: DimSub<D2>,
|
|
|
|
|
S2: Storage<N, D2>,
|
|
|
|
|
DefaultAllocator: Allocator<N, DimDiff<DimSum<D1, U1>, D2>>,
|
|
|
|
|
{
|
|
|
|
|
let vec = self.len();
|
|
|
|
|
let ker = kernel.len();
|
2019-02-15 10:54:26 +08:00
|
|
|
|
|
2019-03-03 05:00:40 +08:00
|
|
|
|
if ker == 0 || ker > vec {
|
|
|
|
|
panic!("convolve_valid expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker);
|
|
|
|
|
}
|
2019-02-11 03:40:32 +08:00
|
|
|
|
|
2019-03-03 05:00:40 +08:00
|
|
|
|
let result_len = self.data.shape().0.add(U1).sub(kernel.data.shape().0);
|
|
|
|
|
let mut conv = VectorN::zeros_generic(result_len, U1);
|
2019-02-11 03:40:32 +08:00
|
|
|
|
|
2019-03-03 05:00:40 +08:00
|
|
|
|
for i in 0..(vec - ker + 1) {
|
|
|
|
|
for j in 0..ker {
|
|
|
|
|
conv[i] += self[i + j] * kernel[ker - j - 1];
|
|
|
|
|
}
|
2019-02-07 11:15:33 +08:00
|
|
|
|
}
|
2019-03-03 05:00:40 +08:00
|
|
|
|
conv
|
2019-02-08 09:58:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-31 23:03:02 +08:00
|
|
|
|
/// Returns the convolution of the target vector and a kernel.
|
|
|
|
|
///
|
2019-03-03 05:00:40 +08:00
|
|
|
|
/// The output convolution is the same size as vector, centered with respect to the ‘full’ output.
|
|
|
|
|
/// # Arguments
|
|
|
|
|
///
|
|
|
|
|
/// * `kernel` - A Vector with size > 0
|
|
|
|
|
///
|
|
|
|
|
/// # Errors
|
2019-03-31 23:03:02 +08:00
|
|
|
|
/// Inputs must satisfy `self.len() >= kernel.len() > 0`.
|
|
|
|
|
pub fn convolve_same<D2, S2>(&self, kernel: Vector<N, D2, S2>) -> VectorN<N, D1>
|
2019-03-03 05:00:40 +08:00
|
|
|
|
where
|
2019-03-31 23:03:02 +08:00
|
|
|
|
D2: Dim,
|
2019-03-03 05:00:40 +08:00
|
|
|
|
S2: Storage<N, D2>,
|
2019-03-31 23:03:02 +08:00
|
|
|
|
DefaultAllocator: Allocator<N, D1>,
|
2019-03-03 05:00:40 +08:00
|
|
|
|
{
|
|
|
|
|
let vec = self.len();
|
|
|
|
|
let ker = kernel.len();
|
2019-02-10 10:19:42 +08:00
|
|
|
|
|
2019-03-03 05:00:40 +08:00
|
|
|
|
if ker == 0 || ker > vec {
|
|
|
|
|
panic!("convolve_same expects `self.len() >= kernel.len() > 0`, received {} and {} respectively.",vec,ker);
|
|
|
|
|
}
|
2019-02-11 03:40:32 +08:00
|
|
|
|
|
2019-03-31 23:03:02 +08:00
|
|
|
|
let mut conv = VectorN::zeros_generic(self.data.shape().0, U1);
|
2019-02-10 10:19:42 +08:00
|
|
|
|
|
2019-03-03 05:00:40 +08:00
|
|
|
|
for i in 0..vec {
|
|
|
|
|
for j in 0..ker {
|
|
|
|
|
let val = if i + j < 1 || i + j >= vec + 1 {
|
|
|
|
|
zero::<N>()
|
|
|
|
|
} else {
|
|
|
|
|
self[i + j - 1]
|
|
|
|
|
};
|
|
|
|
|
conv[i] += val * kernel[ker - j - 1];
|
|
|
|
|
}
|
2019-02-10 11:51:20 +08:00
|
|
|
|
}
|
2019-03-31 23:03:02 +08:00
|
|
|
|
|
2019-03-03 05:00:40 +08:00
|
|
|
|
conv
|
2019-02-08 09:58:09 +08:00
|
|
|
|
}
|
2019-02-15 10:54:26 +08:00
|
|
|
|
}
|