def xprop_winograd(I, F, O, padding, minimal=False, trans=False, backward=False):

    if backward:
        # C <=> K and mirror R,S
        F = np.transpose(F[:,::-1,::-1,:], (3,1,2,0)).copy()
        # Invert padding
        padding = [2 - p for p in padding]

    C, Y, X, N = I.shape
    K, P, Q, N = O.shape

    B = 4
    D = B + 2
    Yw = ceil_div(P, B)
    Xw = ceil_div(Q, B)

    Fw = np.empty((D,D,C,K))
    Iw = np.empty((D,D,C,Yw,Xw,N))
    Mw = np.empty((D,D,K,Yw,Xw,N)) #, dtype=np.int64

    # Transform Filters
    for c in range(C):
        for k in range(K):
            trans_F_4x4_3x3(Fw[:,:,c,k], F[c,:,:,k], minimal, trans)

    # Iterate over image transform dimensions and slice out tiles of the image
    for y in range(Yw):
        start_y, stop_y, pad_y = image_slice(y, Y, B, D, padding[0])

        for x in range(Xw):
            start_x, stop_x, pad_x = image_slice(x, X, B, D, padding[1])

            sliceI = I[:, start_y:stop_y, start_x:stop_x, :]

            # add any zero padding if needed
            if any(pad_y) or any(pad_x):
                sliceI = np.pad(sliceI, ((0,0), pad_y, pad_x, (0,0)), 'constant')

            # Apply the Image transform
            for c in range(C):
                for n in range(N):
                    trans_I_4x4_3x3(Iw[:,:,c,y,x,n], sliceI[c,:,:,n], minimal, trans)

    # Fw, scaleF = quantize(Fw, 16)
    # Iw, scaleI = quantize(Iw, 16)

    # Fw = Fw.astype(np.float16).astype(np.float64)
    # Iw = Iw.astype(np.float16).astype(np.float64)

    # Batched gemm for the pointwise multiplication step
    for s in range(D):
        for t in range(D):
            # [K,Yw,Xw,N] = [C,K].T . [C,YwXwN]
            Mw[s,t] = np.dot( Fw[s,t].T, Iw[s,t].reshape(C, -1) ).reshape((K,Yw,Xw,N))

    # print Mw[:,:,0,0,0,0]
    # exit()

    # Mw = Mw.astype(np.float64) * scaleF * scaleI

    # Iterate over the convovled result in the pointwise space and apply inverse transform
    for y in range(Yw):
        p0, p1, plen = output_slice(y, P, B)
        for x in range(Xw):
            q0, q1, qlen = output_slice(x, Q, B)
            for k in range(K):
                for n in range(N):
                    # Toss out any points that don't fit
                    #print y, x, plen, qlen
                    Out = trans_O_4x4_3x3(Mw[:,:,k,y,x,n], minimal, trans)
                    #print Out
                    #print Out[0:plen,0:qlen]
                    O[k,p0:p1,q0:q1,n] = Out[0:plen,0:qlen]
dataset/ETHPy150Open NervanaSystems/neon/neon/backends/winograd4.py/xprop_winograd/original