naz
naz

Reputation: 2072

Constructing a special matrix in numpy dynamically

So my objective is the following, given the size of the matrix s, I am attempting to create a matrix that looks like the following, but for size sxs:

[1 1 0]
[1 1 1]
[0 1 1]

For the size of 4x4, it would look something like the following:

[1 1 0 0]
[1 1 1 0]
[0 1 1 1]
[0 0 1 1]

Therefore you can observe a pattern: there are s-1 number of overlapping mini 2x2 ones matrices.

I was thinking of creating a 2x2 ones matrix and then by using a dynamic referencing (for loop?) like B[:-1,:-1] = ones_matrix, where B is the zeros matrix of size sxs. But I am not sure how to incorporate a for loop here, because if we take say a 4x4 matrix, then we would have to reference B in three ways like so: B[:-1,:-1] = ones_matrix, B[1:-1,1:-1] = ones_matrix, B[2:,2:]=ones_matrix. And I can't figure out a way to do that dynamically for n-sized zeros matrix. Is there perhaps another way to do this?

Upvotes: 2

Views: 242

Answers (3)

DSM
DSM

Reputation: 353199

Method #1: Instead of a bunch of 2x2 matrices, it might be easier to look at it as three diagonals of 1 and combine those:

>>> s = 3
>>> np.diag([1]*s,0) + np.diag([1]*(s-1),-1) + np.diag([1]*(s-1), 1)
array([[1, 1, 0],
       [1, 1, 1],
       [0, 1, 1]])
>>> s = 4
>>> np.diag([1]*s,0) + np.diag([1]*(s-1),-1) + np.diag([1]*(s-1), 1)
array([[1, 1, 0, 0],
       [1, 1, 1, 0],
       [0, 1, 1, 1],
       [0, 0, 1, 1]])

Method #2: (inspired by Divankar's answer), we can think in terms of distance from the centre:

>>> s = 4
>>> i,j = np.indices((s,s))
>>> (abs(i-j) <= 1).astype(int)
array([[1, 1, 0, 0],
       [1, 1, 1, 0],
       [0, 1, 1, 1],
       [0, 0, 1, 1]])

Method #3: we could take advantage of tril or triu and do some arithmetic:

>>> m = np.tril(np.ones((s,s)),1)
>>> m * m.T
array([[ 1.,  1.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  1.,  1.]])
>>> m = np.tril(np.ones((s,s)),2)
>>> m * m.T
array([[ 1.,  1.,  1.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 0.,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  1.,  1.,  1.]])

Upvotes: 3

Divakar
Divakar

Reputation: 221584

Vectorized approach with broadcasting -

A = np.arange(s)
out = ((A[:,None] < A+2) & (A[:,None] > A-2)).astype(int)

Sample run -

In [60]: s = 3
    ...: A = np.arange(s)
    ...: out = ((A[:,None] < A+2) & (A[:,None] > A-2)).astype(int)
    ...: 

In [61]: out
Out[61]: 
array([[1, 1, 0],
       [1, 1, 1],
       [0, 1, 1]])

In [62]: s = 4
    ...: A = np.arange(s)
    ...: out = ((A[:,None] < A+2) & (A[:,None] > A-2)).astype(int)
    ...: 

In [63]: out
Out[63]: 
array([[1, 1, 0, 0],
       [1, 1, 1, 0],
       [0, 1, 1, 1],
       [0, 0, 1, 1]])

Upvotes: 1

Emilien
Emilien

Reputation: 2445

You could use sympy.Matrix also:

from sympy import Matrix
Matrix(4, 4, lambda i,j: 1 if (-2<i-j<2) else 0)

Matrix([
[1, 1, 0, 0],
[1, 1, 1, 0],
[0, 1, 1, 1],
[0, 0, 1, 1]])

Upvotes: 0

Related Questions