11using SparseArrays: SparseMatrixCSC, sparse
2- using ArnoldiMethod: LR
2+ using ArnoldiMethod: SR
3+ using Base: OneTo
34using LinearAlgebra: eigen
45
56"""
@@ -39,7 +40,7 @@ Position nodes on a circle.
3940
4041**Parameters**
4142
42- *G *
43+ *g *
4344a graph
4445
4546**Returns**
@@ -51,7 +52,7 @@ but will be normalized and centered anyway
5152**Examples**
5253
5354```
54- julia> g = simple_house_graph( )
55+ julia> g = smallgraph(:house )
5556julia> locs_x, locs_y = circular_layout(g)
5657```
5758"""
@@ -60,18 +61,18 @@ function circular_layout(g)
6061 return [0.0 ], [0.0 ]
6162 else
6263 # Discard the extra angle since it matches 0 radians.
63- θ = range (0 , stop= 2pi , length= _nv (G )+ 1 )[1 : end - 1 ]
64+ θ = range (0 , stop= 2pi , length= nv (g )+ 1 )[1 : end - 1 ]
6465 return cos .(θ), sin .(θ)
6566 end
6667end
6768
6869"""
6970This function is copy from [IainNZ](https://github.com/IainNZ)'s [GraphLayout.jl](https://github.com/IainNZ/GraphLayout.jl)
7071
71- Use the spring/repulsion model of Fruchterman and Reingold (1991):
72+ Use a modified version of the spring/repulsion model of Fruchterman and Reingold (1991):
7273
73- + Attractive force: f_a(d) = d^2 / k
74- + Repulsive force: f_r(d) = -k^2 / d
74+ + Attractive force: f_a(d) = d / k
75+ + Repulsive force: f_r(d) = -k^2 / d^2
7576
7677where d is distance between two vertices and the optimal distance
7778between vertices k is defined as C * sqrt( area / num_vertices )
@@ -96,63 +97,66 @@ Integer seed for pseudorandom generation of locations (default = 0).
9697
9798**Examples**
9899```
99- julia> g = graphfamous(" karate" )
100+ julia> g = smallgraph(: karate)
100101julia> locs_x, locs_y = spring_layout(g)
101102```
102103"""
103- function spring_layout (g:: AbstractGraph{T} , locs_x, locs_y; C= 2.0 , MAXITER= 100 , INITTEMP= 2.0 ) where {T<: Integer }
104-
105- # size(adj_matrix, 1) != size(adj_matrix, 2) && error("Adj. matrix must be square.")
106- N = nv (g)
104+ function spring_layout (g:: AbstractGraph ,
105+ locs_x= 2 * rand (nv (g)).- 1.0 ,
106+ locs_y= 2 * rand (nv (g)).- 1.0 ;
107+ C= 2.0 ,
108+ MAXITER= 100 ,
109+ INITTEMP= 2.0 )
110+
111+ nvg = nv (g)
107112 adj_matrix = adjacency_matrix (g)
108113
109114 # The optimal distance bewteen vertices
110- K = C * sqrt (4.0 / N)
115+ k = C * sqrt (4.0 / nvg)
116+ k² = k * k
111117
112118 # Store forces and apply at end of iteration all at once
113- force_x = zeros (N )
114- force_y = zeros (N )
119+ force_x = zeros (nvg )
120+ force_y = zeros (nvg )
115121
116122 # Iterate MAXITER times
117123 @inbounds for iter = 1 : MAXITER
118124 # Calculate forces
119- for i = 1 : N
125+ for i = 1 : nvg
120126 force_vec_x = 0.0
121127 force_vec_y = 0.0
122- for j = 1 : N
128+ for j = 1 : nvg
123129 i == j && continue
124130 d_x = locs_x[j] - locs_x[i]
125131 d_y = locs_y[j] - locs_y[i]
126- d = sqrt (d_x^ 2 + d_y^ 2 )
127- if adj_matrix[i,j] != zero (eltype (adj_matrix)) || adj_matrix[j,i] != zero (eltype (adj_matrix))
128- # F = d^2 / K - K^2 / d
129- F_d = d / K - K^ 2 / d^ 2
132+ dist² = (d_x * d_x) + (d_y * d_y)
133+ dist = sqrt (dist²)
134+
135+ if ! ( iszero (adj_matrix[i,j]) && iszero (adj_matrix[j,i]) )
136+ # Attractive + repulsive force
137+ # F_d = dist² / k - k² / dist # original FR algorithm
138+ F_d = dist / k - k² / dist²
130139 else
131140 # Just repulsive
132- # F = -K^2 / d^
133- F_d = - K ^ 2 / d ^ 2
141+ # F_d = -k² / dist # original FR algorithm
142+ F_d = - k² / dist²
134143 end
135- # d / sin θ = d_y/d = fy/F
136- # F /| dy fy -> fy = F*d_y/d
137- # / | cos θ = d_x/d = fx/F
138- # /--- -> fx = F*d_x/d
139- # dx fx
140144 force_vec_x += F_d* d_x
141145 force_vec_y += F_d* d_y
142146 end
143147 force_x[i] = force_vec_x
144148 force_y[i] = force_vec_y
145149 end
146150 # Cool down
147- TEMP = INITTEMP / iter
151+ temp = INITTEMP / iter
148152 # Now apply them, but limit to temperature
149- for i = 1 : N
150- force_mag = sqrt (force_x[i]^ 2 + force_y[i]^ 2 )
151- scale = min (force_mag, TEMP)/ force_mag
153+ for i = 1 : nvg
154+ fx = force_x[i]
155+ fy = force_y[i]
156+ force_mag = sqrt ((fx * fx) + (fy * fy))
157+ scale = min (force_mag, temp) / force_mag
152158 locs_x[i] += force_x[i] * scale
153- # locs_x[i] = max(-1.0, min(locs_x[i], +1.0))
154159 locs_y[i] += force_y[i] * scale
155- # locs_y[i] = max(-1.0, min(locs_y[i], +1.0))
156160 end
157161 end
158162
@@ -165,7 +169,7 @@ function spring_layout(g::AbstractGraph{T}, locs_x, locs_y; C=2.0, MAXITER=100,
165169 map! (z -> scaler (z, min_x, max_x), locs_x, locs_x)
166170 map! (z -> scaler (z, min_y, max_y), locs_y, locs_y)
167171
168- return locs_x,locs_y
172+ return locs_x, locs_y
169173end
170174
171175using Random: MersenneTwister
@@ -181,28 +185,27 @@ Position nodes in concentric circles.
181185
182186**Parameters**
183187
184- *G *
188+ *g *
185189a graph
186190
187191*nlist*
188192Vector of Vector, Vector of node Vector for each shell.
189193
190194**Examples**
191195```
192- julia> g = graphfamous(" karate" )
196+ julia> g = smallgraph(: karate)
193197julia> nlist = Array{Vector{Int}}(2)
194198julia> nlist[1] = [1:5]
195199julia> nlist[2] = [6:num_vertiecs(g)]
196200julia> locs_x, locs_y = shell_layout(g, nlist)
197201```
198202"""
199- function shell_layout (G , nlist:: Union{Nothing, Vector{Vector{Int}}} = nothing )
200- if _nv (G ) == 1
203+ function shell_layout (g , nlist:: Union{Nothing, Vector{Vector{Int}}} = nothing )
204+ if nv (g ) == 1
201205 return [0.0 ], [0.0 ]
202206 end
203207 if nlist == nothing
204- nlist = Array {Vector{Int}} (1 )
205- nlist[1 ] = collect (1 : _nv (G))
208+ nlist = [collect (1 : nv (g))]
206209 end
207210 radius = 0.0
208211 if length (nlist[1 ]) > 1
@@ -217,7 +220,7 @@ function shell_layout(G, nlist::Union{Nothing, Vector{Vector{Int}}} = nothing)
217220 append! (locs_y, radius* sin .(θ))
218221 radius += 1.0
219222 end
220- locs_x, locs_y
223+ return locs_x, locs_y
221224end
222225
223226"""
@@ -237,20 +240,20 @@ the edge weight. If None, then all edge weights are 1.
237240
238241**Examples**
239242```
240- julia> g = graphfamous(" karate" )
243+ julia> g = smallgraph(: karate)
241244julia> weight = rand(num_edges(g))
242245julia> locs_x, locs_y = spectral_layout(g, weight)
243246```
244247"""
245- function spectral_layout (g:: AbstractGraph{T} , weight= nothing ) where {T <: Integer }
248+ function spectral_layout (g:: AbstractGraph , weight= nothing )
246249 if nv (g) == 1
247250 return [0.0 ], [0.0 ]
248251 elseif nv (g) == 2
249252 return [0.0 , 1.0 ], [0.0 , 0.0 ]
250253 end
251254
252255 if weight == nothing
253- weight = ones (length ( edges (g) ))
256+ weight = ones (ne (g ))
254257 end
255258 if nv (g) > 500
256259 A = sparse (Int[src (e) for e in edges (g)],
@@ -276,7 +279,7 @@ function _spectral(A::SparseMatrixCSC)
276279 data = vec (sum (A, dims= 1 ))
277280 D = sparse (Base. OneTo (length (data)), Base. OneTo (length (data)), data)
278281 L = D - A
279- eigenvalues, eigenvectors = LightGraphs. LinAlg. eigs (L, nev= 3 , which= LR ())
282+ eigenvalues, eigenvectors = LightGraphs. LinAlg. eigs (L, nev= 3 , which= SR ())
280283 index = sortperm (real (eigenvalues))[2 : 3 ]
281284 return real (eigenvectors[:, index[1 ]]), real (eigenvectors[:, index[2 ]])
282285end
0 commit comments