Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
logical indexing with larger logical array

Subject: logical indexing with larger logical array

From: Bruno Luong

Date: 5 Nov, 2010 09:44:04

Message: 1 of 13

>> a = [1 2 3];

>> a([false false true false false])

ans =

     3

>> a([false false true true])
??? Index exceeds matrix dimensions.
 
>>

Can someone shed a light (or point towards a document that explains) why the second command throw an error and not the first?

Bruno

Subject: logical indexing with larger logical array

From: Roger Jones

Date: 5 Nov, 2010 10:13:04

Message: 2 of 13

"Bruno Luong" <b.luong@fogale.findmycountry> wrote in message <ib0jl3$6es$1@fred.mathworks.com>...
> >> a = [1 2 3];
>
> >> a([false false true false false])
>
> ans =
>
> 3
>
> >> a([false false true true])
> ??? Index exceeds matrix dimensions.
>
> >>
>
> Can someone shed a light (or point towards a document that explains) why the second command throw an error and not the first?
>
> Bruno

MatLab is very flexible and laid back compared to most environments!

In the example a([false false true false false]), it doesn't matter that you are indexing with a matrix larger than a because you are not asking it to return any elements beyond a's dimensions.

However, in a([false false true true]), you are asking MatLab to return the 3rd and 4th elements of a. But a only has 3 elements. Here there is nothing MatLab can do but return an error.

If you are a programmer, you would probably expect both commands to return an error. It is to MatLab's credit that the first command works. This philosophy is evidenced elsewhere, such as the command x(20) = 1;
Then ML will create a double variable, make it 20 elements, populate them all with zeros and then the last one with 1. In most languages, you would have to do most of this in separate steps.

Subject: logical indexing with larger logical array

From: David Young

Date: 5 Nov, 2010 13:10:06

Message: 3 of 13

"Roger Jones" <leave@mealone.com> wrote
> ...
> If you are a programmer, you would probably expect both commands to return an error.

I certainly would!

> It is to MatLab's credit that the first command works.

I don't agree. I think that logical indexing only makes sense if the index array is always the same size as the indexed array. If this doesn't happen, it's likely to be a bug in the program. It would be more helpful for Matlab to report an error in such cases.

If allowing trailing "false" indexes is intended to be useful, it should work in 2D, not just on vectors, but it doesn't. But look at this:

>> a = [1 2; 3 4]
a =
     1 2
     3 4
>> l = [false true; true false]
l =
     0 1
     1 0
>> a(l)
ans =
     3
     2
>> l = [false true false; true false false; false false false]
l =
     0 1 0
     1 0 0
     0 0 0
>> a(l)
ans =
     3
     4

Here the extra elements of l change the result, so they are not ignored. Thus it's not a useful feature in 2D.

> This philosophy is evidenced elsewhere, such as the command x(20) = 1;

This isn't a comparable example. For one thing, this is documented behaviour, which has a clear purpose. I don't think the "ignore extra false index elements" effect is documented, and I can't see how it's useful.

Subject: logical indexing with larger logical array

From: Steven_Lord

Date: 5 Nov, 2010 13:31:39

Message: 4 of 13



"David Young" <d.s.young.notthisbit@sussex.ac.uk> wrote in message
news:ib0vne$6lh$1@fred.mathworks.com...
> "Roger Jones" <leave@mealone.com> wrote
>> ...
>> If you are a programmer, you would probably expect both commands to
>> return an error.
>
> I certainly would!
>
>> It is to MatLab's credit that the first command works.
>
> I don't agree. I think that logical indexing only makes sense if the index
> array is always the same size as the indexed array. If this doesn't
> happen, it's likely to be a bug in the program. It would be more helpful
> for Matlab to report an error in such cases.
>
> If allowing trailing "false" indexes is intended to be useful, it should
> work in 2D, not just on vectors, but it doesn't. But look at this:
>
>>> a = [1 2; 3 4]
> a =
> 1 2
> 3 4
>>> l = [false true; true false]
> l =
> 0 1
> 1 0
>>> a(l)
> ans = 3
> 2
>>> l = [false true false; true false false; false false false]
> l =
> 0 1 0
> 1 0 0
> 0 0 0
>>> a(l)
> ans =
> 3
> 4
>
> Here the extra elements of l change the result, so they are not ignored.
> Thus it's not a useful feature in 2D.

Actually, only one element of your extended I is really changing the
results.

In this case, a(I) is being treated as a(I(:)). Since the linear indices of
the true values in your extended I are 2 and 4 (whereas for your smaller I
they were elements 2 and 3) and neither 2 nor 4 are greater than numel(a),
MATLAB returns the 2nd and 4th elements of a.

