parameters: (G_coupling,
                       slice_attr='slice',
                       vertex_id_attr='id',
                       edge_type_attr='type',
                       weight_attr='weight')
return_statement: return G_layers, G_interslice, G
docstring: Convert a coupling graph of slices to layers of graphs.
  
    This function converts a graph of slices to layers so that they can be used
    with this package. This function assumes that the slices are represented by
    nodes in ``G_coupling``, and stored in the attribute ``slice_attr``. In other
    words, ``G_coupling.vs[slice_attr]`` should contain :class:`ig.Graph` s . The
    slices will be converted to layers, and nodes in different slices will be
    coupled if the two slices are connected in ``G_coupling``. Nodes in two
    connected slices are identified on the basis of the ``vertex_id_attr``, i.e.
    if two nodes in two connected slices have an identical value of the
    ``vertex_id_attr`` they will be coupled. The ``vertex_id_attr`` should hence
    be unique in each slice.  The weight of the coupling is determined by the
    weight of this link in ``G_coupling``, as determined by the ``weight_attr``.
  
    Parameters
    ----------
    G_coupling : :class:`ig.Graph`
      The graph connecting the different slices.
  
    slice_attr : string
      The vertex attribute which contains the slices.
  
    vertex_id_attr : string
      The vertex attribute which is used to identify whether two nodes in two
      slices represent the same node, and hence, should be coupled.
  
    edge_type_attr : string
      The edge attribute to use for indicating the type of link (``interslice``
      or ``intraslice``).
  
    weight_attr : string
      The edge attribute used to indicate the (coupling) weight.
  
    Returns
    -------
    G_layers : list of :class:`ig.Graph`
      A list of slices converted to layers.
  
    G_interslice : :class:`ig.Graph`
      The interslice coupling layer.
  
    G : :class:`ig.Graph`
      The complete graph containing all layers and interslice couplings.
  
    Notes
    -----
    The distinction between slices and layers is not easy to grasp. Slices in
    this context refer to graphs that somehow represents different aspects of a
    network. The simplest example is probably slices that represents time: there
    are different snapshots network across time, and each snapshot is considered
    a slice. Some nodes may drop out of the network over time, while others enter
    the network. Edges may change over time, or the weight of the links may
    change over time. This is just the simplest example of a slice, and there may
    be different, more complex possibilities. Below an example with three time
    slices:
  
    .. image:: figures/slices.png
  
    Now in order to optimise partitions across these different slices, we
    represent them slightly differently, namely as layers. The idea of layers is
    that all graphs always are defined on the same set of nodes, and that only
    the links differ for different layers. We thus create new nodes as
    combinations of original nodes and slices. For example, if node 1 existed in
    both slice 1 and in slice 2, we will thus create two nodes to build the
    layers: a node 1-1 and a node 1-2. Additionally, if the slices are connected
    in the slice graph, the two nodes would also be connected, so there would be
    a linke between node 1-1 and 1-2. Different slices will then correspond to
    different layers: each layer only contains the link for that particular
    slice. In addition, for methods such as :class:`CPMVertexPartition`,
    so-called ``node_sizes`` are required, and for them to properly function,
    they should be set to 0 (which is handled appropriately in this function, and
    stored in the vertex attribute ``node_size``). We thus obtain equally many
    layers as we have slices, and we need one more layer for representing the
    interslice couplings.  For the example provided above, we thus obtain the
    following:
  
    .. image:: figures/layers_separate.png
  
    The idea of doing community detection with slices is further detailed in [1].
  
    References
    ----------
    .. [1] Mucha, P. J., Richardson, T., Macon, K., Porter, M. A., & Onnela,
           J.-P. (2010).  Community structure in time-dependent, multiscale, and
           multiplex networks. Science, 328(5980), 876-8.
           `10.1126/science.1184819 <http://doi.org/10.1126/science.1184819>`_
    See Also
    --------
    :func:`find_partition_temporal`
  
    :func:`time_slices_to_layers`
