Ejemplo n.º 1
0
def from_networkx(graph: Any) -> Network:
    n = Network(directed=graph.is_directed(), multiedges=graph.is_multigraph())
    for v in graph.nodes:
        n.add_node(v, **graph.nodes[v])
    for e in graph.edges:
        n.add_edge(e[0], e[1], **graph.edges[e])
    return n
Ejemplo n.º 2
0
def lattice_network(start: Optional[int]=0, stop: Optional[int]=10, dims: Optional[int]=2) -> Network:
    """
    Generates a n-dimensional lattice network with coordinates in each dimension 
    ranging from start (inclusive) to stop (exclusive)
    """
    network = Network(directed=False)

    for pos in _multi_dim_range(start, stop, dims):
        network.add_node(Node("".join(str(i)+'-' for i in pos).strip('-'), pos=np.array(pos)))
    
    for v in network.nodes:
        for w in network.nodes:
            if np.sum(np.abs(v['pos']-w['pos']))==1 and (v.uid, w.uid) not in network.edges:
                network.add_edge(v, w)
    return network
Ejemplo n.º 3
0
def train_test_split(network: Network,
                     test_size: Optional[float] = 0.25,
                     train_size: Optional[float] = None,
                     split: Optional[str] = 'node') -> tuple(Network, Network):
    """Returns a train/test split of a network object. This method is implemented for instances of Network and TemporalNetwork. The train/test split is non-destructive and based on object references, i.e. the function returns new Network instances that contain references to the same node/edge objects. The original network is not affected.

    Parameters
    ----------

    network: Union[Network, TemporalNetwork]

        The network or temporal network for which the train/test split shall be performed.

    test_size: Optional[float] = 0.25

        Fraction of the network to include in the test network

    train_size: Optional[float] = 0.25

        Fraction of the network to include in the training network

    split: Optional['str'] = 'node'

        Specifies how the train/test split shall be performed. For 'node' a random subset of nodes is selected, while for 'edge' a random subset of edges is selected.

    Returns
    -------

    Tuple (n1, n2) where n1 is the training network and n2 is the test network

    Examples
    --------

    >>> n = pp.Network() 
    >>> n.add_edge('a', 'b')
    >>> n.add_edge('b', 'c')
    >>> n.add_edge('c', 'd')
    >>> n.add_edge('d', 'a')
    >>> train, test = train_test_split(n, test_size=0.25)
    >>> print(train)
    >>> print(test)
    Network with one node
    Network with three nodes

    """
    test_network = Network(directed=network.directed,
                           multiedges=network.multiedges,
                           uid=network.uid + '_test')
    train_network = Network(directed=network.directed,
                            multiedges=network.multiedges,
                            uid=network.uid + '_train')

    if train_size == None:
        ts = test_size
    else:
        ts = 1.0 - train_size

    if split == 'node':
        test_nodes = choice([v.uid for v in network.nodes],
                            size=int(ts * network.number_of_nodes()),
                            replace=False)
        for v in test_nodes:
            test_network.add_node(network.nodes[v])
        train_nodes = [
            v.uid for v in network.nodes
            if v.uid not in test_network.nodes.uids
        ]
        for v in train_nodes:
            train_network.add_node(network.nodes[v])
        for e in network.edges:
            if e.v.uid in test_network.nodes.uids and e.w.uid in test_network.nodes.uids:
                test_network.add_edge(e)
            if e.v.uid in train_network.nodes.uids and e.w.uid in train_network.nodes.uids:
                train_network.add_edge(e)

    elif split == 'edge':
        for v in network.nodes:
            test_network.add_node(v)
            train_network.add_node(v)
        test_edges = choice([e.uid for e in network.edges],
                            size=int(ts * network.number_of_edges()),
                            replace=False)
        for e in test_edges:
            test_network.add_edge(network.edges[e])
        train_edges = [
            e.uid for e in network.edges
            if e.uid not in test_network.edges.uids
        ]
        for e in train_edges:
            train_network.add_edge(network.edges[e])
    else:
        raise NotImplementedError(
            'Unsupported split method "{0}" for instance of type Network'.
            format(split))

    return train_network, test_network
