3

I want to build a block matrix for a system of equation with n points. The result is an (2n+2)x(2n+2) matrix. In example, for 2 points the matrix is:

1 0 0 0 0 0
a b c d 0 0
e f g h 0 0
0 0 a b c d
0 0 e f g h
0 0 0 0 0 1

For 3 points the matrix is

1 0 0 0 0 0 0 0
a b c d 0 0 0 0
e f g h 0 0 0 0
0 0 a b c d 0 0
0 0 e f g h 0 0
0 0 0 0 a b c d
0 0 0 0 e f g h
0 0 0 0 0 0 0 1

Here, a, b, c, d, e, f, g, h are float values known ahead of time. But I don't know value of n ahead of time. Is there a library in python to do this? I've looked at scipy.sparse.diag, scipy.linalg.block_diag and numpy.bat, but these do not achieve what I want.

2

3 Answers 3

1

We can use np.identity to give us a "square" array (same dimensions in both axis) with the ones and zeros as you specified:

myarr = np.identity(2*n+2)

Then, we define our little subset values for a-h:

subset = np.array([[a,b,c,d],[e,f,g,h]])

Now to replace the corresponding values in our larger array:

for i in range(1, 2*n+2-1, 2):
    myarr[i:i+2, i-1:i+3] = subset

EDIT: this is the output for some random values i chose for a-h:

>>> myarr = np.identity(2*n+2)
>>> subset = np.array([[a,b,c,d],[e,f,g,h]])
>>> for i in range(1, 2*n+2-1, 2):
...     myarr[i:i+2, i-1:i+3] = subset
... 
>>> myarr
array([[  1.,   0.,   0.,   0.,   0.,   0.,   0.,   0.],
       [ 11.,   2.,   3.,   4.,   0.,   0.,   0.,   0.],
       [  5.,   6.,   7.,   9.,   0.,   0.,   0.,   0.],
       [  0.,   0.,  11.,   2.,   3.,   4.,   0.,   0.],
       [  0.,   0.,   5.,   6.,   7.,   9.,   0.,   0.],
       [  0.,   0.,   0.,   0.,  11.,   2.,   3.,   4.],
       [  0.,   0.,   0.,   0.,   5.,   6.,   7.,   9.],
       [  0.,   0.,   0.,   0.,   0.,   0.,   0.,   1.]])
Sign up to request clarification or add additional context in comments.

Comments

0

Here's an approach upon computing those linear indices in a broadcasted manner and then assigning into an zeros-initialized array -

def block_mat(list_, n = 2):
    input_arr = np.array(list_).reshape(-1,4)
    N = 2*n + 2
    M = 2*N + 2

    p,q = input_arr.shape
    I,J,K = np.ix_(M*np.arange(n), N*np.arange(p), np.arange(q))
    idx = I + J + K + N

    out = np.zeros((N,N),dtype=input_arr.dtype)
    out.flat[idx] = input_arr
    out.flat[[0,-1]] = 1
    return out

Sample runs -

1) Input elements :

In [497]: a,b,c,d,e,f,g,h = range(3,11)

In [498]: a,b,c,d,e,f,g,h
Out[498]: (3, 4, 5, 6, 7, 8, 9, 10)

2) Various n cases :

In [499]: block_mat([a,b,c,d,e,f,g,h], n = 2)
Out[499]: 
array([[ 1,  0,  0,  0,  0,  0],
       [ 3,  4,  5,  6,  0,  0],
       [ 7,  8,  9, 10,  0,  0],
       [ 0,  0,  3,  4,  5,  6],
       [ 0,  0,  7,  8,  9, 10],
       [ 0,  0,  0,  0,  0,  1]])

In [500]: block_mat([a,b,c,d,e,f,g,h], n = 3)
Out[500]: 
array([[ 1,  0,  0,  0,  0,  0,  0,  0],
       [ 3,  4,  5,  6,  0,  0,  0,  0],
       [ 7,  8,  9, 10,  0,  0,  0,  0],
       [ 0,  0,  3,  4,  5,  6,  0,  0],
       [ 0,  0,  7,  8,  9, 10,  0,  0],
       [ 0,  0,  0,  0,  3,  4,  5,  6],
       [ 0,  0,  0,  0,  7,  8,  9, 10],
       [ 0,  0,  0,  0,  0,  0,  0,  1]])

In [501]: block_mat([a,b,c,d,e,f,g,h], n = 4)
Out[501]: 
array([[ 1,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 3,  4,  5,  6,  0,  0,  0,  0,  0,  0],
       [ 7,  8,  9, 10,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  3,  4,  5,  6,  0,  0,  0,  0],
       [ 0,  0,  7,  8,  9, 10,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  3,  4,  5,  6,  0,  0],
       [ 0,  0,  0,  0,  7,  8,  9, 10,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  3,  4,  5,  6],
       [ 0,  0,  0,  0,  0,  0,  7,  8,  9, 10],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  1]])

Comments

0

Here is code that will work for you:

import string
n = 3
letters = string.ascii_lowercase
block1 = letters[:4]
block2 = letters[4:8]
matrix = [[1 if b == 0 and i == 0 or b == 2*n+1 and i == 2*n + 1 else 0 for b in range(2*n+2)] for i in range(2*n+2)]
count = 0

for i, a in enumerate(matrix[1:-1]): #fix to account for the fact that we are starting at 2, not 0

    if i%2 == 0:
        matrix[i+1][count:count+4] = list(block1)


    else:
        matrix[i+1][count:count+4] = list(block2)


        count += 2

for i in matrix:
    print i

Output for when n == 3:

[1, 0, 0, 0, 0, 0, 0, 0]
['a', 'b', 'c', 'd', 0, 0, 0, 0]
['e', 'f', 'g', 'h', 0, 0, 0, 0]
[0, 0, 'a', 'b', 'c', 'd', 0, 0]
[0, 0, 'e', 'f', 'g', 'h', 0, 0]
[0, 0, 0, 0, 'a', 'b', 'c', 'd']
[0, 0, 0, 0, 'e', 'f', 'g', 'h']
[0, 0, 0, 0, 0, 0, 0, 1]

Output for when n == 2:

[1, 0, 0, 0, 0, 0]
['a', 'b', 'c', 'd', 0, 0]
['e', 'f', 'g', 'h', 0, 0]
[0, 0, 'a', 'b', 'c', 'd']
[0, 0, 'e', 'f', 'g', 'h']
[0, 0, 0, 0, 0, 1]

I realize that you are not actually using the strings "a", "b", "c", etc., but when you want to use variables, replace block1 with a list of your first four variables and block2 with a list of your last four variables.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.