Why do logical indices implicitly reshape? Is there a workaround?

25 views (last 30 days)
I've encountered this several times, and it always bothers me. Say for example I want to sum each row of matrix A, for values less than 0.5:
A = rand(3);
B = zeros( size(A) );
B(A<0.5) = A(A<0.5);
row_sum = sum( B, 2 );
But it feels like I should be able to simplify this, with something like:
row_sum = sum( A(A<0.5), 2 );
but this obviously fails because while A<0.5 preserves shape, A(A<0.5) returns a vector where the A<0.5 matrix is implicitly linearized.
I get why this happens (A>0.5 elements would be undefined in a matrix), but it seems incongruous with how logical indices are presented to the user as shape-preserving operations. After all, A<0.5 returns a logical matrix and you would need to call find(A<0.5) to acess the linear indices used to generate A(A<0.5).
In my humble opinion, it seems like this is exactly what NaN should exist for. If the default behavior of A(A<0.5) was to return NaN for A(A>0.5), then having functions like sum with 'omitnan' enabled by default would produce more intuitive results. Am I missing something?
Getting back to earth, are there any practical ways to simplify the above process?
  4 Comments
Stephen23
Stephen23 on 3 Aug 2021
Edited: Stephen23 on 3 Aug 2021
"I think I'm missing something..."
When selecting a subset of array-elements, then these cannot maintain the same shape as the array that they are selected from. The introductory examples here
explains this as "MATLAB matches the locations of the value 1 in ind to the corresponding elements of A and B, and lists their values in a column vector." So the introductory tutorials do not imply "shape preserving". Nor does this more detailed article:
which states "The output is always in the form of a column vector."
This blog page
explains "The logical indexing expression C(D) extracts all the values of Ccorresponding to nonzero values of D and returns them as a column vector."
Can you please give a reference to the MATLAB documentation where "... logical indices are presented to the user as shape-preserving operations", as you wrote in your question.
Joel Lynch
Joel Lynch on 3 Aug 2021
Edited: Joel Lynch on 3 Aug 2021
Can you please give a reference to the MATLAB documentation where...
I certainly didn't mean to imply there was an error or inconsistency in the MATLAB documentation; I'm aware this is the normal documented MATLAB behavior. I should have said "logical operations are returned to the user as shape preserving boolean matrices"
My point being that this rule seems counter-intuitive when logical indexing is the primary use of logical operations (or maybe they aren't?). Why not return the linear indices (e.g. find(A<0.5)) that are actually used in logical indexing, and use an inverse function to find(), when the matrix is needed?

Sign in to comment.

Accepted Answer

Jakeb Chouinard
Jakeb Chouinard on 3 Aug 2021
Edited: Jakeb Chouinard on 3 Aug 2021
Assuming that modifying A is not allowed, I think you're close to the most simple way to do what you need.
You could also do something like:
A = rand(3);
B = A;
B(B<0.5) = 0; %or NaN, if that's preferred
sum(B,2)
Or:
A = rand(3);
cmpMatrix = A>=0.5; %CoMParison Matrix
sum(A.*cmpMatrix,2)
  2 Comments
Joel Lynch
Joel Lynch on 3 Aug 2021
Edited: Joel Lynch on 3 Aug 2021
Ah, so you could get one line with:
B = sum(A.*(A<0.5),2);
Maybe not perfect (doesn't generalize to all functions), but it works!
Jakeb Chouinard
Jakeb Chouinard on 3 Aug 2021
Edited: Jakeb Chouinard on 3 Aug 2021
That's the spirit! At least then you're using up less space, though if you'll need to call the comparison matrix again, you may be better off keeping it stored. And just since I know the mods prefer to have questions be closed once answered, could you select my response as an accepted answer?
Cheers!

Sign in to comment.

More Answers (0)

Categories

Find more on Parallel for-Loops (parfor) in Help Center and File Exchange

Products


Release

R2021a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!