Skip to content

Commit 6395d6b

Browse files
committed
feat: complete IGraphAlg dispatch for Graphs.jl wrapper
1 parent 7e70823 commit 6395d6b

2 files changed

Lines changed: 185 additions & 2 deletions

File tree

src/IGraphs.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export LibIGraph, IGraph, IGraphException,
88
IGBitSet,
99
#IGraphList,
1010
IGVectorIntList, IGVectorFloatList, IGMatrixFloatList, IGBitSetList,
11+
IGVectorPtr,
1112
IGAdjList,
1213
IGNull,
1314
IGraphAlg,

src/graph_api_extensions.jl

Lines changed: 184 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
# Explicit import/export of the functions
22
# that are getting new methods,
33
# 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
57
import Graphs.Experimental
68
import Graphs.Experimental: has_isomorph
79

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
913

1014
struct IGraphAlg end
1115

@@ -32,3 +36,181 @@ end
3236
function has_isomorph(g1, g2, ::IGraphAlg)
3337
return LibIGraph.isomorphic(IGraph(g1), IGraph(g2))[1]
3438
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

Comments
 (0)