From 87f853d75cb3d2c2516087def3614ae784b87b59 Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 8 Mar 2021 09:03:22 +0100 Subject: [PATCH 1/6] Overload of assortativity method to account for scalar labelled graphs --- src/community/assortativity.jl | 42 ++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/community/assortativity.jl b/src/community/assortativity.jl index 0d17ae5f4..b6f9732c4 100644 --- a/src/community/assortativity.jl +++ b/src/community/assortativity.jl @@ -34,9 +34,43 @@ function assortativity(g::AbstractGraph{T}) where T return assortativity_coefficient(g, sjk, sj, sk, sjs, sks, nue) end +""" + assortativity(g,labels) +Similar to `assortativity(g)` except that Pearson correlation is calculated +from the correlation between some values associated to each node and stored in +`labels`. + +# Arguments +- `labels` is a dictionary that associates to each vertex index a scalar value + +# Examples +```jldoctest +julia> using LightGraphs + +julia> labels = Dict(collect(1:4) .=> [-1., -1., 1., 1.]) + +julia> assortativity(star_graph(4),labels) +-0.5 +``` +""" +function assortativity(g::AbstractGraph{T},labels::Dict{T,N}) where {T,N<:Number} + nue = ne(g) + sjk = sj = sk = sjs = sks = zero(N) + for d in edges(g) + j = labels[src(d)] + k = labels[dst(d)] + sjk += j*k + sj += j + sk += k + sjs += j^2 + sks += k^2 + end + return assortativity_coefficient(g, sjk, sj, sk, sjs, sks, nue) +end + #= -assortativity coefficient for directed graphs: -see equation (21) in M. E. J. Newman: Mixing patterns in networks, Phys. Rev. E 67, 026126 (2003), +assortativity coefficient for directed graphs: +see equation (21) in M. E. J. Newman: Mixing patterns in networks, Phys. Rev. E 67, 026126 (2003), http://arxiv.org/abs/cond-mat/0209450 =# @traitfn function assortativity_coefficient(g::::IsDirected, sjk, sj, sk, sjs, sks, nue) @@ -44,8 +78,8 @@ http://arxiv.org/abs/cond-mat/0209450 end #= -assortativity coefficient for undirected graphs: -see equation (4) in M. E. J. Newman: Assortative mixing in networks, Phys. Rev. Lett. 89, 208701 (2002), +assortativity coefficient for undirected graphs: +see equation (4) in M. E. J. Newman: Assortative mixing in networks, Phys. Rev. Lett. 89, 208701 (2002), http://arxiv.org/abs/cond-mat/0205405/ =# @traitfn function assortativity_coefficient(g::::(!IsDirected), sjk, sj, sk, sjs, sks, nue) From 2c0ee0c2d54b31b48a8a7265f3a3176285fe91b6 Mon Sep 17 00:00:00 2001 From: Victor Date: Mon, 8 Mar 2021 09:30:56 +0100 Subject: [PATCH 2/6] little fix on assortativity extended --- src/community/assortativity.jl | 18 +++++++++--------- src/community/rich_club.jl | 10 ++++++++++ src/community/s_metric.jl | 27 +++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 src/community/rich_club.jl create mode 100644 src/community/s_metric.jl diff --git a/src/community/assortativity.jl b/src/community/assortativity.jl index b6f9732c4..b0b68110c 100644 --- a/src/community/assortativity.jl +++ b/src/community/assortativity.jl @@ -35,30 +35,30 @@ function assortativity(g::AbstractGraph{T}) where T end """ - assortativity(g,labels) + assortativity(g,attributes) Similar to `assortativity(g)` except that Pearson correlation is calculated -from the correlation between some values associated to each node and stored in -`labels`. +from the correlation between some atrribute values associated to each node and stored in +`attributes`. # Arguments -- `labels` is a dictionary that associates to each vertex index a scalar value +- `attributes` is a dictionary that associates to each vertex index a scalar value # Examples ```jldoctest julia> using LightGraphs -julia> labels = Dict(collect(1:4) .=> [-1., -1., 1., 1.]) +julia> attributes = Dict(collect(1:4) .=> [-1., -1., 1., 1.]) -julia> assortativity(star_graph(4),labels) +julia> assortativity(star_graph(4),attributes) -0.5 ``` """ -function assortativity(g::AbstractGraph{T},labels::Dict{T,N}) where {T,N<:Number} +function assortativity(g::AbstractGraph{T},attributes::Dict{T,N}) where {T,N<:Number} nue = ne(g) sjk = sj = sk = sjs = sks = zero(N) for d in edges(g) - j = labels[src(d)] - k = labels[dst(d)] + j = attributes[src(d)] + k = attributes[dst(d)] sjk += j*k sj += j sk += k diff --git a/src/community/rich_club.jl b/src/community/rich_club.jl new file mode 100644 index 000000000..edd8f23d3 --- /dev/null +++ b/src/community/rich_club.jl @@ -0,0 +1,10 @@ +function rich_club(g::AbstractGraph,k::Int) + E = 0 + for e in edges(g) + if (degree(g,src(e)) >= k) && (degree(g,dst(e)) >= k ) + E +=1 + end + end + N = count(degree(g) .>= k) + return 2*E / (N*(N-1)) +end diff --git a/src/community/s_metric.jl b/src/community/s_metric.jl new file mode 100644 index 000000000..0a37beb5b --- /dev/null +++ b/src/community/s_metric.jl @@ -0,0 +1,27 @@ +function s_metric(g::AbstractGraph) + s = 0 + for e in edges(g) + s += degree(g,src(e)) * degree(g,dst(e)) + end + return s +end + +function s_metric_nx(g::AbstractGraph) + gnx = to_nx(g) + nx.s_metric(gnx,normalized = false) +end + +function smax(g::AbstractGraph) + sm = + return sum(degree(g).^3)/2 + s_metric(g) / sm +end + +function smin(g::AbstractGraph) + Z = vcat([fill(d,d) for d in sort(degree(g),rev=true)]...) + return 0.5 * dot(Z,reverse(Z)) +end + +function smax_metric(g::AbstractGraph) + return s_metric(g) / smax(g) +end From 5cfbc7fac1b200eb9acff5e6fe7b3a4ae020099c Mon Sep 17 00:00:00 2001 From: vboussange Date: Mon, 8 Mar 2021 09:33:14 +0100 Subject: [PATCH 3/6] Delete s_metric.jl --- src/community/s_metric.jl | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 src/community/s_metric.jl diff --git a/src/community/s_metric.jl b/src/community/s_metric.jl deleted file mode 100644 index 0a37beb5b..000000000 --- a/src/community/s_metric.jl +++ /dev/null @@ -1,27 +0,0 @@ -function s_metric(g::AbstractGraph) - s = 0 - for e in edges(g) - s += degree(g,src(e)) * degree(g,dst(e)) - end - return s -end - -function s_metric_nx(g::AbstractGraph) - gnx = to_nx(g) - nx.s_metric(gnx,normalized = false) -end - -function smax(g::AbstractGraph) - sm = - return sum(degree(g).^3)/2 - s_metric(g) / sm -end - -function smin(g::AbstractGraph) - Z = vcat([fill(d,d) for d in sort(degree(g),rev=true)]...) - return 0.5 * dot(Z,reverse(Z)) -end - -function smax_metric(g::AbstractGraph) - return s_metric(g) / smax(g) -end From 5d347d16dcac1678dc086a54dd9b33331d86375d Mon Sep 17 00:00:00 2001 From: vboussange Date: Mon, 8 Mar 2021 09:33:29 +0100 Subject: [PATCH 4/6] Delete rich_club.jl --- src/community/rich_club.jl | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/community/rich_club.jl diff --git a/src/community/rich_club.jl b/src/community/rich_club.jl deleted file mode 100644 index edd8f23d3..000000000 --- a/src/community/rich_club.jl +++ /dev/null @@ -1,10 +0,0 @@ -function rich_club(g::AbstractGraph,k::Int) - E = 0 - for e in edges(g) - if (degree(g,src(e)) >= k) && (degree(g,dst(e)) >= k ) - E +=1 - end - end - N = count(degree(g) .>= k) - return 2*E / (N*(N-1)) -end From b1b57f31ec720ab723dad9df8ce1c2fd91957830 Mon Sep 17 00:00:00 2001 From: vboussange Date: Thu, 11 Mar 2021 15:53:16 +0100 Subject: [PATCH 5/6] Changed attributes types to vector. Added tests. Changed documentation. --- src/community/assortativity.jl | 35 ++++++++++++++------------------- test/community/assortativity.jl | 24 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/community/assortativity.jl b/src/community/assortativity.jl index b0b68110c..8494ef113 100644 --- a/src/community/assortativity.jl +++ b/src/community/assortativity.jl @@ -1,21 +1,35 @@ """ assortativity(g) + assortativity(g,attributes) Return the [assortativity coefficient](https://en.wikipedia.org/wiki/Assortativity) of graph `g`, defined as the Pearson correlation of excess degree between the end vertices of all the edges of the graph. +If `attributes` is provided, Pearson correlation is calculated +from atrribute values associated to each vertex and stored in +vector `attributes`. + The excess degree is equal to the degree of linked vertices minus one, i.e. discounting the edge that links the pair. In directed graphs, the paired values are the out-degree of source vertices and the in-degree of destination vertices. +# Arguments +- `attributes` (optional) is a vector that associates to each vertex `i` a scalar value +`attributes[i]`. + # Examples ```jldoctest julia> using LightGraphs julia> assortativity(star_graph(4)) -1.0 + +julia> attributes = [-1., -1., 1., 1.] + +julia> assortativity(star_graph(4),attributes) +-0.5 ``` """ function assortativity(g::AbstractGraph{T}) where T @@ -34,26 +48,7 @@ function assortativity(g::AbstractGraph{T}) where T return assortativity_coefficient(g, sjk, sj, sk, sjs, sks, nue) end -""" - assortativity(g,attributes) -Similar to `assortativity(g)` except that Pearson correlation is calculated -from the correlation between some atrribute values associated to each node and stored in -`attributes`. - -# Arguments -- `attributes` is a dictionary that associates to each vertex index a scalar value - -# Examples -```jldoctest -julia> using LightGraphs - -julia> attributes = Dict(collect(1:4) .=> [-1., -1., 1., 1.]) - -julia> assortativity(star_graph(4),attributes) --0.5 -``` -""" -function assortativity(g::AbstractGraph{T},attributes::Dict{T,N}) where {T,N<:Number} +function assortativity(g::AbstractGraph{T},attributes::Vector{N}) where {T,N<:Number} nue = ne(g) sjk = sj = sk = sjs = sks = zero(N) for d in edges(g) diff --git a/test/community/assortativity.jl b/test/community/assortativity.jl index 720668945..05528b993 100644 --- a/test/community/assortativity.jl +++ b/test/community/assortativity.jl @@ -20,4 +20,28 @@ using Random, Statistics y = [indegree(g, dst(d))-1 for d in edges(g)] @test @inferred assort ≈ cor([x;y], [y;x]) end + + # Test definition of assortativity as Pearson correlation coefficient + # between some scalar attributes characterising each vertex + @testset "Small graphs with attributes" for n = 5:2:11 + g = grid([1,n]) + attributes = [(-1.)^v for v in vertices(g)] + @test @inferred assortativity(g,attributes) ≈ -1. + end + @testset "Directed ($seed) with attributes" for seed in [1, 2, 3], (_n, _ne) in [(14, 18), (10, 22), (7, 16)] + g = erdos_renyi(_n, _ne; is_directed=true, seed=seed) + attributes = randn(_n) + assort = assortativity(g,attributes) + x = [attributes[src(d)] for d in edges(g)] + y = [attributes[dst(d)] for d in edges(g)] + @test @inferred assort ≈ cor(x, y) + end + @testset "Undirected ($seed) with attributes" for seed in [1, 2, 3], (_n, _ne) in [(14, 18), (10, 22), (7, 16)] + g = erdos_renyi(_n, _ne; is_directed=false, seed=seed) + attributes = randn(_n) + assort = assortativity(g,attributes) + x = [attributes[src(d)] for d in edges(g)] + y = [attributes[dst(d)] for d in edges(g)] + @test @inferred assort ≈ cor([x;y], [y;x]) + end end From a07a60cfb0ac75578f2ae2c262c014393f391801 Mon Sep 17 00:00:00 2001 From: vboussange Date: Tue, 30 Mar 2021 13:40:56 +0200 Subject: [PATCH 6/6] modification following review from sbromberger --- src/community/assortativity.jl | 7 ++++--- test/community/assortativity.jl | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/community/assortativity.jl b/src/community/assortativity.jl index 8494ef113..4b84f8d1a 100644 --- a/src/community/assortativity.jl +++ b/src/community/assortativity.jl @@ -1,6 +1,6 @@ """ assortativity(g) - assortativity(g,attributes) + assortativity(g, attributes) Return the [assortativity coefficient](https://en.wikipedia.org/wiki/Assortativity) of graph `g`, defined as the Pearson correlation of excess degree between @@ -48,9 +48,10 @@ function assortativity(g::AbstractGraph{T}) where T return assortativity_coefficient(g, sjk, sj, sk, sjs, sks, nue) end -function assortativity(g::AbstractGraph{T},attributes::Vector{N}) where {T,N<:Number} +function assortativity(g::AbstractGraph{T}, attributes::Vector{N}) where {T,N<:Number} + P = promote_type(Int64, N) # at least Int64 to reduce risk of overflow nue = ne(g) - sjk = sj = sk = sjs = sks = zero(N) + sjk = sj = sk = sjs = sks = zero(P) for d in edges(g) j = attributes[src(d)] k = attributes[dst(d)] diff --git a/test/community/assortativity.jl b/test/community/assortativity.jl index 05528b993..9847dabec 100644 --- a/test/community/assortativity.jl +++ b/test/community/assortativity.jl @@ -24,14 +24,14 @@ using Random, Statistics # Test definition of assortativity as Pearson correlation coefficient # between some scalar attributes characterising each vertex @testset "Small graphs with attributes" for n = 5:2:11 - g = grid([1,n]) - attributes = [(-1.)^v for v in vertices(g)] - @test @inferred assortativity(g,attributes) ≈ -1. + g = grid([1, n]) + attributes = [(-1.)^v for v in 1:nv(g)] + @test @inferred assortativity(g, attributes) ≈ -1. end @testset "Directed ($seed) with attributes" for seed in [1, 2, 3], (_n, _ne) in [(14, 18), (10, 22), (7, 16)] g = erdos_renyi(_n, _ne; is_directed=true, seed=seed) attributes = randn(_n) - assort = assortativity(g,attributes) + assort = assortativity(g, attributes) x = [attributes[src(d)] for d in edges(g)] y = [attributes[dst(d)] for d in edges(g)] @test @inferred assort ≈ cor(x, y) @@ -39,7 +39,7 @@ using Random, Statistics @testset "Undirected ($seed) with attributes" for seed in [1, 2, 3], (_n, _ne) in [(14, 18), (10, 22), (7, 16)] g = erdos_renyi(_n, _ne; is_directed=false, seed=seed) attributes = randn(_n) - assort = assortativity(g,attributes) + assort = assortativity(g, attributes) x = [attributes[src(d)] for d in edges(g)] y = [attributes[dst(d)] for d in edges(g)] @test @inferred assort ≈ cor([x;y], [y;x])