def test_evaluate_diag_metric_tensor(self, tol):
        """Test that a diagonal metric tensor evaluates correctly"""
        dev = qml.device("default.qubit", wires=2)

        def circuit(a, b, c):
            qml.RX(a, wires=0)
            qml.RY(b, wires=0)
            qml.CNOT(wires=[0, 1])
            qml.PhaseShift(c, wires=1)
            return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliX(1))

        circuit = QNode(circuit, dev)

        a = 0.432
        b = 0.12
        c = -0.432

        # evaluate metric tensor
        g = circuit.metric_tensor((a, b, c))

        # check that the metric tensor is correct
        expected = (np.array([
            1,
            np.cos(a)**2,
            (3 - 2 * np.cos(a)**2 * np.cos(2 * b) - np.cos(2 * a)) / 4
        ]) / 4)
        assert np.allclose(g, np.diag(expected), atol=tol, rtol=0)
    def test_construct_subcircuit(self):
        """Test correct subcircuits constructed"""
        dev = qml.device("default.qubit", wires=2)

        def circuit(a, b, c):
            qml.RX(a, wires=0)
            qml.RY(b, wires=0)
            qml.CNOT(wires=[0, 1])
            qml.PhaseShift(c, wires=1)
            return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliX(1))

        circuit = QNode(circuit, dev)
        circuit.metric_tensor([1, 1, 1], only_construct=True)
        res = circuit._metric_tensor_subcircuits

        # first parameter subcircuit
        assert len(res[(0, )]["queue"]) == 0
        assert res[(0, )]["scale"] == [-0.5]
        assert isinstance(res[(0, )]["observable"][0], qml.PauliX)

        # second parameter subcircuit
        assert len(res[(1, )]["queue"]) == 1
        assert res[(1, )]["scale"] == [-0.5]
        assert isinstance(res[(1, )]["queue"][0], qml.RX)
        assert isinstance(res[(1, )]["observable"][0], qml.PauliY)

        # third parameter subcircuit
        assert len(res[(2, )]["queue"]) == 3
        assert res[(2, )]["scale"] == [1]
        assert isinstance(res[(2, )]["queue"][0], qml.RX)
        assert isinstance(res[(2, )]["queue"][1], qml.RY)
        assert isinstance(res[(2, )]["queue"][2], qml.CNOT)
        assert isinstance(res[(2, )]["observable"][0], qml.Hermitian)
        assert np.all(res[(
            2, )]["observable"][0].params[0] == qml.PhaseShift.generator[0])
    def test_evaluate_subcircuits(self, tol):
        """Test subcircuits evaluate correctly"""
        dev = qml.device("default.qubit", wires=2)

        def circuit(a, b, c):
            qml.RX(a, wires=0)
            qml.RY(b, wires=0)
            qml.CNOT(wires=[0, 1])
            qml.PhaseShift(c, wires=1)
            return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliX(1))

        circuit = QNode(circuit, dev)

        a = 0.432
        b = 0.12
        c = -0.432

        # evaluate subcircuits
        circuit.metric_tensor((a, b, c))

        # first parameter subcircuit
        res = circuit._metric_tensor_subcircuits[(0, )]["result"]
        expected = 0.25
        assert np.allclose(res, expected, atol=tol, rtol=0)

        # second parameter subcircuit
        res = circuit._metric_tensor_subcircuits[(1, )]["result"]
        expected = np.cos(a)**2 / 4
        assert np.allclose(res, expected, atol=tol, rtol=0)

        # third parameter subcircuit
        res = circuit._metric_tensor_subcircuits[(2, )]["result"]
        expected = (3 - 2 * np.cos(a)**2 * np.cos(2 * b) - np.cos(2 * a)) / 16
        assert np.allclose(res, expected, atol=tol, rtol=0)
示例#4
0
def mock_qnode(mock_device):
    """Provides a circuit for the subsequent tests of the operation queue"""
    def circuit(x):
        qml.RX(x, wires=[0])
        qml.CNOT(wires=[0, 1])
        qml.RY(0.4, wires=[0])
        qml.RZ(-0.2, wires=[1])
        return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliZ(1))

    node = QNode(circuit, mock_device)
    node._construct([1.0], {})
    return node
示例#5
0
    def test_evaluate(self, x, y, tol):
        """Tests correct evaluation"""
        dev = qml.device("default.qubit", wires=2)

        def circuit(x, y):
            qml.RX(x, wires=[0])
            qml.RY(y, wires=[1])
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0) @ qml.PauliX(1))

        node = QNode(circuit, dev)
        res = node.evaluate([x, y], {})
        expected = np.sin(y) * np.cos(x)
        assert np.allclose(res, expected, atol=tol, rtol=0)
