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) – A QNode that may have arbitrary return types.

  • *args – In case finite shots are used, further arguments according to metric_tensor() may be passed.

Returns

The function that computes the quantum fisher information matrix.

Return type

func

Note

quantum_fisher coincides with the metric_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 transform metric_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 calling metric_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)