Пример #1
0
def test_unwrap_autograd():
    """Test that unwrapping a tape with Autograd parameters
    works as expected"""
    from pennylane import numpy as anp

    p = [
        anp.tensor(0.1, requires_grad=True),
        anp.tensor(0.2, requires_grad=False),
        0.5,
        anp.tensor(0.3, requires_grad=True),
    ]

    with qml.tape.QuantumTape() as tape:
        qml.RX(p[0], wires=0)
        qml.RY(p[1], wires=0)
        qml.PhaseShift(p[2], wires=0)
        qml.RZ(p[3], wires=0)

    with tape.unwrap() as unwrapped_tape:
        # inside the context manager, all parameters
        # will be unwrapped to NumPy arrays
        params = tape.get_parameters(trainable_only=False)
        assert all(isinstance(i, float) for i in params)
        assert np.allclose(params, [0.1, 0.2, 0.5, 0.3])
        assert tape.trainable_params == {0, 2, 3}

    # outside the context, the original parameters have been restored.
    assert tape.get_parameters(trainable_only=False) == p
Пример #2
0
def test_unwrap_autograd_backward():
    """Test that unwrapping a tape with Autograd parameters
    works as expected during a backwards pass"""
    from pennylane import numpy as anp
    from autograd.numpy.numpy_boxes import ArrayBox

    p = [
        anp.tensor([0.1, 0.5, 0.3], requires_grad=True),
        anp.tensor(0.2, requires_grad=False),
    ]

    def cost(*p):
        with qml.tape.QuantumTape() as tape:
            qml.RX(p[0][0], wires=0)
            qml.RY(p[1], wires=0)
            qml.PhaseShift(p[0][1], wires=0)
            qml.RZ(p[0][2], wires=0)

        with tape.unwrap() as unwrapped_tape:
            # inside the context manager, all parameters
            # will be unwrapped to NumPy arrays
            params = tape.get_parameters(trainable_only=False)
            assert all(isinstance(i, float) for i in params)
            assert np.allclose(params, [0.1, 0.2, 0.5, 0.3])
            assert tape.trainable_params == {0, 2, 3}

        # outside the context, the original parameters have been restored.
        params = tape.get_parameters(trainable_only=False)
        assert any(isinstance(i, ArrayBox) for i in params)

        return p[0][0] * p[1]**2 * anp.sin(p[0][1]) * anp.exp(-0.5 * p[0][2])

    qml.grad(cost)(*p)
    qml.jacobian(qml.grad(cost))(*p)
Пример #3
0
    def test_two_trainable_args(self, opt, opt_name, tol):
        """Tests that a cost function that takes at least two trainable
        arguments executes well."""
        dev = qml.device("default.qubit", wires=2)

        @qml.qnode(dev)
        def circuit(x, y):
            qml.RX(x, wires=0)
            qml.RX(y, wires=0)
            return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

        def cost(x, y, target):
            return (circuit(x, y) - target)**2

        ev = np.tensor(0.7781, requires_grad=False)
        x = np.tensor(0.0, requires_grad=True)
        y = np.tensor(0.0, requires_grad=True)

        original_ev = ev

        (x, y, ev), cost = opt.step_and_cost(cost, x, y, ev)

        # check that the argument to RX doesn't change, as the X rotation doesn't influence <Z>
        assert x == 0
        assert ev == original_ev
Пример #4
0
    def test_passing_requires_grad_arg(self):
        """Test that you can instantiate the Tensor class with the
        requires_grad argument"""
        # default value is true
        x = np.tensor([0, 1, 2])
        assert x.requires_grad

        x = np.tensor([0, 1, 2], requires_grad=True)
        assert x.requires_grad

        x = np.tensor([0, 1, 2], requires_grad=False)
        assert not x.requires_grad
