def test_inverse():
    with pytest.raises(TypeError):
        _ = cirq.inverse(cirq.measure(cirq.NamedQubit('q')))

    def rev_freeze(root):
        return cirq.freeze_op_tree(cirq.inverse(root))

    operations = [
        cirq.GateOperation(_FlipGate(i), [cirq.NamedQubit(str(i))])
        for i in range(10)
    ]
    expected = [
        cirq.GateOperation(_FlipGate(~i), [cirq.NamedQubit(str(i))])
        for i in range(10)
    ]

    # Just an item.
    assert rev_freeze(operations[0]) == expected[0]

    # Flat list.
    assert rev_freeze(operations) == tuple(expected[::-1])

    # Tree.
    assert (rev_freeze(
        (operations[1:5], operations[0],
         operations[5:])) == (tuple(expected[5:][::-1]), expected[0],
                              tuple(expected[1:5][::-1])))

    # Flattening after reversing is equivalent to reversing then flattening.
    t = (operations[1:5], operations[0], operations[5:])
    assert (tuple(cirq.flatten_op_tree(rev_freeze(t))) == tuple(
        rev_freeze(cirq.flatten_op_tree(t))))
def test_inverse():
    with pytest.raises(TypeError):
        _ = cirq.inverse(
            cirq.measure(cirq.NamedQubit('q')))

    def rev_freeze(root):
        return cirq.freeze_op_tree(cirq.inverse(root))

    operations = [
        cirq.GateOperation(_FlipGate(i), [cirq.NamedQubit(str(i))])
        for i in range(10)
    ]
    expected = [
        cirq.GateOperation(_FlipGate(~i), [cirq.NamedQubit(str(i))])
        for i in range(10)
    ]

    # Just an item.
    assert rev_freeze(operations[0]) == expected[0]

    # Flat list.
    assert rev_freeze(operations) == tuple(expected[::-1])

    # Tree.
    assert (
        rev_freeze((operations[1:5], operations[0], operations[5:])) ==
        (tuple(expected[5:][::-1]), expected[0],
         tuple(expected[1:5][::-1])))

    # Flattening after reversing is equivalent to reversing then flattening.
    t = (operations[1:5], operations[0], operations[5:])
    assert (
        tuple(cirq.flatten_op_tree(rev_freeze(t))) ==
        tuple(rev_freeze(cirq.flatten_op_tree(t))))
Example #3
0
def test_flatten_op_tree():
    operations = [
        cirq.GateOperation(cirq.SingleQubitGate(), [cirq.NamedQubit(str(i))])
        for i in range(10)
    ]

    # Empty tree.
    assert list(cirq.flatten_op_tree([[[]]])) == []

    # Just an item.
    assert list(cirq.flatten_op_tree(operations[0])) == operations[:1]

    # Flat list.
    assert list(cirq.flatten_op_tree(operations)) == operations

    # Tree.
    assert list(
        cirq.flatten_op_tree(
            (operations[0], operations[1:5], operations[5:]))) == operations

    # Flatten moment.
    assert list(
        cirq.flatten_op_tree((operations[0], cirq.Moment(operations[1:5]),
                              operations[5:]))) == operations

    # Bad trees.
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_op_tree(None))
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_op_tree(5))
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_op_tree([operations[0], (4, )]))
def test_decomposes_despite_symbol():
    q0, q1 = cirq.NamedQubit('q0'), cirq.NamedQubit('q1')
    gate = cirq.PauliInteractionGate(cirq.Pauli.Z, False, cirq.Pauli.X, False,
                                     half_turns=cirq.Symbol('x'))
    op_tree = gate.default_decompose([q0, q1])
    ops = tuple(cirq.flatten_op_tree(op_tree))
    assert ops
def test_decomposes_despite_symbol():
    q0, q1 = cirq.NamedQubit('q0'), cirq.NamedQubit('q1')
    gate = cirq.PauliInteractionGate(cirq.Pauli.Z, False, cirq.Pauli.X, False,
                                     half_turns=cirq.Symbol('x'))
    op_tree = gate.default_decompose([q0, q1])
    ops = tuple(cirq.flatten_op_tree(op_tree))
    assert ops