docstring_summary: Convert a coupling graph of slices to layers of graphs.
docstring_tokens: Convert a coupling graph of slices to layers of graphs .
function: def slices_to_layers(G_coupling,
                       slice_attr='slice',
                       vertex_id_attr='id',
                       edge_type_attr='type',
                       weight_attr='weight'):
    """ Convert a coupling graph of slices to layers of graphs.
  
    This function converts a graph of slices to layers so that they can be used
    with this package. This function assumes that the slices are represented by
    nodes in ``G_coupling``, and stored in the attribute ``slice_attr``. In other
    words, ``G_coupling.vs[slice_attr]`` should contain :class:`ig.Graph` s . The
    slices will be converted to layers, and nodes in different slices will be
    coupled if the two slices are connected in ``G_coupling``. Nodes in two
    connected slices are identified on the basis of the ``vertex_id_attr``, i.e.
    if two nodes in two connected slices have an identical value of the
    ``vertex_id_attr`` they will be coupled. The ``vertex_id_attr`` should hence
    be unique in each slice.  The weight of the coupling is determined by the
    weight of this link in ``G_coupling``, as determined by the ``weight_attr``.
  
    Parameters
    ----------
    G_coupling : :class:`ig.Graph`
      The graph connecting the different slices.
  
    slice_attr : string
      The vertex attribute which contains the slices.
  
    vertex_id_attr : string
      The vertex attribute which is used to identify whether two nodes in two
      slices represent the same node, and hence, should be coupled.
  
    edge_type_attr : string
      The edge attribute to use for indicating the type of link (``interslice``
      or ``intraslice``).
  
    weight_attr : string
      The edge attribute used to indicate the (coupling) weight.
  
    Returns
    -------
    G_layers : list of :class:`ig.Graph`
      A list of slices converted to layers.
  
    G_interslice : :class:`ig.Graph`
      The interslice coupling layer.
  
    G : :class:`ig.Graph`
      The complete graph containing all layers and interslice couplings.
  
    Notes
    -----
    The distinction between slices and layers is not easy to grasp. Slices in
    this context refer to graphs that somehow represents different aspects of a
    network. The simplest example is probably slices that represents time: there
    are different snapshots network across time, and each snapshot is considered
    a slice. Some nodes may drop out of the network over time, while others enter
    the network. Edges may change over time, or the weight of the links may
    change over time. This is just the simplest example of a slice, and there may
    be different, more complex possibilities. Below an example with three time
    slices:
  
    .. image:: figures/slices.png
  
    Now in order to optimise partitions across these different slices, we
    represent them slightly differently, namely as layers. The idea of layers is
    that all graphs always are defined on the same set of nodes, and that only
    the links differ for different layers. We thus create new nodes as
    combinations of original nodes and slices. For example, if node 1 existed in
    both slice 1 and in slice 2, we will thus create two nodes to build the
    layers: a node 1-1 and a node 1-2. Additionally, if the slices are connected
    in the slice graph, the two nodes would also be connected, so there would be
    a linke between node 1-1 and 1-2. Different slices will then correspond to
    different layers: each layer only contains the link for that particular
    slice. In addition, for methods such as :class:`CPMVertexPartition`,
    so-called ``node_sizes`` are required, and for them to properly function,
    they should be set to 0 (which is handled appropriately in this function, and
    stored in the vertex attribute ``node_size``). We thus obtain equally many
    layers as we have slices, and we need one more layer for representing the
    interslice couplings.  For the example provided above, we thus obtain the
    following:
  
    .. image:: figures/layers_separate.png
  
    The idea of doing community detection with slices is further detailed in [1].
  
    References
    ----------
    .. [1] Mucha, P. J., Richardson, T., Macon, K., Porter, M. A., & Onnela,
           J.-P. (2010).  Community structure in time-dependent, multiscale, and
           multiplex networks. Science, 328(5980), 876-8.
           `10.1126/science.1184819 <http://doi.org/10.1126/science.1184819>`_
    See Also
    --------
    :func:`find_partition_temporal`
  
    :func:`time_slices_to_layers`
  
    """
    if not slice_attr in G_coupling.vertex_attributes():
      raise ValueError("Could not find the vertex attribute {0} in the coupling graph.".format(slice_attr))
  
    if not weight_attr in G_coupling.edge_attributes():
      raise ValueError("Could not find the edge attribute {0} in the coupling graph.".format(weight_attr))
  
    # Create disjoint union of the time graphs
    for v_slice in G_coupling.vs:
      H = v_slice[slice_attr]
      H.vs[slice_attr] = v_slice.index
      if not vertex_id_attr in H.vertex_attributes():
        raise ValueError("Could not find the vertex attribute {0} to identify nodes in different slices.".format(vertex_id_attr ))
      if not weight_attr in H.edge_attributes():
        H.es[weight_attr] = 1
  
    G = disjoint_union_attrs(G_coupling.vs[slice_attr])
    G.es[edge_type_attr] = 'intraslice'
  
    for v_slice in G_coupling.vs:
      for u_slice in v_slice.neighbors(mode=_ig.OUT):
        if v_slice.index < u_slice.index or G_coupling.is_directed():
          nodes_v = G.vs.select(lambda v: v[slice_attr]==v_slice.index)[vertex_id_attr]
          if len(set(nodes_v)) != len(nodes_v):
            err = '\n'.join(
              ['\t{0} {1} times'.format(item, count) for item, count in Counter(nodes_v).items() if count > 1]
              )
            raise ValueError('No unique IDs for slice {0}, require unique IDs:\n{1}'.format(v_slice.index, err))
          nodes_u = G.vs.select(lambda v: v[slice_attr]==u_slice.index)[vertex_id_attr]
          if len(set(nodes_u)) != len(nodes_u):
            err = '\n'.join(
              ['\t{0} {1} times'.format(item, count) for item, count in Counter(nodes_u).items() if count > 1]
              )
            raise ValueError('No unique IDs for slice {0}, require unique IDs:\n{1}'.format(u_slice.index, err))
          common_nodes = set(nodes_v).intersection(set(nodes_u))
          nodes_v = sorted([v for v in G.vs if v[slice_attr] == v_slice.index and v[vertex_id_attr] in common_nodes], key=lambda v: v[vertex_id_attr])
          nodes_u = sorted([v for v in G.vs if v[slice_attr] == u_slice.index and v[vertex_id_attr] in common_nodes], key=lambda v: v[vertex_id_attr])
          edges = zip(nodes_v, nodes_u)
          e_start = G.ecount()
          G.add_edges(edges)
          e_end = G.ecount()
          e_idx = range(e_start, e_end)
          interslice_weight = G_coupling.es[G_coupling.get_eid(v_slice, u_slice)][weight_attr]
          if not interslice_weight is None:
            G.es[e_idx][weight_attr] = interslice_weight
          G.es[e_idx][edge_type_attr] = 'interslice'
  
    # Convert aggregate graph to individual layers for each time slice.
    G_layers = [None]*G_coupling.vcount()
    for v_slice in G_coupling.vs:
      H = G.subgraph_edges(G.es.select(_within=[v.index for v in G.vs if v[slice_attr] == v_slice.index]), delete_vertices=False)
      H.vs['node_size'] = [1 if v[slice_attr] == v_slice.index else 0 for v in H.vs]
      G_layers[v_slice.index] = H
  
    # Create one graph for the interslice links.
    G_interslice = G.subgraph_edges(G.es.select(type_eq='interslice'), delete_vertices=False)
    G_interslice.vs['node_size'] = 0
  
    return G_layers, G_interslice, G
