def _circuit_as_layers(circuit: circuits.Circuit,
                       grouping: _QubitGrouping) -> List[_TransformsThenCzs]:
    """Transforms a circuit into a series of GroupMatrix+CZ layers.

    Args:
        circuit: The circuit to transform.
        grouping: How the circuit's qubits are combined into groups.

    Returns:
        A list of layers. Each layer has a matrix to apply to each group of
        qubits, and a list of CZs to apply to pairs of qubits crossing
        between groups.
    """
    frontier = {q: 0 for q in circuit.all_qubits()}

    layers = []
    while True:
        # Pull within-group operations into per-group matrices.
        any_group_matrices = False
        group_matrices = []
        for g in grouping.groups:
            # Scan for reachable operations contained within the group qubits.
            start_frontier = {q: frontier[q] for q in g}
            end_frontier = circuit.reachable_frontier_from(start_frontier)
            mergeable_ops = circuit.findall_operations_between(start_frontier,
                                                               end_frontier)

            # Advance frontier.
            for q, v in end_frontier.items():
                frontier[q] = v

            # Fold reachable operations into a single group matrix.
            group_matrix = np.eye(1 << len(g)).reshape((2, 2) * len(g))
            if mergeable_ops:
                any_group_matrices = True
            for _, op in mergeable_ops:
                group_matrix = linalg.targeted_left_multiply(
                    left_matrix=protocols.unitary(op).reshape(
                        (2, 2) * len(op.qubits)),
                    right_target=group_matrix,
                    target_axes=[grouping.loc(q)[1] for q in op.qubits])
            group_matrices.append(np.transpose(group_matrix.reshape(
                1 << len(g), 1 << len(g))))

        # Scan for reachable CZ operations between groups.
        end_frontier = circuit.reachable_frontier_from(
            frontier,
            is_blocker=lambda op: grouping.all_in_same_group(*op.qubits))
        cz_ops = circuit.findall_operations_between(frontier, end_frontier)

        # Advance frontier.
        frontier = end_frontier

        # List out qubit index pairs for each CZ.
        cz_indices = []
        for _, cz in cz_ops:
            a, b = cz.qubits
            assert cz == ops.CZ(a, b)
            cz_indices.append((grouping.ind(a), grouping.ind(b)))

        # Combine group and CZ operations into a simulation layer.
        if not any_group_matrices and not cz_indices:
            break
        layer = _TransformsThenCzs(group_matrices=group_matrices,
                                   cz_indices=cz_indices)
        layers.append(layer)

    # We should have processed the whole circuit.
    assert frontier == {q: len(circuit) for q in circuit.all_qubits()}

    return layers
def _circuit_as_layers ( circuit : circuits . Circuit , grouping : _QubitGrouping ) -> List [ _TransformsThenCzs ] : frontier = { q : 0 for q in circuit . all_qubits ( ) } layers = [ ] while True : any_group_matrices = False group_matrices = [ ] for g in grouping . groups : start_frontier = { q : frontier [ q ] for q in g } end_frontier = circuit . reachable_frontier_from ( start_frontier ) mergeable_ops = circuit . findall_operations_between ( start_frontier , end_frontier ) for q , v in end_frontier . items ( ) : frontier [ q ] = v group_matrix = np . eye ( 1 << len ( g ) ) . reshape ( ( 2 , 2 ) * len ( g ) ) if mergeable_ops : any_group_matrices = True for _ , op in mergeable_ops : group_matrix = linalg . targeted_left_multiply ( left_matrix = protocols . unitary ( op ) . reshape ( ( 2 , 2 ) * len ( op . qubits ) ) , right_target = group_matrix , target_axes = [ grouping . loc ( q ) [ 1 ] for q in op . qubits ] ) group_matrices . append ( np . transpose ( group_matrix . reshape ( 1 << len ( g ) , 1 << len ( g ) ) ) ) end_frontier = circuit . reachable_frontier_from ( frontier , is_blocker = lambda op : grouping . all_in_same_group ( * op . qubits ) ) cz_ops = circuit . findall_operations_between ( frontier , end_frontier ) frontier = end_frontier cz_indices = [ ] for _ , cz in cz_ops : a , b = cz . qubits assert cz == ops . CZ ( a , b ) cz_indices . append ( ( grouping . ind ( a ) , grouping . ind ( b ) ) ) if not any_group_matrices and not cz_indices : break layer = _TransformsThenCzs ( group_matrices = group_matrices , cz_indices = cz_indices ) layers . append ( layer ) assert frontier == { q : len ( circuit ) for q in circuit . all_qubits ( ) } return layers
Transforms a circuit into a series of GroupMatrix+CZ layers.

    Args:
        circuit: The circuit to transform.
        grouping: How the circuit's qubits are combined into groups.

    Returns:
        A list of layers. Each layer has a matrix to apply to each group of
        qubits, and a list of CZs to apply to pairs of qubits crossing
        between groups.