Example #1
0
    def test_dot_product_qnodes_qnodes(self, qnodes, interface, tf_support, torch_support):
        """Test that the dot product of qnodes.qnodes can be applied using all interfaces"""
        if interface == "torch" and not torch_support:
            pytest.skip("Skipped, no torch support")

        if interface == "tf" and not tf_support:
            pytest.skip("Skipped, no tf support")

        qnode1, qnode2 = qnodes
        qc1 = qml.QNodeCollection([qnode1, qnode2])
        qc2 = qml.QNodeCollection([qnode1, qnode2])

        # test the dot product of qnodes, qnodes
        cost = qml.dot(qc1, qc2)

        params = [0.5643, -0.45]
        res = cost(params)

        qc1val = qc1(params)
        qc2val = qc2(params)

        if interface in ("tf", "torch"):
            res = res.numpy()
            qc1val = qc1val.numpy()
            qc2val = qc2val.numpy()

        expected = np.dot(qc1val, qc2val)
        assert np.all(res == expected)
Example #2
0
    def test_interface_property(self, interface, tf_support, torch_support):
        """Test that the interface property correctly
        resolves interfaces from the internal QNodes"""
        if interface == "torch" and not torch_support:
            pytest.skip("Skipped, no torch support")

        if interface == "tf" and not tf_support:
            pytest.skip("Skipped, no tf support")

        qc = qml.QNodeCollection()
        assert qc.interface is None

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

        dev = qml.device("default.qubit", wires=1)
        qnodes = [
            qml.QNode(circuit, dev, interface=interface) for i in range(4)
        ]
        qc = qml.QNodeCollection(qnodes)

        if interface == "numpy":
            # Note: the "numpy" interface is deprecated, and
            # now resolves to "autograd"
            interface = "autograd"

        assert qc.interface == interface
Example #3
0
    def test_nested_apply(self, qnodes, interface, tf_support, torch_support, tol):
        """Test that nested apply can be done using all interfaces"""
        if interface == "torch" and not torch_support:
            pytest.skip("Skipped, no torch support")

        if interface == "tf" and not tf_support:
            pytest.skip("Skipped, no tf support")

        qnode1, qnode2 = qnodes
        qc = qml.QNodeCollection([qnode1, qnode2])

        if interface == "tf":
            sinfn = tf.sin
            sfn = tf.reduce_sum
        elif interface == "torch":
            sinfn = torch.sin
            sfn = torch.sum
        elif interface == "jax":
            sinfn = jnp.sin
            sfn = jnp.sum
        else:
            sinfn = np.sin
            sfn = np.sum

        cost = qml.collections.apply(sfn, qml.collections.apply(sinfn, qc))

        params = [0.5643, -0.45]
        res = cost(params)
        expected = sfn(sinfn(qc(params)))

        assert np.allclose(res, expected, atol=tol, rtol=0)
Example #4
0
    def test_grad_tf(self, qnodes, skip_if_no_tf_support, parallel):
        """Test correct gradient of the QNodeCollection using
        the tf interface"""
        qnode1, qnode2 = qnodes

        # calculate the gradient of the collection using tf
        params = Variable([0.5643, -0.45])
        qc = qml.QNodeCollection([qnode1, qnode2])

        with tf.GradientTape() as tape:
            tape.watch(params)

            if parallel:
                with pytest.warns(UserWarning):
                    cost = sum(qc(params, parallel=parallel))
            else:
                cost = sum(qc(params, parallel=parallel))

            # the gradient will be None
            res = tape.gradient(cost, params).numpy()

        # calculate the gradient of the QNodes individually using tf
        params = Variable([0.5643, -0.45])

        with tf.GradientTape() as tape:
            tape.watch(params)
            cost = sum(qnode1(params) + qnode2(params))
            expected = tape.gradient(cost, params).numpy()

        assert np.all(res == expected)
