Beispiel #1
0
    def default_decompose(self, qubits):
        """An adjacency-respecting decomposition.

        0: ───T───@──────────────@───────@──────────@──────────
                  │              │       │          │
        1: ───T───X───@───T^-1───X───@───X──────@───X──────@───
                      │              │          │          │
        2: ───T───────X───T──────────X───T^-1───X───T^-1───X───
        """
        a, b, c = qubits

        # Hacky magic: avoid the non-adjacent edge.
        if hasattr(b, 'is_adjacent'):
            if not b.is_adjacent(a):
                b, c = c, b
            elif not b.is_adjacent(c):
                a, b = b, a

        t = common_gates.T
        sweep_abc = [common_gates.CNOT(a, b),
                     common_gates.CNOT(b, c)]

        yield t(a), t(b), t(c)
        yield sweep_abc
        yield t(b)**-1, t(c)
        yield sweep_abc
        yield t(c)**-1
        yield sweep_abc
        yield t(c)**-1
        yield sweep_abc
Beispiel #2
0
 def _decompose_(self, qubits):
     """See base class."""
     a, b = qubits
     yield common_gates.CNOT(a, b)
     yield common_gates.CNotPowGate(exponent=self._exponent,
                                    global_shift=self.global_shift).on(b, a)
     yield common_gates.CNOT(a, b)
Beispiel #3
0
    def default_decompose(self, qubits):
        a, b, c = qubits

        # Hacky magic: avoid the non-adjacent edge.
        if hasattr(b, 'is_adjacent'):
            if not b.is_adjacent(a):
                b, c = c, b
            elif not b.is_adjacent(c):
                a, b = b, a

        yield common_gates.T.on_each([a, b, c])  # Phase a, b, and c.
        yield common_gates.CNOT(c, b)
        yield common_gates.T(b)**-1  # Counter-phase b ⊕ c.
        yield common_gates.CNOT(a, b)
        yield common_gates.T(b)  # Phase a ⊕ b ⊕ c.
        yield common_gates.CNOT(c, b)
        yield common_gates.T(b)**-1  # Counter-phase a ⊕ b.
        yield common_gates.CNOT(a, b)

        # If a then toggle b and c.
        yield common_gates.CNOT(b, c)
        yield common_gates.CNOT(a, b)
        yield common_gates.CNOT(b, c)

        yield common_gates.T(c)**-1  # Counter-phase a ⊕ c.

        # If a then un-toggle b and c.
        yield common_gates.CNOT(b, c)
        yield common_gates.CNOT(a, b)
        yield common_gates.CNOT(b, c)
Beispiel #4
0
    def _decompose_outside_control(
        self, control: 'cirq.Qid', near_target: 'cirq.Qid', far_target: 'cirq.Qid'
    ) -> 'cirq.OP_TREE':
        """A decomposition assuming one of the targets is in the middle.

        control: ───T──────@────────@───@────────────@────────────────
                           │        │   │            │
           near: ─X─T──────X─@─T^-1─X─@─X────@─X^0.5─X─@─X^0.5────────
                  │          │        │      │         │
            far: ─@─Y^-0.5─T─X─T──────X─T^-1─X─T^-1────X─S─────X^-0.5─
        """
        a, b, c = control, near_target, far_target

        t = common_gates.T
        sweep_abc = [common_gates.CNOT(a, b), common_gates.CNOT(b, c)]

        yield common_gates.CNOT(c, b)
        yield pauli_gates.Y(c) ** -0.5
        yield t(a), t(b), t(c)
        yield sweep_abc
        yield t(b) ** -1, t(c)
        yield sweep_abc
        yield t(c) ** -1
        yield sweep_abc
        yield t(c) ** -1
        yield pauli_gates.X(b) ** 0.5
        yield sweep_abc
        yield common_gates.S(c)
        yield pauli_gates.X(b) ** 0.5
        yield pauli_gates.X(c) ** -0.5
