From 02f106cef3529f17f23d8609ee0da8490e4ba4de Mon Sep 17 00:00:00 2001 From: Tom Bromley <49409390+trbromley@users.noreply.github.com> Date: Thu, 19 Nov 2020 15:44:26 -0500 Subject: [PATCH] Rename VQECost to ExpvalCost (#913) * Rename VQECost to ExpvalCost * Add VQECost as deprecated * Add to changelog * Update PR number * Revert changes to changelog * Change a to an * Add pylint exception * Remove VQECost from docs * Reintroduce docstring --- .github/CHANGELOG.md | 12 ++-- doc/code/qml_qaoa.rst | 4 +- doc/introduction/chemistry.rst | 4 +- pennylane/__init__.py | 2 +- pennylane/optimize/qng.py | 10 ++-- .../layers/particle_conserving_u1.py | 2 +- .../layers/particle_conserving_u2.py | 2 +- pennylane/templates/subroutines/uccsd.py | 2 +- pennylane/utils.py | 2 +- pennylane/vqe/__init__.py | 2 +- pennylane/vqe/vqe.py | 38 ++++++++---- qchem/tests/test_convert_observable.py | 8 +-- tests/test_optimize_qng.py | 6 +- tests/test_qaoa.py | 2 +- tests/test_vqe.py | 59 +++++++++++-------- 15 files changed, 95 insertions(+), 60 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index e7a3939bcaa..d97aa277e99 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -2,8 +2,8 @@

New features since last release

-* The ``VQECost`` class now provides observable optimization using the ``optimize`` argument, - resulting in potentially fewer device executions. +* The ``ExpvalCost`` class (previously ``VQECost``) now provides observable optimization using the + ``optimize`` argument, resulting in potentially fewer device executions. [(#902)](https://github.com/PennyLaneAI/pennylane/pull/902) This is achieved by separating the observables composing the Hamiltonian into qubit-wise @@ -18,8 +18,8 @@ dev = qml.device("default.qubit", wires=2) ansatz = qml.templates.StronglyEntanglingLayers - cost_opt = qml.VQECost(ansatz, H, dev, optimize=True) - cost_no_opt = qml.VQECost(ansatz, H, dev, optimize=False) + cost_opt = qml.ExpvalCost(ansatz, H, dev, optimize=True) + cost_no_opt = qml.ExpvalCost(ansatz, H, dev, optimize=False) params = qml.init.strong_ent_layers_uniform(3, 2) ``` @@ -276,6 +276,10 @@

Breaking changes

+- The ``VQECost`` class has been renamed to ``ExpvalCost`` to reflect its general applicability + beyond VQE. Use of ``VQECost`` is still possible but will result in a deprecation warning. + [(#913)](https://github.com/PennyLaneAI/pennylane/pull/913) +

Documentation

Bug fixes

diff --git a/doc/code/qml_qaoa.rst b/doc/code/qml_qaoa.rst index e9a947c7874..9a0a50888cc 100644 --- a/doc/code/qml_qaoa.rst +++ b/doc/code/qml_qaoa.rst @@ -51,7 +51,7 @@ computational basis states, and then repeatedly apply QAOA layers with the qml.layer(qaoa_layer, 2, params[0], params[1]) -With the circuit defined, we call the device on which QAOA will be executed, as well as the ``qml.VQECost``, which +With the circuit defined, we call the device on which QAOA will be executed, as well as the ``qml.ExpvalCost``, which creates the QAOA cost function: the expected value of the cost Hamiltonian with respect to the parametrized output of the QAOA circuit. @@ -59,7 +59,7 @@ of the QAOA circuit. # Defines the device and the QAOA cost function dev = qml.device('default.qubit', wires=len(wires)) - cost_function = qml.VQECost(circuit, cost_h, dev) + cost_function = qml.ExpvalCost(circuit, cost_h, dev) >>> print(cost_function([[1, 1], [1, 1]])) -1.8260274380964299 diff --git a/doc/introduction/chemistry.rst b/doc/introduction/chemistry.rst index 8b4db7eddcd..1316d1ae92d 100644 --- a/doc/introduction/chemistry.rst +++ b/doc/introduction/chemistry.rst @@ -158,7 +158,7 @@ where a quantum computer is used to prepare the trial wave function of a molecul the expectation value of the *electronic Hamiltonian*, while a classical optimizer is used to find its ground state. -We can use :class:`~.VQECost` to automatically create the required PennyLane QNodes and define +We can use :class:`~.ExpvalCost` to automatically create the required PennyLane QNodes and define the cost function: .. code-block:: python @@ -175,7 +175,7 @@ the cost function: qml.CNOT(wires=[2, 0]) qml.CNOT(wires=[3, 1]) - cost = qml.VQECost(circuit, hamiltonian, dev, interface="torch") + cost = qml.ExpvalCost(circuit, hamiltonian, dev, interface="torch") params = torch.rand([4, 3]) cost(params) diff --git a/pennylane/__init__.py b/pennylane/__init__.py index 255f20f3395..7b13b084d8c 100644 --- a/pennylane/__init__.py +++ b/pennylane/__init__.py @@ -34,7 +34,7 @@ import pennylane.qaoa as qaoa from pennylane.templates import template, broadcast, layer from pennylane.about import about -from pennylane.vqe import Hamiltonian, VQECost +from pennylane.vqe import Hamiltonian, ExpvalCost, VQECost from .circuit_graph import CircuitGraph from .configuration import Configuration diff --git a/pennylane/optimize/qng.py b/pennylane/optimize/qng.py index 311841d7802..cfe6e9c775e 100644 --- a/pennylane/optimize/qng.py +++ b/pennylane/optimize/qng.py @@ -73,7 +73,7 @@ class QNGOptimizer(GradientDescentOptimizer): .. note:: - The QNG optimizer supports single QNodes or :class:`~.VQECost` objects as objective functions. + The QNG optimizer supports single QNodes or :class:`~.ExpvalCost` objects as objective functions. Alternatively, the metric tensor can directly be provided to the :func:`step` method of the optimizer, using the ``metric_tensor_fn`` argument. @@ -91,7 +91,7 @@ class QNGOptimizer(GradientDescentOptimizer): If the objective function is VQE/VQE-like, i.e., a function of a group of QNodes that share an ansatz, there are two ways to use the optimizer: - * Realize the objective function as a :class:`~.VQECost` object, which has + * Realize the objective function as an :class:`~.ExpvalCost` object, which has a ``metric_tensor`` method. * Manually provide the ``metric_tensor_fn`` corresponding to the metric tensor of @@ -100,7 +100,7 @@ class QNGOptimizer(GradientDescentOptimizer): **Examples:** For VQE/VQE-like problems, the objective function for the optimizer can be - realized as a VQECost object. + realized as an ExpvalCost object. >>> dev = qml.device("default.qubit", wires=1) >>> def circuit(params, wires=0): @@ -109,7 +109,7 @@ class QNGOptimizer(GradientDescentOptimizer): >>> coeffs = [1, 1] >>> obs = [qml.PauliX(0), qml.PauliZ(0)] >>> H = qml.Hamiltonian(coeffs, obs) - >>> cost_fn = qml.VQECost(circuit, H, dev) + >>> cost_fn = qml.ExpvalCost(circuit, H, dev) Once constructed, the cost function can be passed directly to the optimizer's ``step`` function: @@ -174,7 +174,7 @@ def step(self, qnode, x, recompute_tensor=True, metric_tensor_fn=None): if not hasattr(qnode, "metric_tensor") and not metric_tensor_fn: raise ValueError( "The objective function must either be encoded as a single QNode or " - "a VQECost object for the natural gradient to be automatically computed. " + "an ExpvalCost object for the natural gradient to be automatically computed. " "Otherwise, metric_tensor_fn must be explicitly provided to the optimizer." ) diff --git a/pennylane/templates/layers/particle_conserving_u1.py b/pennylane/templates/layers/particle_conserving_u1.py index 0a2fbcb7ae2..2750f2eeb0e 100644 --- a/pennylane/templates/layers/particle_conserving_u1.py +++ b/pennylane/templates/layers/particle_conserving_u1.py @@ -219,7 +219,7 @@ def ParticleConservingU1(weights, wires, init_state=None): ansatz = partial(ParticleConservingU1, init_state=ref_state) # Define the cost function - cost_fn = qml.VQECost(ansatz, h, dev) + cost_fn = qml.ExpvalCost(ansatz, h, dev) # Compute the expectation value of 'h' layers = 2 diff --git a/pennylane/templates/layers/particle_conserving_u2.py b/pennylane/templates/layers/particle_conserving_u2.py index eb24bb182d8..67482b6d43f 100644 --- a/pennylane/templates/layers/particle_conserving_u2.py +++ b/pennylane/templates/layers/particle_conserving_u2.py @@ -140,7 +140,7 @@ def ParticleConservingU2(weights, wires, init_state=None): ansatz = partial(ParticleConservingU2, init_state=ref_state) # Define the cost function - cost_fn = qml.VQECost(ansatz, h, dev) + cost_fn = qml.ExpvalCost(ansatz, h, dev) # Compute the expectation value of 'h' for a given set of parameters layers = 1 diff --git a/pennylane/templates/subroutines/uccsd.py b/pennylane/templates/subroutines/uccsd.py index f2859e99d84..a9134d9e87c 100644 --- a/pennylane/templates/subroutines/uccsd.py +++ b/pennylane/templates/subroutines/uccsd.py @@ -145,7 +145,7 @@ def UCCSD(weights, wires, s_wires=None, d_wires=None, init_state=None): ansatz = partial(UCCSD, init_state=ref_state, s_wires=s_wires, d_wires=d_wires) # Define the cost function - cost_fn = qml.VQECost(ansatz, h, dev) + cost_fn = qml.ExpvalCost(ansatz, h, dev) # Compute the expectation value of 'h' for given set of parameters 'params' params = np.random.normal(0, np.pi, len(singles) + len(doubles)) diff --git a/pennylane/utils.py b/pennylane/utils.py index af58d1f08f0..a08f4f3d471 100644 --- a/pennylane/utils.py +++ b/pennylane/utils.py @@ -68,7 +68,7 @@ def decompose_hamiltonian(H, hide_identity=False): + (-0.5) [Z0 X1] + (-0.5) [Z0 Y1] - This Hamiltonian can then be used in defining VQE problems using :class:`~.VQECost`. + This Hamiltonian can then be used in defining VQE problems using :class:`~.ExpvalCost`. """ n = int(np.log2(len(H))) N = 2 ** n diff --git a/pennylane/vqe/__init__.py b/pennylane/vqe/__init__.py index 4823c8dc649..2a969a4636d 100644 --- a/pennylane/vqe/__init__.py +++ b/pennylane/vqe/__init__.py @@ -15,4 +15,4 @@ This package contains functionality for running Variational Quantum Eigensolver (VQE) computations using PennyLane. """ -from .vqe import Hamiltonian, VQECost +from .vqe import Hamiltonian, ExpvalCost, VQECost diff --git a/pennylane/vqe/vqe.py b/pennylane/vqe/vqe.py index 14aafbd4f66..56dbc6a2a2d 100644 --- a/pennylane/vqe/vqe.py +++ b/pennylane/vqe/vqe.py @@ -17,6 +17,7 @@ """ # pylint: disable=too-many-arguments, too-few-public-methods import itertools +import warnings import pennylane as qml from pennylane import numpy as np @@ -40,7 +41,7 @@ class Hamiltonian: simplify (bool): Specifies whether the Hamiltonian is simplified upon initialization (like-terms are combined). The default value is `False`. - .. seealso:: :class:`~.VQECost`, :func:`~.generate_hamiltonian` + .. seealso:: :class:`~.ExpvalCost`, :func:`~.generate_hamiltonian` **Example:** @@ -346,9 +347,10 @@ def __isub__(self, H): raise ValueError(f"Cannot subtract {type(H)} from Hamiltonian") -class VQECost: - """Create a VQE cost function, i.e., a cost function returning the - expectation value of a Hamiltonian. +class ExpvalCost: + """Create a cost function that gives the expectation value of an input Hamiltonian. + + This cost function is useful for a range of problems including VQE and QAOA. Args: ansatz (callable): The ansatz for the circuit before the final measurement step. @@ -382,7 +384,7 @@ class VQECost: **Example:** - To construct a ``VQECost`` cost function, we require a Hamiltonian to measure, and an ansatz + To construct an ``ExpvalCost`` cost function, we require a Hamiltonian to measure, and an ansatz for our variational circuit. We can construct a Hamiltonian manually, @@ -404,7 +406,7 @@ class VQECost: >>> ansatz = qml.templates.StronglyEntanglingLayers >>> dev = qml.device("default.qubit", wires=4) - >>> cost = qml.VQECost(ansatz, H, dev, interface="torch") + >>> cost = qml.ExpvalCost(ansatz, H, dev, interface="torch") >>> params = torch.rand([2, 4, 3]) >>> cost(params) tensor(-0.2316, dtype=torch.float64) @@ -430,8 +432,8 @@ class VQECost: dev = qml.device("default.qubit", wires=2) ansatz = qml.templates.StronglyEntanglingLayers - cost_opt = qml.VQECost(ansatz, H, dev, optimize=True) - cost_no_opt = qml.VQECost(ansatz, H, dev, optimize=False) + cost_opt = qml.ExpvalCost(ansatz, H, dev, optimize=True) + cost_no_opt = qml.ExpvalCost(ansatz, H, dev, optimize=False) params = qml.init.strong_ent_layers_uniform(3, 2) @@ -462,7 +464,7 @@ def __init__( coeffs, observables = hamiltonian.terms self.hamiltonian = hamiltonian - """Hamiltonian: the hamiltonian defining the VQE problem.""" + """Hamiltonian: the input Hamiltonian.""" self.qnodes = None """QNodeCollection: The QNodes to be evaluated. Each QNode corresponds to the expectation @@ -527,7 +529,23 @@ def metric_tensor(self, args, kwargs=None, diag_approx=False, only_construct=Fal "optimized observables. Set the argument optimize=False to obtain " "the metric tensor." ) - # We know that for VQE, all the qnodes share the same ansatz so we select the first + # all the qnodes share the same ansatz so we select the first return self.qnodes.qnodes[0].metric_tensor( args=args, kwargs=kwargs, diag_approx=diag_approx, only_construct=only_construct ) + + +class VQECost(ExpvalCost): + """Create a cost function that gives the expectation value of an input Hamiltonian. + + .. warning:: + Use of :class:`~.VQECost` is deprecated and should be replaced with + :class:`~.ExpvalCost`. + """ + + def __init__(self, *args, **kwargs): + warnings.warn( + "Use of VQECost is deprecated and should be replaced with ExpvalCost", + DeprecationWarning, + ) + super().__init__(*args, **kwargs) diff --git a/qchem/tests/test_convert_observable.py b/qchem/tests/test_convert_observable.py index fffa10792d0..2d04f3ae63d 100644 --- a/qchem/tests/test_convert_observable.py +++ b/qchem/tests/test_convert_observable.py @@ -352,7 +352,7 @@ def test_not_xyz_terms_to_qubit_operator(): def test_integration_observable_to_vqe_cost( monkeypatch, mol_name, terms_ref, expected_cost, custom_wires, tol ): - r"""Test if `convert_observable()` in qchem integrates with `VQECost()` in pennylane""" + r"""Test if `convert_observable()` in qchem integrates with `ExpvalCost()` in pennylane""" qOp = QubitOperator() if terms_ref is not None: @@ -375,7 +375,7 @@ def dummy_ansatz(phis, wires): for phi, w in zip(phis, wires): qml.RX(phi, wires=w) - dummy_cost = qml.VQECost(dummy_ansatz, vqe_observable, dev) + dummy_cost = qml.ExpvalCost(dummy_ansatz, vqe_observable, dev) params = [0.1 * i for i in range(num_qubits)] res = dummy_cost(params) @@ -397,7 +397,7 @@ def test_integration_mol_file_to_vqe_cost( name, core, active, mapping, expected_cost, custom_wires, tol ): r"""Test if the output of `decompose()` works with `convert_observable()` - to generate `VQECost()`""" + to generate `ExpvalCost()`""" ref_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_ref_files") hf_file = os.path.join(ref_dir, name) @@ -424,7 +424,7 @@ def dummy_ansatz(phis, wires): phis = np.load(os.path.join(ref_dir, "dummy_ansatz_parameters.npy")) - dummy_cost = qml.VQECost(dummy_ansatz, vqe_hamiltonian, dev) + dummy_cost = qml.ExpvalCost(dummy_ansatz, vqe_hamiltonian, dev) res = dummy_cost(phis) assert np.abs(res - expected_cost) < tol["atol"] diff --git a/tests/test_optimize_qng.py b/tests/test_optimize_qng.py index 157ef1951cc..9b531136b09 100644 --- a/tests/test_optimize_qng.py +++ b/tests/test_optimize_qng.py @@ -40,7 +40,7 @@ def cost(a): params = 0.5 with pytest.raises( - ValueError, match="The objective function must either be encoded as a single QNode or a VQECost object" + ValueError, match="The objective function must either be encoded as a single QNode or an ExpvalCost object" ): opt.step(cost, params) @@ -143,7 +143,7 @@ def gradient(params): assert np.allclose(cost_fn(theta), -1.41421356, atol=tol, rtol=0) def test_single_qubit_vqe_using_vqecost(self, tol): - """Test single-qubit VQE using VQECost + """Test single-qubit VQE using ExpvalCost has the correct QNG value every step, the correct parameter updates, and correct cost after 200 steps""" dev = qml.device("default.qubit", wires=1) @@ -160,7 +160,7 @@ def circuit(params, wires=0): h = qml.Hamiltonian(coeffs=coeffs, observables=obs_list) - cost_fn = qml.VQECost(ansatz=circuit, hamiltonian=h, device=dev) + cost_fn = qml.ExpvalCost(ansatz=circuit, hamiltonian=h, device=dev) def gradient(params): """Returns the gradient""" diff --git a/tests/test_qaoa.py b/tests/test_qaoa.py index effcb7d9ac4..aabe70b28eb 100644 --- a/tests/test_qaoa.py +++ b/tests/test_qaoa.py @@ -659,7 +659,7 @@ def circuit(params, **kwargs): # Defines the device and the QAOA cost function dev = qml.device('default.qubit', wires=len(wires)) - cost_function = qml.VQECost(circuit, cost_h, dev) + cost_function = qml.ExpvalCost(circuit, cost_h, dev) res = cost_function([[1, 1], [1, 1]]) expected = -1.8260274380964299 diff --git a/tests/test_vqe.py b/tests/test_vqe.py index 0d3ac2cc206..c20aa2c42ed 100644 --- a/tests/test_vqe.py +++ b/tests/test_vqe.py @@ -683,7 +683,7 @@ def test_cost_evaluate(self, params, ansatz, coeffs, observables): """Tests that the cost function evaluates properly""" hamiltonian = qml.vqe.Hamiltonian(coeffs, observables) dev = qml.device("default.qubit", wires=3) - expval = qml.VQECost(ansatz, hamiltonian, dev) + expval = qml.ExpvalCost(ansatz, hamiltonian, dev) assert type(expval(params)) == np.float64 assert np.shape(expval(params)) == () # expval should be scalar @@ -692,7 +692,7 @@ def test_cost_expvals(self, coeffs, observables, expected): """Tests that the cost function returns correct expectation values""" dev = qml.device("default.qubit", wires=2) hamiltonian = qml.vqe.Hamiltonian(coeffs, observables) - cost = qml.VQECost(lambda params, **kwargs: None, hamiltonian, dev) + cost = qml.ExpvalCost(lambda params, **kwargs: None, hamiltonian, dev) assert cost([]) == sum(expected) @pytest.mark.parametrize("ansatz", JUNK_INPUTS) @@ -700,7 +700,7 @@ def test_cost_invalid_ansatz(self, ansatz, mock_device): """Tests that the cost function raises an exception if the ansatz is not valid""" hamiltonian = qml.vqe.Hamiltonian((1.0,), [qml.PauliZ(0)]) with pytest.raises(ValueError, match="not a callable function."): - cost = qml.VQECost(4, hamiltonian, mock_device()) + cost = qml.ExpvalCost(4, hamiltonian, mock_device()) @pytest.mark.parametrize("coeffs, observables, expected", hamiltonians_with_expvals) def test_passing_kwargs(self, coeffs, observables, expected): @@ -709,7 +709,7 @@ def test_passing_kwargs(self, coeffs, observables, expected): keyword arguments.""" dev = qml.device("default.qubit", wires=2) hamiltonian = qml.vqe.Hamiltonian(coeffs, observables) - cost = qml.VQECost(lambda params, **kwargs: None, hamiltonian, dev, h=123, order=2) + cost = qml.ExpvalCost(lambda params, **kwargs: None, hamiltonian, dev, h=123, order=2) # Checking that the qnodes contain the step size and order for qnode in cost.qnodes: @@ -726,12 +726,12 @@ def test_optimize_outside_tape_mode(self): hamiltonian = qml.vqe.Hamiltonian([1], [qml.PauliZ(0)]) with pytest.raises(ValueError, match="Observable optimization is only supported in tape"): - qml.VQECost(lambda params, **kwargs: None, hamiltonian, dev, optimize=True) + qml.ExpvalCost(lambda params, **kwargs: None, hamiltonian, dev, optimize=True) @pytest.mark.parametrize("interface", ["tf", "torch", "autograd"]) def test_optimize(self, interface, tf_support, torch_support): - """Test that a VQECost with observable optimization gives the same result as another - VQECost without observable optimization.""" + """Test that an ExpvalCost with observable optimization gives the same result as another + ExpvalCost without observable optimization.""" if not qml.tape_mode_active(): pytest.skip("This test is only intended for tape mode") if interface == "tf" and not tf_support: @@ -742,14 +742,14 @@ def test_optimize(self, interface, tf_support, torch_support): dev = qml.device("default.qubit", wires=4) hamiltonian = big_hamiltonian - cost = qml.VQECost( + cost = qml.ExpvalCost( qml.templates.StronglyEntanglingLayers, hamiltonian, dev, optimize=True, interface=interface, ) - cost2 = qml.VQECost( + cost2 = qml.ExpvalCost( qml.templates.StronglyEntanglingLayers, hamiltonian, dev, @@ -772,7 +772,7 @@ def test_optimize(self, interface, tf_support, torch_support): assert np.allclose(c1, c2) def test_optimize_grad(self): - """Test that the gradient of VQECost is accessible and correct when using observable + """Test that the gradient of ExpvalCost is accessible and correct when using observable optimization and the autograd interface.""" if not qml.tape_mode_active(): pytest.skip("This test is only intended for tape mode") @@ -780,8 +780,8 @@ def test_optimize_grad(self): dev = qml.device("default.qubit", wires=4) hamiltonian = big_hamiltonian - cost = qml.VQECost(qml.templates.StronglyEntanglingLayers, hamiltonian, dev, optimize=True) - cost2 = qml.VQECost( + cost = qml.ExpvalCost(qml.templates.StronglyEntanglingLayers, hamiltonian, dev, optimize=True) + cost2 = qml.ExpvalCost( qml.templates.StronglyEntanglingLayers, hamiltonian, dev, optimize=False ) @@ -799,7 +799,7 @@ def test_optimize_grad(self): assert np.allclose(dc2, big_hamiltonian_grad) def test_optimize_grad_torch(self, torch_support): - """Test that the gradient of VQECost is accessible and correct when using observable + """Test that the gradient of ExpvalCost is accessible and correct when using observable optimization and the Torch interface.""" if not qml.tape_mode_active(): pytest.skip("This test is only intended for tape mode") @@ -809,7 +809,7 @@ def test_optimize_grad_torch(self, torch_support): dev = qml.device("default.qubit", wires=4) hamiltonian = big_hamiltonian - cost = qml.VQECost( + cost = qml.ExpvalCost( qml.templates.StronglyEntanglingLayers, hamiltonian, dev, @@ -826,7 +826,7 @@ def test_optimize_grad_torch(self, torch_support): assert np.allclose(dc, big_hamiltonian_grad) def test_optimize_grad_tf(self, tf_support): - """Test that the gradient of VQECost is accessible and correct when using observable + """Test that the gradient of ExpvalCost is accessible and correct when using observable optimization and the TensorFlow interface.""" if not qml.tape_mode_active(): pytest.skip("This test is only intended for tape mode") @@ -836,7 +836,7 @@ def test_optimize_grad_tf(self, tf_support): dev = qml.device("default.qubit", wires=4) hamiltonian = big_hamiltonian - cost = qml.VQECost( + cost = qml.ExpvalCost( qml.templates.StronglyEntanglingLayers, hamiltonian, dev, optimize=True, interface="tf" ) @@ -857,7 +857,7 @@ def test_metric_tensor(self): dev = qml.device("default.qubit", wires=4) hamiltonian = big_hamiltonian - cost = qml.VQECost(qml.templates.StronglyEntanglingLayers, hamiltonian, dev, optimize=True) + cost = qml.ExpvalCost(qml.templates.StronglyEntanglingLayers, hamiltonian, dev, optimize=True) with pytest.raises(ValueError, match="Evaluation of the metric tensor is not supported"): cost.metric_tensor(None) @@ -896,7 +896,7 @@ def ansatz(params, **kwargs): a, b = 0.54, 0.123 params = np.array([a, b]) - cost = qml.VQECost(ansatz, H, dev, interface=interface) + cost = qml.ExpvalCost(ansatz, H, dev, interface=interface) dcost = qml.grad(cost, argnum=[0]) res = dcost(params) @@ -939,7 +939,7 @@ def ansatz(params, **kwargs): a, b = 0.54, 0.123 params = torch.autograd.Variable(torch.tensor([a, b]), requires_grad=True) - cost = qml.VQECost(ansatz, H, dev, interface="torch") + cost = qml.ExpvalCost(ansatz, H, dev, interface="torch") loss = cost(params) loss.backward() @@ -986,7 +986,7 @@ def ansatz(params, **kwargs): H = qml.vqe.Hamiltonian(coeffs, observables) a, b = 0.54, 0.123 params = Variable([a, b], dtype=tf.float64) - cost = qml.VQECost(ansatz, H, dev, interface="tf") + cost = qml.ExpvalCost(ansatz, H, dev, interface="tf") with tf.GradientTape() as tape: loss = cost(params) @@ -1019,7 +1019,7 @@ def test_all_interfaces_gradient_agree(self, tol): params = Variable(qml.init.strong_ent_layers_normal(n_layers=3, n_wires=2, seed=1)) ansatz = qml.templates.layers.StronglyEntanglingLayers - cost = qml.VQECost(ansatz, H, dev, interface="tf") + cost = qml.ExpvalCost(ansatz, H, dev, interface="tf") with tf.GradientTape() as tape: loss = cost(params) @@ -1030,7 +1030,7 @@ def test_all_interfaces_gradient_agree(self, tol): params = torch.autograd.Variable(params, requires_grad=True) ansatz = qml.templates.layers.StronglyEntanglingLayers - cost = qml.VQECost(ansatz, H, dev, interface="torch") + cost = qml.ExpvalCost(ansatz, H, dev, interface="torch") loss = cost(params) loss.backward() res_torch = params.grad.numpy() @@ -1038,9 +1038,22 @@ def test_all_interfaces_gradient_agree(self, tol): # NumPy interface params = qml.init.strong_ent_layers_normal(n_layers=3, n_wires=2, seed=1) ansatz = qml.templates.layers.StronglyEntanglingLayers - cost = qml.VQECost(ansatz, H, dev, interface="autograd") + cost = qml.ExpvalCost(ansatz, H, dev, interface="autograd") dcost = qml.grad(cost, argnum=[0]) res = dcost(params) assert np.allclose(res, res_tf, atol=tol, rtol=0) assert np.allclose(res, res_torch, atol=tol, rtol=0) + + +def test_vqe_cost(): + """Tests that VQECost raises a DeprecationWarning but otherwise behaves as ExpvalCost""" + + h = qml.Hamiltonian([1], [qml.PauliZ(0)]) + dev = qml.device("default.qubit", wires=1) + ansatz = qml.templates.StronglyEntanglingLayers + + with pytest.warns(DeprecationWarning, match="Use of VQECost is deprecated"): + cost = qml.VQECost(ansatz, h, dev) + + assert isinstance(cost, qml.ExpvalCost)