Home > Software engineering >  How to create a sparse matrix with a given base matrix?
How to create a sparse matrix with a given base matrix?

Time:06-17

I have the following 2 x 2 matrix

1 0
1 1

I want to expand this matrix with dimensions in powers of 2. For example the matrix with dimension 4 would look like:

1 0 0 0
1 1 0 0
1 0 1 0
1 1 1 1

Essentially, I want to retain the original matrix wherever 1 occurs in the base matrix and fill up zeros where 0 occurs in the base matrix? Is there a fast way to do this in numpy or scipy? I want to be able to expand this to any power of 2, say 512 or 1024.

CodePudding user response:

For relatively small values of the powers of 2 (say up to 10), you can recursively replace every 1 with the inital matrix a using numpy block:

import numpy as np

a = np.array([[1, 0], [1, 1]])

def generate(a, k):
    z = np.zeros_like(a)
    result = a.copy()
    for _ in range(1, k):
        result = eval(f"np.block({str(result.tolist()).replace('1', 'a').replace('0', 'z')})")
    return result

Example for k=3 (8x8 result matrix) generate(a, 3):

array([[1, 0, 0, 0, 0, 0, 0, 0],
       [1, 1, 0, 0, 0, 0, 0, 0],
       [1, 0, 1, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0, 0, 0],
       [1, 0, 0, 0, 1, 0, 0, 0],
       [1, 1, 0, 0, 1, 1, 0, 0],
       [1, 0, 1, 0, 1, 0, 1, 0],
       [1, 1, 1, 1, 1, 1, 1, 1]])

CodePudding user response:

You can combine tile and repeat.

>>> np.tile(arr, (2, 2))

array([[1, 0, 1, 0],
       [1, 1, 1, 1],
       [1, 0, 1, 0],
       [1, 1, 1, 1]]

>>> np.repeat(np.repeat(arr, 2, axis=1), 2, axis=0)

array([[1, 1, 0, 0],
       [1, 1, 0, 0],
       [1, 1, 1, 1],
       [1, 1, 1, 1]])

Then just multiply:

def tile_mask(a):
    tiled = np.tile(a, (2, 2))
    mask = np.repeat(
        np.repeat(a, 2, axis=1),
        2, axis=0
    )
    return tiled * mask

>>> tile_mask(arr)

array([[1, 0, 0, 0],
       [1, 1, 0, 0],
       [1, 0, 1, 0],
       [1, 1, 1, 1]])

I don't know of a good way to do this for higher powers besides recursion though:

def tile_mask(a, n=2):
    
    if n > 2:
        a = tile_mask(a, n-1)
        
    tiled = np.tile(a, (2, 2))
    mask = np.repeat(
        np.repeat(a, 2, axis=1),
        2, axis=0
    )
    return tiled * mask

>>> tile_mask(arr, 3)

array([[1, 0, 0, 0, 0, 0, 0, 0],
       [1, 1, 0, 0, 0, 0, 0, 0],
       [1, 0, 1, 0, 0, 0, 0, 0],
       [1, 1, 1, 1, 0, 0, 0, 0],
       [1, 0, 0, 0, 1, 0, 0, 0],
       [1, 1, 0, 0, 1, 1, 0, 0],
       [1, 0, 1, 0, 1, 0, 1, 0],
       [1, 1, 1, 1, 1, 1, 1, 1]])
  • Related