Published in

Qiskit

# Explore The Clifford Group, A Crucial Tool For Benchmarking, Error Correction, And More

This blog was written by Qiskit Developer Advocate Abby Mitchell with support from Researcher Shelly Garion

The Clifford Group is one of the most important sets of gates in Quantum Computing, thanks to its usefulness in Quantum Error Correction, Randomized Benchmarking, and Entanglement studies. Qiskit’s quantum_info module contains the `Clifford` and `StabilizerState` classes, which give you a bunch of ways to manipulate Cliffords in your Qiskit experiments!

In this blog we’re going to cover the following:

# A Brief(ish) Overview of Clifford Elements

In quantum computing, the Clifford Group is a set of gates defined by the property that they always transform Paulis to Paulis. The Paulis themselves are also elements of the Clifford Group. A Clifford element or circuit is any element or circuit that is comprised only of operators from the Clifford Group, some of which Qiskit can implement:

(For a quick recap on Paulis check out the Qiskit textbook and the `Pauli` class documentation)

For single qubit cases, the sequence of operations Clifford-Pauli-inverse-Clifford is equivalent to doing another Pauli operation. Or, in the case where the Clifford is itself a Pauli, it will change the phase of that same Pauli.

In other words, for a Clifford C and a Pauli P:

Some common examples:

Multi-qubit Clifford gates (e.g. CNOT, swap) transform tensor products of Paulis to other tensor products of Paulis.

## Stabilizers

To better understand Cliffords and implement them using Qiskit, it’s first useful to understand the concept of stabilizers and stabilizer groups. This is because, for example, when it comes to doing calculations for Quantum Error Correction, it is much easier to deal with states in their stabilizer formats, instead of increasingly complex superposition formulas.

When a Pauli operator acts on a state and gives you the same state back, we say that operator is a stabilizer of that state (ie. the state is a +1 eigenstate of the Pauli).

For example, we know that Z|0⟩ = |0⟩

The Z operator acting on the state |0⟩ doesn’t change the state, so we say that Z stabilizes |0⟩.

When considering only 1 qubit, Clifford operators can only produce 6 possible states (|0⟩ , |1⟩ , |+⟩ , |-⟩ , |i⟩ , |-i⟩), each of which can be stabilized by a single Pauli (or Identity). These states are the eigenstates of the Z, X, Y Pauli’s:

Multi-qubit states can also be stabilized by combinations of Paulis. Take the Bell State for example:

This can be stabilized by XX:

It can also be stabilized by II, ZZ and -YY.

A stabilizer group is a group of all the tensor products of Paulis that can stabilize an n-qubit state. The size of a stabilizer group for a given state is always 2^n. Since each stabilizer group only stabilizes a single state, this group can be used as a unique description of that state and we can call that state a stabilizer state.

so, for the state |0⟩, the stabilizer group is: { I, Z }

for the Bell state, the stabilizer group is: { II, XX, -YY, ZZ }

for a 3-qubit GHZ State, the stabilizer group is: { XXX, IZZ, ZIZ, ZZI, III, -XYY, -YXY, -YYX }

For any stabilizer group, we actually only need a subset of the group to be able to generate the rest, this subset is called a generating set and is always of size n.

So for the Bell state:

stabilizer group: { II, XX, -YY, ZZ }

generating set: { XX, ZZ }

Or a GHZ state:

stabilizer group: { XXX, IZZ, ZIZ, ZZI, III, -XYY, -YXY, -YYX }

generating set: { XXX, IZZ, ZIZ }

## Representing Cliffords with Matrices and Stabilizers

We can represent any n-qubit Clifford element by a 2nx2n binary matrix and a 2n binary (phase) vector called a Clifford tableau — and Qiskit can, too. Just as the stabilizer format makes it easier for humans to work with increasingly large Cliffords, this tableau format makes it more efficient for computers to run calculations on increasingly large Cliffords, so they are an incredibly useful computational tool.

Also, be careful not to confuse Clifford tableaus with regular gate matrices. Producing Clifford tableaus is a complex process that is beyond the scope of this blog, but check out [5] for more details! For now we’ll just be focusing on understanding how to interpret tableau representations and later on how to use Qiskit to produce them.

So: the first n rows of the matrix represent the generators for the state’s destabilizer group, and the second n rows are generators of the stabilizer group. We won’t go into too much detail here on destabilizer groups, just know that a destabilizer generating set is a list of Pauli operators that, when combined with the stabilizer generators, produce the full Pauli group for a given number of qubits. At a high level this just helps make it more efficient to run measurement calculations on Cliffords. Check out [5] for more details!

Given all that, we can represent X as:

Using this tableau representation we can also break our Clifford down into its Stabilizers and Destabilizers.

So from this representation we can tell that the state produced by the X gate can be stabilized by -Z

An X gate is a small example of a Clifford element, but we can do this process with Cliffords of any size. For example, a CX can be represented in Clifford tableau form like this:

(Remember you can check out [5] for more details on how to create Clifford tableaus, and we’ll show you how to produce them using Qiskit later on as well!)

And we can find the stabilizer format in a similar way as before:

Being able to convert Clifford elements into their stabilizer formats is worthwhile as it makes it much more efficient to simulate their measurement outcomes. The larger the Clifford element, the larger and more complex the matrix is and the more difficult it is to convert to its stabilizer format. Lucky for you Qiskit has a handy `Clifford` class to do this for you, which we'll go into shortly!

# Why are Clifford Circuits Useful in Quantum Computing?

A Quantum Circuit that only contains Clifford gates can be efficiently simulated on a classical computer [1], and because the Clifford Group doesn’t include the T gate or Toffoli (CCX) they cannot by themselves achieve universality (i.e. it’s not possible to produce any arbitrary unitary just using a combination of Clifford operators, as they only jump between 6 possible states in single qubit cases). So, if they’re not universal and we can simulate them classically anyway then why on earth am I going to so much trouble to tell you about them?

Because of three reasons:

## Quantum Error Correction

For research into error correction it is incredibly common to use stabilizer codes, these are error correcting codes that can be created entirely from stabilizer circuits (i.e. Clifford circuits). By using Clifford circuits exclusively you can still access any of the desired error correcting properties, but it becomes much easier to do the calculations. It is far more convenient to work with calculations using a stabilizer format than writing out the full set of superpositions over every bit string!

## Randomized Benchmarking

Randomized Benchmarking (RB) is a very useful algorithm for estimating the average error rate for a given set of gate operations on a given device. It works by running sequences of random Clifford gates followed by their inverse in order to return the initial state. By running numerous sequences, you can start to build up a picture of how likely it is for the initial state to be returned, and hence what the error rate is. You can learn more about Randomized Benchmarking in the Qiskit Textbook or in this blog post.

## Testing Entanglement

If we prepare large entangled states comprised only of Clifford elements we can efficiently simulate the outcomes and compare with outcomes from real hardware. This provides us with an efficient mechanism for measuring the entanglement performance of real devices, which relies on the fact that Cliffords can be easily simulated classically.

# Implementing Clifford Circuits Using Qiskit

Qiskit has 2 classes that enable you to implement Clifford Circuits in your experiments: the `Clifford` class (for preparing Clifford elements and circuits) and the `StabilizerState` class (a python simulator for Cliffords).

## Clifford Class

The Clifford class allows you to:

• Initialize a Clifford element from a QuantumCircuit/Gate/Instruction/Pauli
• Decompose a Clifford element (i.e. convert a Clifford element to a circuit)
• Generate a random Clifford element
• Compose Clifford elements (i.e. combine multiple Clifford elements into a single element)
• Calculate a tensor product of two Clifford elements
• Calculate the conjugate, transpose, and adjoint of a Clifford element
• Evolve a Pauli by a Clifford, (i.e. calculate: P’ = Cdg⋅P⋅C)

We import the `Clifford` class from the `quantum_info` module:

`from qiskit.quantum_info import Clifford`

Let’s use Qiskit to initialize the Clifford operator CX that we saw earlier on:

`# Create a Quantum Circuit with 1 CX gateqc = QuantumCircuit(2)qc.cx(0, 1)# Generate a Clifford element from the circuitcliff = Clifford(qc)# Print the Cliffordprint(cliff)`

As you can see, Qiskit gives us the same stabilizer format output that we calculated manually from the matrix earlier on:

Alternatively you can import the `CXGate` from the Qiskit circuit library and convert that directly to a Clifford element to get the same output, e.g.

`from qiskit.circuit.library import CXGatecliff = Clifford(CXGate())print(cliff)`

You can also get the matrix form like so (0=False, 1=True):

`# Print the binary matrixprint(cliff.table.array)# Print the phase vectorprint(cliff.table.phase)`

We can do the same thing with any circuit prepared from Clifford gates, such as a large GHZ state:

`# Prepare a large GHZ circuitnq = 25qc = QuantumCircuit(nq)qc.h(0)for i in range(1, nq):    qc.cx(0, i)# Initialise the Cliffordcliff = Clifford(qc)# Print the Cliffordprint(cliff)`

(This becomes especially useful with very large numbers of qubits, try it yourself with `nq=1000`!)

If you need to convert a Clifford element back to a circuit you can decompose it using the `to_circuit()` method:

`# Generate a Clifford element from a CX gatecliff = Clifford(CXGate())# Print the Clifford elementprint(cliff)# Convert the Clifford element to a circuitcirc = cliff.to_circuit()# Print the circuitprint(circ)`

## StabilizerState Class

The StabilizerState Class allows you to:

• Calculate the expectation value of a Pauli operator of a stabilizer state
• Efficiently measure Clifford circuits with many qubits! 🎉
• Calculate the exact probabilities of all the measurement outcomes for certain Clifford circuits

We import the `StabilizerState` class from the `quantum_info` module:

`from qiskit.quantum_info import StabilizerState`

Let’s take our 25 qubit GHZ example from earlier. We could simulate this with a `Statevector` simulator, but it is actually a lot faster to use the `StabilizerState` simulator:

`# Prepare the GHZ statenq = 25qc = QuantumCircuit(nq)qc.h(0)for i in range(1, nq):    qc.cx(0, i)# Define the number of shotsshots=100# Get the sample counts of each outcome for the GHZ state using # the StabilizerState simulatorcounts = StabilizerState(qc).sample_counts(shots)# Get the probabilities of each outcome for the GHZ state using # the StabilizerState simulatorprob = StabilizerState(qc).probabilities_dict(decimals=2)# Print the outcomesprint ("GHZ state outcome counts:", counts)print ("GHZ state outcome probabilities:", prob)`

As you can see the `StabilizerState` simulator is noticeably faster, and clearly the better choice when you're hustling to meet that deadline and every second counts!

`StabilizerState` is a python based simulator in Qiskit's quantum_info module, but there is also a C++ based simulator in Qiskit Aer, which you can use as follows:

`# Import the AerSimulatorfrom qiskit.providers.aer import AerSimulator# Measure the GHZ circuit from earlierqc.measure_all()# Prepare the simulator (method=stabilizer is optional, for clifford circuits # it will be used automatically if no other method is providedsimulator = AerSimulator(method='stabilizer')# Run the Simulator using our GHZ circuit from earlierresult = simulator.run(qc).result()# Get the counts for each possible outcomeresult.get_counts(0)`

The code examples above should be just enough to whet your appetite when it comes to implementing Clifford circuits with Qiskit, but only represent a fraction of what you can do. For more details check out the documentation, take a look at this QEC lab, and keep an eye on the Qiskit Tutorials for more implementation examples coming soon!

# How efficient is the synthesis of Clifford Circuits using Qiskit?

To make Clifford synthesis as efficient as possible Qiskit developers are closely following the latest research, and continuously iterating as new breakthroughs are published.

In this instance, the aim when developing the `Clifford` and `StabilizerState` classes was to reduce the depth of the Clifford circuits as much as possible, so that a user creating a circuit can fit as many operations within their circuit depth limit as possible. In particular the team aimed to reduce the number of 2 qubit operations needed to construct the Clifford circuits, as these are noisier than single qubit ones.

For n≤3 qubits Qiskit uses optimal CX cost decomposition, based on research published in March 2020 from Bravyi and Maslov [2]. However, this approach doesn’t scale well as we increase the number of qubits. By the time we reach n=6 qubits this implementation requires 2.1TB of memory. This is actually quite efficient considering there were 2.1x10^23 possible Clifford gate combinations considered, and that doesn’t even include the Paulis, which would bring the number up to 8.5x10^26.

For n≥4 qubits the Qiskit code is based on ‘greedy Clifford synthesis’, a suggestion published just this year by Bravyi et al. [4] and requires O(n²) CX gates. Greedy Clifford synthesis involves efficiently calculating the cost of each CX gate at each step of the algorithm and choosing the qubit with a minimal CX cost. The Qiskit team found that using this method the CX cost can be reduced by 30–50% for random Cliffords.

While the ‘greedy’ synthesis method is the default, Qiskit also offers users the option to decompose Cliffords based on the Aaronson-Gottesman algorithm, a less efficient “Guassian elimination” style algorithm, developed in 2004 [5]:

`# Import the relevant modulesfrom qiskit.quantum_info import random_cliffordfrom qiskit.quantum_info.synthesis.clifford_decompose import (    decompose_clifford_ag, decompose_clifford_bm, decompose_clifford_greedy)# Generate a random Cliffordcliff = random_clifford(5)# Convert Clifford to a circuit using 'greedy' synthesiscirc = cliff.to_circuit() # default uses 'greedy' synthesiscirc = decompose_clifford_greedy(cliff) # alternativelty you can specify explicitly# Convert Clifford to a circuit using Aaronson-Gottesman synthesiscirc = decompose_clifford_ag(cliff)`

Thank you for reading! If you want more blogs like this, follow the Qiskit blog.

# References

[1] D. Gottesman. Stabilizer Codes and Quantum Error Correction. Ph.D. thesis, California Institute of Technology, Pasadena, CA, 199

[2] Sergey Bravyi and Dmitri Maslov, “Hadamard-free circuits expose the structure of the Clifford group”, https://arxiv.org/abs/2003.09412

[3] Sergey Bravyi , Joseph A. Latone, and Dmitri Maslov, “6 qubit Optimal Clifford Circuits”, https://arxiv.org/abs/2012.06074

[4] Sergey Bravyi, Shaohan Hu, Dmitri Maslov, Ruslan Shaydulin, “Clifford Circuit Optimization with Templates and Symbolic Pauli Gates”

[5] Scott Aaaronson and Daniel Gottesman, “Improved Simulation of Stabilizer Circuits”, Phys. Rev. A 70(052328), 2004. https://arxiv.org/abs/quant-ph/0406196

--

--

## More from Qiskit

A community to discuss Qiskit, programming quantum computers, and anything else related to quantum computing.

## Abby Mitchell

I’m a Quantum Developer Advocate at IBM. I’m particularly passionate about Quantum Computing and encouraging women to pursue careers in technology.