Beispiel #5
0
    def default_decompose(self, qubits):
        """An adjacency-respecting decomposition.

        0: ───p───@──────────────@───────@──────────@──────────
                  │              │       │          │
        1: ───p───X───@───p^-1───X───@───X──────@───X──────@───
                      │              │          │          │
        2: ───p───────X───p──────────X───p^-1───X───p^-1───X───

        where p = T**self._exponent
        """
        a, b, c = qubits

        # Hacky magic: avoid the non-adjacent edge.
        if hasattr(b, 'is_adjacent'):
            if not b.is_adjacent(a):
                b, c = c, b
            elif not b.is_adjacent(c):
                a, b = b, a

        p = common_gates.T**self._exponent
        sweep_abc = [common_gates.CNOT(a, b),
                     common_gates.CNOT(b, c)]

        yield p(a), p(b), p(c)
        yield sweep_abc
        yield p(b)**-1, p(c)
        yield sweep_abc
        yield p(c)**-1
        yield sweep_abc
        yield p(c)**-1
        yield sweep_abc
Beispiel #6
0
    def _decompose_(self, qubits):
        """An adjacency-respecting decomposition.

        0: ───p_0───@──────────────@───────@──────────@──────────
                    │              │       │          │
        1: ───p_1───X───@───p_3────X───@───X──────@───X──────@───
                        │              │          │          │
        2: ───p_2───────X───p_4────────X───p_5────X───p_6────X───

        where p_i = T**(4*x_i) and x_i solve the system of equations
                    [0, 0, 1, 0, 1, 1, 1][x_0]   [r_1]
                    [0, 1, 0, 1, 1, 0, 1][x_1]   [r_2]
                    [0, 1, 1, 1, 0, 1, 0][x_2]   [r_3]
                    [1, 0, 0, 1, 1, 1, 0][x_3] = [r_4]
                    [1, 0, 1, 1, 0, 0, 1][x_4]   [r_5]
                    [1, 1, 0, 0, 0, 1, 1][x_5]   [r_6]
                    [1, 1, 1, 0, 1, 0, 0][x_6]   [r_7]
        where r_i is self._diag_angles_radians[i].

        The above system was created by equating the composition of the gates
        in the circuit diagram to np.diag(self._diag_angles) (shifted by a
        global phase of np.exp(-1j * self._diag_angles[0])).
        """

        a, b, c = qubits
        if hasattr(b, 'is_adjacent'):
            if not b.is_adjacent(a):
                b, c = c, b
            elif not b.is_adjacent(c):
                a, b = b, a
        sweep_abc = [common_gates.CNOT(a, b), common_gates.CNOT(b, c)]
        phase_matrix_inverse = .25 * np.array(
            [[-1, -1, -1, 1, 1, 1, 1], [-1, 1, 1, -1, -1, 1, 1],
             [1, -1, 1, -1, 1, -1, 1], [-1, 1, 1, 1, 1, -1, -1],
             [1, 1, -1, 1, -1, -1, 1], [1, -1, 1, 1, -1, 1, -1],
             [1, 1, -1, -1, 1, 1, -1]])
        shifted_angles_tail = [
            angle - self._diag_angles_radians[0]
            for angle in self._diag_angles_radians[1:]
        ]
        phase_solutions = phase_matrix_inverse.dot(shifted_angles_tail)
        p_gates = [
            pauli_gates.Z**(solution / np.pi) for solution in phase_solutions
        ]

        return [
            p_gates[0](a),
            p_gates[1](b),
            p_gates[2](c),
            sweep_abc,
            p_gates[3](b),
            p_gates[4](c),
            sweep_abc,
            p_gates[5](c),
            sweep_abc,
            p_gates[6](c),
            sweep_abc,
        ]
Beispiel #7
0
    def _decompose_(self, qubits):
        a, b = qubits

        yield common_gates.CNOT(a, b)
        yield common_gates.H(a)
        yield common_gates.CNOT(b, a)
        yield common_gates.S(a)**self._exponent
        yield common_gates.CNOT(b, a)
        yield common_gates.S(a)**-self._exponent
        yield common_gates.H(a)
        yield common_gates.CNOT(a, b)
Beispiel #8
0
 def _decompose_for_basis(
     self, index: int, bit_flip: int, theta: float, qubits: Sequence['cirq.Qid']
 ) -> Iterator[Union['cirq.ZPowGate', 'cirq.CXPowGate']]:
     if index == 0:
         return []
     largest_digit = self._num_qubits_() - (len(bin(index)) - 2)
     yield common_gates.rz(2 * theta)(qubits[largest_digit])
     _flip_bit = self._num_qubits_() - bit_flip - 1
     if _flip_bit < largest_digit:
         yield common_gates.CNOT(qubits[largest_digit], qubits[_flip_bit])
     elif _flip_bit > largest_digit:
         yield common_gates.CNOT(qubits[_flip_bit], qubits[largest_digit])