示例#6
0
    def test_print_applied(self, mock_device):
        """Test that printing applied gates works correctly"""

        H = np.array([[0, 1], [1, 0]])

        def circuit(x):
            qml.RX(x, wires=[0])
            qml.CNOT(wires=[0, 1])
            qml.RY(0.4, wires=[0])
            qml.RZ(-0.2, wires=[1])
            return qml.expval(qml.PauliX(0)), qml.var(qml.Hermitian(H, wires=1))

        expected_qnode_print = textwrap.dedent(
            """\
            Operations
            ==========
            RX({x}, wires=[0])
            CNOT(wires=[0, 1])
            RY(0.4, wires=[0])
            RZ(-0.2, wires=[1])

            Observables
            ===========
            expval(PauliX(wires=[0]))
            var(Hermitian([[0 1]
             [1 0]], wires=[1]))"""
        )

        node = QNode(circuit, mock_device)

        # test before construction
        f = io.StringIO()

        with contextlib.redirect_stdout(f):
            node.print_applied()
            out = f.getvalue().strip()

        assert out == "QNode has not yet been executed."

        # construct QNode
        f = io.StringIO()
        node._set_variables([0.1], {})
        node._construct([0.1], {})

        with contextlib.redirect_stdout(f):
            node.print_applied()
            out = f.getvalue().strip()

        assert out == expected_qnode_print.format(x=0.1)
示例#7
0
    def test_calling_with_kwargs(self, operable_mock_device_2_wires):
        """Various quantum func calling syntax errors."""
        def circuit(x, y=0.2, *, m=0.3, n, **kwargs):
            circuit.in_args = (x, y, m, n)
            return qml.expval(qml.PauliZ(0))

        node = QNode(circuit, operable_mock_device_2_wires, mutable=True)

        with pytest.raises(QuantumFunctionError,
                           match="parameter 'x' given twice"):
            node(0.1, x=1.1)
        with pytest.raises(
                QuantumFunctionError,
                match="'kwargs' cannot be given using the keyword syntax"):
            node(kwargs=1)
        with pytest.raises(QuantumFunctionError,
                           match="takes 2 positional parameters, 3 given"):
            node(0.1, 0.2, 100, n=0.4)
        with pytest.raises(QuantumFunctionError,
                           match="positional parameter 'x' missing"):
            node(n=0.4)
        with pytest.raises(QuantumFunctionError,
                           match="keyword-only parameter 'n' missing"):
            node(0.1)

        # valid calls
        node(x=0.1, n=0.4)
        assert circuit.in_args[2:] == (0.3, 0.4)  # first two are Variables
        node(0.1, n=0.4)
        assert circuit.in_args[2:] == (0.3, 0.4)
示例#8
0
    def test_calling_errors(self, operable_mock_device_2_wires):
        """Good quantum func calling syntax errors (auxiliary-equals-parameters-with-default syntax)."""
        def circuit(x, y=0.2, *args, z=0.3):
            circuit.in_args = (x, y, z)
            return qml.expval(qml.PauliZ(0))

        node = QNode(circuit, operable_mock_device_2_wires, mutable=True)

        with pytest.raises(
                QuantumFunctionError,
                match="'x' cannot be given using the keyword syntax"):
            node(0.1, x=1.1)
        with pytest.raises(QuantumFunctionError,
                           match="Unknown quantum function parameter 'foo'"):
            node(foo=1)
        with pytest.raises(
                QuantumFunctionError,
                match="'args' cannot be given using the keyword syntax"):
            node(args=1)
        with pytest.raises(
                TypeError,
                match="missing 1 required positional argument: 'x'"):
            node(z=0.4)

        # valid calls
        node(0.1)
        assert circuit.in_args[1:] == (0.2, 0.3)  # first is a Variable
        node(0.1, y=1.2)
        assert circuit.in_args[1:] == (1.2, 0.3)
        node(0.1, z=1.3, y=1.2)
        assert circuit.in_args[1:] == (1.2, 1.3)
示例#9
0
    def test_kwarg_as_wire_argument(self, operable_mock_device_2_wires):
        """Error: trying to use a keyword-only parameter as a wire argument in an immutable circuit."""
        def circuit(*, x=None):
            qml.RX(0.5, wires=[x])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

        node = QNode(circuit, operable_mock_device_2_wires, mutable=False)
        with pytest.raises(TypeError, match="Wires must be integers"):
            node(x=1)
