Source code for littleballoffur.exploration_sampling.communitystructureexpansionsampler

import random
import numpy as np
import networkx as nx
import networkit as nk
from typing import Union
from littleballoffur.sampler import Sampler

NKGraph = type(nk.graph.Graph())
NXGraph = nx.classes.graph.Graph


[docs]class CommunityStructureExpansionSampler(Sampler): r"""An implementation of community structure preserving expansion sampling. Starting with a random source node the procedure chooses a node which is connected to the already sampled nodes. This node is the one with the largest community expansion score. The extracted subgraph is always connected. `"For details about the algorithm see this paper." <http://arun.maiya.net/papers/maiya_etal-sampcomm.pdf>`_ Args: number_of_nodes (int): Number of sampled nodes. Default is 100. seed (int): Random seed. Default is 42. """ def __init__(self, number_of_nodes: int = 100, seed: int = 42): self.number_of_nodes = number_of_nodes self.seed = seed self._set_seed() def _create_node_set(self, graph, start_node): """ Choosing a seed node. """ if start_node is not None: if start_node >= 0 and start_node < self.backend.get_number_of_nodes(graph): self._sampled_nodes = set([start_node]) else: raise ValueError("Starting node index is out of range.") else: self._sampled_nodes = set( [random.choice(range(self.backend.get_number_of_nodes(graph)))] ) def _make_target_set(self, graph): """ Creating a new reshuffled frontier list of nodes. """ self._targets = [ neighbor for node in self._sampled_nodes for neighbor in self.backend.get_neighbors(graph, node) ] self._targets = list(set(self._targets).difference(self._sampled_nodes)) random.shuffle(self._targets) def _choose_new_node(self, graph): """ Choosing the node with the largest expansion. The randomization of the list breaks ties randomly. """ largest_expansion = 0 for node in self._targets: expansion = len( set(self.backend.get_neighbors(graph, node)).difference( self._sampled_nodes ) ) if expansion >= largest_expansion: new_node = node self._sampled_nodes.add(new_node)
[docs] def sample( self, graph: Union[NXGraph, NKGraph], start_node: int = None ) -> Union[NXGraph, NKGraph]: """ Sampling nodes iteratively with a community structure expansion sampler. Arg types: * **graph** *(NetworkX or NetworKit graph)* - The graph to be sampled from. * **start_node** *(int, optional)* - The start node. Return types: * **new_graph** *(NetworkX or NetworKit graph)* - The graph of sampled nodes. """ self._deploy_backend(graph) self._check_number_of_nodes(graph) self._create_node_set(graph, start_node) while len(self._sampled_nodes) < self.number_of_nodes: self._make_target_set(graph) self._choose_new_node(graph) new_graph = self.backend.get_subgraph(graph, self._sampled_nodes) return new_graph