Ejemplo n.º 1
0
def test_projection():
    """Test that the Projector observable is correctly supported."""
    wires = 2
    dev = BraketLocalQubitDevice(wires=wires)

    thetas = [1.5, 1.6]
    p_01 = np.cos(thetas[0] / 2)**2 * np.sin(thetas[1] / 2)**2
    p_10 = np.sin(thetas[0] / 2)**2 * np.cos(thetas[1] / 2)**2

    def f(thetas, **kwargs):
        [qml.RY(thetas[i], wires=i) for i in range(wires)]

    measure_types = ["expval", "var", "sample"]
    projector_01 = qml.Projector([0, 1], wires=range(wires))
    projector_10 = qml.Projector([1, 0], wires=range(wires))

    # 01 case
    fs = [qml.map(f, [projector_01], dev, measure=m) for m in measure_types]
    assert np.allclose(fs[0](thetas), p_01)
    assert np.allclose(fs[1](thetas), p_01 - p_01**2)

    samples = fs[2](thetas, shots=100)[0].tolist()
    assert set(samples) == {0, 1}

    # 10 case
    fs = [qml.map(f, [projector_10], dev, measure=m) for m in measure_types]
    assert np.allclose(fs[0](thetas), p_10)
    assert np.allclose(fs[1](thetas), p_10 - p_10**2)

    samples = fs[2](thetas, shots=100)[0].tolist()
    assert set(samples) == {0, 1}
Ejemplo n.º 2
0
    def test_compiled_program_was_correct_compared_with_default_qubit(
            self, qvm, device, tol):
        """Test that QVM device stores the compiled program correctly by comparing it with default.qubit.

        As the results coming from the qvm are stochastic, a constraint of 1 out of 5 runs was added.
        """
        number_of_qnodes = 6
        obs = [qml.PauliZ(0) @ qml.PauliZ(1)]
        obs_list = obs * number_of_qnodes

        dev = qml.device("forest.qvm", device=device, timeout=100)

        shape = qml.StronglyEntanglingLayers.shape(n_layers=4,
                                                   n_wires=dev.num_wires)
        params = np.random.random(size=shape)

        qnodes = qml.map(qml.templates.StronglyEntanglingLayers, obs_list, dev)

        results = qnodes(params)

        dev2 = qml.device("default.qubit", wires=dev.num_wires)
        qnodes2 = qml.map(qml.templates.StronglyEntanglingLayers, obs_list,
                          dev2)

        results2 = qnodes2(params)

        assert np.allclose(results, results2, atol=6e-02, rtol=0)
        assert dev.circuit_hash in dev._compiled_program_dict
        assert len(dev._compiled_program_dict.items()) == 1
Ejemplo n.º 3
0
    def test_multiple_observables_same_wire_mixed(self, mocker):
        """Test that the QNode supports returning observables that are on the
        same wire but with different return types (provided that the observables are Pauli words and
        qubit-wise commuting)"""
        dev = qml.device("default.qubit", wires=3)

        w = np.random.random((2, 3, 3))

        @qnode(dev)
        def f(w):
            qml.templates.StronglyEntanglingLayers(w, wires=range(3))
            return qml.expval(qml.PauliX(0)), qml.var(qml.PauliX(0) @ qml.PauliZ(1))

        spy = mocker.spy(qml.devices.DefaultQubit, "apply")
        res = f(w)
        spy.assert_called_once()

        q1 = qml.map(qml.templates.StronglyEntanglingLayers, [qml.PauliX(0)], dev, measure="expval")
        q2 = qml.map(
            qml.templates.StronglyEntanglingLayers,
            [qml.PauliX(0) @ qml.PauliZ(1)],
            dev,
            measure="var",
        )

        res_2 = np.array([q1(w), q2(w)]).squeeze()

        assert np.allclose(res, res_2)
