|
1 | 1 | # Explicit import/export of the functions |
2 | 2 | # that are getting new methods, |
3 | 3 | # so that `igraphalg_methods` can pick them up. |
4 | | -import Graphs: diameter, radius |
| 4 | +import Graphs: diameter, radius, pagerank, betweenness_centrality, |
| 5 | + core_number, closeness_centrality, eigenvector_centrality, modularity, |
| 6 | + connected_components, strongly_connected_components |
5 | 7 | import Graphs.Experimental |
6 | 8 | import Graphs.Experimental: has_isomorph |
7 | 9 |
|
8 | | -export diameter, radius, has_isomorph |
| 10 | +export diameter, radius, has_isomorph, pagerank, betweenness_centrality, |
| 11 | + core_number, closeness_centrality, eigenvector_centrality, modularity, |
| 12 | + connected_components, strongly_connected_components |
9 | 13 |
|
10 | 14 | struct IGraphAlg end |
11 | 15 |
|
|
32 | 36 | function has_isomorph(g1, g2, ::IGraphAlg) |
33 | 37 | return LibIGraph.isomorphic(IGraph(g1), IGraph(g2))[1] |
34 | 38 | end |
| 39 | + |
| 40 | +function pagerank(g::Graphs.AbstractGraph{U}, ::IGraphAlg; damping=0.85) where U<:Integer |
| 41 | + ig = IGraph(g) |
| 42 | + res = IGVectorFloat() |
| 43 | + val = Ref{Float64}() |
| 44 | + err = LibIGraph.igraph_pagerank(ig.objref[], LibIGraph.IGRAPH_PAGERANK_ALGO_PRPACK, res.objref[], val, LibIGraph.igraph_vss_all(), Graphs.is_directed(g), damping, C_NULL, C_NULL) |
| 45 | + if err != 0 |
| 46 | + error("igraph_pagerank failed with code $err") |
| 47 | + end |
| 48 | + sz = LibIGraph.vector_size(res) |
| 49 | + return [LibIGraph.vector_get(res, i-1) for i in 1:sz] |
| 50 | +end |
| 51 | + |
| 52 | +function betweenness_centrality(g::Graphs.AbstractGraph, ::IGraphAlg) |
| 53 | + ig = IGraph(g) |
| 54 | + res = IGVectorFloat() |
| 55 | + err = LibIGraph.igraph_betweenness(ig.objref[], C_NULL, res.objref[], LibIGraph.igraph_vss_all(), Graphs.is_directed(g), false) |
| 56 | + if err != 0 |
| 57 | + error("igraph_betweenness failed with code $err") |
| 58 | + end |
| 59 | + sz = LibIGraph.vector_size(res) |
| 60 | + return [LibIGraph.vector_get(res, i-1) for i in 1:sz] |
| 61 | +end |
| 62 | + |
| 63 | + |
| 64 | +function core_number(g::Graphs.AbstractGraph, ::IGraphAlg) |
| 65 | + ig = IGraph(g) |
| 66 | + res = IGVectorInt() |
| 67 | + mode = Graphs.is_directed(g) ? LibIGraph.IGRAPH_OUT : LibIGraph.IGRAPH_ALL |
| 68 | + LibIGraph.igraph_coreness(ig.objref, res.objref, mode) |
| 69 | + return collect(res) |
| 70 | +end |
| 71 | + |
| 72 | +function closeness_centrality(g::Graphs.AbstractGraph, ::IGraphAlg) |
| 73 | + ig = IGraph(g) |
| 74 | + res = IGVectorFloat() |
| 75 | + mode = Graphs.is_directed(g) ? LibIGraph.IGRAPH_OUT : LibIGraph.IGRAPH_ALL |
| 76 | + # reachable_count and all_reachable can be NULL if not needed |
| 77 | + LibIGraph.igraph_closeness(ig.objref, res.objref, C_NULL, C_NULL, |
| 78 | + LibIGraph.igraph_vss_all(), |
| 79 | + mode, C_NULL, true) |
| 80 | + return collect(res) |
| 81 | +end |
| 82 | + |
| 83 | +function eigenvector_centrality(g::Graphs.AbstractGraph, ::IGraphAlg) |
| 84 | + ig = IGraph(g) |
| 85 | + res = IGVectorFloat() |
| 86 | + mode = Graphs.is_directed(g) ? LibIGraph.IGRAPH_OUT : LibIGraph.IGRAPH_ALL |
| 87 | + val = Ref{Float64}(0.0) |
| 88 | + LibIGraph.igraph_eigenvector_centrality(ig.objref, res.objref, val, mode, C_NULL, C_NULL) |
| 89 | + return collect(res) |
| 90 | +end |
| 91 | + |
| 92 | +function modularity(g::Graphs.AbstractGraph, c::AbstractVector{<:Integer}, ::IGraphAlg) |
| 93 | + ig = IGraph(g) |
| 94 | + membership = IGVectorInt([Int(x-1) for x in c]) |
| 95 | + res = Ref{Float64}(0.0) |
| 96 | + LibIGraph.igraph_modularity(ig.objref, membership.objref, C_NULL, 1.0, Graphs.is_directed(g), res) |
| 97 | + return res[] |
| 98 | +end |
| 99 | + |
| 100 | +function connected_components(g::Graphs.AbstractGraph, ::IGraphAlg) |
| 101 | + ig = IGraph(g) |
| 102 | + membership = IGVectorInt() |
| 103 | + csize = IGVectorInt() |
| 104 | + no = Ref{LibIGraph.igraph_int_t}(0) |
| 105 | + LibIGraph.igraph_connected_components(ig.objref, membership.objref, csize.objref, no, LibIGraph.IGRAPH_WEAK) |
| 106 | + |
| 107 | + n_comp = Int(no[]) |
| 108 | + mem = collect(membership) |
| 109 | + comps = [Int[] for _ in 1:n_comp] |
| 110 | + for (i, m_val) in enumerate(mem) |
| 111 | + push!(comps[m_val + 1], i) |
| 112 | + end |
| 113 | + return comps |
| 114 | +end |
| 115 | + |
| 116 | +function strongly_connected_components(g::Graphs.AbstractGraph, ::IGraphAlg) |
| 117 | + ig = IGraph(g) |
| 118 | + membership = IGVectorInt() |
| 119 | + csize = IGVectorInt() |
| 120 | + no = Ref{LibIGraph.igraph_int_t}(0) |
| 121 | + LibIGraph.igraph_connected_components(ig.objref, membership.objref, csize.objref, no, LibIGraph.IGRAPH_STRONG) |
| 122 | + |
| 123 | + n_comp = Int(no[]) |
| 124 | + mem = collect(membership) |
| 125 | + comps = [Int[] for _ in 1:n_comp] |
| 126 | + for (i, m_val) in enumerate(mem) |
| 127 | + push!(comps[m_val + 1], i) |
| 128 | + end |
| 129 | + return comps |
| 130 | +end |
| 131 | + |
| 132 | +#= |
| 133 | +function community_leiden(g::IGraph; resolution=1.0, beta=0.01) |
| 134 | + membership = IGVectorInt() |
| 135 | + nb_clusters, quality = LibIGraph.community_leiden_simple(g, IGNull(), LibIGraph.IGRAPH_LEIDEN_OBJECTIVE_MODULARITY, resolution, beta, false, 2, membership) |
| 136 | + sz = LibIGraph.vector_int_size(membership) |
| 137 | + return [LibIGraph.vector_int_get(membership, i-1) for i in 1:sz] |
| 138 | +end |
| 139 | +
|
| 140 | +function community_leiden(g::Graphs.AbstractGraph, ::IGraphAlg; kwargs...) |
| 141 | + return community_leiden(IGraph(g); kwargs...) |
| 142 | +end |
| 143 | +
|
| 144 | +function modularity_matrix(g::IGraph) |
| 145 | + modmat = IGMatrixFloat() |
| 146 | + LibIGraph.modularity_matrix(g, IGNull(), 1.0, modmat, Graphs.is_directed(g)) |
| 147 | + nrow = LibIGraph.matrix_nrow(modmat) |
| 148 | + ncol = LibIGraph.matrix_ncol(modmat) |
| 149 | + return [LibIGraph.matrix_get(modmat, r-1, c-1) for r in 1:nrow, c in 1:ncol] |
| 150 | +end |
| 151 | +
|
| 152 | +function modularity_matrix(g::Graphs.AbstractGraph, ::IGraphAlg) |
| 153 | + return modularity_matrix(IGraph(g)) |
| 154 | +end |
| 155 | +
|
| 156 | +function layout_kamada_kawai(g::IGraph) |
| 157 | + res = IGMatrixFloat() |
| 158 | + LibIGraph.layout_kamada_kawai(g, res, false, 1000, 0.0, 0.0, IGNull(), IGNull(), IGNull(), IGNull(), IGNull()) |
| 159 | + nrow = LibIGraph.matrix_nrow(res) |
| 160 | + return [LibIGraph.matrix_get(res, r-1, 0) => LibIGraph.matrix_get(res, r-1, 1) for r in 1:nrow] |
| 161 | +end |
| 162 | +
|
| 163 | +function layout_kamada_kawai(g::Graphs.AbstractGraph, ::IGraphAlg) |
| 164 | + return layout_kamada_kawai(IGraph(g)) |
| 165 | +end |
| 166 | +
|
| 167 | +function layout_fruchterman_reingold(g::IGraph) |
| 168 | + res = IGMatrixFloat() |
| 169 | + LibIGraph.layout_fruchterman_reingold(g, res, false, 500, 0.0, LibIGraph.IGRAPH_LAYOUT_AUTOGRID, IGNull(), IGNull(), IGNull(), IGNull(), IGNull()) |
| 170 | + nrow = LibIGraph.matrix_nrow(res) |
| 171 | + return [LibIGraph.matrix_get(res, r-1, 0) => LibIGraph.matrix_get(res, r-1, 1) for r in 1:nrow] |
| 172 | +end |
| 173 | +
|
| 174 | +function layout_fruchterman_reingold(g::Graphs.AbstractGraph, ::IGraphAlg) |
| 175 | + return layout_fruchterman_reingold(IGraph(g)) |
| 176 | +end |
| 177 | +
|
| 178 | +function sir_model(g::IGraph, beta, gamma; no_sim=100) |
| 179 | + result = IGVectorPtr() |
| 180 | + LibIGraph.igraph_sir(g.objref, beta, gamma, no_sim, result.objref) |
| 181 | + |
| 182 | + sz = LibIGraph.igraph_vector_ptr_size(result.objref) |
| 183 | + |
| 184 | + sims = [] |
| 185 | + for i in 1:sz |
| 186 | + ptr = LibIGraph.igraph_vector_ptr_get(result.objref, i-1) |
| 187 | + sir_ptr = Ptr{LibIGraph.igraph_sir_t}(ptr) |
| 188 | + sir_obj = unsafe_load(sir_ptr) |
| 189 | + |
| 190 | + times_sz = LibIGraph.igraph_vector_size(Ref(sir_obj.times)) |
| 191 | + times = [LibIGraph.igraph_vector_get(Ref(sir_obj.times), j-1) for j in 1:times_sz] |
| 192 | + |
| 193 | + s_sz = LibIGraph.igraph_vector_int_size(Ref(sir_obj.no_s)) |
| 194 | + s_count = [LibIGraph.igraph_vector_int_get(Ref(sir_obj.no_s), j-1) for j in 1:s_sz] |
| 195 | + |
| 196 | + i_sz = LibIGraph.igraph_vector_int_size(Ref(sir_obj.no_i)) |
| 197 | + i_count = [LibIGraph.igraph_vector_int_get(Ref(sir_obj.no_i), j-1) for j in 1:i_sz] |
| 198 | + |
| 199 | + r_sz = LibIGraph.igraph_vector_int_size(Ref(sir_obj.no_r)) |
| 200 | + r_count = [LibIGraph.igraph_vector_int_get(Ref(sir_obj.no_r), j-1) for j in 1:r_sz] |
| 201 | + |
| 202 | + push!(sims, (times=times, S=s_count, I=i_count, R=r_count)) |
| 203 | + |
| 204 | + # Destroy the sir object |
| 205 | + LibIGraph.igraph_sir_destroy(sir_ptr) |
| 206 | + # Free the sir pointer memory itself (igraph_sir allocates them with malloc) |
| 207 | + LibIGraph.igraph_free(sir_ptr) |
| 208 | + end |
| 209 | + # The result container (IGVectorPtr) will be destroyed by its finalizer. |
| 210 | + return sims |
| 211 | +end |
| 212 | +
|
| 213 | +function sir_model(g::Graphs.AbstractGraph, beta, gamma, ::IGraphAlg; kwargs...) |
| 214 | + return sir_model(IGraph(g), beta, gamma; kwargs...) |
| 215 | +end |
| 216 | +=# |
0 commit comments