Of course I can just implement it, two lines of code. But that seems something that probably is needed quite frequently in matrix computations, so I am surprised I didn’t find it as a Base function.
First I thought that most people would prefer constructing an iterator like (for a 3x3 matrix, for example):
julia> for c in Iterators.filter(c -> c[1] < c[2], CartesianIndices((1:3,1:3)))
@show c
end
c = CartesianIndex(1, 2)
c = CartesianIndex(1, 3)
c = CartesianIndex(2, 3)
That would be fine for my current purposes, except that it does not play well with @threads:
julia> Threads.@threads for c in Iterators.filter(c -> c[1] < c[2], CartesianIndices((1:3,1:3)))
@show c
end
ERROR: TaskFailedException
Stacktrace:
[1] wait
@ ./task.jl:322 [inlined]
[2] threading_run(func::Function)
@ Base.Threads ./threadingconstructs.jl:34
[3] top-level scope
@ ./threadingconstructs.jl:93
nested task error: MethodError: no method matching length(::Base.Iterators.Filter{var"#19#20", CartesianIndices{2, Tuple{UnitRange{Int64}, UnitRange{Int64}}}})
What I am missing here? Should I just use a custom implementation of the indexing, is there a Base function already for that, or some alternative way to iterate that is accepted by @threads?
I don’t think there’s a built-in iterator for this, although it’s been discussed (including for sparse arrays) e.g. here but probably elsewhere too. Maybe someone knows a better link.
While it won’t directly help with threading, something like (CartesianIndex(x,y) for x in 1:3 for y in x+1:3) (i.e Iterators.flatten) may be more efficient than filtering. You can use Iterators.partition and Threads.@spawn to multi-thread this.
Thanks. The custom function resulted to be the most practical alternative for now. For the records, it is this one:
@inline function iuppert(k::Integer,n::Integer)
i = n - 1 - floor(Int,sqrt(-8*k + 4*n*(n-1) + 1)/2 - 0.5)
j = k + i + ( (n-i+1)*(n-i) - n*(n-1) )÷2
return i, j
end
I also needed an iterator over indices of an upper triangular matrix, so after finding this thread, I wrote this small package: GitHub - perrutquist/TriangularIndices.jl
It uses a slightly different formula (compared to the above) which generates the indices for an upper triangle in column-first order.
I don’t need an iterator, I need a direct formula mapping a linear Index of a triangular matrix into cartesian coordinates. After reading various sources on the web like this one I realized that the formula will vary based on quadrant, 0- vs 1-based indexing, row vs column major, and whether the diagonal was included or not. So none of the explicit formulas matched my particular use case (upper right quadrant, 1-based indexing, column major ordering, without the diagonal). I was able to derive a formula to map from cartesian coordinates to a linear index (Index = Int(x*(x-1)/2 -x +y +1) ), but I’m having trouble doing the reverse. This pair of formulas are close, but include the diagonal:
i = Int(ceil(sqrt(2 * idx + 0.25) - 0.5))
j = Int(idx - (i-1) * i / 2)
after having better read the specifics of the problem, I too tried to derive a formula for (i,j).
I ended up with the same result used in the solution.
I leave my notes as an insight on the demonstration process
The first two urq1cmowd functions provide the correct answers, but I thought a purely formulaic approach was possible. I need something efficient because I’m processing a data structure with millions (if not billions) of elements and I don’t have any memory to spare. (Btw, the definition of the upper right quadrant I’m using is simply x ranging from 1:n and j ranging from 1:i-1). Here is a sample of coordinates:
I don’t know if, apart from “aesthetic” issues, for arrays like these, it’s preferable to use SparseArrays, since you already have the coordinates of the non-zero values.