Ejemplo n.º 4
0
    def test_invalid_observable(self):
        """Test that an invalid observable raises an exception"""
        dev = qml.device("default.qubit", wires=1)

        obs_list = [qml.PauliX(0), qml.S(wires=0)]
        template = lambda x, wires: qml.RX(x, wires=0)

        with pytest.raises(ValueError, match="Some or all observables are not valid"):
            qml.map(template, obs_list, dev, measure=["expval", "var"])
Ejemplo n.º 5
0
    def test_compiled_program_was_used(self, qvm, device, monkeypatch):
        """Test that QVM device used the compiled program correctly, after it was stored"""
        dev = qml.device("forest.qvm", device=device, timeout=100)

        number_of_qnodes = 6
        obs = [qml.PauliZ(0) @ qml.PauliZ(1)]
        obs_list = obs * number_of_qnodes

        qnodes = qml.map(qml.templates.StronglyEntanglingLayers, obs_list, dev)
        shape = qml.StronglyEntanglingLayers.shape(n_layers=4,
                                                   n_wires=dev.num_wires)
        params = np.random.random(size=shape)

        # For the first evaluation, use the real compile method
        qnodes[0](params)

        call_history = []
        with monkeypatch.context() as m:
            m.setattr(QuantumComputer, "compile",
                      lambda self, prog: call_history.append(prog))

            for i in range(1, number_of_qnodes):
                qnodes[i](params)

        # Then use the mocked one to see if it was called

        results = qnodes(params)

        assert len(call_history) == 0
        assert dev.circuit_hash in dev._compiled_program_dict
        assert len(dev._compiled_program_dict.items()) == 1
Ejemplo n.º 6
0
    def test_compiled_program_was_stored_mutable_qnode_with_if_statement(
            self, qvm, device, statements):
        """Test that QVM device stores the compiled program when the QNode is mutated correctly"""
        dev = qml.device("forest.qvm", device=device, timeout=100)

        assert len(dev._compiled_program_dict.items()) == 0

        def circuit(params, wires, statement=None):
            if statement:
                qml.Hadamard(0)
            qml.CNOT(wires=[0, 1])

        obs = [qml.PauliZ(0) @ qml.PauliZ(1)]
        obs_list = obs * 6

        qnodes = qml.map(circuit, obs_list, dev)

        for idx, stmt in enumerate(statements):
            qnodes[idx]([], statement=stmt)
            assert dev.circuit_hash in dev._compiled_program_dict

        # Using that True evaluates to 1
        number_of_true = sum(statements)

        # Checks if all elements in the list were either ``True`` or ``False``
        # In such a case we have compiled only one program
        length = 1 if (number_of_true == 6 or number_of_true == 0) else 2
        assert len(dev._compiled_program_dict.items()) == length
Ejemplo n.º 7
0
    def test_multiple_observables_same_wire_expval(self, mocker):
        """Test that the QNode supports returning expectation values of observables that are on the
        same wire (provided that they are Pauli words and qubit-wise commuting)"""
        dev = qml.device("default.qubit", wires=3)

        w = np.random.random((2, 3, 3))

        @qnode(dev)
        def f(w):
            qml.templates.StronglyEntanglingLayers(w, wires=range(3))
            return (
                qml.expval(qml.PauliX(0)),
                qml.expval(qml.PauliX(0) @ qml.PauliZ(1)),
                qml.expval(qml.PauliX(2)),
            )

        spy = mocker.spy(qml.devices.DefaultQubit, "apply")
        res = f(w)
        spy.assert_called_once()

        obs = [qml.PauliX(0), qml.PauliX(0) @ qml.PauliZ(1), qml.PauliX(2)]
        qnodes = qml.map(qml.templates.StronglyEntanglingLayers, obs, dev)
        res_2 = qnodes(w)

        assert np.allclose(res, res_2)
