def sample_states(<EOL>graph, spanning_cluster=True, model='<STR_LIT>', copy_result=True<EOL>):
if model != '<STR_LIT>':<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if spanning_cluster:<EOL><INDENT>auxiliary_node_attributes = nx.get_node_attributes(graph, '<STR_LIT>')<EOL>auxiliary_nodes = auxiliary_node_attributes.keys()<EOL>if not list(auxiliary_nodes):<EOL><INDENT>raise ValueError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>)<EOL><DEDENT>spanning_sides = list(set(auxiliary_node_attributes.values()))<EOL>if len(spanning_sides) != <NUM_LIT:2>:<EOL><INDENT>raise ValueError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>)<EOL><DEDENT>auxiliary_edge_attributes = nx.get_edge_attributes(graph, '<STR_LIT>')<EOL><DEDENT>if spanning_cluster:<EOL><INDENT>perc_graph = graph.subgraph(<EOL>[<EOL>node for node in graph.nodes_iter()<EOL>if '<STR_LIT>' not in graph.node[node]<EOL>]<EOL>)<EOL><DEDENT>else:<EOL><INDENT>perc_graph = graph<EOL><DEDENT>perc_edges = perc_graph.edges()<EOL>num_nodes = nx.number_of_nodes(perc_graph)<EOL>num_edges = nx.number_of_edges(perc_graph)<EOL>ret = dict()<EOL>ret['<STR_LIT:n>'] = <NUM_LIT:0><EOL>ret['<STR_LIT:N>'] = num_nodes<EOL>ret['<STR_LIT:M>'] = num_edges<EOL>ret['<STR_LIT>'] = <NUM_LIT:1><EOL>ret['<STR_LIT>'] = np.ones(<NUM_LIT:5>) * (num_nodes - <NUM_LIT:1>)<EOL>if spanning_cluster:<EOL><INDENT>ret['<STR_LIT>'] = False<EOL><DEDENT>if copy_result:<EOL><INDENT>yield copy.deepcopy(ret)<EOL><DEDENT>else:<EOL><INDENT>yield ret<EOL><DEDENT>perm_edges = np.random.permutation(num_edges)<EOL>ds = nx.utils.union_find.UnionFind()<EOL>if spanning_cluster:<EOL><INDENT>ds_spanning = nx.utils.union_find.UnionFind()<EOL>side_roots = dict()<EOL>for side in spanning_sides:<EOL><INDENT>nodes = [<EOL>node for (node, node_side) in auxiliary_node_attributes.items()<EOL>if node_side is side<EOL>]<EOL>ds_spanning.union(*nodes)<EOL>side_roots[side] = ds_spanning[nodes[<NUM_LIT:0>]]<EOL><DEDENT>for (edge, edge_side) in auxiliary_edge_attributes.items():<EOL><INDENT>ds_spanning.union(side_roots[edge_side], *edge)<EOL><DEDENT>side_roots = [<EOL>ds_spanning[side_root] for side_root in side_roots.values()<EOL>]<EOL><DEDENT>max_cluster_root = next(perc_graph.nodes_iter())<EOL>for n in range(num_edges):<EOL><INDENT>ret['<STR_LIT:n>'] = n + <NUM_LIT:1><EOL>edge_index = perm_edges[n]<EOL>edge = perc_edges[edge_index]<EOL>ret['<STR_LIT>'] = edge<EOL>roots = [<EOL>ds[node] for node in edge<EOL>]<EOL>weights = [<EOL>ds.weights[root] for root in roots<EOL>]<EOL>if roots[<NUM_LIT:0>] is not roots[<NUM_LIT:1>]:<EOL><INDENT>ds.union(*roots)<EOL>if spanning_cluster:<EOL><INDENT>ds_spanning.union(*roots)<EOL>ret['<STR_LIT>'] = (<EOL>ds_spanning[side_roots[<NUM_LIT:0>]] == ds_spanning[side_roots[<NUM_LIT:1>]]<EOL>)<EOL><DEDENT>root = ds[edge[<NUM_LIT:0>]]<EOL>weight = ds.weights[root]<EOL>for i in [<NUM_LIT:0>, <NUM_LIT:1>]:<EOL><INDENT>if roots[i] is max_cluster_root:<EOL><INDENT>continue<EOL><DEDENT>ret['<STR_LIT>'] -= weights[i] ** np.arange(<NUM_LIT:5>)<EOL><DEDENT>if max_cluster_root in roots:<EOL><INDENT>max_cluster_root = root<EOL>ret['<STR_LIT>'] = weight<EOL><DEDENT>else:<EOL><INDENT>if ret['<STR_LIT>'] >= weight:<EOL><INDENT>ret['<STR_LIT>'] += weight ** np.arange(<NUM_LIT:5>)<EOL><DEDENT>else:<EOL><INDENT>max_cluster_root = root<EOL>ret['<STR_LIT>'] += ret['<STR_LIT>'] ** np.arange(<NUM_LIT:5>)<EOL>ret['<STR_LIT>'] = weight<EOL><DEDENT><DEDENT><DEDENT>if copy_result:<EOL><INDENT>yield copy.deepcopy(ret)<EOL><DEDENT>else:<EOL><INDENT>yield ret<EOL><DEDENT><DEDENT>
Generate successive sample states of the percolation model