Example #5
0
    def test_dot_product_qnodes_tensor(self, qnodes, interface, tf_support, torch_support):
        """Test that the dot product of qnodes.tensor can be applied using all interfaces"""
        if interface == "torch" and not torch_support:
            pytest.skip("Skipped, no torch support")

        if interface == "tf" and not tf_support:
            pytest.skip("Skipped, no tf support")

        qnode1, _ = qnodes
        qc = qml.QNodeCollection([qnode1])
        coeffs = [0.5, -0.1]

        if interface == "torch":
            coeffs = torch.tensor(coeffs, dtype=torch.float64)

        if interface == "tf":
            coeffs = tf.cast(coeffs, dtype=tf.float64)

        # test the dot product of qnodes, tensor
        cost = qml.dot(qc, coeffs)

        params = [0.5643, -0.45]
        res = cost(params)
        qcval = qc(params)

        if interface in ("tf", "torch"):
            res = res.numpy()
            qcval = qcval.numpy()
            coeffs = coeffs.numpy()

        expected = np.dot(qcval, coeffs)
        assert np.all(res == expected)
Example #6
0
    def test_mismatching_interface(self, monkeypatch):
        """Test exception raised if the interfaces don't match"""
        dev = qml.device("default.qubit", wires=1)

        @qml.qnode(dev, interface=None)
        def circuit1(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        @qml.qnode(dev, interface="autograd")
        def circuit2(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        qc1 = qml.QNodeCollection([circuit1])
        qc2 = qml.QNodeCollection([circuit2])
        with pytest.raises(ValueError, match="have non-matching interfaces"):
            qml.dot(qc1, qc2)
Example #7
0
    def test_eval_autograd(self, qnodes):
        """Test correct evaluation of the QNodeCollection using
        the Autograd interface"""
        qnode1, qnode2 = qnodes
        qc = qml.QNodeCollection([qnode1, qnode2])
        params = [0.5643, -0.45]

        res = qc(params)
        expected = np.vstack([qnode1(params), qnode2(params)])
        assert np.all(res == expected)
Example #8
0
    def test_eval_tf(self, qnodes, skip_if_no_tf_support):
        """Test correct evaluation of the QNodeCollection using
        the tf interface"""
        qnode1, qnode2 = qnodes
        qc = qml.QNodeCollection([qnode1, qnode2])
        params = [0.5643, -0.45]

        res = qc(params).numpy()
        expected = np.vstack([qnode1(params), qnode2(params)])
        assert np.all(res == expected)
Example #9
0
    def test_indexing(self):
        """Test that indexing into the QNodeCollection correctly works"""
        def circuit(x):
            qml.RX(x, wires=0)
            return qml.expval(qml.PauliZ(0))

        dev = qml.device("default.qubit", wires=1)
        qnodes = [qml.QNode(circuit, dev) for i in range(4)]

        qc = qml.QNodeCollection(qnodes)
        assert qc[2] == qnodes[2]
Example #10
0
    def test_init_with_qnodes(self):
        """Test that a QNode collection can be initialized with QNodes"""
        dev = qml.device("default.qubit", wires=1)

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

        qnodes = [qml.QNode(circuit, dev) for i in range(4)]
        qc = qml.QNodeCollection(qnodes)

        assert qc.qnodes == qnodes
        assert len(qc) == 4
Example #11
0
    def test_unknown_interface(self, monkeypatch):
        """Test exception raised if the interface is unknown"""
        monkeypatch.setattr(qml.QNodeCollection, "interface", "invalid")
        dev = qml.device("default.qubit", wires=1)

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

        qnodes = [qml.QNode(circuit, dev) for i in range(4)]
        qc = qml.QNodeCollection(qnodes)
        with pytest.raises(ValueError, match="Unknown interface invalid"):
            qml.sum(qc)
Example #12
0
    def test_extend_qnodes(self):
        """Test that a list of QNodes is correctly appended"""
        qc = qml.QNodeCollection()
        assert qc.qnodes == []

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

        dev = qml.device("default.qubit", wires=1)
        qnodes = [qml.QNode(circuit, dev) for i in range(4)]
        qc.extend(qnodes)

        assert qc.qnodes == [] + qnodes
Example #13
0
    def test_append_qnode(self):
        """Test that a QNode is correctly appended"""
        qc = qml.QNodeCollection()
        assert qc.qnodes == []

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

        dev = qml.device("default.qubit", wires=1)
        qnode = qml.QNode(circuit, dev)
        qc.append(qnode)

        assert qc.qnodes == [qnode]
Example #14
0
    def test_grad_autograd(self, qnodes):
        """Test correct gradient of the QNodeCollection using
        the Autograd interface"""
        qnode1, qnode2 = qnodes

        params = [0.5643, -0.45]
        qc = qml.QNodeCollection([qnode1, qnode2])
        cost_qc = lambda params: np.sum(qc(params))
        grad_qc = qml.grad(cost_qc, argnum=0)

        cost_expected = lambda params: np.sum(qnode1(params) + qnode2(params))
        grad_expected = qml.grad(cost_expected, argnum=0)

        res = grad_qc(params)
        expected = grad_expected(params)

        assert np.all(res == expected)
Example #15
0
    def test_extend_multiple_interface_qnodes(self):
        """Test that an error is returned if QNodes with differing
        interfaces are attempted to be added to a QNodeCollection"""
        qc = qml.QNodeCollection()

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

        dev = qml.device("default.qubit", wires=1)
        qnodes = [
            qml.QNode(circuit, dev, interface="autograd"),
            qml.QNode(circuit, dev, interface=None),
        ]

        with pytest.raises(ValueError, match="do not all use the same interface"):
            qc.extend(qnodes)
Example #16
0
    def test_extend_interface_mistmatch(self):
        """Test that an error is returned if QNodes with a differing
        interface to the QNode collection are appended"""
        qc = qml.QNodeCollection()

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

        dev = qml.device("default.qubit", wires=1)
        qnode1 = qml.QNode(circuit, dev, interface="autograd")
        qnode2 = qml.QNode(circuit, dev, interface=None)

        qc.extend([qnode1])

        with pytest.raises(ValueError, match="Interface mismatch"):
            qc.extend([qnode2])
Example #17
0
    def test_unknown_interface(self, monkeypatch):
        """Test exception raised if the interface is unknown"""
        monkeypatch.setattr(qml.QNodeCollection, "interface", "invalid")
        dev = qml.device("default.qubit", wires=1)

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

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

        qc = qml.QNodeCollection([circuit1, circuit2])
        with pytest.raises(ValueError, match="Unknown interface invalid"):
            qml.dot([1, 2], qc)
Example #18
0
    def test_grad_torch(self, qnodes, skip_if_no_torch_support, parallel):
        """Test correct gradient of the QNodeCollection using
        the torch interface"""
        qnode1, qnode2 = qnodes

        # calculate the gradient of the collection using pytorch
        params = torch.autograd.Variable(torch.tensor([0.5643, -0.45]), requires_grad=True)
        qc = qml.QNodeCollection([qnode1, qnode2])
        cost = torch.sum(qc(params, parallel=parallel))
        cost.backward()
        res = params.grad.numpy()

        # calculate the gradient of the QNodes individually using pytorch
        params = torch.autograd.Variable(torch.tensor([0.5643, -0.45]), requires_grad=True)
        cost = torch.sum(qnode1(params) + qnode2(params))
        cost.backward()
        expected = params.grad.numpy()

        assert np.all(res == expected)
Example #19
0
    def test_apply_summation(self, qnodes, interface, tf_support, torch_support, tol):
        """Test that summation can be applied using all interfaces"""
        if interface == "torch" and not torch_support:
            pytest.skip("Skipped, no torch support")

        if interface == "tf" and not tf_support:
            pytest.skip("Skipped, no tf support")

        qnode1, qnode2 = qnodes
        qc = qml.QNodeCollection([qnode1, qnode2])
        cost = qml.sum(qc)

        params = [0.5643, -0.45]
        res = cost(params)
        expected = sum(qc[0](params) + qc[1](params))

        if interface in ("tf", "torch"):
            res = res.numpy()
            expected = expected.numpy()

        assert np.allclose(res, expected, atol=tol, rtol=0)
Example #20
0
    def __init__(self, n_qubits, q_depth, q_delta=0.1):
        """
        This is the quantum generator as described in https://arxiv.org/pdf/2010.06201.pdf
        """
        super().__init__()
        self.q_params = nn.ParameterList([
            nn.Parameter(q_delta * torch.randn(q_depth * n_qubits))
            for i in range(8)
        ])
        self.n_qubits = n_qubits
        self.q_depth = q_depth
        # Spread of the random parameters for the paramaterised quantum gates
        self.q_delta = q_delta

        device = qml.device('lightning.qubit', wires=self.n_qubits)
        self.quantum_sim = QuantumSim(n_qubits, q_depth)

        self.qnodes = qml.QNodeCollection([
            qml.QNode(self.quantum_sim.circuit, device, interface="torch")
            for i in range(8)
        ])
    return qml.expval(A1 @ B2)


@qml.qnode(dev)
def measure_A2B1():
    bell_pair()
    return qml.expval(A2 @ B1)


@qml.qnode(dev)
def measure_A2B2():
    bell_pair()
    return qml.expval(A2 @ B2)


circuits = qml.QNodeCollection(
    [measure_A1B1, measure_A1B2, measure_A2B1, measure_A2B2])

# now we measure each circuit and construct the CHSH inequality
expvals = circuits()

# The CHSH operator is A1 @ B1 + A1 @ B2 + A2 @ B1 - A2 @ B2
CHSH_expval = np.sum(expvals[:3]) - expvals[3]
print(CHSH_expval)

##############################################################################
# The output here is :math:`2\sqrt{2}`, which is the maximal value of the
# CHSH inequality. States which have a value
# :math:`\langle CHSH \rangle \geq 2` can safely be considered
# "quantum".
#
# .. note:: In this situation "quantum" means that there is
    qml.CZ(wires=[0, 1])
    qml.CZ(wires=[1, 2])
    qml.CZ(wires=[1, 3])

    for i in range(n_wires):
        qml.Rot(*params[0, 1, i], wires=i)
    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)), qml.expval(
        qml.PauliZ(2))


##############################################################################
# We finally combine the two devices into a :class:`~.pennylane.QNodeCollection` that uses the
# PyTorch interface:

qnodes = qml.QNodeCollection([
    qml.QNode(circuit0, dev0, interface="torch"),
    qml.QNode(circuit1, dev1, interface="torch")
])

##############################################################################
# Postprocessing into a prediction
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
# The ``predict_point`` function below allows us to find the ensemble prediction, as well as keeping
# track of the individual predictions from each QPU.
#
# We include a ``parallel`` keyword argument for evaluating the :class:`~.pennylane.QNodeCollection`
# in a parallel asynchronous manner. This feature requires the ``dask`` library, which can be
# installed using ``pip install "dask[delayed]"``. When ``parallel=True``, we are able to make
# predictions faster because we do not need to wait for one QPU to output before running on the
# other.
Example #23
0
 def test_sequence(self):
     """Test that the QNodeCollection is a sequence type"""
     qc = qml.QNodeCollection()
     assert isinstance(qc, Sequence)
Example #24
0
 def test_empty_init(self):
     """Test that an empty QNode collection can be initialized"""
     qc = qml.QNodeCollection()
     assert qc.qnodes == []
     assert len(qc) == 0