Qfim metric tensor verify diagonal elements

import pennylane as qml
from pennylane import numpy as np


n_qubits = 2
dev = qml.device("default.qubit", wires=n_qubits)


weights = np.random.random(size=(n_qubits, 2), requires_grad=True)  
x = np.random.random(size=(2,)) 


@qml.qnode(dev)
def circuit(weights, x):
   
    for i in range(n_qubits):
        qml.RX(x[i], wires=i)
        qml.RY(weights[i, 0], wires=i)
        qml.RZ(weights[i, 1], wires=i)
 
    return qml.expval(qml.PauliZ(0))


def compute_qfim_and_ggrad(weights, x):
  
    cost_fn = lambda w: circuit(w, x)

  
    qfim = qml.gradients.quantum_fisher(circuit)(weights, x)
    
  
    ggrad = qml.grad(cost_fn)(weights)
    
    return qfim, ggrad


qfim, ggrad = compute_qfim_and_ggrad(weights, x)
print(qfim)
print("\nGradient (ggrad):")
print(ggrad)

metric_fn = qml.metric_tensor(circuit, approx="diag")(weights, x)

print(metric_fn)

It works, but how can i have diag elements or block-diagonal elements of qfim. Second question is qfim=4. metric tensor (qml.gradients.quantum_fisher — PennyLane 0.38.1 documentation). But on verification, it did not 4 times of metric tensor elements. is there anything mistake. Can you please help.

Name: PennyLane
Version: 0.38.0
Summary: PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemistry. Train a quantum computer the same way as a neural network.
Home-page: https://github.com/PennyLaneAI/pennylane
Author: 
Author-email: 
License: Apache License 2.0
Location: /home/bhatia87/.conda/envs/cent7/2020.11-py38/xyz2/lib/python3.10/site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, packaging, pennylane-lightning, requests, rustworkx, scipy, toml, typing-extensions
Required-by: PennyLane_Lightning

Platform info:           Linux-3.10.0-1160.108.1.el7.x86_64-x86_64-with-glibc2.17
Python version:          3.10.14
Numpy version:           1.23.5
Scipy version:           1.10.0
Installed devices:
- lightning.qubit (PennyLane_Lightning-0.38.0)
- default.clifford (PennyLane-0.38.0)
- default.gaussian (PennyLane-0.38.0)
- default.mixed (PennyLane-0.38.0)
- default.qubit (PennyLane-0.38.0)
- default.qubit.autograd (PennyLane-0.38.0)
- default.qubit.jax (PennyLane-0.38.0)
- default.qubit.legacy (PennyLane-0.38.0)
- default.qubit.tf (PennyLane-0.38.0)
- default.qubit.torch (PennyLane-0.38.0)
- default.qutrit (PennyLane-0.38.0)
- default.qutrit.mixed (PennyLane-0.38.0)
- default.tensor (PennyLane-0.38.0)
- null.qubit (PennyLane-0.38.0)

Hi @Amandeep ,

how can i have diag elements or block-diagonal elements of qfim

I guess you can calculate the variance of the parameters as shown in the PennyLane demo on Quantum natural gradient.
Look at the section on the block-diagonal metric tensor and you’ll see that the diagonal terms are given by the variance.

Regarding your question about comparing the metric tensor (MT) to the quantum fisher information matrix (QFIM), there were several issues in your code. On one hand you were computing the diagonal approximation of the metric tensor. If you want to compare the QFIM to the MT you need to use the full MT, not using approximations.
Note that to get the full MT you need an auxiliary qubit.

On the other hand you had trouble comparing because of the shape of weights. I would recommend making it one-dimensional so that you can compare properly. See an example below. This requires a slight change in how you specify the parameters in the gates in your circuit, as seen in the code below.

Finally, since you don’t want to calculate the metric tensor with respect to x you must set requires_grad=False when you define it.

Now you can make a proper comparison and see that quantum_fisher coincides with the metric_tensor with a prefactor of 4.

# modified example
import pennylane as qml
from pennylane import numpy as np


n_qubits = 2
dev = qml.device("default.qubit", wires=n_qubits)


weights = np.random.random(size=(4, ), requires_grad=True)  # mod
x = np.random.random(size=(2,), requires_grad=False) # mod


@qml.qnode(dev)
def circuit(weights, x):
   
    for i in range(n_qubits):
        qml.RX(x[i], wires=i)
        qml.RY(weights[2*i], wires=i) #mod
        qml.RZ(weights[2*i + 1], wires=i) #mod
 
    return qml.expval(qml.PauliZ(0))


def compute_qfim_and_ggrad(weights, x):
  
    cost_fn = lambda w: circuit(w, x)

  
    qfim = qml.gradients.quantum_fisher(circuit)(weights, x)
    
  
    ggrad = qml.grad(cost_fn)(weights)
    
    return qfim, ggrad


qfim, ggrad = compute_qfim_and_ggrad(weights, x)
print(qfim)
print("\nGradient (ggrad):")
print(ggrad)

# added
dev2 = qml.device("default.qubit", wires=n_qubits+1)

@qml.qnode(dev2)
def circuit2(weights, x):
   
    for i in range(n_qubits):
        qml.RX(x[i], wires=i)
        qml.RY(weights[2*i], wires=i) #mod
        qml.RZ(weights[2*i + 1], wires=i) #mod
 
    return qml.expval(qml.PauliZ(0))

metric_fn = qml.metric_tensor(circuit2)(weights, x) # mod approx="diag"

print(metric_fn)

# Check if they coincide with a prefactor of 4
print('quantum_fisher coincides with the metric_tensor with a prefactor of 4: ',np.allclose(qfim,4*metric_fn))