The following is a guest post by Olivia Di Matteo from the Quantum Software and Algorithms Research group at The University of British Columbia, showcasing The Ionizer, a package that simply transpiles and optimizes PennyLane circuits into IonQ's native trapped-ion gate set (GPI, GPI2, MS).
It's an exciting time to be a researcher in quantum information science. We now have real quantum computers of all shapes and sizes, which we can access for free over the cloud. However, under the hood, these devices are built using a variety of different qubit technologies and, in a sense, each hardware device has its own preferred language. To bridge this gap in efficiency, we are developing The Ionizer, an elegant package that implements PennyLane quantum circuits into IonQ's native trapped-ion gate set.

For quantum operations to be executed on different quantum computers, they have to be implemented in hardware-specific ways. And, depending on the device, some implementations may be more straightforward than others. In a sense, each hardware device has its own preferred language, and to run algorithms on them, we need to translate, or transpile them into these hardware-native operations. This is usually done behind the scenes, either by your software framework or the hardware provider's toolchain after you submit your job — but there are some special use cases where you yourself may need to work directly with the native gates.
The purpose of this blog post is to provide a detailed introduction to one specific gate set, that of IonQ's trapped ion processors, and show how we can use PennyLane's quantum transforms to write a custom transpiler that both translates and optimizes our circuits. The transpiler, which we named The Ionizer, is openly available on GitHub, so you can explore the code while you read this post.
Contents
- Universal gate sets
- Working with the IonQ native gate set
- Automating transpilation with The Ionizer
- Next steps
- Additional references
Universal gate sets
As alluded to above, the set of gates we use to express our algorithms is like a language. Over many millennia, humans have developed thousands of different languages. Some are similar, for example, in the characters they use or the way that words are ordered, while others use entirely different sets of characters that carry meaning in and of themselves.

Regardless, we can, for the most part, use any language (if we have a way to translate it) to convey what we mean. However, learning a new language is very challenging! The same is true for quantum gate sets. There are numerous universal gate sets for quantum computing, examples of which are shown below.

When we learn about or teach quantum algorithms, we traditionally do so using gates from these sets, which include Pauli rotations, Clifford gates, and Toffolis. They have nice properties that make them intuitive to understand and simple to use to express algorithms (e.g., as rotations in 3D space). Furthermore, we really only need three gates at a time to create a universal gate set. A common choice is two Pauli rotations, such as RZ and RY, and the two-qubit CNOT gate:
However, the set of these three gates is not necessarily the best option for every hardware modality. IonQ's trapped ion processors use a completely different set of three gates (two single-qubit gates and one two-qubit gate):
Working with the IonQ native gate set
Let's first try and get a handle on how these gates work, and then we will discuss how to transpile to them from our usual gate set.
Single-qubit gates
A common way to see how a single-qubit gate works is to look at its action on the Bloch sphere. Our favourite Pauli rotations have a very natural interpretation as rotations around the Cartesian axes:

The key thing to note is that the axes of these rotations are fixed, but the amount that we rotate is variable. For the GPI and GPI2 gates, it's the opposite: the amount that we rotate is fixed, and the parameter controls the axis in the xy-plane around which we rotate:
As the names suggest, the GPI gate always rotates the state by \pi, whereas GPI2 always rotates by \pi/2. From this description, you might immediately notice there are a couple of special cases:
and
This leads to some unintuitive behaviour. For one, the adjoints of these gates cannot be obtained just by negating their parameters. In fact,
The action on the Bloch sphere (see above) provides intuition for how this works.
Next, suppose we apply two of the same Pauli rotations in a row, but using different rotation angles. This is equivalent to applying that rotation with the sum of the angles, e.g.,
Let's try the same thing with the GPI gate:
They don't compose in the same way! However, this still shows us something important, namely, how to implement RZ with GPI gates:
Even more interestingly, if we apply a GPI gate after an RZ gate, we find
This means that we don't have to implement any RZs that precede a GPI gate; we can just adjust the GPI gate itself. This is sometimes called a virtual application of RZ gates. It works for GPI2 as well:
Now that we know how to deal with RZ, in order to build up to a universal gate set, we need to look into RX and/or RY. With a bit of matrix multiplication, you can find that
Using all these relationships we can derive that an arbitrary 3-parameter unitary operation can be decomposed as
These gates are indeed universal for single-qubit operations!
Two-qubit gates
The two-qubit entangling gate,
is the final piece we need to be able to work with this gate set. The name of this gate, MS, stands for Mølmer–Sørensen, the two scientists who originally proposed its implementation.
To understand how it works, let's apply it to the computational basis states:
The MS gate is interesting because, unlike the CNOT gate, whose entangling behaviour emerges only when we apply it to a superposition, it produces entangled states straight up from computational basis states. You might be wondering, does this mean MS is a better entangling gate than CNOT? We will not go into details, but there is a variety of interesting work on the question of the entangling power of two-qubit gates and which one to use: Huang et al. (2023), Lin et al. (2022), Peterson et al. (2021), or Zanardi et al. (2000).
Just as we did for the single-qubit gates, let's re-express MS in terms of the gates we are familiar with. To find the decomposition, first write both MS and CNOT as exponentials of Pauli operations (i.e., Pauli rotations):
Note that in the CNOT, the Z part is acting only on the first qubit. We can take advantage of a trick relating the three Pauli rotations to write
When exponentiated, something similar happens:
This means we can rewrite the CNOT gate.
The last equality follows because all the Paulis in the exponential commute, so we can implement a product of the exponentials of individual terms in any order. Writing it in this way makes something even clearer: there is an MS gate hiding there, in the final exponentiated term! The remaining exponentials are just RX rotations (or the identity), so we find
Now, we could in principle use our expressions for RX and RY to convert to GPI gates, but notice that these are actually some of the special cases we mentioned earlier, since RX(\pi/2) = \sqrt{X} and similarly for RY. With this, and making use of the expressions for the adjoints, we find:
We can express this more clearly as a circuit:

Automating transpilation with The Ionizer
In the previous sections, we saw that, once we express our algorithm in terms of Pauli rotations and CNOTs (which we can always do), there are direct translations we can make to obtain our algorithm in terms of gates native to the IonQ devices. However, just unrolling all the operations is likely to give us a very inefficient circuit! For example, an RY gate followed by and RX gate would unroll to six GPI and GPI2 gates, whereas we showed that we can implement any single-qubit unitary with only three.
This is where PennyLane, quantum transforms, and The Ionizer come into play. The Ionizer package contains implementations of the three key gates (GPI, GPI2, and MS) as PennyLane operations, as well as a set of transforms that implement the relationships described in the previous section. Quantum transforms are composable metaprograms that take circuits as input, and return one or more modified circuits as output (and potentially a classical processing function). This is a very natural way to express many aspects of quantum circuit compilation that involves translating and manipulating different parts of a circuit. For more details about transforms, you can refer to our paper or a previous PennyLane blog post on the subject.
The main contribution of the Ionizer is a transform called @ionize
. Applying
it as a decorator will transpile and optimize your circuit, using just a single
extra line of code.
from ionizer.transforms import ionize @qml.qnode(dev) @ionize def circuit(x): qml.Hadamard(wires=0) qml.CNOT(wires=[0, 1]) qml.RX(x, wires=1) return qml.expval(qml.PauliZ(0))
>>> qml.draw(circuit)(0.3) 0: ──GPI2(0.00)─╭MS──GPI2(-1.57)─────────────────────────┤ <Z> 1: ──GPI2(3.14)─╰MS──GPI2(1.57)───GPI(-1.42)──GPI2(1.57)─┤
Under the hood, @ionize
is actually applying a sequence of modular transforms
that perform various aspects of the transpilation process. Let's see a
step-by-step example on a slightly more complicated circuit:

The first thing we do is unroll all the gates into gates whose translations to GPI and GPI2 are pre-programmed.
Next, we transpile everything except the RZ gate into these gates.
The RZ gates are applied virtually to obtain a circuit expressed in terms of native gates only.
However, after this step, there is still a lot going on. We now begin to optimize the circuit by pushing all commuting gates to one side of the MS gates.
Then, for sequences of single-qubit gates longer than three, we perform fusion.
After this, we may still be able to optimize further, so @ionize
repeatedly
pushes commuting gates through, and attempts to optimize what remains through
pattern matching against some simple 2- and 3-gate circuit identities, and
applies gate fusion for other cases. At the end of the day, our circuit looks
like this:

Next steps
In the months ahead, The Ionizer itself will undergo further development. While it currently performs transpilation, it doesn't yet preserve differentiability for all the parameters (which is a key selling point of both transforms themselves, and PennyLane as a whole!). More can also be done to optimize the resulting circuits, and in particular we need to search for and implement identities related to the 2-qubit MS gate, and determine a more optimal ordering of the transforms that happen internally.
We hope this post is helpful not only for understanding a different language for representing quantum computations, but that it provides a motivating example for writing your own custom transpilation tools to share with the community. On that note, suggestions and contributions of new features are very welcome: feel free to leave a comment, get in touch, or open an issue on the The Ionizer repository!
Additional references
- IonQ documentation: Getting started with Native Gates
About the author
Olivia Di Matteo
Quantum computing researcher interested in circuits, algorithms, open-source quantum software, and education.