>> This philosophy is evidenced elsewhere, such as the command x(20) = 1;
>
> This isn't a comparable example. For one thing, this is documented
> behaviour, which has a clear purpose. I don't think the "ignore extra
> false index elements" effect is documented, and I can't see how it's
> useful.

--
Steve Lord
slord@mathworks.com
comp.soft-sys.matlab (CSSM) FAQ: http://matlabwiki.mathworks.com/MATLAB_FAQ
To contact Technical Support use the Contact Us link on
http://www.mathworks.com

Subject: logical indexing with larger logical array

From: dpb

Date: 5 Nov, 2010 13:41:49

Message: 5 of 13

David Young wrote:
> "Roger Jones" <leave@mealone.com> wrote
>> ...
>> If you are a programmer, you would probably expect both commands to
>> return an error.
>
> I certainly would!
>
>> It is to MatLab's credit that the first command works.
>
> I don't agree. I think that logical indexing only makes sense if the
> index array is always the same size as the indexed array. If this
> doesn't happen, it's likely to be a bug in the program. It would be more
> helpful for Matlab to report an error in such cases.
>
> If allowing trailing "false" indexes is intended to be useful, it should
> work in 2D, not just on vectors, but it doesn't. But look at this:
>
>>> a = [1 2; 3 4]
...
>>> l = [false true false; true false false; false false false]
...
>>> a(l)
> ans =
> 3
> 4
>
> Here the extra elements of l change the result, so they are not ignored.
> Thus it's not a useful feature in 2D.
...

Nota Bene:

 > a(:)'
ans =
      1 3 2 4
 >> l(:)'
ans =
      0 1 0 1 0 0 0 0 0

The returned elements are from the locations in consecutive memory that
correspond to those same positions in memory of the logical array.

One could clearly write code dependent on the behavior; whether that's
_a_good_thing_ (tm) is certainly debatable.

I'd suggest TMW _NOT_ change behavior owing to compatibility but should
be documented as to how it performs.

It's one of those things that could be considered somewhat akin to
selecting levels of warnings in compiled languages -- it may not be
detectable at compile-time so then does one want run-time bounds
protection and that penalty or the better performance of turning
bounds-checking off?

--

Subject: logical indexing with larger logical array

From: David Young

Date: 5 Nov, 2010 14:11:03

Message: 6 of 13

Steven and dbp: thanks. Actually, I understood the reason for the 2D behaviour (that a(I) is the same as a(I(:))).

My problem was with Roger's claim that ignoring the trailing index elements is a virtue, and perhaps even useful in some way. For that to be the case, I still believe that the correct 2D behaviour would be to strip off both extra rows and columns as the first step.

By the way, I agree that there's no strong case for changing the behaviour - but some documentation would be good.

Subject: logical indexing with larger logical array

From: David Young

Date: 5 Nov, 2010 14:34:04

Message: 7 of 13

Just thought it would be worth noting what the documentation says on the topic. From Helpwin > MATLAB > User's Guide > Mathematics > Matrices and Arrays > Matrix Indexing > Using Logicals in Array Indexing:

"In most cases, the logical indexing array should have the same number of elements as the array being indexed into, but this is not a requirement. The indexing array may have smaller (but not larger) dimensions"

There is then an example which shows that in a(I), if I is smaller than a, then I(:) is padded with logical zeros.

Subject: logical indexing with larger logical array

From: Bruno Luong

Date: 5 Nov, 2010 14:38:03

Message: 8 of 13

To me it looks like the logical indexing engine performs the bound checking with *every* elements that corresponds to TRUE. That's why it issues an error with outside TRUE and not outside FALSE. If the checking is performed once before the scan on the sizes of the array and the logical array, there might be some speed gain.

I agree that the virtue of being able of passing FALSE beyond the limit is ...none. It likely a bug of the program when such calling occurs, and the programmer should be alerted.

When the logical array is shorter, Matlab pads the missing tail with FALSE. This behavior is documented and useful.

In any case, the behavior when invoking with longer logical array must be documented.

Bruno

Subject: logical indexing with larger logical array

From: dpb

Date: 5 Nov, 2010 16:06:13

Message: 9 of 13

Bruno Luong wrote:
> To me it looks like the logical indexing engine performs the bound
> checking with *every* elements that corresponds to TRUE. That's why it
> issues an error with outside TRUE and not outside FALSE. If the checking
> is performed once before the scan on the sizes of the array and the
> logical array, there might be some speed gain.
>
> I agree that the virtue of being able of passing FALSE beyond the limit
> is ...none. It likely a bug of the program when such calling occurs, and
> the programmer should be alerted.
>
> When the logical array is shorter, Matlab pads the missing tail with
> FALSE. This behavior is documented and useful.
>
> In any case, the behavior when invoking with longer logical array must
> be documented.

