Coverage for src/abcd_graph/graph/core/abcd_objects/community.py: 98%
64 statements
« prev ^ index » next coverage.py v7.5.3, created at 2024-11-17 23:31 +0100
« prev ^ index » next coverage.py v7.5.3, created at 2024-11-17 23:31 +0100
1__all__ = ["Community", "BackgroundGraph"]
3from abcd_graph.graph.core.abcd_objects.abstract import AbstractCommunity
4from abcd_graph.graph.core.abcd_objects.edge import Edge
5from abcd_graph.graph.core.abcd_objects.utils import (
6 build_recycle_list,
7 choose_other_edge,
8 rewire_edge,
9)
10from abcd_graph.graph.core.constants import BACKGROUND_GRAPH_ID
13class Community(AbstractCommunity):
14 def __init__(
15 self,
16 edges: list[Edge],
17 vertices: list[int],
18 deg_b: dict[int, int],
19 deg_c: dict[int, int],
20 community_id: int,
21 ) -> None:
22 super().__init__(edges, community_id)
24 self._vertices = vertices
25 self._deg_b = deg_b
26 self._deg_c = deg_c
28 def __eq__(self, other: object) -> bool:
29 if not isinstance(other, AbstractCommunity):
30 return False
31 return self.community_id == other.community_id
33 def __hash__(self) -> int:
34 return hash(self.community_id)
36 @property
37 def vertices(self) -> list[int]:
38 return self._vertices
40 @property
41 def average_degree(self) -> float:
42 return sum(self.degree_sequence.values()) / len(self.vertices)
44 @property
45 def degree_sequence(self) -> dict[int, int]:
46 res = {}
47 for vert in self.vertices:
48 res[vert] = self._deg_c[vert] + self._deg_b[vert]
49 return res
51 @property
52 def local_deg_c(self) -> dict[int, int]:
53 return {k: v for k, v in self._deg_c.items() if k in self.vertices}
55 @property
56 def empirical_xi(self) -> float:
57 return sum(self._deg_b[i] for i in self.vertices) / (
58 sum(self._deg_b[i] for i in self.vertices) + sum(self.local_deg_c.values())
59 )
61 def push_to_background(self, edges: list[Edge], deg_b: dict[int, int]) -> None:
62 for edge in edges:
63 if edge.is_loop:
64 for i in range(self.adj_dict[edge]):
65 self.adj_dict[edge] -= 1
66 if self.adj_dict[edge] == 0:
67 del self.adj_dict[edge]
69 self._update_degree_sequences(edge, deg_b)
70 else:
71 for i in range(self.adj_dict[edge] - 1):
72 self.adj_dict[edge] -= 1
74 self._update_degree_sequences(edge, deg_b)
76 def _update_degree_sequences(self, edge: Edge, deg_b: dict[int, int]) -> None:
77 deg_b[edge.v1] += 1
78 deg_b[edge.v2] += 1
79 self._deg_c[edge.v1] -= 1
80 self._deg_c[edge.v2] -= 1
82 def rewire_community(self) -> None:
83 while len(self._bad_edges) > 0:
84 for edge in self._bad_edges:
85 other_edge = choose_other_edge(self.adj_dict, edge)
86 rewire_edge(self.adj_dict, edge, other_edge)
88 new_bad_edges = build_recycle_list(self.adj_dict)
89 if len(new_bad_edges) >= len(self._bad_edges):
90 self.push_to_background(new_bad_edges, self._deg_b)
91 return
92 else:
93 self._bad_edges = new_bad_edges
96class BackgroundGraph(AbstractCommunity):
97 def __init__(self, edges: list[Edge]) -> None:
98 super().__init__(edges, community_id=-BACKGROUND_GRAPH_ID)