Best practices

I am running a code which is diagonalizing very large matrices, hence I need to reach the best possible performance. when scanning a vector I was using the following syntax

for i in 1:length(vec)

which works fine. However, I am recently receiving the following warning

Indexing with indices obtained from length, size etc is discouraged. Use eachindex or axes instead.

Is it just a good practice? or the performance is also affected?

It is best practice. I am not sure if it improves performance, but it is conceivable. It will certainly not harm it.

At any rate, it is strongly recommended, and will improve the safety and generality of your code.

3 Likes

thank you

Using eachindex ensures that your code can work with arrays that do not necessarily start with index 1. These types of arrays can be created using OffsetArrays.jl.

2 Likes

If you’re diagonalizing large matrices, odds are the diagonalization is the performance critical part, not the way you index into your vectors.

That said, I’ve been taught iteration is better than indexing (they are the same thing for normal arrays, but it’s a good habit):

for item in vec

Or, if you need a counter for some reason

for (i, item) in enumerate(vec)
4 Likes

Or
for (i, item) in pairs(vec)
if you want the indice in the vec with the item

8 Likes

I agree, but, more emphatically: enumerate is the wrong function, pairs is the right one, but people always forget it.

Edit: Ah, well, @gustaphe did say ‘counter’, which is alright. I just have a knee-jerk reaction to all the uses of enumerate.

3 Likes

eachindex usually improves performance anyways because it uses cartesian directly.

3 Likes

Yeah, I see it the other way, I normally either need the indices or just the items, if I need something together with the items it’s probably a counter.

(Plus, pairs is so obscure a name I didn’t dare recommending it without double checking)

Oh, that is very different from my experience. I think it’s probably 80-20 that I need pairs.

Yeah, that’s what I think is a bit sad. Particularly because I very often see enumerate being used to get indices in the wild.

I would say (as a mnemotechnic) that pairs is for pairs of (key, value) , here (index,value), while, clearly, enumerate goes from one to the end, so is for a counter.

By the way, for enumerate it is easy to test for the first iteration ( i == 1), but how to test with last iteration ? ( does ( i == end) works? I do not see how it could). Possibly it is no a real worry, because less frequently interesting that test for first iter, but it arises sometime nevertheless.

On the other side with pairs you can do ( i == firstindex(v) ) and ( i == lastindex(v) ), even if it is somewhat verbose?

Comment or suggestions welcome.

2 Likes

If vec is meant to a traditional (1-indexed) vector, then the “generality” argument should be weighed against the simplicity/portability of length().

I believe this trade-off is a bit different for package developers and end-users (especially newcomers to Julia).

Not sure I understand. Is 1:length() more portable?

As for simplicity, eachindex() is simpler than 1:length(), but perhaps less familiar to newcomers. But, once you’ve heard of it, you know it.

1 Like

Is 1:length() more portable?

Well, in the sense that it looks pretty similar to what you would do in some of Julia’s competitors.

1 Like

Absolutely, but there are plenty of reasonable things pairs(vec) could have meant. I don’t know what I would have wanted it to be called, I just know that I never feel entire certain what pairs does (or more likely what it’s called).

i == length(vec) && return
1 Like

That’s a feature. Less risk of off-by-one if you’re translating from eachindex than from 1:length.

eachindex is fine and even for (i, item) in enumerate(vec) is something that most of us can handle (although it isn’t pretty).
The real problem starts when dealing with matrices (and more). Things like for t = 4:T;i =2:N;x[t,i] = x[t-3,i-1];... are very easy in traditional notation, but become rather involved when you want to handle OffsetArrays (and what not). I believe this might become a serious hurdle in trying to attract new users.

1 Like

Thanks all for the discussion!

1 Like
for c in CartesianIndices(M)

?

btw, enumerate doesn’t work with OffsetArray because i starts at 1

in this case, perhaps this: