Count CNOT gates and Pauli gates in Hamiltonian

Dear friends,

I have recently started looking at the qubit tapering and its application in quantum chemistry. Is there anyway to count the number of CNOT gates or Pauli gates in a given Hamiltonian. So, it can be used to compare the no. of gates in a Hamiltonian before and qubit tapering.

Thank you.

Hi @raghavv, I don’t think we have a gate-counting function but you could export your circuit to qasm and then count the gates from there. Here’s an example of how to export a circuit to qasm:

import pennylane as qml

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

def f(x):
    qml.RX(x, wires=0)
    return qml.expval(qml.PauliZ(0))
qnode = qml.QNode(f, dev)
qnode(0.3)

qsm = qnode.tape.to_openqasm(wires=0)
print(qsm) 

You should get the following output:

OPENQASM 2.0;
include “qelib1.inc”;
qreg q[1];
creg c[1];
rx(0.3) q[0];
measure q[0] -> c[0];

Please let me know if this helps!

HI @CatalinaAlbornoz. Thank you for your kind response.

I am not quiet sure, how to print the no. of gates involved. Actually, I want to know how many Pauli Gates are there for the Hamiltonian of a system. For eg. the Hamiltonian for H2 molecule can be obtained as.

symbols = [“H”, “H”]
x = np.array([8.14341433,1.84432727,0.00000000,
5.25213336,1.84432727,0.00000000]
, requires_grad=True)

Hamil = qml.qchem.molecular_hamiltonian(symbols, x,
active_electrons=active_electrons,
active_orbitals=active_MOs,
basis=basis
)[0]
So now , there are many attributes to the Hamil such as

  1. Hamil.coeffs [give coefficients of Pauli gates acting on each qubit]

array([-0.49629479, 0.09146749, 0.09146749, -0.03203197, -0.03203197,
0.13733085, 0.05786586, -0.05786586, -0.05786586, 0.05786586,
0.08131198, 0.13917784, 0.13917784, 0.08131198, 0.1449807 ])

  1. Hamil.terms

Pauli terms and their coefficients and the qubit index

(array([-0.49629479, 0.09146749, 0.09146749, -0.03203197, -0.03203197,
0.13733085, 0.05786586, -0.05786586, -0.05786586, 0.05786586,
0.08131198, 0.13917784, 0.13917784, 0.08131198, 0.1449807 ]),
[Identity(wires=[0]),
PauliZ(wires=[0]),
PauliZ(wires=[1]),
PauliZ(wires=[2]),
PauliZ(wires=[3]),
PauliZ(wires=[0]) @ PauliZ(wires=[1]),
PauliY(wires=[0]) @ PauliX(wires=[1]) @ PauliX(wires=[2]) @ PauliY(wires=[3]),
PauliY(wires=[0]) @ PauliY(wires=[1]) @ PauliX(wires=[2]) @ PauliX(wires=[3]),
PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliY(wires=[2]) @ PauliY(wires=[3]),
PauliX(wires=[0]) @ PauliY(wires=[1]) @ PauliY(wires=[2]) @ PauliX(wires=[3]),
PauliZ(wires=[0]) @ PauliZ(wires=[2]),
PauliZ(wires=[0]) @ PauliZ(wires=[3]),
PauliZ(wires=[1]) @ PauliZ(wires=[2]),
PauliZ(wires=[1]) @ PauliZ(wires=[3]),
PauliZ(wires=[2]) @ PauliZ(wires=[3])])

  1. Hamil.ops

[Identity(wires=[0]),
PauliZ(wires=[0]),
PauliZ(wires=[1]),
PauliZ(wires=[2]),
PauliZ(wires=[3]),
PauliZ(wires=[0]) @ PauliZ(wires=[1]),
PauliY(wires=[0]) @ PauliX(wires=[1]) @ PauliX(wires=[2]) @ PauliY(wires=[3]),
PauliY(wires=[0]) @ PauliY(wires=[1]) @ PauliX(wires=[2]) @ PauliX(wires=[3]),
PauliX(wires=[0]) @ PauliX(wires=[1]) @ PauliY(wires=[2]) @ PauliY(wires=[3]),
PauliX(wires=[0]) @ PauliY(wires=[1]) @ PauliY(wires=[2]) @ PauliX(wires=[3]),
PauliZ(wires=[0]) @ PauliZ(wires=[2]),
PauliZ(wires=[0]) @ PauliZ(wires=[3]),
PauliZ(wires=[1]) @ PauliZ(wires=[2]),
PauliZ(wires=[1]) @ PauliZ(wires=[3]),
PauliZ(wires=[2]) @ PauliZ(wires=[3])]

And looks like these attributes print the Pauli Operators. I just want to know if there is a way to count these operators like, how many Pauli(X,Y,Z) etc.

Thank you very much.

Hi @raghavv, thanks for clarifying your question. I haven’t seen any function that counts them. You would have to create your own function for that.

Hi @CatalinaAlbornoz. Thank you for the comments. I will look into it. Please let me know if you happen to come across any such thing. Thank you

Hi @raghavv. I asked a colleague about this and he put together a function that does what you need. It might not be super stable but it seems to work. You can modify it to count a specific Pauli operator if that’s what you need.

from pennylane.ops.qubit.non_parametric_ops import PauliX, PauliY, PauliZ 
from pennylane.operation import Tensor

def count_paulis(H):
    """
    Counts the number of Pauli operations in a Hamiltonian. Note that each Pauli
    operator contained in tensor products are counted individually e.g:
    qml.PauliX(0) @ qml.PauliX(1) counts as 2. Identity operations are not 
    counted as Pauli operations here.
    
    Args: 
        H (qml.Hamiltonian): The Hamiltonian containing operations to be counted
    
    Returns:
        count (int): the number of Pauli operations contained in the Hamiltonian
    """
    pauli_types = (PauliX, PauliY, PauliZ)

    count = 0
    for op in H.ops:
        if type(op) == Tensor:
            for obs in op.obs:
                if type(obs) in pauli_types:
                    count += 1
        elif type(op) in pauli_types:
            count += 1
            
    return count 

I hope this helps you!

1 Like

Hi @CatalinaAlbornoz. Thank you so much for asking your colleague and thanks for sharing the code. Thats’s so nice of you. It works, this is the kind I was looking for.

On the other hand, I also tried my hand with shell, the following line counted the Pauli gates (X,Y,Z). Just sharing.
grep -o PauliZ Pauli_Gates.txt | wc -l

That’s great! I’m glad we could help @raghavv.

And thanks for sharing the shell command you used. Should people use it with the code above saved as Pauli_Gates.txt? Or is that a different file?

Hi @CatalinaAlbornoz. One can run the command Hamiltonian.ops and then list the Pauli gates and save it to a text file. And the run the grep command (grep -o PauliZ Pauli_Gates.txt | wc -l). Hope that is clear.

Thank you for the clarity

Oh thanks for the details @raghavv!

1 Like