@@ -49,45 +49,6 @@ function adjacency_matrix(g::SimpleGraph, dir::Symbol=:out, T::DataType=Int)
49
49
end
50
50
51
51
52
- """
53
- Given two oriented edges i->j and k->l in g, the
54
- non-backtraking matrix B is defined as
55
-
56
- B[i->j, k->l] = δ(j,k)* (1 - δ(i,l))
57
-
58
- returns a matrix B, and an edgemap storing the oriented edges' positions in B
59
- """
60
- function non_backtracking_matrix (g:: SimpleGraph )
61
- # idedgemap = Dict{Int, Edge}()
62
- edgeidmap = Dict {Edge, Int} ()
63
- m = 0
64
- for e in edges (g)
65
- m += 1
66
- edgeidmap[e] = m
67
- end
68
-
69
- if ! is_directed (g)
70
- for e in edges (g)
71
- m += 1
72
- edgeidmap[reverse (e)] = m
73
- end
74
- end
75
-
76
- B = zeros (Float64, m, m)
77
-
78
- for (e,u) in edgeidmap
79
- i, j = src (e), dst (e)
80
- for k in in_neighbors (g,i)
81
- k == j && continue
82
- v = edgeidmap[Edge (k, i)]
83
- B[v, u] = 1
84
- end
85
- end
86
-
87
- return B, edgeidmap
88
- end
89
-
90
-
91
52
""" Returns a sparse [Laplacian matrix](https://en.wikipedia.org/wiki/Laplacian_matrix)
92
53
for a graph `g`, indexed by `[src, dst]` vertices. For undirected graphs, `dir`
93
54
defaults to `:out`; for directed graphs, `dir` defaults to `:both`. `T`
@@ -126,6 +87,7 @@ adjacency_spectrum(g::DiGraph, dir::Symbol=:both, T::DataType=Int) = eigvals(ful
126
87
127
88
128
89
# GraphMatrices integration
90
+ # CombinatorialAdjacency(g) returns a type that supports iterative linear solvers and eigenvector solvers.
129
91
@require GraphMatrices begin
130
92
131
93
function CombinatorialAdjacency (g:: Graph )
@@ -167,3 +129,151 @@ function incidence_matrix(g::SimpleGraph, T::DataType=Int)
167
129
spmx = SparseMatrixCSC (n_v,n_e,colpt,rowval,nzval)
168
130
return spmx
169
131
end
132
+
133
+ """
134
+ Given two oriented edges i->j and k->l in g, the
135
+ non-backtraking matrix B is defined as
136
+
137
+ B[i->j, k->l] = δ(j,k)* (1 - δ(i,l))
138
+
139
+ returns a matrix B, and an edgemap storing the oriented edges' positions in B
140
+ """
141
+ function non_backtracking_matrix (g:: SimpleGraph )
142
+ # idedgemap = Dict{Int, Edge}()
143
+ edgeidmap = Dict {Edge, Int} ()
144
+ m = 0
145
+ for e in edges (g)
146
+ m += 1
147
+ edgeidmap[e] = m
148
+ end
149
+
150
+ if ! is_directed (g)
151
+ for e in edges (g)
152
+ m += 1
153
+ edgeidmap[reverse (e)] = m
154
+ end
155
+ end
156
+
157
+ B = zeros (Float64, m, m)
158
+
159
+ for (e,u) in edgeidmap
160
+ i, j = src (e), dst (e)
161
+ for k in in_neighbors (g,i)
162
+ k == j && continue
163
+ v = edgeidmap[Edge (k, i)]
164
+ B[v, u] = 1
165
+ end
166
+ end
167
+
168
+ return B, edgeidmap
169
+ end
170
+
171
+ """ Nonbacktracking: a compact representation of the nonbacktracking operator
172
+
173
+ g: the underlying graph
174
+ edgeidmap: the association between oriented edges and index into the NBT matrix
175
+
176
+ The Nonbacktracking operator can be used for community detection.
177
+ This representation is compact in that it uses only ne(g) additional storage
178
+ and provides an implicit representation of the matrix B_g defined below.
179
+
180
+ Given two oriented edges i->j and k->l in g, the
181
+ non-backtraking matrix B is defined as
182
+
183
+ B[i->j, k->l] = δ(j,k)* (1 - δ(i,l))
184
+
185
+ This type is in the style of GraphMatrices.jl and supports the necessary operations
186
+ for computed eigenvectors and conducting linear solves.
187
+
188
+ Additionally the contract!(vertexspace, nbt, edgespace) method takes vectors represented in
189
+ the domain of B and represents them in the domain of the adjacency matrix of g.
190
+ """
191
+ type Nonbacktracking{G}
192
+ g:: G
193
+ edgeidmap:: Dict{Edge,Int}
194
+ m:: Int
195
+ end
196
+
197
+ function Nonbacktracking (g:: SimpleGraph )
198
+ edgeidmap = Dict {Edge, Int} ()
199
+ m = 0
200
+ for e in edges (g)
201
+ m += 1
202
+ edgeidmap[e] = m
203
+ end
204
+ if ! is_directed (g)
205
+ for e in edges (g)
206
+ m += 1
207
+ edgeidmap[reverse (e)] = m
208
+ end
209
+ end
210
+ return Nonbacktracking (g, edgeidmap, m)
211
+ end
212
+
213
+ size (nbt:: Nonbacktracking ) = (nbt. m,nbt. m)
214
+ eltype (nbt:: Nonbacktracking ) = Float64
215
+ issym (nbt:: Nonbacktracking ) = false
216
+
217
+ function * {G, T<: Number }(nbt:: Nonbacktracking{G} , x:: Vector{T} )
218
+ length (x) == nbt. m || error (" dimension mismatch" )
219
+ y = zeros (T, length (x))
220
+ for (e,u) in nbt. edgeidmap
221
+ i, j = src (e), dst (e)
222
+ for k in in_neighbors (nbt. g,i)
223
+ k == j && continue
224
+ v = nbt. edgeidmap[Edge (k, i)]
225
+ y[v] += x[u]
226
+ end
227
+ end
228
+ return y
229
+ end
230
+
231
+ function coo_sparse (nbt:: Nonbacktracking )
232
+ m = nbt. m
233
+ #= I,J = zeros(Int, m), zeros(Int, m) =#
234
+ I,J = zeros (Int, 0 ), zeros (Int, 0 )
235
+ for (e,u) in nbt. edgeidmap
236
+ i, j = src (e), dst (e)
237
+ for k in in_neighbors (nbt. g,i)
238
+ k == j && continue
239
+ v = nbt. edgeidmap[Edge (k, i)]
240
+ #= J[u] = v =#
241
+ #= I[u] = u =#
242
+ push! (I, v)
243
+ push! (J, u)
244
+ end
245
+ end
246
+ return I,J,1.0
247
+ end
248
+
249
+ sparse (nbt:: Nonbacktracking ) = sparse (coo_sparse (nbt)... , nbt. m,nbt. m)
250
+
251
+ function * {G, T<: Number }(nbt:: Nonbacktracking{G} , x:: AbstractMatrix{T} )
252
+ y = zeros (x)
253
+ for i in 1 : nbt. m
254
+ y[:,i] = nbt * x[:,i]
255
+ end
256
+ return y
257
+ end
258
+
259
+ """ contract!(vertexspace, nbt, edgespace) in place version of
260
+ contract(nbt, edgespace). modifies first argument
261
+ """
262
+ function contract! (vertexspace:: Vector , nbt:: Nonbacktracking , edgespace:: Vector )
263
+ for i= 1 : nv (nbt. g)
264
+ for j in neighbors (nbt. g, i)
265
+ u = nbt. edgeidmap[Edge (j,i)]
266
+ vertexspace[i] += edgespace[u]
267
+ end
268
+ end
269
+ end
270
+
271
+ """ contract(nbt, edgespace)
272
+ Integrates out the edges by summing over the edges incident to each vertex.
273
+ """
274
+ function contract (nbt:: Nonbacktracking , edgespace:: Vector )
275
+ y = zeros (eltype (edgespace), nv (nbt. g))
276
+ contract! (y,nbt,edgespace)
277
+ return y
278
+ end
279
+
0 commit comments