示例#10
0
    def test_bad_wire_argument(self, operable_mock_device_2_wires):
        """Error: wire arguments must be intergers."""
        def circuit(x):
            qml.RX(x, wires=[0.5])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(2))

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(TypeError, match="Wires must be integers"):
            node(1)
示例#11
0
    def test_keywordargs_used(self, qubit_device_1_wire, tol):
        """Tests that qnodes use keyword arguments."""
        def circuit(w, x=None):
            qml.RX(x, wires=[0])
            return qml.expval(qml.PauliZ(0))

        node = QNode(circuit, qubit_device_1_wire)
        c = node(1.0, x=np.pi)
        assert c == pytest.approx(-1.0, abs=tol)
示例#12
0
    def test_arg_as_wire_argument(self, operable_mock_device_2_wires):
        """Error: trying to use a differentiable parameter as a wire argument."""
        def circuit(x):
            qml.RX(0.5, wires=[x])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(2))

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(TypeError, match="Wires must be integers"):
            node(1)
示例#13
0
    def test_arraylike_args_used(self, qubit_device_2_wires, tol):
        """Tests that qnodes use array-like positional arguments."""
        def circuit(x):
            qml.RX(x[0], wires=[0])
            qml.RX(x[1], wires=[1])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

        node = QNode(circuit, qubit_device_2_wires)
        c = node([np.pi, np.pi])
        assert c == pytest.approx([-1.0, -1.0], abs=tol)
示例#14
0
    def test_observable_on_nonexistant_wire(self, operable_mock_device_2_wires):
        """Error: an observable is measured on a non-existant wire."""

        def circuit(x):
            qml.RX(x, wires=[0])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(2))

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(QuantumFunctionError, match="applied to invalid wire"):
            node(0.5)
示例#15
0
    def test_calling_bad_errors(self, operable_mock_device_2_wires):
        """Confusing quantum func calling errors and bugs (auxiliary-equals-parameters-with-default syntax)."""
        def circuit(x=0.1):
            return qml.expval(qml.PauliZ(0))

        node = QNode(circuit, operable_mock_device_2_wires)

        with pytest.raises(TypeError,
                           match="got multiple values for argument 'x'"):
            node(0.3)  # default arg given positionally, wrong error message
示例#16
0
    def test_simple_valid_call(self, operable_mock_device_2_wires):
        """Old QNode gives an error here, "got multiple values for argument 'x'"
        """
        def circuit(x=0):
            qml.RX(x, wires=[0])
            return qml.expval(qml.PauliZ(0))

        node = QNode(circuit, operable_mock_device_2_wires)
        node(0.3)
        assert node.ops[0].parameters[0] == 0.3
示例#17
0
    def test_return_of_non_observable(self, operable_mock_device_2_wires):
        """Error: qfunc returns something besides observables."""
        def circuit(x):
            qml.RX(x, wires=[0])
            return qml.expval(qml.PauliZ(wires=0)), 0.3

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(QuantumFunctionError,
                           match="A quantum function must return either"):
            node(0.5)
示例#18
0
    def test_keywordargs_with_kwargs(self, qubit_device_1_wire, tol):
        """Tests that nothing happens if unknown keyword arg passed with
        qnodes accepting **kwargs."""
        def circuit(w, x=None, **kwargs):
            qml.RX(x, wires=[0])
            return qml.expval(qml.PauliZ(0))

        node = QNode(circuit, qubit_device_1_wire)
        c = node(1.0, x=np.pi, y=10)
        assert c == pytest.approx(-1.0, abs=tol)
示例#19
0
    def test_multiple_keywordargs_used(self, qubit_device_2_wires, tol):
        """Tests that qnodes can use multiple keyword-only arguments."""
        def circuit(w, *, x=None, y=None):
            qml.RX(x, wires=[0])
            qml.RX(y, wires=[1])
            qml.RZ(w, wires=[0])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

        node = QNode(circuit, qubit_device_2_wires)
        c = node(1.0, x=np.pi, y=np.pi / 2)
        assert c == pytest.approx([-1.0, 0.0], abs=tol)
示例#20
0
    def test_observable_order_violated(self, operable_mock_device_2_wires):
        """Error: qfunc does not return all observables in the correct order."""
        def circuit(x):
            qml.RX(x, wires=[0])
            ex = qml.expval(qml.PauliZ(wires=1))
            return qml.expval(qml.PauliZ(wires=0)), ex

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(QuantumFunctionError,
                           match="All measured observables must be returned"):
            node(0.5)
