def test_invalid_decompose(self, operable_mock_device_2_wires):
        """Test that an error is raised if the device
        does not support an operation arising from a
        decomposition."""
        class DummyOp(qml.operation.Operation):
            """Dummy operation"""

            num_params = 0
            num_wires = 1
            par_domain = "R"
            grad_method = "A"

            @staticmethod
            def decomposition(wires=None):
                ops = [qml.Hadamard(wires=wires)]
                return ops

        queue = [
            qml.Rot(0, 1, 2, wires=0),
            DummyOp(wires=0),
            qml.RX(6, wires=0)
        ]

        with pytest.raises(qml.DeviceError,
                           match="DummyOp not supported on device"):
            decompose_queue(queue, operable_mock_device_2_wires)
    def test_decompose_queue(self, operable_mock_device_2_wires):
        """Test that decompose queue works correctly
        when an operation exists that can be decomposed"""

        queue = [
            qml.Rot(0, 1, 2, wires=0),
            qml.U3(3, 4, 5, wires=0),
            qml.RX(6, wires=0)
        ]

        res = decompose_queue(queue, operable_mock_device_2_wires)

        assert len(res) == 5

        assert res[0].name == "Rot"
        assert res[0].parameters == [0, 1, 2]

        assert res[1].name == "Rot"
        assert res[1].parameters == [5, 3, -5]

        assert res[2].name == "PhaseShift"
        assert res[2].parameters == [5]

        assert res[3].name == "PhaseShift"
        assert res[3].parameters == [4]

        assert res[4].name == "RX"
        assert res[4].parameters == [6]
Esempio n. 3
0
    def test_decompose_queue_recursive(self, operable_mock_device_2_wires_with_inverses):
        """Test that decompose queue works correctly
        when an operation exists that can be decomposed"""

        queue = [qml.CRY(1, wires=[0, 1]), qml.U3(3, 4, 5, wires=0)]

        res = decompose_queue(queue, operable_mock_device_2_wires_with_inverses)

        assert len(res) == 9

        assert res[0].name == "RY"
        assert res[0].parameters == [0.5]

        assert res[1].name == "CNOT"

        assert res[2].name == "RY"
        assert res[2].parameters == [-0.5]

        assert res[3].name == "CNOT"

        assert res[4].name == "RZ"
        assert res[4].parameters == [5]

        assert res[5].name == "RY"
        assert res[5].parameters == [3]

        assert res[6].name == "RZ"
        assert res[6].parameters == [-5]

        assert res[7].name == "PhaseShift"
        assert res[7].parameters == [5]

        assert res[8].name == "PhaseShift"
        assert res[8].parameters == [4]
Esempio n. 4
0
    def test_no_decomposition(self, operable_mock_device_2_wires):
        """Test that decompose queue makes no changes
        if there are no operations to be decomposed"""

        queue = [qml.Rot(0, 1, 2, wires=0), qml.CNOT(wires=[0, 1]), qml.RX(6, wires=0)]

        res = decompose_queue(queue, operable_mock_device_2_wires)
        assert res == queue
    def test_decompose_queue_inv(self,
                                 operable_mock_device_2_wires_with_inverses):
        """Test that decompose queue works correctly
        when an operation exists that can be decomposed"""

        queue = [
            qml.Rot(0, 1, 2, wires=0).inv(),
            qml.U3(3, 4, 5, wires=0).inv(),
            qml.RX(6, wires=0).inv(),
        ]

        res = decompose_queue(queue,
                              operable_mock_device_2_wires_with_inverses)

        assert len(res) == 9

        assert res[0].name == "RZ.inv"
        assert res[0].parameters == [2]

        assert res[1].name == "RY.inv"
        assert res[1].parameters == [1]

        assert res[2].name == "RZ.inv"
        assert res[2].parameters == [0]

        assert res[3].name == "PhaseShift.inv"
        assert res[3].parameters == [4]

        assert res[4].name == "PhaseShift.inv"
        assert res[4].parameters == [5]

        assert res[5].name == "RZ.inv"
        assert res[5].parameters == [-5]

        assert res[6].name == "RY.inv"
        assert res[6].parameters == [3]

        assert res[7].name == "RZ.inv"
        assert res[7].parameters == [5]

        assert res[8].name == "RX.inv"
        assert res[8].parameters == [6]
Esempio n. 6
0
    def to_openqasm(self, rotations=True):
        """Serialize the circuit as an OpenQASM 2.0 program.

        Only operations are serialized; all measurements
        are assumed to take place in the computational basis.

        .. note::

            The serialized OpenQASM program assumes that gate definitions
            in ``qelib1.inc`` are available.

        Args:
            rotations (bool): in addition to serializing user-specified
                operations, also include the gates that diagonalize the
                measured wires such that they are in the eigenbasis of the circuit observables.

        Returns:
            str: OpenQASM serialization of the circuit
        """
        # We import decompose_queue here to avoid a circular import
        from pennylane.qnodes.base import decompose_queue  # pylint: disable=import-outside-toplevel

        class QASMSerializerDevice:
            """A mock device, to be used when performing the decomposition.
            The short_name is used in error messages if the decomposition fails.
            """

            # pylint: disable=too-few-public-methods
            short_name = "QASM serializer"
            supports_operation = staticmethod(lambda x: x in OPENQASM_GATES)

        # add the QASM headers
        qasm_str = "OPENQASM 2.0;\n"
        qasm_str += 'include "qelib1.inc";\n'

        if self.num_wires == 0:
            # empty circuit
            return qasm_str

        # create the quantum and classical registers
        qasm_str += "qreg q[{}];\n".format(self.num_wires)
        qasm_str += "creg c[{}];\n".format(self.num_wires)

        # get the user applied circuit operations
        operations = self.operations

        if rotations:
            # if requested, append diagonalizing gates corresponding
            # to circuit observables
            operations += self.diagonalizing_gates

        # decompose the queue
        decomposed_ops = decompose_queue(operations, QASMSerializerDevice)

        # create the QASM code representing the operations
        for op in decomposed_ops:
            gate = OPENQASM_GATES[op.name]
            wires = ",".join(["q[{}]".format(w) for w in op.wires])
            params = ""

            if op.num_params > 0:
                # If the operation takes parameters, construct a string
                # with parameter values.
                params = "(" + ",".join([str(p) for p in op.parameters]) + ")"

            qasm_str += "{name}{params} {wires};\n".format(name=gate, params=params, wires=wires)

        # apply computational basis measurements to each quantum register
        # NOTE: This is not strictly necessary, we could inspect self.observables,
        # and then only measure wires which are requested by the user. However,
        # some devices which consume QASM require all registers be measured, so
        # measure all wires to be safe.
        for wire in range(self.num_wires):
            qasm_str += "measure q[{wire}] -> c[{wire}];\n".format(wire=wire)

        return qasm_str