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 )
@@ -93,63 +94,66 @@ Initial "temperature", controls movement per iteration
93
94
94
95
**Examples**
95
96
```
96
- julia> g = graphfamous(" karate" )
97
+ julia> g = smallgraph(: karate)
97
98
julia> locs_x, locs_y = spring_layout(g)
98
99
```
99
100
"""
100
- function spring_layout (g:: AbstractGraph{T} , locs_x= 2 * rand (nv (g)).- 1.0 , locs_y= 2 * rand (nv (g)).- 1.0 ; C= 2.0 , MAXITER= 100 , INITTEMP= 2.0 ) where {T<: Integer }
101
-
102
- # size(adj_matrix, 1) != size(adj_matrix, 2) && error("Adj. matrix must be square.")
103
- N = nv (g)
101
+ function spring_layout (g:: AbstractGraph ,
102
+ locs_x= 2 * rand (nv (g)).- 1.0 ,
103
+ locs_y= 2 * rand (nv (g)).- 1.0 ;
104
+ C= 2.0 ,
105
+ MAXITER= 100 ,
106
+ INITTEMP= 2.0 )
107
+
108
+ nvg = nv (g)
104
109
adj_matrix = adjacency_matrix (g)
105
110
106
111
# The optimal distance bewteen vertices
107
- K = C * sqrt (4.0 / N)
112
+ k = C * sqrt (4.0 / nvg)
113
+ k² = k * k
108
114
109
115
# Store forces and apply at end of iteration all at once
110
- force_x = zeros (N )
111
- force_y = zeros (N )
116
+ force_x = zeros (nvg )
117
+ force_y = zeros (nvg )
112
118
113
119
# Iterate MAXITER times
114
120
@inbounds for iter = 1 : MAXITER
115
121
# Calculate forces
116
- for i = 1 : N
122
+ for i = 1 : nvg
117
123
force_vec_x = 0.0
118
124
force_vec_y = 0.0
119
- for j = 1 : N
125
+ for j = 1 : nvg
120
126
i == j && continue
121
127
d_x = locs_x[j] - locs_x[i]
122
128
d_y = locs_y[j] - locs_y[i]
123
- d = sqrt (d_x^ 2 + d_y^ 2 )
124
- if adj_matrix[i,j] != zero (eltype (adj_matrix)) || adj_matrix[j,i] != zero (eltype (adj_matrix))
125
- # F = d^2 / K - K^2 / d
126
- F_d = d / K - K^ 2 / d^ 2
129
+ dist² = (d_x * d_x) + (d_y * d_y)
130
+ dist = sqrt (dist²)
131
+
132
+ if ! ( iszero (adj_matrix[i,j]) && iszero (adj_matrix[j,i]) )
133
+ # Attractive + repulsive force
134
+ # F_d = dist² / k - k² / dist # original FR algorithm
135
+ F_d = dist / k - k² / dist²
127
136
else
128
137
# Just repulsive
129
- # F = -K^2 / d^
130
- F_d = - K ^ 2 / d ^ 2
138
+ # F_d = -k² / dist # original FR algorithm
139
+ F_d = - k² / dist²
131
140
end
132
- # d / sin θ = d_y/d = fy/F
133
- # F /| dy fy -> fy = F*d_y/d
134
- # / | cos θ = d_x/d = fx/F
135
- # /--- -> fx = F*d_x/d
136
- # dx fx
137
141
force_vec_x += F_d* d_x
138
142
force_vec_y += F_d* d_y
139
143
end
140
144
force_x[i] = force_vec_x
141
145
force_y[i] = force_vec_y
142
146
end
143
147
# Cool down
144
- TEMP = INITTEMP / iter
148
+ temp = INITTEMP / iter
145
149
# Now apply them, but limit to temperature
146
- for i = 1 : N
147
- force_mag = sqrt (force_x[i]^ 2 + force_y[i]^ 2 )
148
- scale = min (force_mag, TEMP)/ force_mag
150
+ for i = 1 : nvg
151
+ fx = force_x[i]
152
+ fy = force_y[i]
153
+ force_mag = sqrt ((fx * fx) + (fy * fy))
154
+ scale = min (force_mag, temp) / force_mag
149
155
locs_x[i] += force_x[i] * scale
150
- # locs_x[i] = max(-1.0, min(locs_x[i], +1.0))
151
156
locs_y[i] += force_y[i] * scale
152
- # locs_y[i] = max(-1.0, min(locs_y[i], +1.0))
153
157
end
154
158
end
155
159
@@ -162,7 +166,7 @@ function spring_layout(g::AbstractGraph{T}, locs_x=2*rand(nv(g)).-1.0, locs_y=2*
162
166
map! (z -> scaler (z, min_x, max_x), locs_x, locs_x)
163
167
map! (z -> scaler (z, min_y, max_y), locs_y, locs_y)
164
168
165
- return locs_x,locs_y
169
+ return locs_x, locs_y
166
170
end
167
171
168
172
"""
@@ -172,28 +176,27 @@ Position nodes in concentric circles.
172
176
173
177
**Parameters**
174
178
175
- *G *
179
+ *g *
176
180
a graph
177
181
178
182
*nlist*
179
183
Vector of Vector, Vector of node Vector for each shell.
180
184
181
185
**Examples**
182
186
```
183
- julia> g = graphfamous(" karate" )
187
+ julia> g = smallgraph(: karate)
184
188
julia> nlist = Array{Vector{Int}}(2)
185
189
julia> nlist[1] = [1:5]
186
190
julia> nlist[2] = [6:num_vertiecs(g)]
187
191
julia> locs_x, locs_y = shell_layout(g, nlist)
188
192
```
189
193
"""
190
- function shell_layout (G , nlist:: Union{Nothing, Vector{Vector{Int}}} = nothing )
191
- if _nv (G ) == 1
194
+ function shell_layout (g , nlist:: Union{Nothing, Vector{Vector{Int}}} = nothing )
195
+ if nv (g ) == 1
192
196
return [0.0 ], [0.0 ]
193
197
end
194
198
if nlist == nothing
195
- nlist = Array {Vector{Int}} (1 )
196
- nlist[1 ] = collect (1 : _nv (G))
199
+ nlist = [collect (1 : nv (g))]
197
200
end
198
201
radius = 0.0
199
202
if length (nlist[1 ]) > 1
@@ -208,7 +211,7 @@ function shell_layout(G, nlist::Union{Nothing, Vector{Vector{Int}}} = nothing)
208
211
append! (locs_y, radius* sin .(θ))
209
212
radius += 1.0
210
213
end
211
- locs_x, locs_y
214
+ return locs_x, locs_y
212
215
end
213
216
214
217
"""
@@ -228,20 +231,20 @@ the edge weight. If None, then all edge weights are 1.
228
231
229
232
**Examples**
230
233
```
231
- julia> g = graphfamous(" karate" )
234
+ julia> g = smallgraph(: karate)
232
235
julia> weight = rand(num_edges(g))
233
236
julia> locs_x, locs_y = spectral_layout(g, weight)
234
237
```
235
238
"""
236
- function spectral_layout (g:: AbstractGraph{T} , weight= nothing ) where {T <: Integer }
239
+ function spectral_layout (g:: AbstractGraph , weight= nothing )
237
240
if nv (g) == 1
238
241
return [0.0 ], [0.0 ]
239
242
elseif nv (g) == 2
240
243
return [0.0 , 1.0 ], [0.0 , 0.0 ]
241
244
end
242
245
243
246
if weight == nothing
244
- weight = ones (length ( edges (g) ))
247
+ weight = ones (ne (g ))
245
248
end
246
249
if nv (g) > 500
247
250
A = sparse (Int[src (e) for e in edges (g)],
@@ -267,7 +270,7 @@ function _spectral(A::SparseMatrixCSC)
267
270
data = vec (sum (A, dims= 1 ))
268
271
D = sparse (Base. OneTo (length (data)), Base. OneTo (length (data)), data)
269
272
L = D - A
270
- eigenvalues, eigenvectors = LightGraphs. LinAlg. eigs (L, nev= 3 , which= LR ())
273
+ eigenvalues, eigenvectors = LightGraphs. LinAlg. eigs (L, nev= 3 , which= SR ())
271
274
index = sortperm (real (eigenvalues))[2 : 3 ]
272
275
return real (eigenvectors[:, index[1 ]]), real (eigenvectors[:, index[2 ]])
273
276
end
0 commit comments