Beispiel #9
0
    def _decompose_(self, qubits):
        a, b = qubits

        yield common_gates.CNOT(a, b)
        yield common_gates.H(a)
        yield common_gates.CNOT(b, a)
        yield common_gates.ZPowGate(exponent=self._exponent / 2,
                                    global_shift=self.global_shift).on(a)
        yield common_gates.CNOT(b, a)
        yield common_gates.ZPowGate(exponent=-self._exponent / 2,
                                    global_shift=-self.global_shift).on(a)
        yield common_gates.H(a)
        yield common_gates.CNOT(a, b)
Beispiel #10
0
    def default_decompose(self, qubits):
        c, t1, t2 = qubits

        # Hacky magic: cross the non-adjacent edge.
        need_hop = hasattr(t1, 'is_adjacent') and not t1.is_adjacent(t2)

        cnot = common_gates.CNOT(t2, t1) if not need_hop else [
            common_gates.CNOT(t2, c),
            common_gates.CNOT(c, t1),
            common_gates.CNOT(t2, c),
            common_gates.CNOT(c, t1),
        ]
        yield cnot
        yield TOFFOLI(c, t1, t2)
        yield cnot
Beispiel #11
0
def xor_nonlocal_decompose(
        qubits: Iterable[raw_types.Qid],
        onto_qubit: 'cirq.Qid') -> Iterable[raw_types.Operation]:
    """Decomposition ignores connectivity."""
    for qubit in qubits:
        if qubit != onto_qubit:
            yield common_gates.CNOT(qubit, onto_qubit)
Beispiel #12
0
    def _decompose_(self, qubits):
        """An adjacency-respecting decomposition.

        0: ───p───@──────────────@───────@──────────@──────────
                  │              │       │          │
        1: ───p───X───@───p^-1───X───@───X──────@───X──────@───
                      │              │          │          │
        2: ───p───────X───p──────────X───p^-1───X───p^-1───X───

        where p = T**self._exponent
        """
        a, b, c = qubits

        # Hacky magic: avoid the non-adjacent edge.
        if hasattr(b, 'is_adjacent'):
            if not b.is_adjacent(a):
                b, c = c, b
            elif not b.is_adjacent(c):
                a, b = b, a

        p = common_gates.T**self._exponent
        sweep_abc = [common_gates.CNOT(a, b), common_gates.CNOT(b, c)]
        global_phase = 1j ** (2 * self.global_shift * self._exponent)
        global_phase = (
            complex(global_phase)
            if protocols.is_parameterized(global_phase) and global_phase.is_complex
            else global_phase
        )
        global_phase_operation = (
            [global_phase_op.global_phase_operation(global_phase)]
            if protocols.is_parameterized(global_phase) or abs(global_phase - 1.0) > 0
            else []
        )
        return global_phase_operation + [
            p(a),
            p(b),
            p(c),
            sweep_abc,
            p(b) ** -1,
            p(c),
            sweep_abc,
            p(c) ** -1,
            sweep_abc,
            p(c) ** -1,
            sweep_abc,
        ]
Beispiel #13
0
    def _decompose_(self, qubits):
        """An adjacency-respecting decomposition.

        0: ───p───@──────────────@───────@──────────@──────────
                  │              │       │          │
        1: ───p───X───@───p^-1───X───@───X──────@───X──────@───
                      │              │          │          │
        2: ───p───────X───p──────────X───p^-1───X───p^-1───X───

        where p = T**self._exponent
        """
        if protocols.is_parameterized(self):
            return NotImplemented

        a, b, c = qubits

        # Hacky magic: avoid the non-adjacent edge.
        if hasattr(b, 'is_adjacent'):
            if not b.is_adjacent(a):
                b, c = c, b
            elif not b.is_adjacent(c):
                a, b = b, a

        p = common_gates.T**self._exponent
        sweep_abc = [common_gates.CNOT(a, b), common_gates.CNOT(b, c)]

        return [
            p(a),
            p(b),
            p(c),
            sweep_abc,
            p(b)**-1,
            p(c),
            sweep_abc,
            p(c)**-1,
            sweep_abc,
            p(c)**-1,
            sweep_abc,
        ]
