How to Kronecker by row (one dimension only)

I have two matrices A and B. Rather than a full Kronecker product kron(A,B), I would like to Kronecker in a row-by-row fashion. That is, the first row of the resulting matrix should have kron(A[1,:],B[1,:]), the second row kron(A[2,:],B[2,:]), and so on. The two matrices will have the same number of rows of course.

mapslices seems to only accept one item, not two. I think I want something like map(kron,zip(eachrow(A),eachrow(B))) but this does not work. It is also important that the ordering of the columns is the same as what kron(A,B) would produce.

I have a function that works, but when is that ever enough? :smiley:

function kronrow(X,Y)
    N,K = size(X)
    L = size(Y,2)
    res = Matrix{Float64}(undef,N,K*L)
    for i=1:N
        res[i,:] = @views kron(X[i,:],Y[i,:])
    end
    return res
end

Is there a better way?

Have you taken a look at https://github.com/MichielStock/Kronecker.jl? It provides lazy evaluation of Kronecker products and may fit your use case, though I don’t believe there is a built-in function which does as your request.

2 Likes

Yes, you can do this just by reshaping and broadcasting:

X, Y = rand(Int8, 2,2), ones(Int, 2,3);
kronrow(X, Y)

using TensorCast
@cast K[r,(j,i)] := X[r,i] * Y[r,j]  # (j,i) to match kron

hkron(X::AbstractMatrix, Y::AbstractMatrix) = reshape(reshape(X, size(X,1), 1, size(X,2)) .* Y, size(X,1), size(X,2) * size(Y,2))
hkron(X,Y)
1 Like

Thanks! Both of those are faster than kronrow – 2-3x for my problem size, but 10x faster for larger problems.