def test_regular_keyword_arguments(self, mock_device):
        """Test that regular keyword arguments are properly converted to Variable instances."""
        def circuit(*, a=1, b=2, c=3, d=4):
            qml.RX(a, wires=[0])
            qml.RY(b, wires=[0])
            qml.RZ(c, wires=[0])
            qml.RZ(d, wires=[0])

            return qml.expval(qml.PauliX(0))

        node = BaseQNode(circuit, mock_device)
        arg_vars, kwarg_vars = node._make_variables([], {"b": 3})

        expected_kwarg_vars = {
            "a": [Variable(0, "a", is_kwarg=True)],
            "b": [Variable(0, "b", is_kwarg=True)],
            "c": [Variable(0, "c", is_kwarg=True)],
            "d": [Variable(0, "d", is_kwarg=True)],
        }

        assert not arg_vars

        for expected_key in expected_kwarg_vars:
            for var, expected in zip(
                    qml.utils._flatten(kwarg_vars[expected_key]),
                    qml.utils._flatten(expected_kwarg_vars[expected_key]),
            ):
                assert var == expected
    def test_variadic_arguments(self, mock_device):
        """Test that variadic arguments are properly converted to Variable instances."""
        def circuit(a, *b):
            qml.RX(a, wires=[0])
            qml.RX(b[0], wires=[0])
            qml.RX(b[1][1], wires=[0])
            qml.RX(b[2], wires=[0])

            return qml.expval(qml.PauliX(0))

        node = BaseQNode(circuit, mock_device)
        arg_vars, kwarg_vars = node._make_variables(
            [0.1, 0.2, np.array([0, 1, 2, 3]), 0.5], {})

        expected_arg_vars = [
            Variable(0, "a"),
            Variable(1, "b[0]"),
            Variable(2, "b[1][0]"),
            Variable(3, "b[1][1]"),
            Variable(4, "b[1][2]"),
            Variable(5, "b[1][3]"),
            Variable(6, "b[2]"),
        ]

        assert not kwarg_vars

        for var, expected in zip(qml.utils._flatten(arg_vars),
                                 expected_arg_vars):
            assert var == expected
    def test_regular_arguments(self, mock_device):
        """Test that regular arguments are properly converted to Variable instances."""
        def circuit(a, b, c, d):
            qml.RX(a, wires=[0])
            qml.RY(b, wires=[0])
            qml.RZ(c, wires=[0])
            qml.RZ(d, wires=[0])

            return qml.expval(qml.PauliX(0))

        node = BaseQNode(circuit, mock_device)
        arg_vars, kwarg_vars = node._make_variables([1.0, 2.0, 3.0, 4.0], {})

        expected_arg_vars = [
            Variable(0, "a"),
            Variable(1, "b"),
            Variable(2, "c"),
            Variable(3, "d"),
        ]

        for var, expected in zip(qml.utils._flatten(arg_vars),
                                 expected_arg_vars):
            assert var == expected

        assert not kwarg_vars
    def test_array_arguments(self, mock_device):
        """Test that array arguments are properly converted to Variable instances."""
        def circuit(weights):
            qml.RX(weights[0, 0], wires=[0])
            qml.RY(weights[0, 1], wires=[0])
            qml.RZ(weights[1, 0], wires=[0])
            qml.RZ(weights[1, 1], wires=[0])

            return qml.expval(qml.PauliX(0))

        node = BaseQNode(circuit, mock_device)

        weights = np.array([[1, 2], [3, 4]])
        arg_vars, kwarg_vars = node._make_variables([weights], {})

        expected_arg_vars = [
            Variable(0, "weights[0,0]"),
            Variable(1, "weights[0,1]"),
            Variable(2, "weights[1,0]"),
            Variable(3, "weights[1,1]"),
        ]

        for var, expected in zip(qml.utils._flatten(arg_vars),
                                 expected_arg_vars):
            assert var == expected

        assert not kwarg_vars
    def test_prune_tensors_construct(self, mock_device):
        """Test that the tensors are pruned in construct."""
        def circuit(x):
            return qml.expval(qml.PauliX(0) @ qml.Identity(1))

        qnode = BaseQNode(circuit, mock_device)
        qnode._construct([1.0], {})

        assert qnode.ops[0].name == "PauliX"
        assert len(qnode.ops[0].wires) == 1
        assert qnode.ops[0].wires[0] == 0
    def test_prune_tensors(self, mock_device):
        """Test that the _prune_tensors auxiliary method prunes correct for
        a single Identity in the Tensor."""
        px = qml.PauliX(1)
        obs = qml.Identity(0) @ px

        def circuit(x):
            return qml.expval(obs)

        qnode = BaseQNode(circuit, mock_device)

        assert qnode._prune_tensors(obs) == px
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 = BaseQNode(circuit, mock_device)
    node._construct([1.0], {})
    return node
    def test_prune_tensors_no_pruning_took_place(self, mock_device):
        """Test that the _prune_tensors auxiliary method returns
        the original tensor if no observables were pruned."""
        px = qml.PauliX(1)
        obs = px

        def circuit(x):
            return qml.expval(obs)

        qnode = BaseQNode(circuit, mock_device)

        assert qnode._prune_tensors(obs) == px
    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 = BaseQNode(circuit, dev)
        res = node.evaluate([x, y], {})
        expected = np.sin(y) * np.cos(x)
        assert np.allclose(res, expected, atol=tol, rtol=0)
