|
| 1 | +## Standard graph |
| 2 | + |
| 3 | +""" |
| 4 | + Graph{T} |
| 5 | +
|
| 6 | +Undirected graph structure stored in Compressed Sparse Column (CSC) format. |
| 7 | +
|
| 8 | +# Fields |
| 9 | +
|
| 10 | +- `colptr::Vector{T}`: same as for `SparseMatrixCSC` |
| 11 | +- `rowval::Vector{T}`: same as for `SparseMatrixCSC` |
| 12 | +""" |
1 | 13 | struct Graph{T<:Integer} |
2 | 14 | colptr::Vector{T} |
3 | 15 | rowval::Vector{T} |
4 | 16 | end |
5 | 17 |
|
6 | 18 | Graph(A::SparseMatrixCSC) = Graph(A.colptr, A.rowval) |
| 19 | +Graph(A::AbstractMatrix) = Graph(sparse(A)) |
7 | 20 |
|
8 | 21 | Base.length(g::Graph) = length(g.colptr) - 1 |
| 22 | +SparseArrays.nnz(g::Graph) = length(g.rowval) |
9 | 23 |
|
| 24 | +vertices(g::Graph) = 1:length(g) |
10 | 25 | neighbors(g::Graph, v::Integer) = view(g.rowval, g.colptr[v]:(g.colptr[v + 1] - 1)) |
| 26 | +degree(g::Graph, v::Integer) = length(g.colptr[v]:(g.colptr[v + 1] - 1)) |
11 | 27 |
|
12 | | -## Adjacency graph |
| 28 | +maximum_degree(g::Graph) = maximum(Base.Fix1(degree, g), vertices(g)) |
| 29 | +minimum_degree(g::Graph) = minimum(Base.Fix1(degree, g), vertices(g)) |
| 30 | + |
| 31 | +## Bipartite graph |
13 | 32 |
|
14 | 33 | """ |
15 | | - AdjacencyGraph |
| 34 | + BipartiteGraph{T} |
16 | 35 |
|
17 | | -Undirected graph representing the nonzeros of a symmetrix matrix (typically a Hessian matrix). |
| 36 | +Undirected bipartite graph structure stored in bidirectional Compressed Sparse Column format (redundancy allows for faster access). |
18 | 37 |
|
19 | | -The adjacency graph of a symmetrix matrix `A ∈ ℝ^{n × n}` is `G(A) = (V, E)` where |
| 38 | +A bipartite graph has two "sides", which we number `1` and `2`. |
20 | 39 |
|
21 | | -- `V = 1:n` is the set of rows or columns |
22 | | -- `(i, j) ∈ E` whenever `A[i, j] ≠ 0` and `i ≠ j` |
| 40 | +# Fields |
| 41 | +
|
| 42 | +- `g1::Graph{T}`: contains the neighbors for vertices on side `1` |
| 43 | +- `g2::Graph{T}`: contains the neighbors for vertices on side `2` |
23 | 44 | """ |
24 | | -struct AdjacencyGraph{T} |
25 | | - g::Graph{T} |
| 45 | +struct BipartiteGraph{T<:Integer} |
| 46 | + g1::Graph{T} |
| 47 | + g2::Graph{T} |
26 | 48 | end |
27 | 49 |
|
28 | | -function AdjacencyGraph(H::SparseMatrixCSC) |
29 | | - g = Graph(H - Diagonal(H)) |
30 | | - return AdjacencyGraph(g) |
31 | | -end |
| 50 | +Base.length(bg::BipartiteGraph, ::Val{1}) = length(bg.g1) |
| 51 | +Base.length(bg::BipartiteGraph, ::Val{2}) = length(bg.g2) |
| 52 | +SparseArrays.nnz(bg::BipartiteGraph) = nnz(bg.g1) |
32 | 53 |
|
33 | | -Base.length(ag::AdjacencyGraph) = length(ag.g) |
| 54 | +""" |
| 55 | + vertices(bg::BipartiteGraph, Val(side)) |
34 | 56 |
|
| 57 | +Return the list of vertices of `bg` from the specified `side` as a range `1:n`. |
35 | 58 | """ |
36 | | - neighbors(ag::AdjacencyGraph, v::Integer) |
| 59 | +vertices(bg::BipartiteGraph, ::Val{side}) where {side} = 1:length(bg, Val(side)) |
37 | 60 |
|
38 | | -Return the neighbors of `v` in the graph `ag`. |
39 | 61 | """ |
40 | | -neighbors(ag::AdjacencyGraph, v::Integer) = neighbors(ag.g, v) |
| 62 | + neighbors(bg::BipartiteGraph, Val(side), v::Integer) |
41 | 63 |
|
42 | | -degree(ag::AdjacencyGraph, v::Integer) = length(neighbors(ag, v)) |
| 64 | +Return the neighbors of `v` (a vertex from the specified `side`, `1` or `2`), in the graph `bg`. |
| 65 | +""" |
| 66 | +neighbors(bg::BipartiteGraph, ::Val{1}, v::Integer) = neighbors(bg.g1, v) |
| 67 | +neighbors(bg::BipartiteGraph, ::Val{2}, v::Integer) = neighbors(bg.g2, v) |
43 | 68 |
|
44 | | -## Bipartite graph |
| 69 | +degree(bg::BipartiteGraph, ::Val{1}, v::Integer) = degree(bg.g1, v) |
| 70 | +degree(bg::BipartiteGraph, ::Val{2}, v::Integer) = degree(bg.g2, v) |
| 71 | + |
| 72 | +function maximum_degree(bg::BipartiteGraph, ::Val{side}) where {side} |
| 73 | + return maximum(v -> degree(bg, Val(side), v), vertices(bg, Val(side))) |
| 74 | +end |
| 75 | + |
| 76 | +function minimum_degree(bg::BipartiteGraph, ::Val{side}) where {side} |
| 77 | + return minimum(v -> degree(bg, Val(side), v), vertices(bg, Val(side))) |
| 78 | +end |
| 79 | + |
| 80 | +## Construct from matrices |
| 81 | + |
| 82 | +""" |
| 83 | + adjacency_graph(H::AbstractMatrix) |
| 84 | +
|
| 85 | +Return a [`Graph`](@ref) representing the nonzeros of a symmetric matrix (typically a Hessian matrix). |
| 86 | +
|
| 87 | +The adjacency graph of a symmetrix matric `A ∈ ℝ^{n × n}` is `G(A) = (V, E)` where |
| 88 | +
|
| 89 | +- `V = 1:n` is the set of rows or columns `i`/`j` |
| 90 | +- `(i, j) ∈ E` whenever `A[i, j] ≠ 0` and `i ≠ j` |
| 91 | +""" |
| 92 | +adjacency_graph(H::SparseMatrixCSC) = Graph(H - Diagonal(H)) |
| 93 | +adjacency_graph(H::AbstractMatrix) = adjacency_graph(sparse(H)) |
45 | 94 |
|
46 | 95 | """ |
47 | | - BipartiteGraph |
| 96 | + bipartite_graph(J::AbstractMatrix) |
48 | 97 |
|
49 | | -Undirected bipartite graph representing the nonzeros of a non-symmetric matrix (typically a Jacobian matrix). |
| 98 | +Return a [`BipartiteGraph`](@ref) representing the nonzeros of a non-symmetric matrix (typically a Jacobian matrix). |
50 | 99 |
|
51 | 100 | The bipartite graph of a matrix `A ∈ ℝ^{m × n}` is `Gb(A) = (V₁, V₂, E)` where |
52 | 101 |
|
53 | 102 | - `V₁ = 1:m` is the set of rows `i` |
54 | 103 | - `V₂ = 1:n` is the set of columns `j` |
55 | 104 | - `(i, j) ∈ E` whenever `A[i, j] ≠ 0` |
56 | 105 | """ |
57 | | -struct BipartiteGraph{T} |
58 | | - g1::Graph{T} |
59 | | - g2::Graph{T} |
60 | | -end |
61 | | - |
62 | | -function BipartiteGraph(J::SparseMatrixCSC) |
63 | | - g1 = Graph(SparseMatrixCSC(transpose(J))) # rows to columns |
| 106 | +function bipartite_graph(J::SparseMatrixCSC) |
| 107 | + g1 = Graph(transpose(J)) # rows to columns |
64 | 108 | g2 = Graph(J) # columns to rows |
65 | 109 | return BipartiteGraph(g1, g2) |
66 | 110 | end |
67 | 111 |
|
68 | | -Base.length(bg::BipartiteGraph, ::Val{1}) = length(bg.g1) |
69 | | -Base.length(bg::BipartiteGraph, ::Val{2}) = length(bg.g2) |
| 112 | +bipartite_graph(J::AbstractMatrix) = bipartite_graph(sparse(J)) |
70 | 113 |
|
71 | 114 | """ |
72 | | - neighbors(bg::BipartiteGraph, Val(side), v::Integer) |
| 115 | + column_intersection_graph(J::AbstractMatrix) |
73 | 116 |
|
74 | | -Return the neighbors of `v`, which is a vertex from the specified `side` (`1` or `2`), in the graph `bg`. |
75 | | -""" |
76 | | -neighbors(bg::BipartiteGraph, ::Val{1}, v::Integer) = neighbors(bg.g1, v) |
77 | | -neighbors(bg::BipartiteGraph, ::Val{2}, v::Integer) = neighbors(bg.g2, v) |
| 117 | +Return a [`Graph`](@ref) representing the column intersections of a non-symmetric matrix (typically a Jacobian matrix). |
| 118 | +
|
| 119 | +The column intersection graph of a matrix `A ∈ ℝ^{m × n}` is `Gc(A) = (V, E)` where |
78 | 120 |
|
79 | | -function degree(bg::BipartiteGraph, ::Val{side}, v::Integer) where {side} |
80 | | - return length(neighbors(bg, Val(side), v)) |
| 121 | +- `V = 1:n` is the set of columns `j` |
| 122 | +- `(j1, j2) ∈ E` whenever `A[:, j1] ∩ A[:, j2] ≠ ∅` |
| 123 | +""" |
| 124 | +function column_intersection_graph(J::SparseMatrixCSC) |
| 125 | + A = transpose(J) * J |
| 126 | + return adjacency_graph(A - Diagonal(A)) |
81 | 127 | end |
| 128 | + |
| 129 | +column_intersection_graph(J::AbstractMatrix) = column_intersection_graph(sparse(J)) |
0 commit comments