Home > Blockchain >  How can I produce this sparsity pattern elegantly with numpy?
How can I produce this sparsity pattern elegantly with numpy?

Time:10-23

For a D-dimensional problem I'm trying to generate a 2d ndarray with a particular sparsity pattern.

I've been trying to figure out how to interleave vectors using np.meshgrid and the like but just can't get there.

The sparsity matrix (it doesn't need to actually be sparse, just contain 0s and 1s) is of shape (2^D, D) where D is the number of dimensions.

For D=2 the matrix looks like this:

two_d = [
    [0, 0],
    [1, 0],
    [0, 1],
    [1, 1],
]

For D=3 it's like this:

three_d = [
    [0, 0, 0],
    [1, 0, 0],
    [0, 1, 0],
    [1, 1, 0],
    [0, 0, 1],
    [1, 0, 1],
    [0, 1, 1],
    [1, 1, 1],
]

It's a super obvious sparsity pattern but I'm struggling figure out how to reproduce that elegantly with numpy.

Note: the row-ordering doesn't actually matter, as long as all rows are present.

CodePudding user response:

Eligigance is in the eye of the beholder. There are a number of tools for generating the values; putting them into the desired layout is just basic numpy manipulation.

A good basic way to produce these arrays is:

In [6]: np.array(list(itertools.product([0,1],repeat=2)))
Out[6]: 
array([[0, 0],
       [0, 1],
       [1, 0],
       [1, 1]])
In [7]: np.array(list(itertools.product([0,1],repeat=3)))
Out[7]: 
array([[0, 0, 0],
       [0, 0, 1],
       [0, 1, 0],
       [0, 1, 1],
       [1, 0, 0],
       [1, 0, 1],
       [1, 1, 0],
       [1, 1, 1]])

From the comments:

In [16]: np.indices((2,2))
Out[16]: 
array([[[0, 0],
        [1, 1]],

       [[0, 1],
        [0, 1]]])
In [17]: np.indices((2,)*2).T.reshape(-1,2)
Out[17]: 
array([[0, 0],
       [1, 0],
       [0, 1],
       [1, 1]])
In [18]: np.indices((2,)*3).T.reshape(-1,3)
Out[18]: 
array([[0, 0, 0],
       [1, 0, 0],
       ...

In [20]: np.meshgrid(np.arange(2),np.arange(2),indexing='ij')
Out[20]: 
[array([[0, 0],
        [1, 1]]),
 array([[0, 1],
        [0, 1]])]
In [21]: np.transpose(np.meshgrid(np.arange(2),np.arange(2),indexing='ij')).resh
    ...: ape(-1,2)
Out[21]: 
array([[0, 0],
       [1, 0],
       [0, 1],
       [1, 1]])

The 'ij' isn't essential; it just makes an initial set of arrays that looks like the indices.

mgrid also can be used. and:

np.array(list(np.ndindex(2,2,2)))

Another approach is to reverse engineer three_d.

In [55]: res = np.zeros((2**3,3),int)

Setting every other element of the 1st column is easy:

In [56]: res[1::2,0]=1
In [57]: res
Out[57]: 
array([[0, 0, 0],
       [1, 0, 0],
       [0, 0, 0],
       [1, 0, 0],
       [0, 0, 0],
       [1, 0, 0],
       [0, 0, 0],
       [1, 0, 0]])

setting pairs of values in the 2nd is trickier:

In [58]: res[:,1].reshape(-1,4)[:,2:]=1
In [59]: res
Out[59]: 
array([[0, 0, 0],
       [1, 0, 0],
       [0, 1, 0],
       [1, 1, 0],
       [0, 0, 0],
       [1, 0, 0],
       [0, 1, 0],
       [1, 1, 0]])

setting a contiguous block of the third is again easy:

In [60]: res[4:,2]=1
In [61]: res
Out[61]: 
array([[0, 0, 0],
       [1, 0, 0],
       [0, 1, 0],
       [1, 1, 0],
       [0, 0, 1],
       [1, 0, 1],
       [0, 1, 1],
       [1, 1, 1]])
  • Related