Ejemplo n.º 8
0
    def test_multiple_devices(self, mocker):
        """Test that passing multiple devices to ExpvalCost works correctly"""

        dev = [
            qml.device("default.qubit", wires=2),
            qml.device("default.mixed", wires=2)
        ]
        spy = mocker.spy(DefaultQubit, "apply")
        spy2 = mocker.spy(DefaultMixed, "apply")

        obs = [qml.PauliZ(0), qml.PauliZ(1)]
        h = qml.Hamiltonian([1, 1], obs)

        qnodes = qml.ExpvalCost(qml.templates.BasicEntanglerLayers, h, dev)
        w = qml.init.basic_entangler_layers_uniform(3, 2, seed=1967)

        res = qnodes(w)

        spy.assert_called_once()
        spy2.assert_called_once()

        mapped = qml.map(qml.templates.BasicEntanglerLayers, obs, dev)
        exp = sum(mapped(w))

        assert np.allclose(res, exp)

        with pytest.warns(
                UserWarning,
                match="ExpvalCost was instantiated with multiple devices."):
            qnodes.metric_tensor([w])
Ejemplo n.º 9
0
    def test_qnode_collection_integration(self):
        """Test that a PassthruQNode using default.qubit.jax works with QNodeCollections."""
        dev = qml.device("default.qubit.jax", wires=2)

        def ansatz(weights, **kwargs):
            qml.RX(weights[0], wires=0)
            qml.RY(weights[1], wires=1)
            qml.CNOT(wires=[0, 1])

        obs_list = [
            qml.PauliX(0) @ qml.PauliY(1),
            qml.PauliZ(0),
            qml.PauliZ(0) @ qml.PauliZ(1)
        ]
        qnodes = qml.map(ansatz, obs_list, dev, interface="jax")
        if not qml.tape_mode_active():
            assert qnodes.interface == "jax"

        weights = jnp.array([0.1, 0.2])

        def cost(weights):
            return jnp.sum(jnp.array(qnodes(weights)))

        grad = jax.grad(cost)(weights)
        assert grad.shape == weights.shape
Ejemplo n.º 10
0
    def test_mapping_over_observables_as_tuples(self):
        """Test that mapping over a tuple of observables produces
        a QNodeCollection with the correct QNodes, with a single
        device broadcast."""
        dev = qml.device("default.qubit", wires=1)
        obs_list = (qml.PauliX(0), qml.PauliY(0))
        template = lambda x, wires: qml.RX(x, wires=0)

        qc = qml.map(template, obs_list, dev)

        assert len(qc) == 2

        # evaluate collection so that queue is populated
        qc(1)

        assert len(qc[0].ops) == 2
        assert qc[0].ops[0].name == "RX"
        assert qc[0].ops[1].name == "PauliX"

        assert len(qc[1].ops) == 2
        assert qc[1].ops[0].name == "RX"
        assert qc[1].ops[1].name == "PauliY"

        # test that device is broadcast
        assert qc[0].device is qc[1].device
Ejemplo n.º 11
0
 def test_circuits_evaluate(self, ansatz, observables, params, mock_device,
                            seed):
     """Tests that the circuits returned by ``vqe.circuits`` evaluate properly"""
     dev = mock_device(wires=3)
     circuits = qml.map(ansatz, observables, device=dev)
     res = circuits(params)
     assert all(val == 1.0 for val in res)
Ejemplo n.º 12
0
    def test_qnode_collection_integration(self):
        """Test that a PassthruQNode default.qubit.tf works with QNodeCollections."""
        dev = qml.device("default.qubit.tf", wires=2)

        obs_list = [
            qml.PauliX(0) @ qml.PauliY(1),
            qml.PauliZ(0),
            qml.PauliZ(0) @ qml.PauliZ(1)
        ]
        qnodes = qml.map(qml.templates.StronglyEntanglingLayers,
                         obs_list,
                         dev,
                         interface="tf")

        assert qnodes.interface == "tf"

        weights = tf.Variable(
            qml.init.strong_ent_layers_normal(n_wires=2, n_layers=2))

        @tf.function
        def cost(weights):
            return tf.reduce_sum(qnodes(weights))

        with tf.GradientTape() as tape:
            res = qnodes(weights)

        grad = tape.gradient(res, weights)

        assert isinstance(grad, tf.Tensor)
        assert grad.shape == weights.shape
