# Translating a 1d convolution from Python to Julia

Hi all,

I am trying to port some code written in Python. It performs a 1d convolution on a 3d array. The Python and Julia code output arrays with different dimensions and values. Does anyone know the equivalent code on Julia?

Julia

``````using DSP
x = [0 0 1 2 3 5 0 0; 0 0 4 5 6 5 0 0 ;;; 0 0 2 3 4 5 0 0 ; 0 0 5 6 7 5 0 0]
z = [5,6,7,10]
conv(x, z)
``````

output:

``````5×8×2 Array{Int64, 3}:
[:, :, 1] =
0  0   5  10  15  25  0  0
0  0  26  37  48  55  0  0
0  0  31  44  57  65  0  0
0  0  38  55  72  85  0  0
0  0  40  50  60  50  0  0

[:, :, 2] =
0  0  10  15  20  25  0  0
0  0  37  48  59  55  0  0
0  0  44  57  70  65  0  0
0  0  55  72  89  85  0  0
0  0  50  60  70  50  0  0
``````

Python

``````import scipy
x1 = np.array([[0,0,1,2,3,5,0,0],[0,0,4,5,6,5,0,0]])
x2 = np.array([[0,0,2,3,4,5,0,0],[0,0,5,6,7,5,0,0]])
x = np.dstack((x1, x2))
z = [5,6,7,10]
scipy.ndimage.convolve1d(x, z, axis=1, mode='constant', cval=0)
``````

output:

``````array([[[  5,  10],
[ 16,  27],
[ 34,  52],
[ 67,  90],
[ 71,  88],
[ 65,  75],
[ 50,  50],
[  0,   0]],

[[ 20,  25],
[ 49,  60],
[ 88, 106],
[136, 159],
[122, 139],
[ 95, 105],
[ 50,  50],
[  0,   0]]])
``````

I suggest determining how the `convolve1d` is defined in numpy.
Do the same for the `conv` operation in `DSP`.
Then generate the correct calls in Julia.

In practice, I’ve found the simplest is to apply the operations to simple
arrays and see what happens by inspection. You can do that in both
scipy and julia REPLs.

Things to look for

• Expanding dimensions versus circular correlation or implicit padding
• Dimension order and index offsets
• Differences in print or display representations
• Applying a 1-D operation along a specific dimension of a multi-dimensional data array
• You julia and numpy versions (I think repeated `;;;` inside `[]` changed in recent versions of julia

N.B. I haven’t used scipy/numpy and not used the DSP package in Julia.

1 Like

Thank you. This is good advice. I read through the documentation and code to the best of my ability and tried to discern patterns with simpler examples. The problem is that the behavior of the functions become more divergent as the number of dimensions increases.

The scipy documentation provides the following example:

``````convolve1d([2, 8, 0, 4, 1, 9, 9, 0], [1, 3], cval=0)
array([14, 24,  4, 13, 12, 36, 27,  0])
``````

In Julia, the code produces:

``````conv([2, 8, 0, 4, 1, 9, 9, 0], [1, 3])
9-element Vector{Int64}:
2
14
24
4
13
12
36
27
0
``````

The results are similar except for an additional 2 in the Julia output. In my first example involving a 3d array, the arrays differ in ways that I have yet to understand.

The following produces the same result:

``````using DSP
x = [0 0 1 2 3 5 0 0; 0 0 4 5 6 5 0 0 ;;; 0 0 2 3 4 5 0 0 ; 0 0 5 6 7 5 0 0]
z = [5,6,7,10]

n, m = length(z)÷2, size(x,2)
r0 = conv.(eachslice(x,dims=1), (z,))
r = [view(u,n+1:n+m,:) for u in r0]

julia> r[1]
8×2 Matrix{Int64}:
5  10
16  27
34  52
67  90
71  88
65  75
50  50
0   0

julia> r[2]
8×2 Matrix{Int64}:
20   25
49   60
88  106
136  159
122  139
95  105
50   50
0    0
``````

The result of the DSP convolution must be cut off at the beginning and end, so that its output has the same length as the input.

1 Like

Thank you for your help! I will study this in more detail tomorrow.

Adding `view()` inside the comprehension above provides better performance (NB: edited the post), but another way to trim the convolution output is:

``````r = selectdim.(r0, 1, (n+1:n+m,))
``````
1 Like

Thanks for your help! I will mark your answer as a solution. I will provide an update if I am clever enough to find a more efficient solution (I suspect that `convolve1d` in `scipy` is more efficient because it is not manipulating intermediate arrays). But in either case, having a correct solution is very helpful!

1 Like