The "bad" behavior imo is this (sticking w/ David's example) --

 >> a(l(size(a)))
ans =
      1 3
 >> a(l)
ans =
      3
      4
 >>

The behavior of concatenating 'false' in shorter in vectors is clear;
what is perverse is the conversion to linear indexing in the 2D (and
presumably higher altho I didn't check it) that returns a somewhat
surprising result when the logic array is mapped onto the indexed array.

IMO it's too bad the behavior wasn't codified as in the first of the two
snippets above but I'd consider not breaking old code probably of higher
import than fixing the behavior at this point.

--

Subject: logical indexing with larger logical array

From: Jan Simon

Date: 5 Nov, 2010 16:26:04

Message: 10 of 13

Dear Bruno,

> In any case, the behavior when invoking with longer logical array must be documented.

Logical indexing is faster than an equivalent numerical index method, because the range checks can be omitted - I thought...
Then the length of the logical index vector must be limited to the number of elements of the indexed array.

Bruno's interesting question let me start a short test (Matlab 2009a, WinXP 32):
  x = rand(1, 120000);

  ind = 1:60000;
  tic; for i=1:2000; q = x(ind); clear('q'); end; toc
>> 8.31 sec

  ind = uint16(1:60000);
  tic; for i=1:2000; q = x(ind); clear('q'); end; toc
>> 2.64 sec

  ind = uint32(1:60000);
  tic; for i=1:2000; q = x(ind); clear('q'); end; toc
>> 2.82 sec

  ind = true(1, 60000);
  tic; for i=1:2000; q = x(ind); clear('q'); end; toc
>> 2.81 sec

  ind = [true(1, 60000), false(1, 60000)];
  tic; for i=1:2000; q = x(ind); clear('q'); end; toc
>> 3.23 sec

(The relations do not change, if I put these lines in an M-file to allow the JIT to perform its magic destiny.)

Conclusion:
1. Time(UINT32) == Time(Logical indexing) means, that with logical indexing a boundary check is performed for the 32bit *memory position* of each TRUE element.
2. Trailing FALSE are processed fast. I cannot distinguish the time needed for the data copy and the boundary checks.
3. Using UINT16 as index, the *value* is checked, which takes 10% less time (I've subtracted the time for the pure data copy).

Strange. I had the feeling that the logical indexing is surprisingly fast. So let's hope that TMW did the preallocation efficiently. A short check with a C-mex:
% PSEUDOCODE: CopyIndex.c -----------------------
  // Input: Double array X, Logical array Index

  // *One* boundary check at the beginning:
  if (numel(Y) > numel(X)) {
     mexErrMsgTxt("Index exceeds matrix dimensions');
  }

  Y = mxMalloc(numel(Index) * sizeof(double));
  Yp = Y;
  for i = 1:numel(Index) {
     if (Index[i]) {
        *Yp++ = X[i];
     }
  }
  Y = mxRealloc(Y, (Yp-Y)*sizeof(double));
  plhs[0] = CreateDoubleVector from Y.
% END ------------------------------------

Measure the time again:
  ind = true(1, 60000);
  tic; for i=1:2000; q = CopyIndex(x, ind); clear('q'); end; toc
>> 0.93 sec

Wow. If was 2.81 sec for "q = x(ind)". 3 times faster...
I hoped, that the worst-case check reveals the weakness of my naive approach:
  ind = [true, false(1, 59999)];
  tic; for i=1:2000; q = CopyIndex(x, ind); clear('q'); end; toc
>> 0.46 sec
  tic; for i=1:2000; q = x(ind); clear('q'); end; toc
>> 0.46 sec
No weakness. A naive C-approach can clearly beat logical indexing.

Well, Bruno, I think you hit an important point. The boundary check for each element kill the performance of logical indexing.

If I've recovered from this shock, I'll polish the C-source and submit it to the FEX. Then I hope that someone shows me my silly mistake or any to harsh limitations and I'll remove the submission fast again. Otherwise I had to insert an ugly user-defined function in 10.000 lines of my code to get an efficient data copy?!?

Jan

Subject: logical indexing with larger logical array

From: Jan Simon

Date: 6 Nov, 2010 10:47:03

Message: 11 of 13

Dear Readers,

During my trials to program an efficient indexed data copy, I found this behaviour:

(WinXP 32bit, Matlab 2009a, Pentium-M)
  x = rand(1, 60000);

  tic; for i = 1:2000; q = x(1:60000); clear('q'); end; toc
  tic; for i = 1:2000; q = x(2:60000); clear('q'); end; toc
  tic; for i = 1:2000; q = x(3:60000); clear('q'); end; toc
  tic; for i = 1:2000; q = x(4:60000); clear('q'); end; toc
  >> 0.69 sec
  >> 0.88 sec
  >> 0.67 sec
  >> 0.88 sec
and so on, until q gets much smaller... Again the relations do not change if the code is inserted in an M-file, such that the JIT can engage the after burning.

The DOUBLE values occupy 64 bits. So I seems that the alignment to 128-bit limits seems to be important: 30% different in the runtime!!!
An equivalent C-MEX files shows the same behaviour, if it calls mxCreateDoubleArray to reserve the memory and MEMCPY to copy the contiguos memory block.

1. I did not expect a 32-bit Matlab to profit from 128-bit alignment.
2. Can we ask Matlab to align arrays at 128 bit limits?
3. How do the timings look in 64-bit Matlab?
4. Can I force mxMalloc to use a 128-bit limit?
5. Again: I'm deeply nervous about the seemingly inefficient implementation of logical indexing.
6. In the ancient Matlab 6.5 this is beaten by a naive C-Mex:
  x = rand(1, 60000);
  y = x(1:60000); % Naive C with MEMCPY
But lukily Matlab 2009a handles this efficiently - either [1:60000] is not constructed explicitely or a smarter boundary check is applied, or both.
But again: If the C-Mex checks for the 128bit alignment and in case of non-aligned memory copies one DOUBLE at first and the trailing memory by MEMCPY, one can always get the faster speed.

Looking in my FEX submissions, it is obvious, that I like accelerating built-in Matlab functions. But I do not feel comfortable, when I start mexing such basics as indexed data copies.

Does anyone else share my impression, that it is really surprising that logical indexing can be done much faster by a naive C-Mex function and that the 128bit alignment is such important, but not considered by TMW?
I know, it is the end of the week, but I have the feeling, that an efficient data copy would accelerate almost every program.

Kind regards, Jan

Subject: logical indexing with larger logical array

From: Bruno Luong

Date: 6 Nov, 2010 12:18:03

Message: 12 of 13

"Jan Simon" <matlab.THIS_YEAR@nMINUSsimon.de> wrote in message <ib3bn7$5r2$1@fred.mathworks.com>...
> Dear Readers,
>
> During my trials to program an efficient indexed data copy, I found this behaviour:
>
> (WinXP 32bit, Matlab 2009a, Pentium-M)
> x = rand(1, 60000);
>
> tic; for i = 1:2000; q = x(1:60000); clear('q'); end; toc
> tic; for i = 1:2000; q = x(2:60000); clear('q'); end; toc
> tic; for i = 1:2000; q = x(3:60000); clear('q'); end; toc
> tic; for i = 1:2000; q = x(4:60000); clear('q'); end; toc
> >> 0.69 sec
> >> 0.88 sec
> >> 0.67 sec
> >> 0.88 sec

- Matlab 2010B-32 on Windows7 64
Elapsed time is 0.128332 seconds.
Elapsed time is 0.107837 seconds.
Elapsed time is 0.118339 seconds.
Elapsed time is 0.109299 seconds.

- Matlab 2010B-64 on Windows7 64
Elapsed time is 0.252830 seconds.
Elapsed time is 0.248273 seconds.
Elapsed time is 0.254037 seconds.
Elapsed time is 0.250068 seconds.

Bruno

Subject: logical indexing with larger logical array

From: Jan Simon

Date: 6 Nov, 2010 12:59:04

Message: 13 of 13

Dear Bruno,

Thanks for the 64 bit measurement. It seems like the 64 bit Matlab is less or not susceptible for the 128 bit alignment.
*But*:

> > tic; for i = 1:2000; q = x(1:60000); clear('q'); end; toc
>
> - Matlab 2010B-32 on Windows7 64
> Elapsed time is 0.128332 seconds.
>
> - Matlab 2010B-64 on Windows7 64
> Elapsed time is 0.252830 seconds.

The copy of 60.000 * 8 bytes takes the double time under 64-bit Matlab?
Of course addressing 64 bits takes longer than 32 bits. But I naively expected, that the memory addressing is implemented as a single-cycle-CPU call as for 32-bit addressing. Obviously I have to do some 64-bit lessons.

Kind regards, Jan

Tags for this Thread

No tags are associated with this thread.

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us