Beispiel #14
0
def assert_act_on_clifford_tableau_effect_matches_unitary(val: Any) -> None:
    """Checks that act_on with CliffordTableau generates stabilizers that
    stabilize the final state vector. Does not work with Operations or Gates
    expecting non-qubit Qids."""

    # pylint: disable=unused-variable
    __tracebackhide__ = True
    # pylint: enable=unused-variable

    num_qubits_val = protocols.num_qubits(val)

    if not protocols.has_unitary(val) or \
            protocols.qid_shape(val) != (2,) * num_qubits_val:
        return None

    qubits = LineQubit.range(protocols.num_qubits(val) * 2)
    qubit_map = {qubit: i for i, qubit in enumerate(qubits)}

    circuit = Circuit()
    for i in range(num_qubits_val):
        circuit.append([
            common_gates.H(qubits[i]),
            common_gates.CNOT(qubits[i], qubits[-i - 1])
        ])
    if hasattr(val, "on"):
        circuit.append(val.on(*qubits[:num_qubits_val]))
    else:
        circuit.append(val.with_qubits(*qubits[:num_qubits_val]))

    tableau = _final_clifford_tableau(circuit, qubit_map)
    if tableau is None:
        return None

    state_vector = np.reshape(final_state_vector(circuit, qubit_order=qubits),
                              protocols.qid_shape(qubits))

    assert all(
        state_vector_has_stabilizer(state_vector, stab)
        for stab in tableau.stabilizers()), (
            "act_on clifford tableau is not consistent with "
            "final_state_vector simulation.\n\nval: {!r}".format(val))
Beispiel #15
0
    def _decompose_inside_control(self,
                                  target1: raw_types.QubitId,
                                  control: raw_types.QubitId,
                                  target2: raw_types.QubitId
                                  ) -> op_tree.OP_TREE:
        """A decomposition assuming the control separates the targets.

        target1: ─@─X───────T──────@────────@─────────X───@─────X^-0.5─
                  │ │              │        │         │   │
        control: ─X─@─X─────@─T^-1─X─@─T────X─@─X^0.5─@─@─X─@──────────
                      │     │        │        │         │   │
        target2: ─────@─H─T─X─T──────X─T^-1───X─T^-1────X───X─H─S^-1───
        """
        a, b, c = target1, control, target2
        yield common_gates.CNOT(a, b)
        yield common_gates.CNOT(b, a)
        yield common_gates.CNOT(c, b)
        yield common_gates.H(c)
        yield common_gates.T(c)
        yield common_gates.CNOT(b, c)
        yield common_gates.T(a)
        yield common_gates.T(b)**-1
        yield common_gates.T(c)
        yield common_gates.CNOT(a, b)
        yield common_gates.CNOT(b, c)
        yield common_gates.T(b)
        yield common_gates.T(c)**-1
        yield common_gates.CNOT(a, b)
        yield common_gates.CNOT(b, c)
        yield common_gates.X(b)**0.5
        yield common_gates.T(c)**-1
        yield common_gates.CNOT(b, a)
        yield common_gates.CNOT(b, c)
        yield common_gates.CNOT(a, b)
        yield common_gates.CNOT(b, c)
        yield common_gates.H(c)
        yield common_gates.S(c)**-1
        yield common_gates.X(a)**-0.5
Beispiel #16
0
 def _decompose_(self, qubits):
     """See base class."""
     a, b = qubits
     yield common_gates.CNOT(a, b)
     yield common_gates.CNOT(b, a)**self._exponent
     yield common_gates.CNOT(a, b)
