2
votes

Suppose we have two square matrices "x" and "y" of dimension nxn and a numeric variable "a". I want to concatenate those matrices a number of times depending on the parameter "a", so to obtain a bigger square matrix "xy". This new matrix will contain only copies of the first two matrices arranged in the following way : matrix "x" on the main diagonal of the new matrix "xy" and matrix "y" in all other entries of the matrix "xy".

Here some example to clarify the question:

input: two 2x2 matrices

x=np.array([[1,1],[1,1]])
y=np.array([[2,2],[2,2]])

for a=2 expected output:

xy=np.array([[1,1,2,2],
            [1,1,2,2],
            [2,2,1,1],
            [2,2,1,1]])

for a=3expected output:

xy=np.array([[1,1,2,2,2,2],
            [1,1,2,2,2,2],
            [2,2,1,1,2,2],
            [2,2,1,1,2,2],
            [2,2,2,2,1,1],
            [2,2,2,2,1,1]])`

what I'm looking for is a code for the generic case with a=n

1

1 Answers

1
votes

One possible way of doing that may be.

Given x, y and concatenation factor a, first create a block diagonal matrix X of a blocks of x, then take all non zero index X_idx of it, i.e. the index of block diagonal elements. Here, I suppose that your x does not contain zero components.

Now, create a matrix Y, which is just a tile of shape (a,a) of y blocks. Finally, let's make the diagonal blocks of Y zero by applying the X_idx mask to it and sum X and Y to obtain the desired XY matrix. It follows:

import numpy as np
from scipy.linalg import block_diag

x = np.array([[1,1],[1,1]])
y = np.array([[2,2],[2,2]])    
a = 3

X =  block_diag(*[x]*a)
X_idx = np.nonzero(X)
Y = np.tile(y,(a,a))
Y[X_idx] = 0
XY = X + Y

which outputs the corresponding XY

>>> array([[1, 1, 2, 2, 2, 2],
           [1, 1, 2, 2, 2, 2],
           [2, 2, 1, 1, 2, 2],
           [2, 2, 1, 1, 2, 2],
           [2, 2, 2, 2, 1, 1],
           [2, 2, 2, 2, 1, 1]])

In case x have zero values, just replace np.nonzero call by:

X_idx = (np.repeat(np.arange(a*x.shape[0]),x.shape[0]),
         np.r_[[np.tile(np.arange(i,i+x.shape[0]),x.shape[0]) for i in range(0,a*x.shape[0],x.shape[0])]].ravel())