Пример #5
0
def _execute(
    parameters,
    tapes=None,
    device=None,
    execute_fn=None,
    gradient_fn=None,
    gradient_kwargs=None,
    _n=1,
    max_diff=2,
):  # pylint: disable=dangerous-default-value,unused-argument
    """Autodifferentiable wrapper around ``Device.batch_execute``.

    The signature of this function is designed to work around Autograd restrictions.
    Note that the ``parameters`` argument is dependent on the ``tapes`` argument;
    this function should always be called as follows:

    >>> parameters = [autograd.builtins.list(t.get_parameters()) for t in tapes])
    >>> parameters = autograd.builtins.tuple(parameters)
    >>> _execute(parameters, tapes=tapes, device=device)

    In particular:

    - ``parameters`` is dependent on the provided tapes: always extract them as above
    - ``tapes`` is a *required* argument
    - ``device`` is a *required* argument

    The private argument ``_n`` is used to track nesting of derivatives, for example
    if the nth-order derivative is requested. Do not set this argument unless you
    understand the consequences!
    """
    with qml.tape.Unwrap(*tapes):
        res, jacs = execute_fn(tapes, **gradient_kwargs)

    for i, r in enumerate(res):

        if isinstance(res[i], np.ndarray):
            # For backwards compatibility, we flatten ragged tape outputs
            # when there is no sampling
            r = np.hstack(
                res[i]) if res[i].dtype == np.dtype("object") else res[i]
            res[i] = np.tensor(r)

        elif isinstance(res[i], tuple):
            res[i] = tuple(np.tensor(r) for r in res[i])

        else:
            res[i] = qml.math.toarray(res[i])

    return res, jacs
Пример #6
0
    def test_multiple_gate_parameter(self):
        """Test that when supplied a PennyLane tensor, a QNode passes arguments
        as unwrapped tensors to a gate taking multiple parameters"""
        dev = qml.device("qiskit.aer", wires=1)

        @qml.qnode(dev)
        def circuit(phi=None):
            for idx, x in enumerate(phi):
                qml.Rot(*x, wires=idx)
            return qml.expval(qml.PauliZ(0))

        phi = tensor([[0.04439891, 0.14490549, 3.29725643]])


        with qml._queuing.OperationRecorder() as rec:
            circuit(phi=phi)

        # Test the rotation applied
        assert rec.queue[0].name == "Rot"
        assert len(rec.queue[0].parameters) == 3

        # Test that the gate parameters are not PennyLane tensors,
        # but are instead floats
        assert not isinstance(rec.queue[0].parameters[0], tensor)
        assert isinstance(rec.queue[0].parameters[0], float)

        assert not isinstance(rec.queue[0].parameters[1], tensor)
        assert isinstance(rec.queue[0].parameters[1], float)

        assert not isinstance(rec.queue[0].parameters[2], tensor)
        assert isinstance(rec.queue[0].parameters[2], float)
Пример #7
0
    def test_extra_parameters_were_passed(self, recorder):
        """Tests that loading raises an error when extra parameters were
        passed."""

        theta = Parameter("θ")
        phi = Parameter("φ")
        x = np.tensor(0.5, requires_grad=False)
        y = np.tensor(0.3, requires_grad=False)

        qc = QuantumCircuit(3, 1)

        quantum_circuit = load(qc)

        with pytest.raises(QiskitError):
            with recorder:
                quantum_circuit(params={theta: x, phi: y})
Пример #8
0
    def test_single_gate_parameter(self, monkeypatch):
        """Test that when supplied a PennyLane tensor, a QNode passes an
        unwrapped tensor as the argument to a gate taking a single parameter"""
        dev = qml.device("qiskit.aer", wires=4)

        @qml.qnode(dev)
        def circuit(phi=None):
            for y in phi:
                for idx, x in enumerate(y):
                    qml.RX(x, wires=idx)
            return qml.expval(qml.PauliZ(0))

        phi = tensor([[0.04439891, 0.14490549, 3.29725643, 2.51240058]])

        with qml._queuing.OperationRecorder() as rec:
            circuit(phi=phi)

        for i in range(phi.shape[1]):
            # Test each rotation applied
            assert rec.queue[0].name == "RX"
            assert len(rec.queue[0].parameters) == 1

            # Test that the gate parameter is not a PennyLane tensor, but a
            # float
            assert not isinstance(rec.queue[0].parameters[0], tensor)
            assert isinstance(rec.queue[0].parameters[0], float)
Пример #9
0
    def test_requires_grad_setter(self):
        """Test that the value of requires_grad can be changed
        on an instantiated object"""
        # default value is true
        x = np.tensor([0, 1, 2])
        assert x.requires_grad

        x.requires_grad = False
        assert not x.requires_grad
Пример #10
0
    def test_string_representation(self, capsys):
        """Test the string representation is correct"""
        x = np.tensor([0, 1, 2])
        print(x.__repr__())
        captured = capsys.readouterr()
        assert "tensor([0, 1, 2], requires_grad=True)" in captured.out

        x.requires_grad = False
        print(x.__repr__())
        captured = capsys.readouterr()
        assert "tensor([0, 1, 2], requires_grad=False)" in captured.out
