33"""
44 Graph{loops,T}
55
6- Undirected graph structure stored in Compressed Sparse Column (CSC) format .
7- Note that the underyling CSC may not be square, so the term "graph" is slightly abusive .
6+ Store a sparse matrix ( in CSC) without its values, keeping only the pattern of nonzeros .
7+ It can be seen as a graph mapping columns to rows, hence the name `Graph` .
88
99The type parameter `loops` must be set to:
1010- `true` if coefficients `(i, i)` present in the CSC are counted as edges in the graph (e.g. for each half of a bipartite graph)
1111- `false` otherwise (e.g. for an adjacency graph)
1212
1313# Fields
1414
15- - `colptr::Vector{T}`: same as for `SparseMatrixCSC`
16- - `rowval::Vector{T}`: same as for `SparseMatrixCSC`
15+ Copied from `SparseMatrixCSC`:
16+
17+ - `m::Int`: number of rows
18+ - `n::Int`: number of columns
19+ - `colptr::Vector{T}`: column `j` is in `colptr[j]:(colptr[j+1]-1)`
20+ - `rowval::Vector{T}`: row indices of stored values
1721"""
1822struct Graph{loops,T<: Integer }
23+ m:: Int
24+ n:: Int
1925 colptr:: Vector{T}
2026 rowval:: Vector{T}
2127end
2228
2329function Graph {loops} (S:: SparseMatrixCSC{Tv,Ti} ) where {loops,Tv,Ti}
24- return Graph {loops,Ti} (S. colptr, S. rowval)
30+ return Graph {loops,Ti} (S. m, S . n, S . colptr, S. rowval)
2531end
2632
27- Base. length (g:: Graph ) = length (g. colptr) - 1
33+ SparseArrays. nnz (g:: Graph ) = length (g. rowval)
34+ SparseArrays. rowvals (g:: Graph ) = g. rowval
35+ SparseArrays. nzrange (g:: Graph , j:: Integer ) = g. colptr[j]: (g. colptr[j + 1 ] - 1 )
36+
37+ nb_vertices (g:: Graph ) = g. n
38+ vertices (g:: Graph ) = 1 : nb_vertices (g)
2839
29- SparseArrays . nnz (g:: Graph{true} ) = length (g. rowval)
40+ nb_edges (g:: Graph{true} ) = length (g. rowval)
3041
31- function SparseArrays . nnz (g:: Graph{false} )
32- n = 0
33- for j in 1 : ( length (g . colptr) - 1 )
34- for k in g . colptr[j] : (g . colptr[j + 1 ] - 1 )
35- i = g . rowval [k]
42+ function nb_edges (g:: Graph{false} )
43+ e = 0
44+ for j in vertices (g )
45+ for k in nzrange (g, j )
46+ i = rowvals (g) [k]
3647 if i != j
37- n += 1
48+ e += 1
3849 end
3950 end
4051 end
41- return n
52+ return e
4253end
4354
44- vertices (g:: Graph ) = 1 : length (g)
45-
4655function neighbors (g:: Graph{true} , v:: Integer )
47- return view (g . rowval, g . colptr[v] : (g . colptr[v + 1 ] - 1 ))
56+ return view (rowvals (g), nzrange (g, v ))
4857end
4958
5059function neighbors (g:: Graph{false} , v:: Integer )
51- neighbors_with_loops = view (g . rowval, g . colptr[v] : (g . colptr[v + 1 ] - 1 ))
60+ neighbors_with_loops = view (rowvals (g), nzrange (g, v ))
5261 return Iterators. filter (!= (v), neighbors_with_loops) # TODO : optimize
5362end
5463
5564function degree (g:: Graph{true} , v:: Integer )
56- return length (g . colptr[v] : (g . colptr[v + 1 ] - 1 ))
65+ return length (nzrange (g, v ))
5766end
5867
5968function degree (g:: Graph{false} , v:: Integer )
60- d = length (g . colptr[v] : (g . colptr[v + 1 ] - 1 ))
61- for k in g . colptr[v] : (g . colptr[v + 1 ] - 1 )
62- if g . rowval [k] == v
69+ d = length (nzrange (g, v ))
70+ for k in nzrange (g, v )
71+ if rowvals (g) [k] == v
6372 d -= 1
6473 end
6574 end
6978maximum_degree (g:: Graph ) = maximum (Base. Fix1 (degree, g), vertices (g))
7079minimum_degree (g:: Graph ) = minimum (Base. Fix1 (degree, g), vertices (g))
7180
81+ """
82+ transpose(g::Graph)
83+
84+ Return a [`Graph`](@ref) corresponding to the transpose of (the underlying matrix of) `g`.
85+ """
86+ function Base. transpose (g:: Graph{loops,T} ) where {loops,T}
87+ S = SparseMatrixCSC {T,T} (g. m, g. n, g. colptr, g. rowval, g. rowval)
88+ Sᵀ = convert (SparseMatrixCSC, transpose (S)) # TODO : use ftranspose! without segfault?
89+ return Graph {loops} (Sᵀ)
90+ end
91+
7292# # Bipartite graph
7393
7494"""
@@ -88,16 +108,17 @@ struct BipartiteGraph{T<:Integer}
88108 g2:: Graph{true,T}
89109end
90110
91- Base. length (bg:: BipartiteGraph , :: Val{1} ) = length (bg. g1)
92- Base. length (bg:: BipartiteGraph , :: Val{2} ) = length (bg. g2)
93- SparseArrays. nnz (bg:: BipartiteGraph ) = nnz (bg. g1)
111+ nb_vertices (bg:: BipartiteGraph , :: Val{1} ) = nb_vertices (bg. g1)
112+ nb_vertices (bg:: BipartiteGraph , :: Val{2} ) = nb_vertices (bg. g2)
113+
114+ nb_edges (bg:: BipartiteGraph ) = nb_edges (bg. g1)
94115
95116"""
96117 vertices(bg::BipartiteGraph, Val(side))
97118
98119Return the list of vertices of `bg` from the specified `side` as a range `1:n`.
99120"""
100- vertices (bg:: BipartiteGraph , :: Val{side} ) where {side} = 1 : length (bg, Val (side))
121+ vertices (bg:: BipartiteGraph , :: Val{side} ) where {side} = 1 : nb_vertices (bg, Val (side))
101122
102123"""
103124 neighbors(bg::BipartiteGraph, Val(side), v::Integer)
@@ -159,7 +180,7 @@ function bipartite_graph(A::SparseMatrixCSC; symmetric_pattern::Bool=false)
159180 checksquare (A) # proxy for checking full symmetry
160181 g1 = g2
161182 else
162- g1 = Graph {true} ( convert (SparseMatrixCSC, transpose (A)) ) # rows to columns
183+ g1 = transpose (g2 ) # rows to columns
163184 end
164185 return BipartiteGraph (g1, g2)
165186end
0 commit comments