""" PHASE 6a: Synthetic social graph construction. We don't have access to real social media sharing data (no Twitter/WhatsApp API access, and that data is not publicly available for a hackathon anyway). Instead we generate a synthetic network using the Barabasi-Albert model, which produces the same "hub-and-spoke" structure real social networks have (a few highly-connected accounts, many loosely-connected ones) -- this is a standard, well-established technique in network science for studying spread dynamics without needing real platform data. This graph structure is what the GNN reasons over. """ import networkx as nx import numpy as np def generate_social_graph(num_nodes: int = 150, m: int = 3, seed: int | None = None) -> nx.Graph: """ Generates a synthetic social network with realistic hub structure. num_nodes: total simulated accounts in the network m: number of edges each new node attaches with (controls hub concentration) """ return nx.barabasi_albert_graph(num_nodes, m, seed=seed) def graph_node_features(G: nx.Graph, seed: int | None = None) -> np.ndarray: """ Builds a [num_nodes, 2] feature matrix: feature 0: normalized degree centrality (how "hub-like" this account is) feature 1: random engagement/susceptibility score (how likely this account is to reshare content it sees -- stands in for real engagement-rate data we don't have access to) """ rng = np.random.default_rng(seed) degrees = dict(G.degree()) max_deg = max(degrees.values()) or 1 features = [] for node in G.nodes(): deg_norm = degrees[node] / max_deg susceptibility = rng.uniform(0.2, 0.9) features.append([deg_norm, susceptibility]) return np.array(features, dtype=np.float32) def top_hub_nodes(G: nx.Graph, k: int = 3) -> list[int]: """Returns the k highest-degree nodes -- the accounts most responsible for spread.""" degrees = dict(G.degree()) return sorted(degrees, key=degrees.get, reverse=True)[:k] if __name__ == "__main__": # Quick manual test -- run: python gnn/graph_utils.py G = generate_social_graph(seed=42) feats = graph_node_features(G, seed=42) hubs = top_hub_nodes(G, k=3) print(f"Graph: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges") print(f"Node feature matrix shape: {feats.shape}") print(f"Top 3 hub nodes (by degree): {hubs}") print(f"Degree of top hub: {G.degree(hubs[0])}")