Пример #11
0
    def test_indexing(self, grad):
        """Test that indexing into a tensor always returns a tensor"""
        x = np.tensor([[0, 1, 2], [3, 4, 5]], requires_grad=grad)

        assert isinstance(x[0], np.tensor)
        assert x[0].requires_grad is grad

        assert isinstance(x[0, 0], np.tensor)
        assert x[0, 0].requires_grad is grad
        assert x[0, 0].shape == tuple()
        assert x[0, 0].item() == 0
Пример #12
0
    def test_one_non_trainable_one_trainable(self, opt):
        """Tests that a cost function that takes one non-trainable and one
        trainable parameter executes well."""
        dev = qml.device("default.qubit", wires=2)

        @qml.qnode(dev)
        def circuit(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

        def cost(target, x):  # Note: the order of the arguments has been swapped
            return (circuit(x) - target) ** 2

        ev = np.tensor(0.7781, requires_grad=False)
        x = np.tensor(0.0, requires_grad=True)

        original_ev = ev

        (ev, x), cost = opt.step_and_cost(cost, ev, x)
        # check that the argument to RX doesn't change, as the X rotation doesn't influence <Z>
        assert x == 0
        assert ev == original_ev
Пример #13
0
    def test_multiple_gate_parameter(self):
        """Test that a QNode handles passing multiple tensor objects to the
        same gate without an error"""
        dev = qml.device("qiskit.aer", wires=1)

        @qml.qnode(dev)
        def circuit(phi=None):
            for idx, x in enumerate(phi):
                qml.Rot(*x, wires=idx)
            return qml.expval(qml.PauliZ(0))

        phi = tensor([[0.04439891, 0.14490549, 3.29725643]])

        circuit(phi=phi)
Пример #14
0
    def test_quantum_circuit_error_passing_parameters_not_required(self, recorder):
        """Tests the load method raises a QiskitError if arguments
        that are not required were passed."""

        theta = Parameter("θ")
        angle = np.tensor(0.5, requires_grad=False)

        qc = QuantumCircuit(3, 1)
        qc.z([0])

        quantum_circuit = load(qc)

        with pytest.raises(QiskitError):
            with recorder:
                quantum_circuit(params={theta: angle})
Пример #15
0
    def test_quantum_circuit_error_by_passing_wrong_parameters(self, recorder):
        """Tests the load method for a QuantumCircuit raises a QiskitError,
        if the wrong type of arguments were passed."""

        theta = Parameter("θ")
        angle = np.tensor("some_string_instead_of_an_angle", requires_grad=False)

        qc = QuantumCircuit(3, 1)
        qc.rz(theta, [0])

        quantum_circuit = load(qc)

        with pytest.raises(QiskitError):
            with recorder:
                quantum_circuit(params={theta: angle})
Пример #16
0
    def test_tensor_gradient_no_error(self, monkeypatch):
        """Tests that the gradient calculation of a circuit that contains a
        RandomLayers template taking a PennyLane tensor as differentiable
        argument executes without error.
        """
        dev = qml.device("default.qubit", wires=4)

        @qml.qnode(dev)
        def circuit(phi):

            # Random quantum circuit
            RandomLayers(phi, wires=list(range(4)))
            return qml.expval(qml.PauliZ(0))

        phi = tensor([[0.04439891, 0.14490549, 3.29725643, 2.51240058]])

        qml.jacobian(circuit)(phi)
Пример #17
0
    def test_multiple_gate_parameter(self):
        """Test that when supplied a PennyLane tensor, a QNode passes arguments
        as unwrapped tensors to a gate taking multiple parameters"""
        dev = qml.device("default.qubit", wires=1)

        @qml.qnode(dev, diff_method="parameter-shift")
        def circuit(phi=None):
            for idx, x in enumerate(phi):
                qml.Rot(*x, wires=idx)
            return qml.expval(qml.PauliZ(0))

        phi = np.tensor([[0.04439891, 0.14490549, 3.29725643]])

        with qml._queuing.OperationRecorder() as rec:
            circuit(phi=phi)

        # Test the rotation applied
        assert rec.queue[0].name == "Rot"
        assert len(rec.queue[0].parameters) == 3
Пример #18
0
    def test_tracker(self):
        """Tests the device tracker with batch execution."""
        dev = qml.device('qiskit.aer', shots=100, wires=3)

        @qml.qnode(dev, diff_method="parameter-shift")
        def circuit(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        x = tensor(0.1, requires_grad=True)

        with qml.Tracker(dev) as tracker:
            qml.grad(circuit)(x)

        expected = {'executions': [1, 1, 1],
                     'shots': [100, 100, 100],
                     'batches': [1, 1],
                     'batch_len': [1, 2]}

        assert tracker.history == expected
Пример #19
0
    def test_single_gate_parameter(self, monkeypatch):
        """Test that when supplied a PennyLane tensor, a QNode passes an
        unwrapped tensor as the argument to a gate taking a single parameter"""
        dev = qml.device("default.qubit", wires=4)

        @qml.qnode(dev, diff_method="parameter-shift")
        def circuit(phi=None):
            for y in phi:
                for idx, x in enumerate(y):
                    qml.RX(x, wires=idx)
            return qml.expval(qml.PauliZ(0))

        phi = np.tensor([[0.04439891, 0.14490549, 3.29725643, 2.51240058]])

        with qml.tape.OperationRecorder() as rec:
            circuit(phi=phi)

        for i in range(phi.shape[1]):
            # Test each rotation applied
            assert rec.queue[0].name == "RX"
            assert len(rec.queue[0].parameters) == 1
Пример #20
0
    def test_tensor_unwrapped(self, monkeypatch):
        """Test that the random_layer() function used by RandomLayers passes a
        float value to its gate after successfully unwrapping a one element
        PennyLane tensor.

        The test involves using RandomLayers, which then calls random_layer
        internally. Eventually each gate used by random_layer receives a single
        scalar. In this test case, this is done by indexing into a PennyLane
        tensor two times.
        """
        dev = qml.device("default.qubit", wires=4)

        lst = []

        # Mock function that accumulates gate parameters
        mock_func = lambda par, wires: lst.append(par)

        with monkeypatch.context() as m:

            # Mock the gates used in RandomLayers
            m.setattr(pennylane.templates.layers.random, "RX", mock_func)
            m.setattr(pennylane.templates.layers.random, "RY", mock_func)
            m.setattr(pennylane.templates.layers.random, "RZ", mock_func)

            @qml.qnode(dev)
            def circuit(phi=None):

                # Random quantum circuit
                RandomLayers(phi, wires=list(range(4)))

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

            phi = tensor([[0.04439891, 0.14490549, 3.29725643, 2.51240058]])

            # Call the QNode, accumulate parameters
            circuit(phi=phi)

            # Check parameters
            assert all([isinstance(x, float) for x in lst])
Пример #21
0
 def astensor(tensor):
     return np.tensor(tensor)
Пример #22
0
class AutogradBox(qml.math.TensorBox):
    """Implements the :class:`~.TensorBox` API for ``pennylane.numpy`` tensors.

    For more details, please refer to the :class:`~.TensorBox` documentation.
    """

    abs = wrap_output(lambda self: np.abs(self.data))
    angle = wrap_output(lambda self: np.angle(self.data))
    arcsin = wrap_output(lambda self: np.arcsin(self.data))
    cast = wrap_output(lambda self, dtype: np.tensor(self.data, dtype=dtype))
    diag = staticmethod(wrap_output(lambda values, k=0: np.diag(values, k=k)))
    expand_dims = wrap_output(
        lambda self, axis: np.expand_dims(self.data, axis=axis))
    ones_like = wrap_output(lambda self: np.ones_like(self.data))
    reshape = wrap_output(lambda self, shape: np.reshape(self.data, shape))
    sqrt = wrap_output(lambda self: np.sqrt(self.data))
    sum = wrap_output(lambda self, axis=None, keepdims=False: np.sum(
        self.data, axis=axis, keepdims=keepdims))
    T = wrap_output(lambda self: self.data.T)
    squeeze = wrap_output(lambda self: self.data.squeeze())

    @staticmethod
    def astensor(tensor):
        return np.tensor(tensor)

    @staticmethod
    @wrap_output
    def concatenate(values, axis=0):
        return np.concatenate(AutogradBox.unbox_list(values), axis=axis)

    @staticmethod
    @wrap_output
    def dot(x, y):
        x, y = AutogradBox.unbox_list([x, y])

        if x.ndim == 0 and y.ndim == 0:
            return x * y

        if x.ndim == 2 and y.ndim == 2:
            return x @ y

        return np.dot(x, y)

    @property
    def interface(self):
        return "autograd"

    def numpy(self):
        if hasattr(self.data, "_value"):
            # Catches the edge case where the data is an Autograd arraybox,
            # which only occurs during backpropagation.
            return self.data._value

        return self.data.numpy()

    @property
    def requires_grad(self):
        return self.data.requires_grad

    @wrap_output
    def scatter_element_add(self, index, value):
        size = self.data.size
        flat_index = np.ravel_multi_index(index, self.shape)
        t = [0] * size
        t[flat_index] = value
        self.data = self.data + np.array(t).reshape(self.shape)
        return self.data

    @property
    def shape(self):
        return self.data.shape

    @staticmethod
    @wrap_output
    def stack(values, axis=0):
        return np.stack(AutogradBox.unbox_list(values), axis=axis)

    @wrap_output
    def take(self, indices, axis=None):
        indices = self.astensor(indices)

        if axis is None:
            return self.data.flatten()[indices]

        fancy_indices = [slice(None)] * axis + [indices]
        return self.data[tuple(fancy_indices)]

    @staticmethod
    @wrap_output
    def where(condition, x, y):
        return np.where(condition, *AutogradBox.unbox_list([x, y]))
Пример #23
0
 def cast(self, dtype):
     return AutogradBox(np.tensor(self.data, dtype=dtype))
Пример #24
0
plt.scatter(X_test[np.where(y_train == 1)[0],0], X_test[np.where(y_train == 1)[0],1], color="b", marker="x", label="test, 1")
plt.scatter(X_test[np.where(y_train == -1)[0],0], X_test[np.where(y_train == -1)[0],1], color="r", marker="x", label="test, -1")
plt.ylim([0, 1])
plt.xlim([0, 1])
plt.legend()

X = X_train

opt_param = np.tensor([[[ 6.22961793,  6.1909463 ,  6.24821366,  1.88800397,  1.6515437 ],
                        [-3.50578116,  2.87429701, -0.55558014, -2.97461847,  4.3646466 ]],
                       [[ 4.59893525, -0.01877453,  4.86909045,  1.61046237,  4.3342154 ],
                        [ 6.54969706,  0.76974914,  6.13216135,  3.19770538,  0.35820405]],
                       [[-0.06825097,  5.46138114, -0.38685812,  2.62531926,  5.94363286],
                        [ 3.84330489,  7.62532526,  3.31992264,  4.53318486,  2.90021471]],
                       [[ 3.27271762,  6.284331  , -0.0095848 ,  1.71022713,  1.72119449],
                        [ 5.26413732, -0.5363315 ,  0.02694912,  1.85543017,  0.09469438]],
                       [[ 1.61977233,  2.12403094,  1.52887576,  1.87843468,  5.10722657],
                        [ 1.83547388,  0.10519713, -0.14516422,  2.34971729, -0.15396484]],
                       [[ 1.15227788,  4.42815449,  4.77992685,  2.00495827,  4.68944624],
                        [ 1.90477385, -0.22817579,  6.21664772,  0.34922366,  6.44687527]],
                       [[ 4.47834114,  5.80827321,  4.8221783 ,  2.07389821,  0.40258912],
                        [ 6.07380714,  6.33676481,  6.17787822,  1.86149763,  6.59189267]],
                       [[ 5.56242829,  4.49153866,  3.66496649,  4.76465886,  0.80552847],
                        [ 3.36765317,  3.41585518,  1.40441779,  1.24372229,  5.85030332]]], requires_grad=True)
if use_trained_params:
    param = np.copy(opt_param)
    print(f"Using trained parameters with average magnitude {np.mean(np.abs(param))}")
else:
    np.random.seed(43)
    param = np.random.random(size=opt_param.shape) * 4 * np.pi - 2 * np.pi
    print(f"Using untrained parameters with average magnitude {np.mean(np.abs(param))}")
Пример #25
0
# Amplitude damping projects a state to :math:`|0\rangle` with probability :math:`p` and
# otherwise leaves it unchanged. It is
# described by the Kraus operators
#
# .. math::
#
#     K_0 = \begin{pmatrix}1 & 0\\ 0 & \sqrt{1-p}\end{pmatrix}, \quad
#     K_1 = \begin{pmatrix}0 & \sqrt{p}\\ 0 & 0\end{pmatrix}.
#
# What damping parameter (:math:`p`) explains the experimental outcome? We can answer this question
# by optimizing the channel parameters to reproduce the experimental
# observation! 💪 Since the parameter :math:`p` is a probability, we use a sigmoid function to
# ensure that the trainable parameters give rise to a valid channel parameter, i.e., a number
# between 0 and 1.
#
ev = np.tensor([0.7781], requires_grad=False)  # observed expectation value


def sigmoid(x):
    return 1 / (1 + np.exp(-x))


@qml.qnode(dev)
def damping_circuit(x):
    qml.Hadamard(wires=0)
    qml.CNOT(wires=[0, 1])
    qml.AmplitudeDamping(sigmoid(x), wires=0)  # p = sigmoid(x)
    qml.AmplitudeDamping(sigmoid(x), wires=1)
    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))