qml.qinfo.transforms.quantum_fisher¶
-
quantum_fisher
(qnode, *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\).
- Parameters
qnode (
QNode
) – AQNode
that may have arbitrary return types.*args – In case finite shots are used, further arguments according to
metric_tensor()
may be passed.
- Returns
A function that computes the quantum fisher information matrix.
- Return type
func
Note
quantum_fisher
coincides with themetric_tensor
with a prefactor of \(4\). Internally,adjoint_metric_tensor()
is used when executing on a device with exact expectations (shots=None
) that inherits from"default.qubit"
. In all other cases, i.e. if a device with finite shots is used, the hardware compatible transformmetric_tensor()
is used. Please refer to their respective documentations for details on the arguments.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:
n_wires = 2 dev = qml.device("default.qubit", wires=n_wires) H = 1.*qml.PauliX(0) @ qml.PauliX(1) - 0.5 * qml.PauliZ(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 = pnp.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.qinfo.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.qinfo.quantum_fisher(circ)(params)
Alternatively, we can fall back on the block-diagonal QFIM without the additional wire.
>>> qfim = qml.qinfo.quantum_fisher(circ, approx="block-diag")(params)