Ejemplo n.º 4
0
def ER_nm(n: int, m: int,
          directed: bool = False,
          loops: bool = False,
          multiedges: bool = False,
          node_uids: Optional[list] = None) -> Union[Network, None]:
    """(n, m) Erdös-Renyi model.

    Generates a random graph with a fixed number of n nodes and m edges based on
    the Erdös-Renyi model.

    Parameters
    ----------
    n : int

        The number of nodes in the generated network

    m : int

        The number of randomly generated edges in the network

    directed : bool

        Whether a directed network should be generated

    loops : bool

        Whether or not the generated network may contain
        loops.

    multi_edge : bool

        Whether or not the same edge can be added multiple times

    node_uids : list

        Optional list of node uids that will be used.

    Examples
    --------
    Generate random undirected network with 10 nodes and 25 edges

    >>> import pathpy as pp
    >>> random_graph = pp.algorithms.random_graphs.ER_nm(n=10, m=25)
    >>> print(random_graph.summary())
    ...

    """
    # Check parameter sanity
    M = max_edges(n, directed=directed, loops=loops, multiedges=multiedges)
    if m > M:
        LOG.error(
            'Given network type with n nodes can have at most {} edges.'.format(M))
        return None

    network = Network(directed=directed)

    if node_uids is None or len(node_uids) != n:
        LOG.info('No valid node uids given, generating numeric node uids')
        node_uids = []
        for i in range(n):
            node_uids.append(str(i))

    for i in range(n):
        network.add_node(node_uids[i])

    edges = 0
    while edges < m:
        v, w = np.random.choice(node_uids, size=2, replace=loops)
        if multiedges or network.nodes[w] not in network.successors[v]:
            network.add_edge(v, w)
            edges += 1
    return network
Ejemplo n.º 5
0
def Molloy_Reed(degrees: Union[np.array, Dict[int, float]], multiedge: bool = False, relax: bool=False, node_uids: Optional[list] = None) -> Optional[Network]:
    """Generate Molloy-Reed graph.

    Generates a random undirected network with given degree sequence based on
    the Molloy-Reed algorithm.

    .. note::

        The condition proposed by Erdös and Gallai (1967) is used to test
        whether the degree sequence is graphic, i.e. whether a network with the
        given degree sequence exists.

    Parameters
    ----------
    degrees : list

        List of integer node degrees. The number of nodes of the generated
        network corresponds to len(degrees).

    relax : bool

        If True, we conceptually allow self-loops and multi-edges, but do not
        add them to the network This implies that the generated network may not
        have exactly sum(degrees)/2 links, but it ensures that the algorithm
        always finishes.

    node_uids : list

        Optional list of node uids that will be used.

    Examples
    --------
    Generate random undirected network with given degree sequence

    >>> import pathpy as pp
    >>> random_network = pp.algorithms.random_graphs.Molloy_Reed([1,0])
    >>> print(random_network.summary())
    ...

    Network generation fails for non-graphic sequences

    >>> import pathpy as pp
    >>> random_network = pp.algorithms.random_graphs.Molloy_Reed([1,0])
    >>> print(random_network)
    None

    """

    # assume that we are given a graphical degree sequence
    if not is_graphic_Erdos_Gallai(degrees):
        return None

    # create empty network with n nodes
    n = len(degrees)
    network = Network(directed=False, multiedges=multiedge)

    if node_uids is None or len(node_uids) != n:
        LOG.info('No valid node uids given, generating numeric node uids')
        node_uids = []
        for i in range(n):
            node_uids.append(str(i))
    
    for i in range(n):
        network.add_node(node_uids[i])

    # generate link stubs based on degree sequence
    stubs = []
    for i in range(n):
        for _ in range(int(degrees[i])):
            stubs.append(str(node_uids[i]))

    # connect randomly chosen pairs of link stubs
    while(len(stubs) > 0):
        v, w = np.random.choice(stubs, 2, replace=False)

        if v == w or (multiedge == False and relax == False and network.nodes[w] in network.successors[v]):
            # remove random edge and add stubs
            if network.number_of_edges()>0:
                edge = random.choice(list(network.edges))
                stubs.append(edge.v.uid)
                stubs.append(edge.w.uid)
                network.remove_edge(edge)
        else:
            if not network.nodes[w] in network.successors[v]:
                network.add_edge(v, w)
            stubs.remove(v)
            stubs.remove(w)            
            

    return network