Example #6
0
def test_decomposition_cost(op: cirq.Operation, max_two_cost: int):
    ops = tuple(
        cirq.flatten_op_tree(cirq.google.ConvertToXmonGates().convert(op)))
    two_cost = len([e for e in ops if len(e.qubits) == 2])
    over_cost = len([e for e in ops if len(e.qubits) > 2])
    assert over_cost == 0
    assert two_cost == max_two_cost
Example #7
0
def test_flatten_op_tree():
    operations = [
        cirq.GateOperation(cirq.Gate(), [cirq.NamedQubit(str(i))])
        for i in range(10)
    ]

    # Empty tree.
    assert list(cirq.flatten_op_tree([[[]]])) == []

    # Just an item.
    assert list(cirq.flatten_op_tree(operations[0])) == operations[:1]

    # Flat list.
    assert list(cirq.flatten_op_tree(operations)) == operations

    # Tree.
    assert list(cirq.flatten_op_tree((operations[0],
                                      operations[1:5],
                                      operations[5:]))) == operations

    # Bad trees.
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_op_tree(None))
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_op_tree(5))
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_op_tree([operations[0], (4,)]))
    def _decompose_(self, qubits):
        a, b, c, d = qubits

        weights_to_exponents = (self._exponent / 4.) * np.array([
            [1, -1, 1],
            [1, 1, -1],
            [-1, 1, 1]
        ])
        exponents = weights_to_exponents.dot(self.weights)

        basis_change = list(cirq.flatten_op_tree([
            cirq.CNOT(b, a),
            cirq.CNOT(c, b),
            cirq.CNOT(d, c),
            cirq.CNOT(c, b),
            cirq.CNOT(b, a),
            cirq.CNOT(a, b),
            cirq.CNOT(b, c),
            cirq.CNOT(a, b),
            [cirq.X(c), cirq.X(d)],
            [cirq.CNOT(c, d), cirq.CNOT(d, c)],
            [cirq.X(c), cirq.X(d)],
            ]))

        controlled_Zs = list(cirq.flatten_op_tree([
            cirq.CZPowGate(exponent=exponents[0])(b, c),
            cirq.CNOT(a, b),
            cirq.CZPowGate(exponent=exponents[1])(b, c),
            cirq.CNOT(b, a),
            cirq.CNOT(a, b),
            cirq.CZPowGate(exponent=exponents[2])(b, c)
            ]))

        controlled_swaps = [
            [cirq.CNOT(c, d), cirq.H(c)],
            cirq.CNOT(d, c),
            controlled_Zs,
            cirq.CNOT(d, c),
            [cirq.inverse(op) for op in reversed(controlled_Zs)],
            [cirq.H(c), cirq.CNOT(c, d)],
            ]

        yield basis_change
        yield controlled_swaps
        yield basis_change[::-1]
Example #9
0
def test_swap_network_gate_permutation(part_lens, acquaintance_size):
    n_qubits = sum(part_lens)
    qubits = cirq.LineQubit.range(n_qubits)
    swap_network_gate = SwapNetworkGate(part_lens, acquaintance_size)
    operations = cirq.decompose_once_with_qubits(swap_network_gate, qubits)
    operations = list(cirq.flatten_op_tree(operations))
    mapping = {q: i for i, q in enumerate(qubits)}
    update_mapping(mapping, operations)
    assert mapping == {q: i for i, q in enumerate(reversed(qubits))}
Example #10
0
def test_transform_bad_tree():
    with pytest.raises(TypeError):
        _ = list(cirq.transform_op_tree(None))
    with pytest.raises(TypeError):
        _ = list(cirq.transform_op_tree(5))
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_op_tree(cirq.transform_op_tree([
            cirq.GateOperation(cirq.Gate(), [cirq.NamedQubit('q')]), (4,)
        ])))
Example #11
0
def test_transform_bad_tree():
    with pytest.raises(TypeError):
        _ = list(cirq.transform_op_tree(None))
    with pytest.raises(TypeError):
        _ = list(cirq.transform_op_tree(5))
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_op_tree(cirq.transform_op_tree([
            cirq.GateOperation(cirq.Gate(), [cirq.QubitId()]), (4,)
        ])))