Ejemplo n.º 13
0
    def test_passing_kwargs(self):
        """Test that the step size and order used for the finite differences
        differentiation method were passed to the QNode instances using the
        keyword arguments."""
        dev = qml.device("default.qubit", wires=1)

        obs_list = [qml.PauliX(0), qml.PauliY(0)]
        template = lambda x, wires: qml.RX(x, wires=0)

        qc = qml.map(template,
                     obs_list,
                     dev,
                     measure=["expval", "var"],
                     h=123,
                     order=2)

        qc(1)

        assert len(qc) == 2

        # Checking the h attribute which contains the step size
        assert qc[0].h == 123
        assert qc[1].h == 123

        # Checking that the order is set in each QNode
        assert qc[0].order == 2
        assert qc[1].order == 2
Ejemplo n.º 14
0
    def test_mapping_over_devices(self):
        """Test that mapping over a list of devices produces
        a QNodeCollection with the correct QNodes"""
        dev_list = [qml.device("default.qubit", wires=1), qml.device("default.qubit", wires=1)]

        obs_list = [qml.PauliX(0), qml.PauliY(0)]
        template = lambda x, wires: qml.RX(x, wires=0)

        qc = qml.map(template, obs_list, dev_list)

        assert len(qc) == 2

        # evaluate collection so that queue is populated
        qc(1)

        queue = qc[0].qtape.operations + qc[0].qtape.observables
        assert len(queue) == 2
        assert queue[0].name == "RX"
        assert queue[1].name == "PauliX"

        queue = qc[1].qtape.operations + qc[1].qtape.observables
        assert len(queue) == 2
        assert queue[0].name == "RX"
        assert queue[1].name == "PauliY"

        # test that device is not broadcast
        assert qc[0].device is not qc[1].device
Ejemplo n.º 15
0
    def test_multiple_devices(self, mocker):
        """Test that passing multiple devices to ExpvalCost works correctly"""

        dev = [qml.device("default.qubit", wires=2), qml.device("default.mixed", wires=2)]
        spy = mocker.spy(DefaultQubit, "apply")
        spy2 = mocker.spy(DefaultMixed, "apply")

        obs = [qml.PauliZ(0), qml.PauliZ(1)]
        h = qml.Hamiltonian([1, 1], obs)

        qnodes = qml.ExpvalCost(qml.templates.BasicEntanglerLayers, h, dev)
        np.random.seed(1967)
        w = np.random.random(qml.templates.BasicEntanglerLayers.shape(n_layers=3, n_wires=2))

        res = qnodes(w)

        spy.assert_called_once()
        spy2.assert_called_once()

        mapped = qml.map(qml.templates.BasicEntanglerLayers, obs, dev)
        exp = sum(mapped(w))

        assert np.allclose(res, exp)

        with pytest.warns(UserWarning, match="ExpvalCost was instantiated with multiple devices."):
            qml.metric_tensor(qnodes, approx="block-diag")(w)
Ejemplo n.º 16
0
    def test_mapping_over_measurements(self):
        """Test that mapping over a list of measurement types produces
        a QNodeCollection with the correct QNodes"""
        dev = qml.device("default.qubit", wires=1)

        obs_list = [qml.PauliX(0), qml.PauliY(0)]
        template = lambda x, wires: qml.RX(x, wires=0)

        qc = qml.map(template, obs_list, dev, measure=["expval", "var"])

        assert len(qc) == 2

        # evaluate collection so that queue is populated
        qc(1)

        queue = qc[0].qtape.operations + qc[0].qtape.observables
        assert len(queue) == 2
        assert queue[0].name == "RX"
        assert queue[1].name == "PauliX"
        assert queue[1].return_type == qml.operation.Expectation

        queue = qc[1].qtape.operations + qc[1].qtape.observables
        assert len(queue) == 2
        assert queue[0].name == "RX"
        assert queue[1].name == "PauliY"
        assert queue[1].return_type == qml.operation.Variance
