[PYTHON] Folded tensor-like notation

I found a way to do the convolution operation only with the array operation of numpy's ndarray. However, I am using the tensor-like class of my own module. Variables and subscripts mean the elements of a set (general definitions are unstudied and unclear).

Formula

However, it uses self-defined arithmetic rules.

I,J,K,L\subset\mathbb{N}, i\in I,j\in J,k\in K,l\in L , x_{ik}\in\left\\{ i_{i}+k_{k}\right\\} , y_{jl}\in\left\\{ j_{j}+l_{l}\right\\} ,I_{ij}\in\mathbb{R}^{|I|\\times |J|},h^{kl}\in\mathbb{R}^{|K|\\times |L|}

will do.


\bar{I}_{ij}	=	I_{x_{ik}y_{jl}}h^{kl}

Program implementation example

Compared with the result of scipy.signal.fftcomvolve.

from scipy.signal import *

def convolve2d_tensorlike(I, h, mode="full"):
    hrows = h.shape[0]
    hcols = h.shape[1]
    add = zeros(h.shape[0]-1)
    rows = I.shape[0]
    cols = I.shape[1]

    add = array(h.shape)-1
    if mode=="full":

        I_zeros = zeros(array(I.shape) + 2*add)
        I_zeros[add[0]:-add[1], add[0]:-add[1]] = I
        I = I_zeros
    elif mode=="valid":
        add = array(h.shape)-1
    else:
        I_zeros = zeros(array(I.shape) + add)
        I_zeros[add[0]/2:-add[0]/2,add[1]/2:-add[1]/2] = I
        I = I_zeros
    
    rows = I.shape[0]
    cols = I.shape[1]
    i = tensor(cols*arange(rows-add[0]), "i", "d")
    j = tensor(arange(cols-add[0]), "j", "d")
    k = tensor(cols*arange(hrows), "k", "d")
    l = tensor(arange(hcols), "l", "d")
    h = tensor(h, "kl", "uu")

    x = (i + j + k + l)

    x.transpose("ijkl") #X in the above equation_{ik}y_{jl}Corresponds to
    
    I_bar = tensor(I.flatten()[x.arr.flatten().astype(int)]
                   .reshape(x.arr.shape), "ijkl", "dddd")
    I_bar = I_bar * h
    I_bar.transpose("ij")
    
    return I_bar.arr

I = array([[1,5,99,7,6],
           [6,5,38,7,2],
           [1,6,8,2,6],
           [7,5,2,3,7],
           [3,5,8,7,1]])
h = ones((3,3))
print "fftconvolve(I, h,'full')"
print  convolve2d_tensorlike(I, h,"full") 
print 

print "fftconvolve(I, h,'full')"
print  convolve2d_tensorlike(I, h, 'full')
print 

print "fftconvolve(I, h,'same'')"
print  fftconvolve(I, h,"same") 
print 

print "convolve2d_tensorlike(I, h,'same'')"
print  convolve2d_tensorlike(I, h,"same") 
print 

print "fftconvolve(I, h,'valid'')"
print  fftconvolve(I, h,"valid") 
print 

print "convolve2d_tensorlike(I, h,'valid'')"
print  convolve2d_tensorlike(I, h,"valid") 
print 

Execution result

fftconvolve(I, h,'full')
[[   1.    6.  105.  111.  112.   13.    6.]
 [   7.   17.  154.  161.  159.   22.    8.]
 [   8.   24.  169.  177.  175.   30.   14.]
 [  14.   30.   78.   76.   75.   27.   15.]
 [  11.   27.   45.   46.   44.   26.   14.]
 [  10.   20.   30.   30.   28.   18.    8.]
 [   3.    8.   16.   20.   16.    8.    1.]]

fftconvolve(I, h,'full')
[[   1.    6.  105.  111.  112.   13.    6.]
 [   7.   17.  154.  161.  159.   22.    8.]
 [   8.   24.  169.  177.  175.   30.   14.]
 [  14.   30.   78.   76.   75.   27.   15.]
 [  11.   27.   45.   46.   44.   26.   14.]
 [  10.   20.   30.   30.   28.   18.    8.]
 [   3.    8.   16.   20.   16.    8.    1.]]

fftconvolve(I, h,'same'')
[[  17.  154.  161.  159.   22.]
 [  24.  169.  177.  175.   30.]
 [  30.   78.   76.   75.   27.]
 [  27.   45.   46.   44.   26.]
 [  20.   30.   30.   28.   18.]]

convolve2d_tensorlike(I, h,'same'')
[[  17.  154.  161.  159.   22.]
 [  24.  169.  177.  175.   30.]
 [  30.   78.   76.   75.   27.]
 [  27.   45.   46.   44.   26.]
 [  20.   30.   30.   28.   18.]]

fftconvolve(I, h,'valid'')
[[ 169.  177.  175.]
 [  78.   76.   75.]
 [  45.   46.   44.]]

convolve2d_tensorlike(I, h,'valid'')
[[ 169.  177.  175.]
 [  78.   76.   75.]
 [  45.   46.   44.]]
 
a = arange(9).reshape((3,3))
#a=
#[[0 1 2]
# [3 4 5]
# [6 7 8]]
#
print a[ix_([0,1,2],[2,0,1])] 
#<-Returns the elements of matrix a as the following matrix(line,Column)
#[[(0,2), (0,0), (0,1)]
# [(1,2), (1,0), (1,1)]
# [(1,2), (1,0), (1,1)]]

print a[ix_([0,1],[2,0])] 
#[[(0,2), (0,0)]
# [(1,2), (1,0)]]




#Applicable to N dimensions
a = arange(27).reshape((3,3,3))
print a
print

print a[ix_([0,1,2],[2,0,1],[0,2,1])] #OK
print 

print a[ix_([0,1,2],[2,0,1])] #This is also OK
print 
print a[ix_([0,1,2],[2,0,1],[0,1,2])] #a[ix_([0,1,2],[2,0,1])]Equivalent to
print 

print a[ix_([0,1,2],[2,0,1],[0,1,2],[0,1,2])] #NG, 

Therefore, $ I_ {x_ {ik} y_ {jk}} $ passes the tensor for indexing $ x_ {ik}, y_ {jl} $ of rank 2 to $ I \ (x, y ) $ and ranks. It means to get $ I $ of 4, but I can't just assign it to python. Therefore, in the above, indexing is performed after setting the rank to 1 with flatten ().

Recommended Posts

Folded tensor-like notation
Comprehension notation
Format notation
Comprehension notation