Search code examples
pythonmatlabnumpymatrix-indexing

Logical indexing using a mask works in numpy, not in Matlab


I'm trying to reproduce the following Python code in MATLAB, using a sparse matrix.

>>> print(M)
[[0 0 0 0 0]
 [0 1 1 1 0]
 [0 1 0 1 0]
 [0 1 1 1 0]
 [0 0 0 0 0]]
>>> im2var = np.arange(5 * 5).reshape((5, 5))
>>> A = np.zeros((25, 25), dtype=int)
>>> A[im2var[M == 1], im2var[M == 1]] = 1
>>> print(A)
[[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]

This is what I've written in MATLAB

M = [
    0 0 0 0 0;
    0 1 1 1 0;
    0 1 0 1 0;
    0 1 1 1 0;
    0 0 0 0 0
];

im2var = reshape(1:25, [5 5]);
A = zeros(25, 25);
A(im2var(M == 1), im2var(M == 1)) = 1;
num2str(A)

When I run the MATLAB script, I get the following matrix, which is clearly different from the Numpy output.

ans =

  25x73 char array

    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  1  1  1  0  0  1  0  1  0  0  1  1  1  0  0  0  0  0  0'
    '0  0  0  0  0  0  1  1  1  0  0  1  0  1  0  0  1  1  1  0  0  0  0  0  0'
    '0  0  0  0  0  0  1  1  1  0  0  1  0  1  0  0  1  1  1  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  1  1  1  0  0  1  0  1  0  0  1  1  1  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  1  1  1  0  0  1  0  1  0  0  1  1  1  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  1  1  1  0  0  1  0  1  0  0  1  1  1  0  0  0  0  0  0'
    '0  0  0  0  0  0  1  1  1  0  0  1  0  1  0  0  1  1  1  0  0  0  0  0  0'
    '0  0  0  0  0  0  1  1  1  0  0  1  0  1  0  0  1  1  1  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'

Thanks for any assistance!

EDIT: I would also like to accomplish the following effect, but the current answer doesn't seem to work for two sets of indices.

In Python:

>>> Mp = np.roll(M, 1, axis=1)
>>> A[im2var[M==1], im2var[Mp==1]] = -1
>>> print(A[5:15,5:15])
[[ 0  0  0  0  0  0  0  0  0  0]
 [ 0  1 -1  0  0  0  0  0  0  0]
 [ 0  0  1 -1  0  0  0  0  0  0]
 [ 0  0  0  1 -1  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  1 -1  0  0]
 [ 0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  1 -1]
 [ 0  0  0  0  0  0  0  0  0  0]]

By using the current answer's suggestion, I wrote the following code.

M = [
    0 0 0 0 0;
    0 1 1 1 0;
    0 1 0 1 0;
    0 1 1 1 0;
    0 0 0 0 0
];

Mp = circshift(M, 1, 2);

ind = find(M);
indp = find(Mp);

A = zeros(25, 25);
A(sub2ind(size(A), ind, ind)) = 1;
A(sub2ind(size(A), ind, indp)) = -1;

num2str(A)

While the diagonal 1s have successfully showed up, the -1s are in the wrong place.

ans =

  25x73 char array

    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  1  0  0  0  0 -1  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  1  0  0  0  0 -1  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  1  0  0  0  0 -1  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0 -1  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0 -1  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0 -1  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0 -1  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  0  0  0  0 -1  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0'

EDIT 2:

According to the edited answer, I tried the following code.

M = [
    0 0 0 0 0;
    0 1 1 1 0;
    0 1 0 1 0;
    0 1 1 1 0;
    0 0 0 0 0
];

Mp = circshift(M, 1, 2);

ind = find(M);
indp = find(Mp.');

A = zeros(25, 25);
A(sub2ind(size(A), ind, ind)) = 1;
A(sub2ind(size(A), ind, indp)) = -1;

num2str(A(5:14, 5:14))

but it still doesn't yield the same result as the Python code in EDIT 1.

ans =

  10x28 char array

    '0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0'
    '0  0  1 -1  0  0  0  0  0  0'
    '0  0  0  1 -1  0  0  0  0  0'
    '0  0  0  0  1 -1  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  1 -1  0'
    '0  0  0  0  0  0  0  0  0  0'
    '0  0  0  0  0  0  0  0  0  1'

Solution

  • In MATLAB, you get relevant row and column subscripts of A returned by im2var(M == 1) of your targeted places for ones. This can alternately be done with find(M.') without the need to initialise im2var or just find(M) since M equals transpose(M) in your case. find(M) returns linear indices where M is not zero but the linear indices of M are the same as row and column subscripts of A. You cannot directly use these row and column subscripts and need to convert them into linear indices and then proceed i.e.

    ind = find(M);     % ind = find(M.'); in general
    A(sub2ind(size(A),ind,ind)) = 1;
    

    P.S: Note that MATLAB follows the column major order whereas NumPy follows the row major order.