qml.gradients.quantum_fisher¶
- quantum_fisher(tape, device, *args, **kwargs)[source]¶
Returns a function that computes the quantum fisher information matrix (QFIM) of a given
QNode
.Given a parametrized quantum state \(|\psi(\bm{\theta})\rangle\), the quantum fisher information matrix (QFIM) quantifies how changes to the parameters \(\bm{\theta}\) are reflected in the quantum state. The metric used to induce the QFIM is the fidelity \(f = |\langle \psi | \psi' \rangle|^2\) between two (pure) quantum states. This leads to the following definition of the QFIM (see eq. (27) in arxiv:2103.15191):
\[\text{QFIM}_{i, j} = 4 \text{Re}\left[ \langle \partial_i \psi(\bm{\theta}) | \partial_j \psi(\bm{\theta}) \rangle - \langle \partial_i \psi(\bm{\theta}) | \psi(\bm{\theta}) \rangle \langle \psi(\bm{\theta}) | \partial_j \psi(\bm{\theta}) \rangle \right]\]with short notation \(| \partial_j \psi(\bm{\theta}) \rangle := \frac{\partial}{\partial \theta_j}| \psi(\bm{\theta}) \rangle\).
See also
metric_tensor()
,adjoint_metric_tensor()
,classical_fisher()
- Parameters
tape (QNode or QuantumTape or Callable) – A quantum circuit that may have arbitrary return types.
*args – In case finite shots are used, further arguments according to
metric_tensor()
may be passed.
- Returns
The transformed circuit as described in
qml.transform
. Executing this circuit will provide the quantum Fisher information in the form of a tensor.- Return type
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]
Note
quantum_fisher
coincides with themetric_tensor
with a prefactor of \(4\). Internally,adjoint_metric_tensor()
is used when executing on"default.qubit"
with exact expectations (shots=None
). In all other cases, e.g. if a device with finite shots is used, the hardware-compatible transformmetric_tensor()
is used, which may require an additional wire on the device. Please refer to the respective documentations for details.Example
The quantum Fisher information matrix (QIFM) can be used to compute the natural gradient for Quantum Natural Gradient Descent. A typical scenario is optimizing the expectation value of a Hamiltonian:
from pennylane import numpy as np n_wires = 2 dev = qml.device("default.qubit", wires=n_wires) H = 1.*qml.X(0) @ qml.X(1) - 0.5 * qml.Z(1) @qml.qnode(dev) def circ(params): qml.RY(params[0], wires=1) qml.CNOT(wires=(1,0)) qml.RY(params[1], wires=1) qml.RZ(params[2], wires=1) return qml.expval(H) params = np.array([0.5, 1., 0.2], requires_grad=True)
The natural gradient is then simply the QFIM multiplied by the gradient:
>>> grad = qml.grad(circ)(params) >>> grad array([ 0.59422561, -0.02615095, -0.05146226]) >>> qfim = qml.gradients.quantum_fisher(circ)(params) >>> qfim tensor([[1. , 0. , 0. ], [0. , 1. , 0. ], [0. , 0. , 0.77517241]], requires_grad=True) >>> qfim @ grad tensor([ 0.59422561, -0.02615095, -0.03989212], requires_grad=True)
When using real hardware or finite shots,
quantum_fisher
is internally callingmetric_tensor()
. To obtain the full QFIM, we need an auxilary wire to perform the Hadamard test.>>> dev = qml.device("default.qubit", wires=n_wires+1, shots=1000) >>> @qml.qnode(dev) ... def circ(params): ... qml.RY(params[0], wires=1) ... qml.CNOT(wires=(1,0)) ... qml.RY(params[1], wires=1) ... qml.RZ(params[2], wires=1) ... return qml.expval(H) >>> qfim = qml.gradients.quantum_fisher(circ)(params)
Alternatively, we can fall back on the block-diagonal QFIM without the additional wire.
>>> qfim = qml.gradients.quantum_fisher(circ, approx="block-diag")(params)