Example #12
0
def test_flatten_to_ops_or_moments():
    operations = [
        cirq.GateOperation(cirq.testing.SingleQubitGate(),
                           [cirq.NamedQubit(str(i))]) for i in range(10)
    ]
    op_tree = [operations[0], cirq.Moment(operations[1:5]), operations[5:]]
    output = [operations[0], cirq.Moment(operations[1:5])] + operations[5:]
    assert list(cirq.flatten_to_ops_or_moments(op_tree)) == output
    assert list(cirq.flatten_op_tree(op_tree, preserve_moments=True)) == output

    # Bad trees.
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_to_ops_or_moments(None))
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_to_ops_or_moments(5))
    with pytest.raises(TypeError):
        _ = list(cirq.flatten_to_ops_or_moments([operations[0], (4, )]))
Example #13
0
 def simulate_op(op, temp_state):
     indices = [qubit_map[q] for q in op.qubits]
     if isinstance(op.gate, cirq.ResetChannel):
         self._simulate_reset(op, temp_state, indices)
     elif cirq.is_measurement(op):
         if perform_measurements:
             self._simulate_measurement(
                 op, temp_state, indices, measurements)
     else:
         if cirq.num_qubits(op) <= 3:
             self._simulate_from_matrix(op, temp_state, indices)
         else:
             decomp_ops = cirq.decompose_once(op, default=None)
             if decomp_ops is None:
                 self._simulate_from_matrix(op, temp_state, indices)
             else:
                 for sub_op in cirq.flatten_op_tree(decomp_ops):
                     simulate_op(sub_op, temp_state)
Example #14
0
def test_linear_permutation_gate(n_elements, n_permuted):
    qubits = cirq.LineQubit.range(n_elements)
    elements = tuple(range(n_elements))
    elements_to_permute = random.sample(elements, n_permuted)
    permuted_elements = random.sample(elements_to_permute, n_permuted)
    permutation = {e: p for e, p in
                   zip(elements_to_permute, permuted_elements)}
    cca.PermutationGate.validate_permutation(permutation, n_elements)
    gate = cca.LinearPermutationGate(n_elements, permutation)
    ct.assert_equivalent_repr(gate)
    assert gate.permutation() == permutation
    mapping = dict(zip(qubits, elements))
    for swap in cirq.flatten_op_tree(cirq.decompose_once_with_qubits(
            gate, qubits)):
        assert isinstance(swap, cirq.GateOperation)
        swap.gate.update_mapping(mapping, swap.qubits)
    for i in range(n_elements):
        p = permutation.get(elements[i], i)
        assert mapping.get(qubits[p], elements[i]) == i
Example #15
0
def test_linear_permutation_gate():
    for _ in range(20):
        n_elements = randint(5, 20)
        n_permuted = randint(0, n_elements)
        qubits = [cirq.NamedQubit(s) for s in alphabet[:n_elements]]
        elements = tuple(range(n_elements))
        elements_to_permute = sample(elements, n_permuted)
        permuted_elements = sample(elements_to_permute, n_permuted)
        permutation = {e: p for e, p in
                       zip(elements_to_permute, permuted_elements)}
        PermutationGate.validate_permutation(permutation, n_elements)
        gate = LinearPermutationGate(permutation)
        assert gate.permutation(n_elements) == permutation
        mapping = dict(zip(qubits, elements))
        for swap in cirq.flatten_op_tree(cirq.decompose_once_with_qubits(
                gate, qubits)):
            assert isinstance(swap, cirq.GateOperation)
            swap.gate.update_mapping(mapping, swap.qubits)
        for i in range(n_elements):
            p = permutation.get(elements[i], i)
            assert mapping.get(qubits[p], elements[i]) == i
Example #16
0
 def simulate_op(op, temp_state):
     indices = [qubit_map[q] for q in op.qubits]
     if isinstance(op.gate, cirq.ResetChannel):
         self._simulate_reset(op, temp_state, indices)
     elif cirq.is_measurement(op):
         if perform_measurements:
             self._simulate_measurement(op, temp_state, indices,
                                        measurements)
     else:
         decomp_ops = cirq.decompose_once(op, default=None)
         if decomp_ops is None:
             self._simulate_from_matrix(op, temp_state, indices)
         else:
             try:
                 temp2_state = temp_state.copy()
                 for sub_op in cirq.flatten_op_tree(decomp_ops):
                     simulate_op(sub_op, temp2_state)
                 temp_state[...] = temp2_state
             except ValueError:
                 # Non-classical unitary in the decomposition
                 self._simulate_from_matrix(op, temp_state, indices)
