def _estimate_pauli_traces_clifford(
    n_qubits: int, stabilizer_basis: list[cirq.DensePauliString], n_measured_operators: int | None
) -> list[PauliTrace]:
    """Estimates the Pauli traces in case the circuit is Clifford.

    When we have a Clifford circuit, there are 2**n Pauli traces that have probability 1/2**n
    and all the other traces have probability 0. In addition, there is a fast
    way to compute find out what the traces are. See the documentation of
    cirq.CliffordTableau for more detail. This function uses the speedup to sample
    the Pauli states with non-zero probability.

    Args:
        n_qubits: An integer that is the number of qubits.
        stabilizer_basis: The basis of the Pauli states with non-zero probability.
        n_measured_operators: The total number of Pauli measurements, or None to
            explore each Pauli state once.

    Returns:
        A list of Pauli states (represented as tuples of Pauli string, rho_i,
            and probability.
    """

    # When the circuit consists of Clifford gates only, we can sample the
    # Pauli states more efficiently as described on page 4 of:
    # https://arxiv.org/abs/1104.4695

    d = 2**n_qubits

    if n_measured_operators is not None:
        dense_pauli_strings = _randomly_sample_from_stabilizer_bases(
            stabilizer_basis, n_measured_operators, n_qubits
        )
        assert len(dense_pauli_strings) == n_measured_operators
    else:
        dense_pauli_strings = _enumerate_all_from_stabilizer_bases(stabilizer_basis, n_qubits)
        assert len(dense_pauli_strings) == 2**n_qubits

    pauli_traces: list[PauliTrace] = []
    for dense_pauli_string in dense_pauli_strings:
        # The code below is equivalent to getting the state vectors from the
        # Clifford tableau and then calling compute_characteristic_function()
        # on the results (albeit with a  wave function instead of a density
        # matrix). It is, however, unnecessary to do so. Instead we directly
        # obtain the scalar rho_i.
        rho_i = dense_pauli_string.coefficient

        assert np.isclose(rho_i.imag, 0.0, atol=1e-6)
        rho_i = rho_i.real

        dense_pauli_string *= rho_i

        assert np.isclose(abs(rho_i), 1.0, atol=1e-6)
        Pr_i = 1.0 / d

        pauli_traces.append(PauliTrace(P_i=dense_pauli_string.sparse(), rho_i=rho_i, Pr_i=Pr_i))
    return pauli_traces
Estimates the Pauli traces in case the circuit is Clifford.

    When we have a Clifford circuit, there are 2**n Pauli traces that have probability 1/2**n
    and all the other traces have probability 0. In addition, there is a fast
    way to compute find out what the traces are. See the documentation of
    cirq.CliffordTableau for more detail. This function uses the speedup to sample
    the Pauli states with non-zero probability.

    Args:
        n_qubits: An integer that is the number of qubits.
        stabilizer_basis: The basis of the Pauli states with non-zero probability.
        n_measured_operators: The total number of Pauli measurements, or None to
            explore each Pauli state once.

    Returns:
        A list of Pauli states (represented as tuples of Pauli string, rho_i,
            and probability.
    
examples/direct_fidelity_estimation.py