Let's go through a simple implementation of np.convolve whose documentation can be found here.
import numpy as np
def convolve_1d(a, filter):
N, M = len(a), len(filter)
assert N >= M # assumption in the question
# in the full mode (default of np.convolve), result length is N+M-1
# therefore, pad should be M-1 on each side
# N-M+2p+1 == N+M-1 => p = M-1
result_length = N+M-1
result = np.zeros(result_length) # allocating memory for result
p = M-1
padded_a = np.pad(a,p)
flipped_filter = np.flip(filter)
for i in range(result_length):
result[i] = np.sum(np.multiply(flipped_filter, padded_a[i:i+M]))
return result
a = np.array([1,2,3,4])
filter = np.array([1,-1,3])
convolve_1d(a, filter)
results in
array([ 1., 1., 4., 7., 5., 12.])
which is the same as the result for np.convolve(a, filter).
So, it basically pads the input array with zeros, flips the filter and sums the element-wise multiplication of two arrays.
I am not sure about the index that you mentioned; the result is a 1d array and you can index its elements.
To add stride to this function, we need to modify the result_length and multiply the stride to the iterator:
def convolve_1d_strided(a, filter, stride):
N, M = len(a), len(filter)
assert N >= M # assumption in the question
# in the full mode (default of np.convolve), result length is N+M-1
# therefore, pad should be M-1 on each side
# N-M+2p+1 == N+M-1 => p = M-1
result_length = (N+M-1)//stride
result = np.zeros(result_length) # allocating memory for result
p = M-1
padded_a = np.pad(a,p)
flipped_filter = np.flip(filter)
for i in range(result_length):
result[i] = np.sum(np.multiply(flipped_filter, padded_a[i*stride:i*stride+M]))
return result
a = np.array([1,2,3,4])
filter = np.array([1,-1,3])
convolve_1d_strided(a, filter, 2)
array([1., 4., 5.])
Hope it helps and if that is what you liked to see, I am happy to expand it to two dimensions.