Example #17
0
    def _decompose_(self, qubits):
        """The goal is to effect a rotation around an axis in the XY plane in
        each of three orthogonal 2-dimensional subspaces.

        First, the following basis change is performed:
            0000 ↦ 0001        0001 ↦ 1111
            1111 ↦ 0010        1110 ↦ 1100
                               0010 ↦ 0000
            0110 ↦ 0101        1101 ↦ 0011
            1001 ↦ 0110        0100 ↦ 0100
            1010 ↦ 1001        1011 ↦ 0111
            0101 ↦ 1010        1000 ↦ 1000
            1100 ↦ 1101        0111 ↦ 1011
            0011 ↦ 1110

        Note that for each 2-dimensional subspace of interest, the first two
        qubits are the same and the right two qubits are different. The desired
        rotations thus can be effected by a complex-version of a partial SWAP
        gate on the latter two qubits, controlled on the first two qubits. This
        partial SWAP-like gate can  be decomposed such that it is parameterized
        solely by a rotation in the ZY plane on the third qubit. These are the
        `individual_rotations`; call them U0, U1, U2.

        To decompose the double controlled rotations, we use four other
        rotations V0, V1, V2, V3 (the `combined_rotations`) such that
            U0 = V3 · V1 · V0
            U1 = V3 · V2 · V1
            U2 = V2 · V0
        """

        if self._is_parameterized_():
            return NotImplemented

        individual_rotations = [
            la.expm(0.5j * self.exponent *
                    np.array([[np.real(w), 1j * s * np.imag(w)],
                              [-1j * s * np.imag(w), -np.real(w)]]))
            for s, w in zip([1, -1, -1], self.weights)
        ]

        combined_rotations = {}
        combined_rotations[0] = la.sqrtm(
            np.linalg.multi_dot([
                la.inv(individual_rotations[1]), individual_rotations[0],
                individual_rotations[2]
            ]))
        combined_rotations[1] = la.inv(combined_rotations[0])
        combined_rotations[2] = np.linalg.multi_dot([
            la.inv(individual_rotations[0]), individual_rotations[1],
            combined_rotations[0]
        ])
        combined_rotations[3] = individual_rotations[0]

        controlled_rotations = {
            i: cirq.ControlledGate(
                cirq.MatrixGate(combined_rotations[i], qid_shape=(2, )))
            for i in range(4)
        }

        a, b, c, d = qubits

        basis_change = list(
            cirq.flatten_op_tree([
                cirq.CNOT(b, a),
                cirq.CNOT(c, b),
                cirq.CNOT(d, c),
                cirq.CNOT(c, b),
                cirq.CNOT(b, a),
                cirq.CNOT(a, b),
                cirq.CNOT(b, c),
                cirq.CNOT(a, b),
                [cirq.X(c), cirq.X(d)],
                [cirq.CNOT(c, d), cirq.CNOT(d, c)],
                [cirq.X(c), cirq.X(d)],
            ]))

        controlled_rotations = list(
            cirq.flatten_op_tree([
                controlled_rotations[0](b, c),
                cirq.CNOT(a, b), controlled_rotations[1](b, c),
                cirq.CNOT(b, a),
                cirq.CNOT(a, b), controlled_rotations[2](b, c),
                cirq.CNOT(a, b), controlled_rotations[3](b, c)
            ]))

        controlled_swaps = [
            [cirq.CNOT(c, d), cirq.H(c)],
            cirq.CNOT(d, c),
            controlled_rotations,
            cirq.CNOT(d, c),
            [cirq.inverse(op) for op in reversed(controlled_rotations)],
            [cirq.H(c), cirq.CNOT(c, d)],
        ]

        return [basis_change, controlled_swaps, basis_change[::-1]]
Example #18
0
def _assert_equivalent_op_tree(x: cirq.OP_TREE, y: cirq.OP_TREE):
    a = list(cirq.flatten_op_tree(x))
    b = list(cirq.flatten_op_tree(y))
    assert a == b
Example #19
0
def quick_circuit(*moments: Iterable[cirq.OP_TREE]) -> cirq.Circuit:
    return cirq.Circuit([
        cirq.Moment(cast(Iterable[cirq.Operation], cirq.flatten_op_tree(m)))
        for m in moments
    ])
Example #20
0
def test_w_circuit_gate_locality(n_qubits):
    qubits = cirq.LineQubit.range(n_qubits)
    ops = generate_w_state_circuit(qubits)
    for op in cirq.flatten_op_tree(ops):
        assert len(op.qubits) <= 2