Beispiel #17
0
    def _decompose_inside_control(
        self, target1: 'cirq.Qid', control: 'cirq.Qid', target2: 'cirq.Qid'
    ) -> 'cirq.OP_TREE':
        """A decomposition assuming the control separates the targets.

        target1: ─@─X───────T──────@────────@─────────X───@─────X^-0.5─
                  │ │              │        │         │   │
        control: ─X─@─X─────@─T^-1─X─@─T────X─@─X^0.5─@─@─X─@──────────
                      │     │        │        │         │   │
        target2: ─────@─H─T─X─T──────X─T^-1───X─T^-1────X───X─H─S^-1───
        """
        a, b, c = target1, control, target2
        yield common_gates.CNOT(a, b)
        yield common_gates.CNOT(b, a)
        yield common_gates.CNOT(c, b)
        yield common_gates.H(c)
        yield common_gates.T(c)
        yield common_gates.CNOT(b, c)
        yield common_gates.T(a)
        yield common_gates.T(b) ** -1
        yield common_gates.T(c)
        yield common_gates.CNOT(a, b)
        yield common_gates.CNOT(b, c)
        yield common_gates.T(b)
        yield common_gates.T(c) ** -1
        yield common_gates.CNOT(a, b)
        yield common_gates.CNOT(b, c)
        yield pauli_gates.X(b) ** 0.5
        yield common_gates.T(c) ** -1
        yield common_gates.CNOT(b, a)
        yield common_gates.CNOT(b, c)
        yield common_gates.CNOT(a, b)
        yield common_gates.CNOT(b, c)
        yield common_gates.H(c)
        yield common_gates.S(c) ** -1
        yield pauli_gates.X(a) ** -0.5
Beispiel #18
0
def assert_all_implemented_act_on_effects_match_unitary(
        val: Any,
        assert_tableau_implemented: bool = False,
        assert_ch_form_implemented: bool = False) -> None:
    """Uses val's effect on final_state_vector to check act_on(val)'s behavior.

    Checks that act_on with CliffordTableau or StabilizerStateCHForm behaves
    consistently with act_on through final state vector. Does not work with
    Operations or Gates expecting non-qubit Qids. If either of the
    assert_*_implmented args is true, fails if the corresponding method is not
    implemented for the test circuit.

    Args:
        val: A gate or operation that may be an input to protocols.act_on.
        assert_tableau_implemented: asserts that protocols.act_on() works with
          val and ActOnCliffordTableauArgs inputs.
        assert_ch_form_implemented: asserts that protocols.act_on() works with
          val and ActOnStabilizerStateChFormArgs inputs.
    """

    # pylint: disable=unused-variable
    __tracebackhide__ = True
    # pylint: enable=unused-variable

    num_qubits_val = protocols.num_qubits(val)

    if (protocols.is_parameterized(val) or not protocols.has_unitary(val)
            or protocols.qid_shape(val) != (2, ) * num_qubits_val):
        if assert_tableau_implemented or assert_ch_form_implemented:
            assert False, ("Could not assert if any act_on methods were "
                           "implemented. Operating on qudits or with a "
                           "non-unitary or parameterized operation is "
                           "unsupported.\n\nval: {!r}".format(val))
        return None

    qubits = LineQubit.range(protocols.num_qubits(val) * 2)
    qubit_map = {qubit: i for i, qubit in enumerate(qubits)}

    circuit = Circuit()
    for i in range(num_qubits_val):
        circuit.append([
            common_gates.H(qubits[i]),
            common_gates.CNOT(qubits[i], qubits[-i - 1])
        ])
    if hasattr(val, "on"):
        circuit.append(val.on(*qubits[:num_qubits_val]))
    else:
        circuit.append(val.with_qubits(*qubits[:num_qubits_val]))

    state_vector = np.reshape(final_state_vector(circuit, qubit_order=qubits),
                              protocols.qid_shape(qubits))

    tableau = _final_clifford_tableau(circuit, qubit_map)
    if tableau is None:
        assert (
            not assert_tableau_implemented
        ), "Failed to generate final tableau for the test circuit.\n\nval: {!r}".format(
            val)
    else:
        assert all(
            state_vector_has_stabilizer(state_vector, stab)
            for stab in tableau.stabilizers()), (
                "act_on clifford tableau is not consistent with "
                "final_state_vector simulation.\n\nval: {!r}".format(val))

    stabilizer_ch_form = _final_stabilizer_state_ch_form(circuit, qubit_map)
    if stabilizer_ch_form is None:
        assert not assert_ch_form_implemented, ("Failed to generate final "
                                                "stabilizer state CH form "
                                                "for the test circuit."
                                                "\n\nval: {!r}".format(val))
    else:
        np.testing.assert_allclose(
            np.reshape(stabilizer_ch_form.state_vector(),
                       protocols.qid_shape(qubits)),
            state_vector,
            atol=1e-07,
            err_msg=
            f"stabilizer_ch_form.state_vector disagrees with state_vector for {val!r}",
            verbose=True,
        )