Ejemplo n.º 17
0
    def test_qnode_collection_integration(self):
        """Test that a PassthruQNode default.qubit.autograd works with QNodeCollections."""
        dev = qml.device("default.qubit.autograd", wires=2)

        def ansatz(weights, **kwargs):
            qml.RX(weights[0], wires=0)
            qml.RY(weights[1], wires=1)
            qml.CNOT(wires=[0, 1])

        obs_list = [
            qml.PauliX(0) @ qml.PauliY(1),
            qml.PauliZ(0),
            qml.PauliZ(0) @ qml.PauliZ(1)
        ]
        qnodes = qml.map(ansatz, obs_list, dev, interface="autograd")

        assert qnodes.interface == "autograd"

        weights = np.array([0.1, 0.2], requires_grad=True)

        def cost(weights):
            return np.sum(qnodes(weights))

        grad = qml.grad(cost)(weights)[0]
        assert grad.shape == weights.shape
Ejemplo n.º 18
0
    def test_QNodes_have_right_interface(self, ansatz, observables, params, mock_device):
        """Test that QNodes have the torch interface"""
        dev = mock_device(wires=3)
        circuits = qml.map(ansatz, observables, device=dev, interface="torch")
        assert all(c.interface == "torch" for c in circuits)

        res = [c(params) for c in circuits]
        assert all(isinstance(val, torch.Tensor) for val in res)
Ejemplo n.º 19
0
    def test_circuits_valid_init(self, ansatz, observables, mock_device):
        """Tests that a collection of circuits is properly created by vqe.circuits"""
        dev = mock_device()
        circuits = qml.map(ansatz, observables, device=dev)

        assert len(circuits) == len(observables)
        assert all(callable(c) for c in circuits)
        assert all(c.device == dev for c in circuits)
Ejemplo n.º 20
0
    def test_QNodes_have_right_interface(self, ansatz, observables, params, mock_device, interface):
        """Test that QNodes have the Autograd interface"""
        dev = mock_device(wires=3)
        circuits = qml.map(ansatz, observables, device=dev, interface=interface)

        assert all(c.interface == "autograd" for c in circuits)

        res = [c(params) for c in circuits]
        assert all(isinstance(val, (np.ndarray, float)) for val in res)
Ejemplo n.º 21
0
    def test_QNodes_have_right_interface(self, ansatz, observables, params, mock_device, interface):
        """Test that QNodes have the Autograd interface"""
        mock_device.num_wires = 3
        circuits = qml.map(ansatz, observables, device=mock_device, interface=interface)

        assert all(c.interface == "autograd" for c in circuits)
        assert all(c.__class__.__name__ == "AutogradQNode" for c in circuits)

        res = [c(params) for c in circuits]
        assert all(isinstance(val, float) for val in res)