示例#21
0
    def test_invisible_operations(self, operable_mock_device_2_wires):
        """Error: an operation does not affect the measurements."""

        def circuit(x):
            qml.RX(x, wires=[0])
            qml.RX(x, wires=[1])  # on its own component in the circuit graph
            return qml.expval(qml.PauliZ(0))

        node = QNode(circuit, operable_mock_device_2_wires, properties={"vis_check": True})
        with pytest.raises(QuantumFunctionError, match="cannot affect the output"):
            node(0.5)
示例#22
0
    def test_cv_operations_on_qubit_device(self, operable_mock_device_2_wires):
        """Error: cannot use CV operations on a qubit device."""
        def circuit(x):
            qml.Displacement(0.5, 0, wires=[0])
            return qml.expval(qml.X(0))

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(
                QuantumFunctionError,
                match="a qubit device; CV operations are not allowed"):
            node(0.5)
示例#23
0
    def test_arraylike_keywordargs_used(self, qubit_device_2_wires, tol):
        """Tests that qnodes use array-like keyword-only arguments."""
        def circuit(w, *, x=None):
            qml.RX(x[0], wires=[0])
            qml.RX(x[1], wires=[1])
            qml.RZ(w, wires=[0])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

        node = QNode(circuit, qubit_device_2_wires)
        c = node(1.0, x=[np.pi, np.pi / 2])
        assert c == pytest.approx([-1.0, 0.0], abs=tol)
示例#24
0
    def test_multiple_measurements_on_same_wire(self, operable_mock_device_2_wires):
        """Error: the same wire is measured multiple times."""

        def circuit(x):
            qml.RX(x, wires=[0])
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)), qml.expval(qml.PauliX(0))

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(QuantumFunctionError, match="can only be measured once"):
            node(0.5)
示例#25
0
    def test_unused_positional_parameter(self, operable_mock_device_2_wires):
        """Error: a positional parameter is not used in the circuit."""
        def circuit(a, x):
            qml.RX(a, wires=[0])
            return qml.expval(qml.PauliZ(0))

        node = QNode(circuit,
                     operable_mock_device_2_wires,
                     properties={"par_check": True})
        with pytest.raises(QuantumFunctionError,
                           match="The positional parameters"):
            node(1.0, 2.0)
示例#26
0
    def test_operations_after_observables(self, operable_mock_device_2_wires):
        """Error: qfunc contains operations after observables."""
        def circuit(x):
            qml.RX(x, wires=[0])
            ex = qml.expval(qml.PauliZ(wires=1))
            qml.RY(0.5, wires=[0])
            return qml.expval(qml.PauliZ(wires=0))

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(QuantumFunctionError,
                           match="gates must precede measured"):
            node(0.5)
示例#27
0
    def test_observable_with_no_measurement_type(self,
                                                 operable_mock_device_2_wires):
        """Error: observable lacks the measurement type."""
        def circuit(x):
            qml.RX(x, wires=[0])
            return qml.expval(qml.PauliZ(wires=0)), qml.PauliZ(wires=1)

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(
                QuantumFunctionError,
                match="does not have the measurement type specified"):
            node(0.5)
示例#28
0
    def test_keywordarg_updated_in_multiple_calls(self, qubit_device_2_wires,
                                                  tol):
        """Tests that qnodes update keyword arguments in consecutive calls."""
        def circuit(w, x=None):
            qml.RX(w, wires=[0])
            qml.RX(x, wires=[1])
            return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

        node = QNode(circuit, qubit_device_2_wires)
        c1 = node(0.1, x=0.0)
        c2 = node(0.1, x=np.pi)
        assert c1[1] != c2[1]
示例#29
0
    def test_mixing_of_cv_and_qubit_operations(self,
                                               operable_mock_device_2_wires):
        """Error: qubit and CV operations are mixed in the same qfunc."""
        def circuit(x):
            qml.RX(x, wires=[0])
            qml.Displacement(0.5, 0, wires=[0])
            return qml.expval(qml.PauliZ(0))

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(
                QuantumFunctionError,
                match="Continuous and discrete operations are not allowed"):
            node(0.5)
示例#30
0
    def test_qubit_operations_on_CV_device(self, operable_mock_device_2_wires, monkeypatch):
        """Error: cannot use qubit operations on a CV device."""
        monkeypatch.setattr(operable_mock_device_2_wires, "capabilities", lambda: {"model": "cv"})

        def circuit(x):
            qml.RX(0.5, wires=[0])
            return qml.expval(qml.PauliZ(0))

        node = QNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(
            QuantumFunctionError, match="a CV device; qubit operations are not allowed"
        ):
            node(0.5)