text: """Operations on many graphs.
  """
  #    Copyright (C) 2013 by
  #    Aric Hagberg <hagberg@lanl.gov>
  #    Dan Schult <dschult@colgate.edu>
  #    Pieter Swart <swart@lanl.gov>
  #    All rights reserved.
  #    BSD license.
  try:
      from itertools import izip_longest as zip_longest
  except ImportError:  # Python3 has zip_longest
      from itertools import zip_longest
  import networkx as nx
  
  __author__ = """\n""".join(['Robert King <kingrobertking@gmail.com>',
                              'Aric Hagberg <aric.hagberg@gmail.com>'])
  
  __all__ = ['union_all', 'compose_all', 'disjoint_union_all',
             'intersection_all']
  
  
  def union_all(graphs, rename=(None,)):
      """Return the union of all graphs.
  
      The graphs must be disjoint, otherwise an exception is raised.
  
      Parameters
      ----------
      graphs : list of graphs
         List of NetworkX graphs
  
      rename : bool , default=(None, None)
         Node names of G and H can be changed by specifying the tuple
         rename=('G-','H-') (for example).  Node "u" in G is then renamed
         "G-u" and "v" in H is renamed "H-v".
  
      Returns
      -------
      U : a graph with the same type as the first graph in list
  
      Raises
      ------
      ValueError
         If `graphs` is an empty list.
  
      Notes
      -----
      To force a disjoint union with node relabeling, use
      disjoint_union_all(G,H) or convert_node_labels_to integers().
  
      Graph, edge, and node attributes are propagated to the union graph.
      If a graph attribute is present in multiple graphs, then the value
      from the last graph in the list with that attribute is used.
  
      See Also
      --------
      union
      disjoint_union_all
      """
      if not graphs:
          raise ValueError('cannot apply union_all to an empty list')
      graphs_names = zip_longest(graphs, rename)
      U, gname = next(graphs_names)
      for H, hname in graphs_names:
          U = nx.union(U, H, (gname, hname))
          gname = None
      return U
  
  
  def disjoint_union_all(graphs):
      """Return the disjoint union of all graphs.
  
      This operation forces distinct integer node labels starting with 0
      for the first graph in the list and numbering consecutively.
  
      Parameters
      ----------
      graphs : list
         List of NetworkX graphs
  
      Returns
      -------
      U : A graph with the same type as the first graph in list
  
      Raises
      ------
      ValueError
         If `graphs` is an empty list.
  
      Notes
      -----
      It is recommended that the graphs be either all directed or all undirected.
  
      Graph, edge, and node attributes are propagated to the union graph.
      If a graph attribute is present in multiple graphs, then the value
      from the last graph in the list with that attribute is used.
      """
      if not graphs:
          raise ValueError('cannot apply disjoint_union_all to an empty list')
      graphs = iter(graphs)
      U = next(graphs)
      for H in graphs:
          U = nx.disjoint_union(U, H)
      return U
  
  
  def compose_all(graphs):
      """Return the composition of all graphs.
  
      Composition is the simple union of the node sets and edge sets.
      The node sets of the supplied graphs need not be disjoint.
  
      Parameters
      ----------
      graphs : list
         List of NetworkX graphs
  
      Returns
      -------
      C : A graph with the same type as the first graph in list
  
      Raises
      ------
      ValueError
         If `graphs` is an empty list.
  
      Notes
      -----
      It is recommended that the supplied graphs be either all directed or all
      undirected.
  
      Graph, edge, and node attributes are propagated to the union graph.
      If a graph attribute is present in multiple graphs, then the value
      from the last graph in the list with that attribute is used.
      """
      if not graphs:
          raise ValueError('cannot apply compose_all to an empty list')
      graphs = iter(graphs)
      C = next(graphs)
      for H in graphs:
          C = nx.compose(C, H)
      return C
  
  
  def intersection_all(graphs):
      """Return a new graph that contains only the edges that exist in
      all graphs.
  
      All supplied graphs must have the same node set.
  
      Parameters
      ----------
      graphs : list
         List of NetworkX graphs
  
      Returns
      -------
      R : A new graph with the same type as the first graph in list
  
      Raises
      ------
      ValueError
         If `graphs` is an empty list.
  
      Notes
      -----
      Attributes from the graph, nodes, and edges are not copied to the new
      graph.
      """
      if not graphs:
          raise ValueError('cannot apply intersection_all to an empty list')
      graphs = iter(graphs)
      R = next(graphs)
      for H in graphs:
          R = nx.intersection(R, H)
      return R
  