[julia-users] Re: General question on indexing

2015-11-16 Thread hustf
Seth,
thanks for that, and yes we can move over there, but I need some time to 
study it before I contribute in the context. I've been looking at 
GraphLayout - spring.jl, and thinking along the same lines about speed. I'm 
delaying a commit because the package has a coherent coding style but which 
I find hard to follow - and an interface problem with Compose. Also, I 
don't realistically expect to make a real improvement except in my own 
skills.

>From the documentation and small tests, I did not expect any improvements 
using @simd as long as there are "if"-sentences in the middle of it. So 
perhaps this format of the adjacency matrix may help? This for both 
directed and non-directed graphs. The type definition AdjMatrix just a 
small adaption of Maq7 above. Each node could be processed from one row and 
a submatrix pointing to the positions of just the other nodes.

# using 'current node -neighbour node ' notation:
4x4 Array{Int64,2}:
  0  21  31  41
 12   0  32  42
 13  23   0  43
 14  24  34   0

julia> ama =AdjMatrix(am)
3x4 AdjMatrix:
 12  21  31  41
 13  23  32  42
 14  24  34  43



[julia-users] Re: General question on indexing

2015-11-16 Thread hustf
Seth, I appreciate that. As a novice programmer I appreciate to have 
exchanges with you guys who are making this. I'm using commercial software 
every day that hasn't made progress since the nineties. 

I worked through something like fifteen types for the adjacency matrix 
(and, by the way, tuples for storage worked out, but was slower). I suppose 
Julia is fast so that we don't actually need to optimize like this all the 
time, but it's an excellent lesson. 

In the example I gave above you may have noted some confusion about 
rows-columns order. Those algorithms which were adapted from text books or 
other languages seem to walk along rows. In Julia, you walk faster 
downhill. And with @simd. 


[julia-users] Re: General question on indexing

2015-11-16 Thread Seth
I wish I walked faster with @simd - for some reason I'm getting the same 
performance as described 
here: https://groups.google.com/d/msg/julia-users/DycY6jwDcWs/yYXHsWF9AwAJ

One of the key objectives for LightGraphs is to be as fast as possible, so 
while Julia itself is pretty darn good, we want to eke every possible 
performance gain out of it so that we can scale to very large graphs. This 
also includes memory allocation, so fast and small. We're getting to the 
point where improving one results in bad performance in the other. That's 
both a good sign (that we've optimized away the low-hanging fruit) and a 
bad sign (that we may be hitting the limits of what we can do). I'm sure 
we've missed some stuff, though.

Thanks for the discussion. Feel free to join us over 
at https://github.com/JuliaGraphs/LightGraphs.jl/issues if this sort of 
stuff interests you :)

Seth.



On Monday, November 16, 2015 at 11:28:15 AM UTC-8, hustf wrote:
>
> Seth, I appreciate that. As a novice programmer I appreciate to have 
> exchanges with you guys who are making this. I'm using commercial software 
> every day that hasn't made progress since the nineties. 
>
> I worked through something like fifteen types for the adjacency matrix 
> (and, by the way, tuples for storage worked out, but was slower). I suppose 
> Julia is fast so that we don't actually need to optimize like this all the 
> time, but it's an excellent lesson. 
>
> In the example I gave above you may have noted some confusion about 
> rows-columns order. Those algorithms which were adapted from text books or 
> other languages seem to walk along rows. In Julia, you walk faster 
> downhill. And with @simd. 
>


Re: [julia-users] Re: General question on indexing

2015-11-15 Thread Tim Holy
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



Re: [julia-users] Re: General question on indexing

2015-11-15 Thread Seth
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 
>
>

Re: [julia-users] Re: General question on indexing

2015-11-15 Thread Tim Holy
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



Re: [julia-users] Re: General question on indexing

2015-11-15 Thread Seth
That's very cool and close to what I need. Thanks. I'm using adjacency 
lists (vectors of vectors) but I'm sure I can adapt this code.

On Sunday, November 15, 2015 at 6:12:19 PM UTC-8, Tim Holy wrote:
>
> 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 
>
>

[julia-users] Re: General question on indexing

2015-11-15 Thread Seth
Hustf, I don't know why my reply didn't show up here yesterday, but I 
wanted to thank you for the code. I'm looking at how to make that work. 
Thanks for your response.

On Saturday, November 14, 2015 at 2:18:45 PM UTC-8, 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
>
>
>
>
>

[julia-users] Re: General question on indexing

2015-11-14 Thread hustf
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