qml.ExpvalCost

class ExpvalCost(ansatz, hamiltonian, device, interface='autograd', diff_method='best', optimize=False, **kwargs)[source]

Bases: object

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.

Parameters
  • ansatz (callable) –

    The ansatz for the circuit before the final measurement step. Note that the ansatz must have the following signature:

    ansatz(params, **kwargs)
    

    where params are the trainable weights of the variational circuit, and kwargs are any additional keyword arguments that need to be passed to the template.

  • hamiltonian (Hamiltonian) – Hamiltonian operator whose expectation value should be measured

  • device (Device, Sequence[Device]) – Corresponding device(s) where the resulting cost function should be executed. This can either be a single device, or a list of devices of length matching the number of terms in the Hamiltonian.

  • interface (str, None) – Which interface to use. This affects the types of objects that can be passed to/returned to the cost function. Supports all interfaces supported by the qnode() decorator.

  • diff_method (str, None) – The method of differentiation to use with the created cost function. Supports all differentiation methods supported by the qnode() decorator.

  • optimize (bool) – Whether to optimize the observables composing the Hamiltonian by separating them into qubit-wise commuting groups. Each group can then be executed within a single QNode, resulting in fewer QNodes to evaluate.

Returns

a cost function with signature cost_fn(params, **kwargs) that evaluates the expectation of the Hamiltonian on the provided device(s)

Return type

callable

Example:

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,

coeffs = [0.2, -0.543]
obs = [
    qml.PauliX(0) @ qml.PauliZ(1) @ qml.PauliY(3),
    qml.PauliZ(0) @ qml.Hadamard(2)
]
H = qml.vqe.Hamiltonian(coeffs, obs)

Alternatively, the molecular_hamiltonian() function from the Quantum Chemistry module can be used to generate a molecular Hamiltonian.

Once we have our Hamiltonian, we can select an ansatz and construct the cost function.

>>> ansatz = qml.templates.StronglyEntanglingLayers
>>> dev = qml.device("default.qubit", wires=4)
>>> cost = qml.ExpvalCost(ansatz, H, dev, interface="torch")
>>> params = torch.rand([2, 4, 3])
>>> cost(params)
tensor(-0.2316, dtype=torch.float64)

The cost function can then be minimized using any gradient descent-based optimizer.

Optimizing observables:

Setting optimize=True can be used to decrease the number of device executions. The observables composing the Hamiltonian can be separated into groups that are qubit-wise commuting using the grouping module. These groups can be executed together on a single qnode, resulting in a lower device overhead:

commuting_obs = [qml.PauliX(0), qml.PauliX(0) @ qml.PauliZ(1)]
H = qml.vqe.Hamiltonian([1, 1], commuting_obs)

dev = qml.device("default.qubit", wires=2)
ansatz = qml.templates.StronglyEntanglingLayers

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)

Grouping these commuting observables leads to fewer device executions:

>>> cost_opt(params)
>>> ex_opt = dev.num_executions
>>> cost_no_opt(params)
>>> ex_no_opt = dev.num_executions - ex_opt
>>> print("Number of executions:", ex_no_opt)
Number of executions: 2
>>> print("Number of executions (optimized):", ex_opt)
Number of executions (optimized): 1

__call__(*args, **kwargs)

Call self as a function.

__call__(*args, **kwargs)[source]

Call self as a function.

Contents

Using PennyLane

Development

API