-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added functions for computing the dynamical, top-2, top-bottom, and uniform degree assortativity.
- Loading branch information
Showing
12 changed files
with
237 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
black==21.5b1 | ||
black==22.3.0 | ||
pre-commit>=2.12 | ||
isort==5.10.1 | ||
pylint>=2.10 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import numpy as np | ||
import pytest | ||
|
||
import xgi | ||
from xgi.algorithms.assortativity import choose_degrees | ||
from xgi.exception import XGIError | ||
|
||
|
||
def test_dynamical_assortativity(edgelist1, edgelist6): | ||
|
||
H = xgi.Hypergraph() | ||
with pytest.raises(XGIError): | ||
xgi.dynamical_assortativity(H) | ||
|
||
H.add_nodes_from([0, 1, 2]) | ||
|
||
with pytest.raises(XGIError): | ||
xgi.dynamical_assortativity(H) | ||
|
||
with pytest.raises(XGIError): | ||
H1 = xgi.Hypergraph(edgelist1) | ||
xgi.dynamical_assortativity(H1) | ||
|
||
H1 = xgi.Hypergraph(edgelist6) | ||
|
||
assert abs(xgi.dynamical_assortativity(H1) - -0.0526) < 1e-3 | ||
|
||
|
||
def test_degree_assortativity(edgelist1, edgelist6): | ||
H1 = xgi.Hypergraph(edgelist1) | ||
assert -1 <= xgi.degree_assortativity(H1, kind="uniform") <= 1 | ||
assert -1 <= xgi.degree_assortativity(H1, kind="top-2") <= 1 | ||
assert -1 <= xgi.degree_assortativity(H1, kind="top-bottom") <= 1 | ||
|
||
H2 = xgi.Hypergraph(edgelist6) | ||
assert -1 <= xgi.degree_assortativity(H2, kind="uniform") <= 1 | ||
assert -1 <= xgi.degree_assortativity(H2, kind="top-2") <= 1 | ||
assert -1 <= xgi.degree_assortativity(H2, kind="top-bottom") <= 1 | ||
|
||
|
||
def test_choose_degrees(edgelist1, edgelist6): | ||
H1 = xgi.Hypergraph(edgelist1) | ||
k = H1.degree() | ||
|
||
with pytest.raises(XGIError): | ||
e = H1.edges.members(1) | ||
choose_degrees(e, k) | ||
|
||
e = H1.edges.members(0) | ||
assert np.all(np.array(choose_degrees(e, k)) == 1) | ||
|
||
e = H1.edges.members(3) | ||
assert set(choose_degrees(e, k, kind="top-2")) == {1, 2} | ||
assert set(choose_degrees(e, k, kind="top-bottom")) == {1, 2} | ||
|
||
H2 = xgi.Hypergraph(edgelist6) | ||
e = H2.edges.members(2) | ||
k = H2.degree() | ||
assert set(choose_degrees(e, k, kind="top-2")) == {2, 3} | ||
assert set(choose_degrees(e, k, kind="top-bottom")) == {1, 3} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import pytest | ||
import pandas as pd | ||
import pytest | ||
|
||
import xgi | ||
from xgi.exception import IDNotFound | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import pytest | ||
import pandas as pd | ||
import pytest | ||
|
||
import xgi | ||
from xgi.exception import IDNotFound | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
from . import connected | ||
from . import assortativity, connected | ||
from .assortativity import * | ||
from .connected import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import random | ||
from itertools import combinations | ||
|
||
import numpy as np | ||
|
||
import xgi | ||
from xgi.exception import XGIError | ||
|
||
__all__ = ["dynamical_assortativity", "degree_assortativity"] | ||
|
||
|
||
def dynamical_assortativity(H): | ||
"""Computes the dynamical assortativity of a uniform hypergraph. | ||
Parameters | ||
---------- | ||
H : xgi.Hypergraph | ||
Hypergraph of interest | ||
Returns | ||
------- | ||
float | ||
The dynamical assortativity | ||
Raises | ||
------ | ||
XGIError | ||
If the hypergraph is not uniform, or if there are no nodes | ||
or no edges | ||
References | ||
---------- | ||
Nicholas Landry and Juan G. Restrepo, | ||
Hypergraph assortativity: A dynamical systems perspective, | ||
Chaos 2022. | ||
DOI: 10.1063/5.0086905 | ||
""" | ||
if not xgi.is_uniform(H): | ||
raise XGIError("Hypergraph must be uniform!") | ||
|
||
if H.num_nodes == 0 or H.num_edges == 0: | ||
raise XGIError("Hypergraph must contain nodes and edges!") | ||
|
||
degs = H.degree() | ||
k1 = np.mean(list(degs.values())) | ||
k2 = np.mean(np.power(list(degs.values()), 2)) | ||
kk1 = np.mean( | ||
[ | ||
degs[n1] * degs[n2] | ||
for e in H.edges | ||
for n1, n2 in combinations(H.edges.members(e), 2) | ||
] | ||
) | ||
|
||
return kk1 * k1**2 / k2**2 - 1 | ||
|
||
|
||
def degree_assortativity(H, kind="uniform", exact=False, num_samples=1000): | ||
"""Computes the degree assortativity of a hypergraph | ||
Parameters | ||
---------- | ||
H : Hypergraph | ||
The hypergraph of interest | ||
kind : str, default: "uniform" | ||
the type of degree assortativity. valid choices are | ||
"uniform", "top-2", and "top-bottom". | ||
exact : bool, default: False | ||
whether to compute over all edges or | ||
sample randomly from the set of edges | ||
num_samples : int, default: 1000 | ||
if not exact, specify the number of samples for the computation. | ||
Returns | ||
------- | ||
float | ||
the degree assortativity | ||
References | ||
---------- | ||
Phil Chodrow, | ||
Configuration models of random hypergraphs, | ||
Journal of Complex Networks 2020. | ||
DOI: 10.1093/comnet/cnaa018 | ||
""" | ||
degs = H.degree() | ||
if exact: | ||
k1k2 = [ | ||
choose_degrees(H.edges.members(e), degs, kind) | ||
for e in H.edges | ||
if len(H.edges.members(e)) > 1 | ||
] | ||
else: | ||
edges = [e for e in H.edges if len(H.edges.members(e)) > 1] | ||
k1k2 = [ | ||
choose_degrees(H.edges.members(random.choice(edges)), degs, kind) | ||
for _ in range(num_samples) | ||
] | ||
return np.corrcoef(np.array(k1k2).T)[0, 1] | ||
|
||
|
||
def choose_degrees(e, k, kind="uniform"): | ||
"""Choose the degrees of two nodes in a hyperedge. | ||
Parameters | ||
---------- | ||
e : iterable | ||
the members in a hyperedge | ||
k : dict | ||
the degrees where keys are node IDs and values are degrees | ||
kind : str, default: "uniform" | ||
the type of degree assortativity, options are | ||
"uniform", "top-2", and "top-bottom". | ||
Returns | ||
------- | ||
tuple | ||
two degrees selected from the edge | ||
Raises | ||
------ | ||
XGIError | ||
if invalid assortativity function chosen | ||
References | ||
---------- | ||
Phil Chodrow, | ||
Configuration models of random hypergraphs, | ||
Journal of Complex Networks 2020. | ||
DOI: 10.1093/comnet/cnaa018 | ||
""" | ||
if len(e) > 1: | ||
if kind == "uniform": | ||
i = np.random.randint(len(e)) | ||
j = i | ||
while i == j: | ||
j = np.random.randint(len(e)) | ||
return (k[e[i]], k[e[j]]) | ||
|
||
elif kind == "top-2": | ||
degs = sorted([k[i] for i in e])[-2:] | ||
random.shuffle(degs) | ||
return degs | ||
|
||
elif kind == "top-bottom": | ||
# this selects the largest and smallest degrees in one line | ||
degs = sorted([k[i] for i in e])[:: len(e) - 1] | ||
random.shuffle(degs) | ||
return degs | ||
|
||
else: | ||
raise XGIError("Invalid choice function!") | ||
else: | ||
raise XGIError("Edge must have more than one member!") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters