コード例 #1
0
    def test_array_arguments(self, mock_device):
        """Test that array arguments are properly converted to VariableRef 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 = [
            VariableRef(0, "weights[0,0]"),
            VariableRef(1, "weights[0,1]"),
            VariableRef(2, "weights[1,0]"),
            VariableRef(3, "weights[1,1]"),
        ]

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

        assert not kwarg_vars
コード例 #2
0
    def test_regular_keyword_arguments(self, mock_device):
        """Test that regular keyword arguments are properly converted to VariableRef 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" : [VariableRef(0, "a", is_kwarg=True)],
            "b" : [VariableRef(0, "b", is_kwarg=True)],
            "c" : [VariableRef(0, "c", is_kwarg=True)],
            "d" : [VariableRef(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
コード例 #3
0
def test_variable_str():
    """Variable informal string rep."""
    p = VariableRef(0)
    assert str(p) == "VariableRef: name = None, idx = 0"
    assert str(-p) == "VariableRef: name = None, idx = 0, * -1"

    p = VariableRef(0, name="kw1")
    assert str(p) == "VariableRef: name = kw1, idx = 0"
    assert str(2.1 * p) == "VariableRef: name = kw1, idx = 0, * 2.1"
コード例 #4
0
def test_variable_repr():
    """Variable string rep."""
    p = VariableRef(0)
    assert repr(p) == "<VariableRef(None:0)>"
    assert repr(-p) == "<VariableRef(None:0 * -1)>"
    assert repr(1.2 * p * 0.4) == "<VariableRef(None:0 * 0.48)>"
    assert repr(1.2 * p / 2.5) == "<VariableRef(None:0 * 0.48)>"

    p = VariableRef(0, name="kw1")
    assert repr(p) == "<VariableRef(kw1:0)>"
    assert repr(-p) == "<VariableRef(kw1:0 * -1)>"
    assert repr(1.2 * p * 0.4) == "<VariableRef(kw1:0 * 0.48)>"
    assert repr(1.2 * p / 2.5) == "<VariableRef(kw1:0 * 0.48)>"
コード例 #5
0
def test_keyword_variable(par_keyword, name, ind, mult, tol):
    """Keyword variable evaluation."""
    v = VariableRef(ind, name, is_kwarg=True)

    assert v.name == name
    assert v.mult == 1
    assert v.idx == ind
    variable_eval_asserts(v, par_keyword[name][ind], mult, tol)
コード例 #6
0
def test_variable_val(par_positional, ind, mult, tol):
    """Positional variable evaluation."""
    v = VariableRef(ind)

    assert v.name is None
    assert v.mult == 1
    assert v.idx == ind
    variable_eval_asserts(v, par_positional[ind], mult, tol)
コード例 #7
0
    def test_variadic_arguments(self, mock_device):
        """Test that variadic arguments are properly converted to VariableRef 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 = [
            VariableRef(0, "a"),
            VariableRef(1, "b[0]"),
            VariableRef(2, "b[1][0]"),
            VariableRef(3, "b[1][1]"),
            VariableRef(4, "b[1][2]"),
            VariableRef(5, "b[1][3]"),
            VariableRef(6, "b[2]"),
        ]

        assert not kwarg_vars

        for var, expected in zip(qml.utils._flatten(arg_vars), expected_arg_vars):
            assert var == expected
コード例 #8
0
    def test_regular_arguments(self, mock_device):
        """Test that regular arguments are properly converted to VariableRef 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 = [
            VariableRef(0, "a"),
            VariableRef(1, "b"),
            VariableRef(2, "c"),
            VariableRef(3, "d"),
        ]

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

        assert not kwarg_vars
コード例 #9
0
    def test_array_keyword_arguments(self, mock_device):
        """Test that array keyword arguments are properly converted to VariableRef instances."""
        def circuit(*, a=np.array([[1, 0], [0, 1]]), b=np.array([1,2,3])):
            qml.RX(a[0, 0], wires=[0])
            qml.RX(a[0, 1], wires=[0])
            qml.RX(a[1, 0], wires=[0])
            qml.RX(a[1, 1], wires=[0])
            qml.RY(b[0], wires=[0])
            qml.RY(b[1], wires=[0])
            qml.RY(b[2], wires=[0])

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

        node = BaseQNode(circuit, mock_device)
        arg_vars, kwarg_vars = node._make_variables([], {"b" : np.array([6,7,8,9])})

        expected_kwarg_vars = {
            "a" : [
                VariableRef(0, "a[0,0]", is_kwarg=True),
                VariableRef(1, "a[0,1]", is_kwarg=True),
                VariableRef(2, "a[1,0]", is_kwarg=True),
                VariableRef(3, "a[1,1]", is_kwarg=True),
            ],
            "b" : [
                VariableRef(0, "b[0]", is_kwarg=True),
                VariableRef(1, "b[1]", is_kwarg=True),
                VariableRef(2, "b[2]", is_kwarg=True),
                VariableRef(3, "b[3]", 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
コード例 #10
0
class TestOperations:
    """Tests the logic related to operations"""

    def test_op_queue_accessed_outside_execution_context(self, mock_qubit_device):
        """Tests that a call to op_queue outside the execution context raises the correct error"""

        with pytest.raises(
            ValueError, match="Cannot access the operation queue outside of the execution context!"
        ):
            mock_qubit_device.op_queue

    def test_op_queue_is_filled_during_execution(
        self, mock_qubit_device_with_paulis_and_methods, monkeypatch
    ):
        """Tests that the op_queue is correctly filled when apply is called and that accessing
           op_queue raises no error"""
        queue = [qml.PauliX(wires=0), qml.PauliY(wires=1), qml.PauliZ(wires=2)]

        observables = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)), qml.sample(qml.PauliZ(2))]

        circuit_graph = CircuitGraph(queue + observables, {})

        call_history = []

        with monkeypatch.context() as m:
            m.setattr(QubitDevice, "apply", lambda self, x, **kwargs: call_history.extend(x + kwargs.get('rotations', [])))
            mock_qubit_device_with_paulis_and_methods.execute(circuit_graph)

        assert call_history == queue

        assert len(call_history) == 3
        assert isinstance(call_history[0], qml.PauliX)
        assert call_history[0].wires == [0]

        assert isinstance(call_history[1], qml.PauliY)
        assert call_history[1].wires == [1]

        assert isinstance(call_history[2], qml.PauliZ)
        assert call_history[2].wires == [2]

    def test_unsupported_operations_raise_error(self, mock_qubit_device_with_paulis_and_methods):
        """Tests that the operations are properly applied and queued"""
        queue = [qml.PauliX(wires=0), qml.PauliY(wires=1), qml.Hadamard(wires=2)]

        observables = [qml.expval(qml.PauliZ(0)), qml.var(qml.PauliZ(1)), qml.sample(qml.PauliZ(2))]

        circuit_graph = CircuitGraph(queue + observables, {})

        with pytest.raises(DeviceError, match="Gate Hadamard not supported on device"):
            mock_qubit_device_with_paulis_and_methods.execute(circuit_graph)

    numeric_queues = [
                        [
                            qml.RX(0.3, wires=[0])
                        ],
                        [
                            qml.RX(0.3, wires=[0]),
                            qml.RX(0.4, wires=[1]),
                            qml.RX(0.5, wires=[2]),
                        ]
                     ]

    variable = VariableRef(1)
    symbolic_queue = [
                        [qml.RX(variable, wires=[0])],
                    ]


    observables = [
                    [qml.PauliZ(0)],
                    [qml.PauliX(0)],
                    [qml.PauliY(0)]
                 ]

    @pytest.mark.parametrize("observables", observables)
    @pytest.mark.parametrize("queue", numeric_queues + symbolic_queue)
    def test_passing_keyword_arguments_to_execute(self, mock_qubit_device_with_paulis_rotations_and_methods, monkeypatch, queue, observables):
        """Tests that passing keyword arguments to execute propagates those kwargs to the apply()
        method"""
        circuit_graph = CircuitGraph(queue + observables, {})

        call_history = {}

        with monkeypatch.context() as m:
            m.setattr(QubitDevice, "apply", lambda self, x, **kwargs: call_history.update(kwargs))
            mock_qubit_device_with_paulis_rotations_and_methods.execute(circuit_graph, hash=circuit_graph.hash)

        len(call_history.items()) == 1
        call_history["hash"] = circuit_graph.hash
コード例 #11
0
ファイル: base.py プロジェクト: mpofukelvintafadzwa/pennylane
    def _make_variables(self, args, kwargs):
        """Create the :class:`~.variable.VariableRef` instances representing the QNode's arguments.

        The created :class:`~.variable.VariableRef` instances are given in the same nested structure
        as the original arguments. The :class:`~.variable.VariableRef` instances are named according
        to the argument names given in the QNode definition. Consider the following example:

        .. code-block:: python3

            @qml.qnode(dev)
            def qfunc(a, w):
                qml.Hadamard(0)
                qml.CRX(a, wires=[0, 1])
                qml.Rot(w[0], w[1], w[2], wires=[1])
                qml.CRX(-a, wires=[0, 1])

                return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

        In this example, ``_make_variables`` will return the following :class:`~.variable.VariableRef` instances

        .. code-block:: python3

            >>> qfunc(3.4, [1.2, 3.4, 5.6])
            -0.031664133410566786
            >>> qfunc._make_variables([3.4, [1.2, 3.4, 5.6]], {})
            ["a", ["w[0]", "w[1]", "w[2]"]], {}

        where the VariableRef instances are replaced with their name for readability.

        Args:
            args (tuple[Any]): Positional arguments passed to the quantum function.
                During the construction we are not concerned with the numerical values, but with
                the nesting structure.
                Each positional argument is replaced with a :class:`~.variable.VariableRef` instance.
            kwargs (dict[str, Any]): Auxiliary arguments passed to the quantum function.
        """
        # Get the name of the qfunc's arguments
        full_argspec = inspect.getfullargspec(self.func)

        # args
        variable_name_strings = []
        for variable_name, variable_value in zip(full_argspec.args, args):
            variable_name_strings.append(
                self._determine_structured_variable_name(
                    variable_value, variable_name))

        # varargs
        len_diff = len(args) - len(full_argspec.args)
        if len_diff > 0:
            for idx, variable_value in enumerate(args[-len_diff:]):
                variable_name = "{}[{}]".format(full_argspec.varargs, idx)

                variable_name_strings.append(
                    self._determine_structured_variable_name(
                        variable_value, variable_name))

        arg_vars = [
            VariableRef(idx, name)
            for idx, name in enumerate(_flatten(variable_name_strings))
        ]
        self.num_variables = len(arg_vars)

        # arrange the newly created VariableRefs in the nested structure of args
        arg_vars = unflatten(arg_vars, args)

        # kwargs
        # if not mutable: must convert auxiliary arguments to named VariableRefs so they can be updated without re-constructing the circuit
        #kwarg_vars = {}
        #for key, val in kwargs.items():
        #    temp = [VariableRef(idx, name=key) for idx, _ in enumerate(_flatten(val))]
        #    kwarg_vars[key] = unflatten(temp, val)

        variable_name_strings = {}
        kwarg_vars = {}
        for variable_name in full_argspec.kwonlyargs:
            if variable_name in kwargs:
                variable_value = kwargs[variable_name]
            else:
                variable_value = full_argspec.kwonlydefaults[variable_name]

            if isinstance(variable_value, np.ndarray):
                variable_name_string = np.empty_like(variable_value,
                                                     dtype=object)

                for index in np.ndindex(*variable_name_string.shape):
                    variable_name_string[index] = "{}[{}]".format(
                        variable_name, ",".join([str(i) for i in index]))

                kwarg_variable = [
                    VariableRef(idx, name=name, is_kwarg=True)
                    for idx, name in enumerate(_flatten(variable_name_string))
                ]
            else:
                kwarg_variable = VariableRef(0,
                                             name=variable_name,
                                             is_kwarg=True)

            kwarg_vars[variable_name] = kwarg_variable

        return arg_vars, kwarg_vars
コード例 #12
0
                  ([[-2.3, 0.1], -1.], [(1, ), ()], 'max'),
                  ([[-2.3, 0.1], -1.], [(3, ), ()], 'min')]

LAYERS_PASS = [
    ([[1], [2], [3]], 1),
    ([[[1], [2], [3]], [['a'], ['b'], ['c']]], 3),
]

LAYERS_FAIL = [
    ([1, 2, 3], None),
    ([[[1], [2], [3]], [['b'], ['c']]], 3),
]

NO_VARIABLES_PASS = [[[], np.array([1., 4.])], [1, 'a']]

NO_VARIABLES_FAIL = [[[VariableRef(0.1)],
                      VariableRef([0.1])],
                     np.array([VariableRef(0.3),
                               VariableRef(4.)]),
                     VariableRef(-1.)]

OPTIONS_PASS = [("a", ["a", "b"])]

OPTIONS_FAIL = [("c", ["a", "b"])]

TYPE_PASS = [(["a"], list, type(None)), (1, int, type(None)), ("a", int, str),
             (VariableRef(1.), list, VariableRef)]

TYPE_FAIL = [("a", list, type(None)), (VariableRef(1.), int, list),
             (1., VariableRef, type(None))]
コード例 #13
0
def kwarg_variable(monkeypatch):
    """A mocked VariableRef instance for a keyword variable."""
    monkeypatch.setattr(VariableRef, "kwarg_values",
                        {"kwarg_test": [0, 1, 2, 3]})
    yield VariableRef(1, "kwarg_test", True)
コード例 #14
0
def variable(monkeypatch):
    """A mocked VariableRef instance for a non-keyword variable."""
    monkeypatch.setattr(VariableRef, "positional_arg_values", [0, 1, 2, 3])
    yield VariableRef(2, "test")
コード例 #15
0
class TestCircuitGraphHash:
    """Test the creation of a hash on a CircuitGraph"""

    numeric_queues = [([qml.RX(0.3, wires=[0])], [], 'RX!0.3![0]|||'),
                      ([
                          qml.RX(0.3, wires=[0]),
                          qml.RX(0.4, wires=[1]),
                          qml.RX(0.5, wires=[2]),
                      ], [], 'RX!0.3![0]RX!0.4![1]RX!0.5![2]|||')]

    @pytest.mark.parametrize("queue, observable_queue, expected_string",
                             numeric_queues)
    def test_serialize_numeric_arguments(self, queue, observable_queue,
                                         expected_string):
        """Tests that the same hash is created for two circuitgraphs that have numeric arguments."""
        circuit_graph_1 = CircuitGraph(queue + observable_queue, {})
        circuit_graph_2 = CircuitGraph(queue + observable_queue, {})

        assert circuit_graph_1.serialize() == circuit_graph_2.serialize()
        assert expected_string == circuit_graph_1.serialize()

    variable = VariableRef(1)

    symbolic_queue = [
        ([qml.RX(variable, wires=[0])], [], 'RX!V1![0]|||'),
    ]

    @pytest.mark.parametrize("queue, observable_queue, expected_string",
                             symbolic_queue)
    def test_serialize_symbolic_argument(self, queue, observable_queue,
                                         expected_string):
        """Tests that the same hash is created for two circuitgraphs that have symbolic arguments."""
        circuit_graph_1 = CircuitGraph(queue + observable_queue, {})
        circuit_graph_2 = CircuitGraph(queue + observable_queue, {})

        assert circuit_graph_1.serialize() == circuit_graph_2.serialize()
        assert expected_string == circuit_graph_1.serialize()

    variable = VariableRef(1)

    symbolic_queue = [
        ([
            qml.RX(variable, wires=[0]),
            qml.RX(0.3, wires=[1]),
            qml.RX(variable, wires=[2])
        ], [], 'RX!V1![0]RX!0.3![1]RX!V1![2]|||'),
    ]

    @pytest.mark.parametrize("queue, observable_queue, expected_string",
                             symbolic_queue)
    def test_serialize_numeric_and_symbolic_argument(self, queue,
                                                     observable_queue,
                                                     expected_string):
        """Tests that the same hash is created for two circuitgraphs that have both numeric and symbolic arguments."""

        circuit_graph_1 = CircuitGraph(queue + observable_queue, {})
        circuit_graph_2 = CircuitGraph(queue + observable_queue, {})

        assert circuit_graph_1.serialize() == circuit_graph_2.serialize()
        assert expected_string == circuit_graph_1.serialize()

    variable = VariableRef(1)

    many_symbolic_queue = [
        ([qml.RX(variable, wires=[0]),
          qml.RX(variable, wires=[1])], [], 'RX!V1![0]' + 'RX!V1![1]' + '|||'),
    ]

    @pytest.mark.parametrize("queue, observable_queue, expected_string",
                             many_symbolic_queue)
    def test_serialize_symbolic_argument_multiple_times(
            self, queue, observable_queue, expected_string):
        """Tests that the same hash is created for two circuitgraphs that have the same symbolic argument
        used multiple times."""
        circuit_graph_1 = CircuitGraph(queue + observable_queue, {})
        circuit_graph_2 = CircuitGraph(queue + observable_queue, {})

        assert circuit_graph_1.serialize() == circuit_graph_2.serialize()
        assert expected_string == circuit_graph_1.serialize()

    variable1 = VariableRef(1)
    variable2 = VariableRef(2)

    multiple_symbolic_queue = [
        ([qml.RX(variable1, wires=[0]),
          qml.RX(variable2,
                 wires=[1])], [], 'RX!V1![0]' + 'RX!V2![1]' + '|||'),
    ]

    @pytest.mark.parametrize("queue, observable_queue, expected_string",
                             multiple_symbolic_queue)
    def test_serialize_multiple_symbolic_arguments(self, queue,
                                                   observable_queue,
                                                   expected_string):
        """Tests that the same hash is created for two circuitgraphs that have multiple symbolic arguments."""

        circuit_graph_1 = CircuitGraph(queue + observable_queue, {})
        circuit_graph_2 = CircuitGraph(queue + observable_queue, {})

        assert circuit_graph_1.serialize() == circuit_graph_2.serialize()
        assert expected_string == circuit_graph_1.serialize()

    observable1 = qml.PauliZ(0)
    observable1.return_type = not None

    observable2 = qml.Hermitian(np.array([[1, 0], [0, -1]]), wires=[0])
    observable2.return_type = not None

    observable3 = Tensor(qml.PauliZ(0) @ qml.PauliZ(1))
    observable3.return_type = not None

    numeric_observable_queue = [
        ([], [observable1], '|||PauliZ[0]'),
        ([], [observable2], '|||Hermitian![[ 1  0]\n [ 0 -1]]![0]'),
        ([], [observable3], '|||[\'PauliZ\', \'PauliZ\'][[0], [1]]')
    ]

    @pytest.mark.parametrize("queue, observable_queue, expected_string",
                             numeric_observable_queue)
    def test_serialize_numeric_arguments_observables(self, queue,
                                                     observable_queue,
                                                     expected_string):
        """Tests that the same hash is created for two circuitgraphs that have identical queues and empty variable_deps."""

        circuit_graph_1 = CircuitGraph(queue + observable_queue, {})
        circuit_graph_2 = CircuitGraph(queue + observable_queue, {})

        assert circuit_graph_1.serialize() == circuit_graph_2.serialize()
        assert expected_string == circuit_graph_1.serialize()