Ejemplo n.º 22
0
    def __init__(
        self,
        ansatz,
        hamiltonian,
        device,
        interface="autograd",
        diff_method="best",
        optimize=False,
        **kwargs,
    ):
        coeffs, observables = hamiltonian.terms

        self.hamiltonian = hamiltonian
        """Hamiltonian: the hamiltonian defining the VQE problem."""

        self.qnodes = None
        """QNodeCollection: The QNodes to be evaluated. Each QNode corresponds to the expectation
        value of each observable term after applying the circuit ansatz."""

        self._optimize = optimize

        if self._optimize:
            if not qml.tape_mode_active():
                raise ValueError(
                    "Observable optimization is only supported in tape mode. Tape "
                    "mode can be enabled with the command:\n"
                    "qml.enable_tape()"
                )

            obs_groupings, coeffs_groupings = qml.grouping.group_observables(observables, coeffs)

            wires = device.wires.tolist()

            @qml.qnode(device, interface=interface, diff_method=diff_method, **kwargs)
            def circuit(*qnode_args, obs, **qnode_kwargs):
                """Converting ansatz into a full circuit including measurements"""
                ansatz(*qnode_args, wires=wires, **qnode_kwargs)
                return [qml.expval(o) for o in obs]

            def cost_fn(*qnode_args, **qnode_kwargs):
                """Combine results from grouped QNode executions with grouped coefficients"""
                total = 0
                for o, c in zip(obs_groupings, coeffs_groupings):
                    res = circuit(*qnode_args, obs=o, **qnode_kwargs)
                    total += sum([r * c_ for r, c_ in zip(res, c)])
                return total

            self.cost_fn = cost_fn

        else:
            self.qnodes = qml.map(
                ansatz, observables, device, interface=interface, diff_method=diff_method, **kwargs
            )

            self.cost_fn = qml.dot(coeffs, self.qnodes)
Ejemplo n.º 23
0
    def __init__(self, ansatz, hamiltonian, device, interface="autograd", diff_method="best"):
        coeffs, observables = hamiltonian.terms
        self.hamiltonian = hamiltonian
        """Hamiltonian: the hamiltonian defining the VQE problem."""

        self.qnodes = qml.map(ansatz, observables, device, interface=interface, diff_method=diff_method)
        """QNodeCollection: The QNodes to be evaluated. Each QNode corresponds to the
        the expectation value of each observable term after applying the circuit ansatz.
        """

        self.cost_fn = qml.dot(coeffs, self.qnodes)
Ejemplo n.º 24
0
    def test_QNodes_have_right_interface(self, ansatz, observables, params, mock_device):
        """Test that QNodes have the tf interface"""
        if ansatz == amp_embed_and_strong_ent_layer:
            pytest.skip("TF doesn't work with ragged arrays")

        dev = mock_device(wires=3)
        circuits = qml.map(ansatz, observables, device=dev, interface="tf")
        assert all(c.interface == "tf" for c in circuits)

        res = [c(params) for c in circuits]
        assert all(isinstance(val, (Variable, tf.Tensor)) for val in res)
Ejemplo n.º 25
0
    def test_single_qubit_vqe(self, tol):
        """Test single-qubit VQE has the correct QNG value
        every step, the correct parameter updates,
        and correct cost after 200 steps"""
        dev = qml.device("default.qubit", wires=1)

        def circuit(params, wires=0):
            qml.RX(params[0], wires=wires)
            qml.RY(params[1], wires=wires)

        coeffs = [1, 1]
        obs_list = [
            qml.PauliX(0),
            qml.PauliZ(0)
        ]

        qnodes = qml.map(circuit, obs_list, dev, measure='expval')
        cost_fn = qml.dot(coeffs, qnodes)

        def gradient(params):
            """Returns the gradient"""
            da = -np.sin(params[0]) * (np.cos(params[1]) + np.sin(params[1]))
            db = np.cos(params[0]) * (np.cos(params[1]) - np.sin(params[1]))
            return np.array([da, db])

        eta = 0.01
        init_params = np.array([0.011, 0.012])
        num_steps = 200

        opt = qml.QNGOptimizer(eta)
        theta = init_params

        # optimization for 200 steps total
        for t in range(num_steps):
            theta_new = opt.step(cost_fn, theta,
                                 metric_tensor_fn=qnodes.qnodes[0].metric_tensor)

            # check metric tensor
            res = opt.metric_tensor
            exp = np.diag([0.25, (np.cos(theta[0]) ** 2)/4])
            assert np.allclose(res, exp, atol=tol, rtol=0)

            # check parameter update
            dtheta = eta * sp.linalg.pinvh(exp) @ gradient(theta)
            assert np.allclose(dtheta, theta - theta_new, atol=tol, rtol=0)

            theta = theta_new

        # check final cost
        assert np.allclose(cost_fn(theta), -1.41421356, atol=tol, rtol=0)
