Haven't tested timing carefully, but something like the following should be 
pretty decent:

julia> immutable LowerTriangularIterator{A<:AbstractMatrix}
           data::A
       end

julia> Base.start(iter::LowerTriangularIterator) = (1,1)
start (generic function with 49 methods)

julia> Base.done(iter::LowerTriangularIterator, state) = state[2] > 
size(iter.data, 2)
done (generic function with 51 methods)

julia> @inline function Base.next(iter::LowerTriangularIterator, state)
           item = iter.data[state[1], state[2]]
           newstate = ifelse(state[1] == size(iter.data, 1), (state[2]+1, 
state[2]+1), (state[1]+1, state[2]))
           item, newstate
       end


To make it vectorize (i.e., SIMD), you might also need definitions like these:
https://github.com/JuliaLang/julia/blob/aa24ee0d0f334e8d9ecbced64bd975a6cc5f240d/base/multidimensional.jl#L134-L150

but perhaps vectorization isn't applicable to your problem anyway.

--Tim

On Sunday, November 15, 2015 05:06:23 PM Seth wrote:
> Thank you, Tim - I'll definitely check it out. Right now I can't seem to
> find an efficient way of doing it, but there are a few tricks in
> Iterators.jl that might work.
> 
> On Sunday, November 15, 2015 at 1:33:29 PM UTC-8, Tim Holy wrote:
> > This may also be a case where writing an iterator that just visits the
> > elements with i >= j might be what you want. You can study the
> > implementation
> > of CartesianIndex in Base for inspiration.
> > 
> > --Tim
> > 
> > On Saturday, November 14, 2015 02:18:45 PM hustf wrote:
> > > I believe this work-in-progress type may be adapted? I wanted to make
> > 
> > this
> > 
> > > faster by using tuples or immutable fixed vectors to store the data or
> > > whatnot, but I guess I'm currently stuck. Help wanted.
> > > 
> > > Compared to looping unnecessarily over a full matrix, this speeds things
> > 
> > up
> > 
> > > by around 35%.
> > > 
> > > immutable Maq7 <:AbstractMatrix{Int}
> > > data::Array{Int64,2}   # upper triangular except diagonal, stored as a
> > > horizontal vector
> > > width::Int64
> > > function Maq7(mat::Matrix{Int64})
> > > if issym(mat)
> > > n=size(mat,1)
> > > if n>1
> > > v=mat[2:n,1]
> > > for col = 2:(n-1)
> > > append!(v,mat[(col+1):n,col])
> > > end
> > > new(v', size(mat,1))
> > > else
> > > error("Ouch, not > (1x1)")
> > > end
> > > else
> > > error("Ouch, not square symmetric")
> > > end
> > > end
> > > end
> > > Base.size(A::Maq7)= A.width, A.width
> > > Base.length(A::Maq7)= div(A.width*(A.width-1), 2)
> > > Base.getindex(A::Maq7, i::Int) = Base.getindex(A.data, i)
> > > function Base.getindex(A::Maq7, r::Int , c::Int )
> > > if c > r
> > > return getindex(A.data, div( (r-1)*(2*A.width -r) , 2 ) + c - r )
> > > elseif r > c
> > > return getindex(A.data, div( (c-1)*(2*A.width -c) , 2 ) + r - c )
> > > else
> > > return zero(eltype(A.data))
> > > end
> > > end
> > > Base.linearindexing(::Type{Maq7}) = Base.LinearFast()
> > > 
> > > 
> > > 
> > > Example:
> > > julia> ms
> > > 
> > > 4x4 Array{Int64,2}:
> > >  7  1  2   3
> > >  1  8  4   5
> > >  2  4  9   6
> > >  3  5  6  10
> > > 
> > > julia> m=Maq7(ms)
> > > 
> > > 4x4 Maq7:
> > >  0  1  2  3
> > >  1  0  4  5
> > >  2  4  0  6
> > >  3  5  6  0
> > > 
> > > julia> collect(m)
> > > 
> > > 6-element Array{Int64,1}:
> > >  1
> > >  2
> > >  3
> > >  4
> > >  5
> > >  6
> > > 
> > > julia> length(m)
> > > 6

Reply via email to