This is a :ref:`generator function <python:tut-generators>` to successively
add one edge at a time from the graph to the percolation model.
At each iteration, it calculates and returns the cluster statistics.

Parameters
----------
graph : networkx.Graph
    The substrate graph on which percolation is to take place

spanning_cluster : bool, optional
    Whether to detect a spanning cluster or not.
    Defaults to ``True``.

model : str, optional
    The percolation model (either ``'bond'`` or ``'site'``).
    Defaults to ``'bond'``.

    .. note:: Other models than ``'bond'`` are not supported yet.

copy_result : bool, optional
    Whether to return a copy or a reference to the result dictionary.
    Defaults to ``True``.

Yields
------
ret : dict
    Cluster statistics

ret['n'] : int
    Number of occupied bonds

ret['N'] : int
    Total number of sites

ret['M'] : int
    Total number of bonds

ret['has_spanning_cluster'] : bool
    ``True`` if there is a spanning cluster, ``False`` otherwise.
    Only exists if `spanning_cluster` argument is set to ``True``.

ret['max_cluster_size'] : int
    Size of the largest cluster (absolute number of sites)

ret['moments'] : 1-D :py:class:`numpy.ndarray` of int
    Array of size ``5``.
    The ``k``-th entry is the ``k``-th raw moment of the (absolute) cluster
    size distribution, with ``k`` ranging from ``0`` to ``4``.

Raises
------
ValueError
    If `model` does not equal ``'bond'``.

ValueError
    If `spanning_cluster` is ``True``, but `graph` does not contain any
    auxiliary nodes to detect spanning clusters.

See also
--------

microcanonical_averages : Evolves multiple sample states in parallel

Notes
-----
Iterating through this generator is a single run of the Newman-Ziff
algorithm. [2]_
The first iteration yields the trivial state with :math:`n = 0` occupied
bonds.

Spanning cluster

    In order to detect a spanning cluster, `graph` needs to contain
    auxiliary nodes and edges, cf. Reference [2]_, Figure 6.
    The auxiliary nodes and edges have the ``'span'`` `attribute
    <http://networkx.github.io/documentation/latest/tutorial/tutorial.html#node-attributes>`_.
    The value is either ``0`` or ``1``, distinguishing the two sides of the
    graph to span.

Raw moments of the cluster size distribution

    The :math:`k`-th raw moment of the (absolute) cluster size distribution
    is :math:`\sum_s' s^k N_s`, where :math:`s` is the cluster size and
    :math:`N_s` is the number of clusters of size :math:`s`. [3]_
    The primed sum :math:`\sum'` signifies that the largest cluster is
    excluded from the sum. [4]_

References
----------
.. [2] Newman, M. E. J. & Ziff, R. M. Fast monte carlo algorithm for site
    or bond percolation. Physical Review E 64, 016706+ (2001),
    `doi:10.1103/physreve.64.016706 <http://dx.doi.org/10.1103/physreve.64.016706>`_.

.. [3] Stauffer, D. & Aharony, A. Introduction to Percolation Theory (Taylor &
   Francis, London, 1994), second edn.

.. [4] Binder, K. & Heermann, D. W. Monte Carlo Simulation in Statistical
   Physics (Springer, Berlin, Heidelberg, 2010),
   `doi:10.1007/978-3-642-03163-2 <http://dx.doi.org/10.1007/978-3-642-03163-2>`_.