As a whole, a given quantum circuit can be interpreted as a single unitary operation
to be applied to an input state. In practice, circuits are decomposed into a universal
set of primitive gates. This decomposition is generally far from unique;
in fact, there are an infinite number of ways to decompose a circuit. Often, primitive
gates are taken to be a the set of gates which are natively available to a particular
quantum processor on which the circuits will be run.
A compiler in this context is a tool that takes a circuit, and returns a specific
decomposition of that circuit. Compilers may not be deterministic; there are
significant advantages to randomizing over some decompositions (see e.g.
A very important class of compilers are what we call transpilers: they are compilers
that translate a given circuit decomposition containing a specific gateset into a
decomposition that uses a different gateset. This is crucial for running circuits on
physical deviced, where the gateset needs to consist solely of gates that are
native to the hardware.
Two common issues that a transpiler needs to solve in order to generate a circuit that
can be run on a physical device are:
Gates inside of theoretical circuits are not directly compatible with the
hardware’s native gateset.
Gates or circuits are specified as unitary matrices, rather than specific gate
If True-Q™ has access to the configuration of the system, it can be used to solve
both of these issues. Our Compiler takes a circuit and
rewrites it using only the gates and connections specified in a given device
configuration which we represent through Config objects.
For example, let’s suppose we have a device that can only perform rotations about the
\(X\) and \(Z\) axis and a \(CNOT\) gate. We can define this
configuration as follows:
Notice that all of the gates in the new circuit are contained in the
Config object, and that single-qubit gates are decomposed into
sequences of the form \(Z(\theta)X(90)Z(\phi)X(90)Z(\gamma)\), which is
consistent with the ‘Mode’ specified in the configuration. Hovering your cursor over
each gate will display the rotation angle.
We can verify numerically that this circuit implements the SWAP gate using an ideal
simulator and calculating the process infidelity between the original SWAP gate
and our transpiled circuit:
Recall that a process infidelity of zero indicates that the operations are equivalent
up to (potentially) a global phase. In this example, our transpiled circuit does
indeed introduce a phase difference, which we can examine when looking at the
resulting operators more closely:
fig,(ax1,ax2)=plt.subplots(1,2,figsize=(8,3))tq.plot_mat(swap_op,ax=ax1)tq.plot_mat(transpiled_op,ax=ax2)ax1.set_title("Original SWAP gate")ax2.set_title("SWAP Gate expressed through native gates")
Text(0.5, 1.0, 'SWAP Gate expressed through native gates')
For simple device configurations, the
from_config() method is a convenient wrapper, but
True-Q™ compilations tools are much more versatile. Take a look at the
Defining Custom Compilers example for more information.