Beispiel #10
0
    def test_print_applied_with_probs(self, mock_device):
        """Test that printing applied gates works correctly when probs are returned"""

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

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

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

            Observables
            ===========
            probs(wires=[0])
            var(Hermitian(array([[0, 1],
                   [1, 0]]), wires=[1]))"""
        )

        node = BaseQNode(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)
    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 = BaseQNode(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)
    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 = BaseQNode(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)
    def test_device_executions(self):
        """Test the number of times a qubit device is executed over a QNode's
        lifetime is tracked by `num_executions`"""

        dev_1 = qml.device("default.qubit", wires=2)

        def circuit_1(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_1 = BaseQNode(circuit_1, dev_1)
        num_evals_1 = 10

        for _ in range(num_evals_1):
            node_1(0.432, 0.12)
        assert dev_1.num_executions == num_evals_1

        # test a second instance of a default qubit device
        dev_2 = qml.device("default.qubit", wires=2)

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

        node_2 = BaseQNode(circuit_2, dev_2)
        num_evals_2 = 5

        for _ in range(num_evals_2):
            node_2(0.432, 0.12)
        assert dev_2.num_executions == num_evals_2

        # test a new circuit on an existing instance of a qubit device
        def circuit_3(x, y):
            qml.RY(y, wires=[1])
            qml.CNOT(wires=[0, 1])
            return qml.expval(qml.PauliZ(0) @ qml.PauliX(1))

        node_3 = BaseQNode(circuit_3, dev_1)
        num_evals_3 = 7

        for _ in range(num_evals_3):
            node_3(0.432, 0.12)
        assert dev_1.num_executions == num_evals_1 + num_evals_3
    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 = BaseQNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(TypeError, match="Wires must be integers"):
            node(1)
    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 = BaseQNode(circuit, operable_mock_device_2_wires, mutable=False)
        with pytest.raises(TypeError, match="Wires must be integers"):
            node(x=1)
    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 = BaseQNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(TypeError, match="Wires must be integers"):
            node(1)
    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 = BaseQNode(circuit, qubit_device_1_wire)
        c = node(1.0, x=np.pi)
        assert c == pytest.approx(-1.0, abs=tol)
    def test_operation_appending(self, mock_device):
        """Tests that operations are correctly appended."""
        CNOT = qml.CNOT(wires=[0, 1])

        def circuit(x):
            qml.QueuingContext.append_operator(CNOT)
            qml.RY(0.4, wires=[0])
            qml.RZ(-0.2, wires=[1])

            return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliZ(1))

        qnode = BaseQNode(circuit, mock_device)
        qnode._construct([1.0], {})

        assert qnode.ops[0].name == "CNOT"
        assert qnode.ops[1].name == "RY"
        assert qnode.ops[2].name == "RZ"
        assert qnode.ops[3].name == "PauliX"
    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 = BaseQNode(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
    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 = BaseQNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(QuantumFunctionError,
                           match="A quantum function must return either"):
            node(0.5)
    def test_simple_valid_call(self, operable_mock_device_2_wires):
        """BaseQNode 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 = BaseQNode(circuit, operable_mock_device_2_wires)
        node(0.3)
        assert node.ops[0].parameters[0] == 0.3
Beispiel #22
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 = BaseQNode(circuit, operable_mock_device_2_wires, properties={"par_check": True})
        with pytest.raises(QuantumFunctionError, match="The positional parameters"):
            node(1.0, 2.0)
Beispiel #23
0
    def test_operation_removal(self, mock_device):
        """Tests that operations are correctly removed."""
        def circuit(x):
            RX = qml.RX(x, wires=[0])
            qml.CNOT(wires=[0, 1])
            qml.RY(0.4, wires=[0])
            qml.RZ(-0.2, wires=[1])

            qml._current_context._remove_op(RX)

            return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliZ(1))

        qnode = BaseQNode(circuit, mock_device)
        qnode._construct([1.0], {})

        assert qnode.ops[0].name == "CNOT"
        assert qnode.ops[1].name == "RY"
        assert qnode.ops[2].name == "RZ"
        assert qnode.ops[3].name == "PauliX"
Beispiel #24
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 = BaseQNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(QuantumFunctionError, match="applied to invalid wire"):
            node(0.5)
    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 = BaseQNode(circuit, qubit_device_1_wire)
        c = node(1.0, x=np.pi, y=10)
        assert c == pytest.approx(-1.0, abs=tol)
    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 = BaseQNode(circuit, qubit_device_2_wires)
        c = node([np.pi, np.pi])
        assert c == pytest.approx([-1.0, -1.0], abs=tol)
    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 = BaseQNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(QuantumFunctionError,
                           match="All measured observables must be returned"):
            node(0.5)
    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 = BaseQNode(circuit, operable_mock_device_2_wires)
        with pytest.raises(
                QuantumFunctionError,
                match="a qubit device; CV operations are not allowed"):
            node(0.5)
    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 = BaseQNode(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)
    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 = BaseQNode(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)