Example #21
0
def swap_network(qubits: Sequence[cirq.Qid],
                 operation: Callable[
                     [int, int, cirq.Qid, cirq.Qid],
                     cirq.OP_TREE] = lambda p, q, p_qubit, q_qubit: (),
                 fermionic: bool = False,
                 offset: bool = False) -> List[cirq.Operation]:
    """Apply operations to pairs of qubits or modes using a swap network.

    This is used for applying operations between arbitrary pairs of qubits or
    fermionic modes using only nearest-neighbor interactions on a linear array
    of qubits. It works by reversing the order of qubits or modes with a
    sequence of swap gates and applying an operation when the relevant qubits
    or modes become adjacent. For fermionic modes, this assumes the
    Jordan-Wigner Transform.

    Examples
    --------

    Input:

    .. testcode::

        import cirq
        from openfermioncirq import swap_network

        qubits = cirq.LineQubit.range(4)
        circuit = cirq.Circuit(swap_network(qubits))
        print(circuit)

    Output:

    .. testoutput::

        0: ───×───────×───────
              │       │
        1: ───×───×───×───×───
                  │       │
        2: ───×───×───×───×───
              │       │
        3: ───×───────×───────

    Input:

    .. testcode::

        circuit = cirq.Circuit(swap_network(qubits, offset=True))
        print(circuit)

    Output:

    .. testoutput::

        0: ───────×───────×───
                  │       │
        1: ───×───×───×───×───
              │       │
        2: ───×───×───×───×───
                  │       │
        3: ───────×───────×───

    Input:

    .. testcode::

        from openfermioncirq import XXYY

        circuit = cirq.Circuit(
            swap_network(
                qubits,
                lambda p, q, a, b: XXYY(a, b) if abs(p - q) == 1
                                   else cirq.CZ(a, b),
                fermionic=True),
            strategy=cirq.InsertStrategy.EARLIEST)
        print(circuit)

    Output:

    .. testoutput::

        0: ───XXYY───×ᶠ────────────@───×ᶠ───────────────
              │      │             │   │
        1: ───XXYY───×ᶠ───@───×ᶠ───@───×ᶠ───XXYY───×ᶠ───
                          │   │             │      │
        2: ───XXYY───×ᶠ───@───×ᶠ───@───×ᶠ───XXYY───×ᶠ───
              │      │             │   │
        3: ───XXYY───×ᶠ────────────@───×ᶠ───────────────

    Args:
        qubits: The qubits sorted so that the j-th qubit in the Sequence
            represents the j-th qubit or fermionic mode.
        operation: Returns extra interactions to perform between qubits/modes as
            they are swapped past each other. A call to this function takes the
            form ``operation(p, q, p_qubit, q_qubit)`` where p and q are indices
            representing either qubits or fermionic modes, and p_qubit and
            q_qubit are the qubits which are currently storing those modes.
        fermionic: If True, use fermionic swaps under the JWT (that is, swap
            fermionic modes instead of qubits). If False, use normal qubit
            swaps.
        offset: If True, then qubit 0 will participate in odd-numbered layers
            instead of even-numbered layers.
    """
    n_qubits = len(qubits)
    order = list(range(n_qubits))
    swap_gate = FSWAP if fermionic else cirq.SWAP
    result = []  # type: List[cirq.Operation]

    for layer_num in range(n_qubits):
        lowest_active_qubit = (layer_num + offset) % 2
        active_pairs = ((i, i + 1)
                        for i in range(lowest_active_qubit, n_qubits - 1, 2))
        for i, j in active_pairs:
            p, q = order[i], order[j]
            extra_ops = operation(p, q, qubits[i], qubits[j])
            result.extend(cirq.flatten_op_tree(extra_ops))
            result.append(swap_gate(qubits[i], qubits[j]))
            order[i], order[j] = q, p

    return result
Example #22
0
def quick_circuit(*moments: Iterable[cirq.OP_TREE]) -> cirq.Circuit:
    return cirq.Circuit([cirq.Moment(cirq.flatten_op_tree(m)) for m in moments])
Example #23
0
 def _op_generator_grad(_qubits):
     op_list = flatten_op_tree(
         op_tree_generator(_qubits, **generator_kwargs),
         preserve_moments=False)  # type: typing.Iterable[cirq.Operation]
     return op_series_grad(list(op_list), parameter)