Repository: scipy/scipy

Issue:
correlate2d's output does not agree with correlate's output in scipy.signal module (Trac #1443)
_Original ticket http://projects.scipy.org/scipy/ticket/1443 on 2011-05-23 by trac user SevenSea, assigned to unknown._

When the 2-dimensional array size is even, correlate2d's output does not agree with correlate's output in scipy.signal module. There is a shift of index in the output of correlate2d function. (Information for comparition: convolv2d works good.)

Testing code:

```
import numpy as np
import scipy.signal as sn

d = np.ones((4,4))
print "data: "
print d

print "correlate(d,d,'same'): "
print sn.correlate(d,d,'same')

print "correlate2d(d,d,'same'): "
print sn.correlate2d(d,d,'same')
```

The output:

```
data: 
[[ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]]
correlate(d,d,'same'): 
[[  4.   6.   8.   6.]
 [  6.   9.  12.   9.]
 [  8.  12.  16.  12.]
 [  6.   9.  12.   9.]]
correlate2d(d,d,'same'): 
[[  9.  12.   9.   6.]
 [ 12.  16.  12.   8.]
 [  9.  12.   9.   6.]
 [  6.   8.   6.   4.]]
```



Discussion:
What is the purpose of `correlate2d` anyways? I don't see the purpose of having a redundant function, when `correlate` can do the same thing. Especially when it appears to be broken, and has been for quite some time.  What am I missing here?
@orodbhen correlate2d has different boundary options for image processing
@endolith That makes sense then. `correlate` doesn't appear to allow explicitly setting the boundary, though. Is it assumed to be zero-padded? Then anything else would have to be done manually in the input, correct? 

I'm not clear on why this difference would cause the output to be offset, though. Is that really a bug, or expected behavior? I see this using `same` and the default boundary setting, like the OP.
> correlate doesn't appear to allow explicitly setting the boundary, though. Is it assumed to be zero-padded?  Then anything else would have to be done manually in the input, correct?

Yes

> I'm not clear on why this difference would cause the output to be offset, though.

It wouldn't, that's unrelated. 

The full output of convolve/correlate is always odd-length, so for odd-length input, `same` mode is unambiguous, you center the truncated output:

```
a = [[1, 0, 1], [0, 1, 1], [1, 1, 2]]

b = [[0, 1, 1], [2, 1, 1], [2, 0, 1]]

correlate(a, b)
Out[6]: 
array([[1, 0, 3, 0, 2],
       [1, 2, 4, 3, 4],
       [2, 3, 7, 6, 6],
       [1, 3, 7, 5, 4],
       [1, 2, 3, 2, 0]])

correlate2d(a, b)
Out[7]: 
array([[1, 0, 3, 0, 2],
       [1, 2, 4, 3, 4],
       [2, 3, 7, 6, 6],
       [1, 3, 7, 5, 4],
       [1, 2, 3, 2, 0]])

correlate(a, b, 'same')
Out[8]: 
array([[2, 4, 3],
       [3, 7, 6],
       [3, 7, 5]])

correlate2d(a, b, 'same')
Out[9]: 
array([[2, 4, 3],
       [3, 7, 6],
       [3, 7, 5]])
```

But for even-length input you can't center the output, so you have to shift it one way or the other.  `correlate` author chose one option and `correlate2d` author chose the other.  

```
a = [[1, 0], [1, 2]]

b = [[0, 1], [2, 0]]

correlate(a, b)
Out[12]: 
array([[0, 2, 0],
       [1, 2, 4],
       [1, 2, 0]])

correlate2d(a, b)
Out[13]: 
array([[0, 2, 0],
       [1, 2, 4],
       [1, 2, 0]])

correlate(a, b, 'same')
Out[14]: 
array([[0, 2],
       [1, 2]])

correlate2d(a, b, 'same')
Out[15]: 
array([[2, 4],
       [2, 0]])
```

I'm not sure if one choice makes more sense in certain contexts or if this is just an accident.

It might be this way for consistency with other software, too.  Should compare with Octave and Matlab.
Based on what @endolith concluded, I'm marking this as a documentation issue. I think we need to add to the `Notes` section of these about which outputs are used in the "same" modes for even-length inputs. Probably not worth a deprecation cycle to unify the behaviors.

Resolving patch:
diff --git a/scipy/signal/signaltools.py b/scipy/signal/signaltools.py
--- a/scipy/signal/signaltools.py
+++ b/scipy/signal/signaltools.py
@@ -166,6 +166,9 @@ def correlate(in1, in2, mode='full', method='auto'):
     `fftconvolve`. In certain cases (i.e., arrays of objects or when
     rounding integers can lose precision), ``method='direct'`` is always used.
 
+    When using "same" mode with even-length inputs, the outputs of `correlate`
+    and `correlate2d` differ: There is a 1-index offset between them.
+
     Examples
     --------
     Implement a matched filter using cross-correlation, to recover a signal
@@ -1593,6 +1596,11 @@ def correlate2d(in1, in2, mode='full', boundary='fill', fillvalue=0):
         A 2-dimensional array containing a subset of the discrete linear
         cross-correlation of `in1` with `in2`.
 
+    Notes
+    -----
+    When using "same" mode with even-length inputs, the outputs of `correlate`
+    and `correlate2d` differ: There is a 1-index offset between them.
+
     Examples
     --------
     Use 2D cross-correlation to find the location of a template in a noisy


Test patch: