[Rd] convolve: request for "usual" behaviour + some improvements + some fixes
hpages at fhcrc.org
Sat Feb 3 02:03:26 CET 2007
There are many problems with current 'convolve' function.
The author of the man page seems to be aware that 'convolve' does _not_ the
Note that the usual definition of convolution of two sequences 'x'
and 'y' is given by 'convolve(x, rev(y), type = "o")'.
and indeed, it does not:
> x <- 1:3
> y <- 3:1
> convolve(x, y, type="o")
 1 4 10 12 9
The "usual" convolution would rather give:
> convolve(x, rev(y), type="o")
 3 8 14 8 3
Also the "usual" convolution is commutative:
> convolve(y, rev(x), type="o")
 3 8 14 8 3
but convolve is not:
> convolve(y, x, type="o")
 9 12 10 4 1
Of course I could write the following wrapper:
usual_convolve <- function(x, y, ...) convolve(x, rev(y))
to work around those issues but 'convolve' has other problems:
(1) The input sequences shouldn't need to have the same length when
type = "circular" (the shortest can be right-padded with 0s up
to the length of the longest).
(2) If the input sequences are both integer vectors, then the result
should be an integer vector too.
(3) The "filter" feature seems to be broken (it's not even clear
what it should do or why we need it though):
> x <- 1:9
> y <- 1
> convolve(x, y, type="f")
Error in convolve(x, y, type = "f") : subscript out of bounds
> convolve(y, x, type="f")
(4) If you look at the source code, you'll see that 'x' is first left-padded
with '0's. The "usual" convolution doesn't do that: it always padd
sequences on the _same_ side (generally on the right).
(5) It's not clear why we need a 'conj' arg. All what it does is
take the conjugate of fft(y) before it does the product with fft(x).
But this has the "non-usual" effect of reverting the expected result:
> round(convolve(as.integer(c(0,0,0,1)), 1:7, type="o"))
 0 0 0 7 6 5 4 3 2 1
Here below is my version of 'convolve' just in case. It does the "usual"
- no need to have 'x' and 'y' of the same length when 'type' is "circular",
- when 'x' and 'y' are integer vectors, the output is an integer vector,
- no more 'conj' arg (not needed, only leads to confusion),
- when type is "filter", the output sequence is the same as with
type="open" but is truncated to the length of 'x' (the original signal)
It can be seen has the result of 'x' filtered by 'y' (the filter).
convolve2 <- function(x, y, type = c("circular", "open", "filter"))
type <- match.arg(type)
nx <- length(x)
ny <- length(y)
if (type == "circular")
nz <- max(nx, ny)
nz <- nx + ny - 1
if (nz > nx)
x[(nx+1):nz] <- as.integer(0)
if (nz > ny)
y[(ny+1):nz] <- as.integer(0)
fx <- fft(x)
fy <- fft(y)
fz <- fx * fy
z <- fft(fz, inverse=TRUE) / nz
if (is.numeric(x) && is.numeric(y))
z <- Re(z)
if (is.integer(x) && is.integer(y))
z <- as.integer(round(z))
if (type == "filter")
More information about the R-devel