function_tokens: def slices_to_layers ( G_coupling , slice_attr = 'slice' , vertex_id_attr = 'id' , edge_type_attr = 'type' , weight_attr = 'weight' ) : if not slice_attr in G_coupling . vertex_attributes ( ) : raise ValueError ( "Could not find the vertex attribute {0} in the coupling graph." . format ( slice_attr ) ) if not weight_attr in G_coupling . edge_attributes ( ) : raise ValueError ( "Could not find the edge attribute {0} in the coupling graph." . format ( weight_attr ) ) # Create disjoint union of the time graphs for v_slice in G_coupling . vs : H = v_slice [ slice_attr ] H . vs [ slice_attr ] = v_slice . index if not vertex_id_attr in H . vertex_attributes ( ) : raise ValueError ( "Could not find the vertex attribute {0} to identify nodes in different slices." . format ( vertex_id_attr ) ) if not weight_attr in H . edge_attributes ( ) : H . es [ weight_attr ] = 1 G = disjoint_union_attrs ( G_coupling . vs [ slice_attr ] ) G . es [ edge_type_attr ] = 'intraslice' for v_slice in G_coupling . vs : for u_slice in v_slice . neighbors ( mode = _ig . OUT ) : if v_slice . index < u_slice . index or G_coupling . is_directed ( ) : nodes_v = G . vs . select ( lambda v : v [ slice_attr ] == v_slice . index ) [ vertex_id_attr ] if len ( set ( nodes_v ) ) != len ( nodes_v ) : err = '\n' . join ( [ '\t{0} {1} times' . format ( item , count ) for item , count in Counter ( nodes_v ) . items ( ) if count > 1 ] ) raise ValueError ( 'No unique IDs for slice {0}, require unique IDs:\n{1}' . format ( v_slice . index , err ) ) nodes_u = G . vs . select ( lambda v : v [ slice_attr ] == u_slice . index ) [ vertex_id_attr ] if len ( set ( nodes_u ) ) != len ( nodes_u ) : err = '\n' . join ( [ '\t{0} {1} times' . format ( item , count ) for item , count in Counter ( nodes_u ) . items ( ) if count > 1 ] ) raise ValueError ( 'No unique IDs for slice {0}, require unique IDs:\n{1}' . format ( u_slice . index , err ) ) common_nodes = set ( nodes_v ) . intersection ( set ( nodes_u ) ) nodes_v = sorted ( [ v for v in G . vs if v [ slice_attr ] == v_slice . index and v [ vertex_id_attr ] in common_nodes ] , key = lambda v : v [ vertex_id_attr ] ) nodes_u = sorted ( [ v for v in G . vs if v [ slice_attr ] == u_slice . index and v [ vertex_id_attr ] in common_nodes ] , key = lambda v : v [ vertex_id_attr ] ) edges = zip ( nodes_v , nodes_u ) e_start = G . ecount ( ) G . add_edges ( edges ) e_end = G . ecount ( ) e_idx = range ( e_start , e_end ) interslice_weight = G_coupling . es [ G_coupling . get_eid ( v_slice , u_slice ) ] [ weight_attr ] if not interslice_weight is None : G . es [ e_idx ] [ weight_attr ] = interslice_weight G . es [ e_idx ] [ edge_type_attr ] = 'interslice' # Convert aggregate graph to individual layers for each time slice. G_layers = [ None ] * G_coupling . vcount ( ) for v_slice in G_coupling . vs : H = G . subgraph_edges ( G . es . select ( _within = [ v . index for v in G . vs if v [ slice_attr ] == v_slice . index ] ) , delete_vertices = False ) H . vs [ 'node_size' ] = [ 1 if v [ slice_attr ] == v_slice . index else 0 for v in H . vs ] G_layers [ v_slice . index ] = H # Create one graph for the interslice links. G_interslice = G . subgraph_edges ( G . es . select ( type_eq = 'interslice' ) , delete_vertices = False ) G_interslice . vs [ 'node_size' ] = 0 return G_layers , G_interslice , G