diff --git a/docs/source/graphs.rst b/docs/source/graphs.rst index d35f59e..28af54e 100644 --- a/docs/source/graphs.rst +++ b/docs/source/graphs.rst @@ -1,6 +1,9 @@ Graphs ======= +.. autoclass:: netin.Graph + :members: + .. toctree:: :maxdepth: 2 :caption: Contents: diff --git a/netin/generators/graph.py b/netin/generators/graph.py index 23acb62..1593e45 100644 --- a/netin/generators/graph.py +++ b/netin/generators/graph.py @@ -73,7 +73,6 @@ def __init__(self, n: int, f_m: float, seed: object = None): self.node_class_values = None # dictionary of node class values self.gen_start_time = None # start time of the generation self.gen_duration = None # duration of the generation - ############################################################ # Init ############################################################ @@ -921,6 +920,35 @@ def copy(self) -> Union[nx.Graph, nx.DiGraph]: g.n_M = self.n_M return g + def homophily_inference(self) -> float: + """ + Calculates the inferred homophily based on https://arxiv.org/abs/2401.13642 + + ##Experimental: For now only undirected and canonical + + Returns + ------- + h_infer: float + Inferred homophily + Raises + ------ + NotImplementedError + If the graph is directed + """ + e = self.calculate_edge_type_counts() + + if self.is_directed(): + raise NotImplementedError("This function only supports undirected graphs") + + else: + e_rs = e['mM'] + e['Mm'] + e_rr = 2 * e['MM'] + e_ss = 2 * e['mm'] + alpha = e_rs / np.sqrt(e_rr * e_ss) + + h_infer = 1 / (1 + alpha) + + return h_infer ###################################################################################################################### # Static functions diff --git a/netin/generators/tests/test_homophily_inference.py b/netin/generators/tests/test_homophily_inference.py new file mode 100644 index 0000000..25ee4d8 --- /dev/null +++ b/netin/generators/tests/test_homophily_inference.py @@ -0,0 +1,70 @@ +from netin import PA +from netin import PAH +from netin import PATC +from netin import PATCH +from netin.utils import constants as const +import netin +import numpy as np + + +class TestHomophilyInference(object): + + def test_patch_case_pah(self): + n = 1000 + k = 2 + f_m = 0.1 + h_MM = 0.7 + h_mm = 0.7 + # seed = 1234 + # g = netin.PAH(n=n, k=k, f_m=f_m, h_MM=h_MM, h_mm=h_mm, seed=seed) + g = netin.PAH(n=n, k=k, f_m=f_m, h_MM=h_MM, h_mm=h_mm) + g.generate() + inferred_homophily = g.homophily_inference() + + c1 = np.abs( inferred_homophily - h_MM ) < 0.1 + + assert c1, "Incorrect value of homophily inference" + + def test_patch_case_pah_neutral(self): + n = 1000 + k = 2 + f_m = 0.1 + h_MM = 0.5 # Changed from 0.7 to 0.5 + h_mm = 0.5 # Changed from 0.7 to 0.5 + g = netin.PAH(n=n, k=k, f_m=f_m, h_MM=h_MM, h_mm=h_mm) + g.generate() + inferred_homophily = g.homophily_inference() + + c1 = np.abs(inferred_homophily - h_MM) < 0.1 + + assert c1, "Incorrect value of homophily inference" + + + def test_patch_case_pa(self): + n = 2000 # Increased network size + k = 4 # Increased average degree + f_m = 0.15 + # h_MM = 0.8 + # h_mm = 0.8 + g = netin.PA(n=n, k=k, f_m=f_m) + g.generate() + inferred_homophily = g.homophily_inference() + + c1 = np.abs(inferred_homophily - 0.5) < 0.1 + + assert c1, "Incorrect value of homophily inference" + + + def test_patch_case_patch_hetero(self): + n = 2000 # Increased network size + k = 4 # Increased average degree + f_m = 0.15 + h_MM = 0.3 + h_mm = 0.3 + g = netin.PATCH(n=n, k=k, f_m=f_m, h_MM=h_MM, h_mm=h_mm, tc = 0.0) + g.generate() + inferred_homophily = g.homophily_inference() + + c1 = np.abs(inferred_homophily - h_mm) < 0.1 + + assert c1, "Incorrect value of homophily inference"