Ejemplo n.º 6
0
def Watts_Strogatz(n: int, s: int, p: float = 0.0, loops: bool = False,
                   node_uids: Optional[list] = None) -> Network:
    """Undirected Watts-Strogatz lattice network

    Generates an undirected Watts-Strogatz lattice network with lattice
    dimensionality one.

    Parameters
    ----------
    n : int

        The number of nodes in the generated network

    s : float

        The number of nearest neighbors that will be connected
        in the ring lattice

    p : float

        The rewiring probability

    node_uids : list

        Optional list of node uids that will be used.

    Examples
    --------
    Generate a Watts-Strogatz network with 100 nodes

    >>> import pathpy as pp
    >>> small_world = pp.algorithms.random_graphs.Watts_Strogatz(n=100, s=2, p=0.1)
    >>> print(small_world.summary())
    ...

    """
    network = Network(directed=False)
    if node_uids is None or len(node_uids) != n:
        LOG.info('No valid node uids given, generating numeric node uids')
        node_uids = []
        for i in range(n):
            network.add_node(Node(str(i)))
            node_uids.append(str(i))
    else:
        for i in range(n):
            network.add_node(node_uids[i])

    # construct a ring lattice (dimension 1)
    for i in range(n):
        if loops:
            x = 0
            y = s
        else:
            x = 1
            y = s+1
        for j in range(x, y):
            v = network.nodes[node_uids[i]]
            w = network.nodes[node_uids[(i+j) % n]]
            if (v.uid, w.uid) not in network.edges:
                network.add_edge(v, w)

    if p == 0:
        # nothing to do here
        return network

    # Rewire each link with probability p
    for edge in tqdm(list(network.edges.values()), 'generating WS network'):
        if np.random.rand() < p:
            # Delete original link and remember source node
            v = edge.v.uid
            network.remove_edge(edge)

            # Find new random tgt, which is not yet connected to src
            new_target = None

            # This loop repeatedly chooses a random target until we find
            # a target not yet connected to src. Note that this could potentially
            # result in an infinite loop depending on parameters.
            while new_target is None:
                x = node_uids[np.random.randint(n)]
                if (x != v or loops) and (v, x) not in network.edges:
                    new_target = x
            network.add_edge(v, new_target)
    return network
Ejemplo n.º 7
0
def ER_np(n: int, p: float, directed: bool = False, loops: bool = False,
          node_uids: Optional[list] = None) -> Network:
    """(n, p) Erdös-Renyi model

    Generates a random graph with a fixed number of n nodes and edge probability
    p based on the Erdös-Renyi model.

    Parameters
    ----------
    n : int

        The number of nodes in the generated network

    p : float

        The probability with which an edge will be created
        between each pair of nodes

    directed : bool

        Whether a directed network should be generated

    loops : bool

        Whether or not the generated network may contain
        loops.

    node_uids : list

        Optional list of node uids that will be used.

    Examples
    --------
    Generate random undirected network with 10 nodes

    >>> import pathpy as pp
    >>> random_graph = pp.algorithms.random_graphs.ER_np(n=10, p=0.03)
    >>> print(random_graph.summary())
    ...

    """
    network = Network(directed=directed)

    if node_uids is None or len(node_uids) != n:
        LOG.info('No valid node uids given, generating numeric node uids')
        node_uids = []
        for i in range(n):
            node_uids.append(str(i))

    for i in range(n):
        network.add_node(node_uids[i])

    for s in tqdm(range(n), 'generating G(n,p) network'):
        if directed:
            x = n
        else:
            x = s+1
        for t in range(x):
            if t == s and not loops:
                continue
            if np.random.random_sample() < p:
                network.add_edge(node_uids[s], node_uids[t])
    return network