1
1
using SparseArrays: SparseMatrixCSC, sparse
2
- using ArnoldiMethod: LR
2
+ using ArnoldiMethod: SR
3
+ using Base: OneTo
3
4
using LinearAlgebra: eigen
4
5
5
6
"""
@@ -39,7 +40,7 @@ Position nodes on a circle.
39
40
40
41
**Parameters**
41
42
42
- *G *
43
+ *g *
43
44
a graph
44
45
45
46
**Returns**
@@ -51,7 +52,7 @@ but will be normalized and centered anyway
51
52
**Examples**
52
53
53
54
```
54
- julia> g = simple_house_graph( )
55
+ julia> g = smallgraph(:house )
55
56
julia> locs_x, locs_y = circular_layout(g)
56
57
```
57
58
"""
@@ -60,18 +61,18 @@ function circular_layout(g)
60
61
return [0.0 ], [0.0 ]
61
62
else
62
63
# 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 ]
64
65
return cos .(θ), sin .(θ)
65
66
end
66
67
end
67
68
68
69
"""
69
70
This function is copy from [IainNZ](https://github.com/IainNZ)'s [GraphLayout.jl](https://github.com/IainNZ/GraphLayout.jl)
70
71
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):
72
73
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
75
76
76
77
where d is distance between two vertices and the optimal distance
77
78
between vertices k is defined as C * sqrt( area / num_vertices )
@@ -96,63 +97,66 @@ Integer seed for pseudorandom generation of locations (default = 0).
96
97
97
98
**Examples**
98
99
```
99
- julia> g = graphfamous(" karate" )
100
+ julia> g = smallgraph(: karate)
100
101
julia> locs_x, locs_y = spring_layout(g)
101
102
```
102
103
"""
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)
107
112
adj_matrix = adjacency_matrix (g)
108
113
109
114
# The optimal distance bewteen vertices
110
- K = C * sqrt (4.0 / N)
115
+ k = C * sqrt (4.0 / nvg)
116
+ k² = k * k
111
117
112
118
# 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 )
115
121
116
122
# Iterate MAXITER times
117
123
@inbounds for iter = 1 : MAXITER
118
124
# Calculate forces
119
- for i = 1 : N
125
+ for i = 1 : nvg
120
126
force_vec_x = 0.0
121
127
force_vec_y = 0.0
122
- for j = 1 : N
128
+ for j = 1 : nvg
123
129
i == j && continue
124
130
d_x = locs_x[j] - locs_x[i]
125
131
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²
130
139
else
131
140
# 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²
134
143
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
140
144
force_vec_x += F_d* d_x
141
145
force_vec_y += F_d* d_y
142
146
end
143
147
force_x[i] = force_vec_x
144
148
force_y[i] = force_vec_y
145
149
end
146
150
# Cool down
147
- TEMP = INITTEMP / iter
151
+ temp = INITTEMP / iter
148
152
# 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
152
158
locs_x[i] += force_x[i] * scale
153
- # locs_x[i] = max(-1.0, min(locs_x[i], +1.0))
154
159
locs_y[i] += force_y[i] * scale
155
- # locs_y[i] = max(-1.0, min(locs_y[i], +1.0))
156
160
end
157
161
end
158
162
@@ -165,7 +169,7 @@ function spring_layout(g::AbstractGraph{T}, locs_x, locs_y; C=2.0, MAXITER=100,
165
169
map! (z -> scaler (z, min_x, max_x), locs_x, locs_x)
166
170
map! (z -> scaler (z, min_y, max_y), locs_y, locs_y)
167
171
168
- return locs_x,locs_y
172
+ return locs_x, locs_y
169
173
end
170
174
171
175
using Random: MersenneTwister
@@ -181,28 +185,27 @@ Position nodes in concentric circles.
181
185
182
186
**Parameters**
183
187
184
- *G *
188
+ *g *
185
189
a graph
186
190
187
191
*nlist*
188
192
Vector of Vector, Vector of node Vector for each shell.
189
193
190
194
**Examples**
191
195
```
192
- julia> g = graphfamous(" karate" )
196
+ julia> g = smallgraph(: karate)
193
197
julia> nlist = Array{Vector{Int}}(2)
194
198
julia> nlist[1] = [1:5]
195
199
julia> nlist[2] = [6:num_vertiecs(g)]
196
200
julia> locs_x, locs_y = shell_layout(g, nlist)
197
201
```
198
202
"""
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
201
205
return [0.0 ], [0.0 ]
202
206
end
203
207
if nlist == nothing
204
- nlist = Array {Vector{Int}} (1 )
205
- nlist[1 ] = collect (1 : _nv (G))
208
+ nlist = [collect (1 : nv (g))]
206
209
end
207
210
radius = 0.0
208
211
if length (nlist[1 ]) > 1
@@ -217,7 +220,7 @@ function shell_layout(G, nlist::Union{Nothing, Vector{Vector{Int}}} = nothing)
217
220
append! (locs_y, radius* sin .(θ))
218
221
radius += 1.0
219
222
end
220
- locs_x, locs_y
223
+ return locs_x, locs_y
221
224
end
222
225
223
226
"""
@@ -237,20 +240,20 @@ the edge weight. If None, then all edge weights are 1.
237
240
238
241
**Examples**
239
242
```
240
- julia> g = graphfamous(" karate" )
243
+ julia> g = smallgraph(: karate)
241
244
julia> weight = rand(num_edges(g))
242
245
julia> locs_x, locs_y = spectral_layout(g, weight)
243
246
```
244
247
"""
245
- function spectral_layout (g:: AbstractGraph{T} , weight= nothing ) where {T <: Integer }
248
+ function spectral_layout (g:: AbstractGraph , weight= nothing )
246
249
if nv (g) == 1
247
250
return [0.0 ], [0.0 ]
248
251
elseif nv (g) == 2
249
252
return [0.0 , 1.0 ], [0.0 , 0.0 ]
250
253
end
251
254
252
255
if weight == nothing
253
- weight = ones (length ( edges (g) ))
256
+ weight = ones (ne (g ))
254
257
end
255
258
if nv (g) > 500
256
259
A = sparse (Int[src (e) for e in edges (g)],
@@ -276,7 +279,7 @@ function _spectral(A::SparseMatrixCSC)
276
279
data = vec (sum (A, dims= 1 ))
277
280
D = sparse (Base. OneTo (length (data)), Base. OneTo (length (data)), data)
278
281
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 ())
280
283
index = sortperm (real (eigenvalues))[2 : 3 ]
281
284
return real (eigenvectors[:, index[1 ]]), real (eigenvectors[:, index[2 ]])
282
285
end
0 commit comments