Ejemplo n.º 26
0
    def test_compiled_program_was_stored(self, qvm, device):
        """Test that QVM device stores the compiled program correctly"""
        dev = qml.device("forest.qvm", device=device, timeout=100)

        assert len(dev._compiled_program_dict.items()) == 0

        def circuit(params, wires):
            qml.Hadamard(0)
            qml.CNOT(wires=[0, 1])

        obs = [qml.PauliZ(0) @ qml.PauliZ(1)]
        obs_list = obs * 6

        qnodes = qml.map(circuit, obs_list, dev)

        qnodes([])
        assert dev.circuit_hash in dev._compiled_program_dict
        assert len(dev._compiled_program_dict.items()) == 1
Ejemplo n.º 27
0
 def __init__(
     self,
     ansatz,
     observables,
     device,
     measure="expval",
     interface="autograd",
     diff_method="best",
     **kwargs,
 ):
     self.qnodes = qml.map(
         ansatz,
         observables,
         device,
         measure=measure,
         interface=interface,
         diff_method=diff_method,
         **kwargs,
     )
Ejemplo n.º 28
0
    def test_compiled_program_was_stored(self):
        """Test that QVM device stores the compiled program correctly"""
        dev = qml.device("default.qubit", wires=3)

        def circuit(params, wires):
            qml.Hadamard(0)
            qml.CNOT(wires=[0, 1])

        obs = [qml.PauliZ(0) @ qml.PauliZ(1)]
        obs_list = obs * 6

        qnodes = qml.map(circuit, obs_list, dev)
        qnodes([], parallel=True)

        hashes = set()
        for qnode in qnodes:
            hashes.add(qnode.circuit.hash)

        assert len(hashes) == 1
Ejemplo n.º 29
0
 def __init__(
     self,
     ansatz,
     observables,
     device,
     measure="expval",
     interface="autograd",
     diff_method="best",
     **kwargs,
 ):
     warn(WARNING_STRING, DeprecationWarning, stacklevel=2)
     self.qnodes = qml.map(
         ansatz,
         observables,
         device,
         measure=measure,
         interface=interface,
         diff_method=diff_method,
         **kwargs,
     )
Ejemplo n.º 30
0
    def test_qnode_collection_integration(self, tol):
        """Test that a PassthruQNode strawberryfields.tf works with QNodeCollections."""
        cutoff = 15
        dev = qml.device("strawberryfields.tf", wires=2, cutoff_dim=cutoff)

        def circuit(weights, input_state=None, **kwargs):
            qml.FockStateVector(input_state, wires=[0, 1])
            qml.TwoModeSqueezing(weights[0], weights[1], wires=[0, 1])

        obs_list = [
            qml.FockStateProjector(np.array([0, 0]), wires=[0, 1]),
            qml.FockStateProjector(np.array([1, 1]), wires=[0, 1]),
        ]

        qnodes = qml.map(circuit, obs_list, dev, interface="tf")

        assert qnodes.interface == "tf"

        weights = tf.Variable([0.12, -0.543])

        def cost(weights):
            vacuum = np.zeros((cutoff, cutoff), dtype=np.complex64)
            vacuum[0, 0] = 1.0 + 0.0j
            vacuum = tf.constant(vacuum)
            return tf.reduce_sum(qnodes(weights, input_state=vacuum))

        with tf.GradientTape() as tape:
            res = cost(weights)

        grad = tape.gradient(res, weights)
        assert isinstance(grad, tf.Tensor)
        assert grad.shape == weights.shape

        R = weights[0]
        expected_grad = [
            -2 * tf.math.tanh(R) / tf.math.cosh(R)**2 + 2 *
            (tf.math.sinh(R) - tf.math.sinh(R)**3) / tf.math.cosh(R)**5,
            0,
        ]

        assert np.allclose(grad, expected_grad, atol=tol, rtol=0)