Qiskit Transpiler for quantum circuits
Asked Answered
G

2

6

In Qiskit there is the transpile() function (see documentation). My understanding of a transpiler is best described as a way of converting one set of gate operations to another set of gate operations, with the intent of running an algorithm on different backends (since the qubit connectivity, i.e. the geometry of the architecture, varies from one quantum computer to the another). There are ways to optimize circuits by reducing redundancies and rewriting things in terms of equivalent gates like changing a CNOT conjugated by Hadamard gates to a CZ to reduce gate count. One might also want to do exactly the opposite and go from a CZ to a CNOT conjugated by Hadamards if there is not a native CZ on the hardware backend. In general this kind of transpiling in order to optimize an arbitrary circuit for some fixed hardware backend is a QMA-complete problem (see here for example...perhaps someone has used LEAN for something similar?). Sometimes variational methods are used to approximate an optimal circuit as well, but I digress.

A slightly different but related problem: Using the Kitaev-Solovay Theorem in Appendix 3 of Nielsen & Chuang, and material in 4.5, we know we can always approximate arbitrary unitary gates with a universal gate set "efficiently" (which is made precise in the book and isn't necessarily important here). Just how efficiently is an open question I think, but there is some upper and lower bound at least.

Given this, one would expect the Qiskit transpile() function to approximate unitary gates and refactor the gate set to an optimal (minimized) gate set in order to optimize circuits, but perhaps to have issues with large circuits with many nonstandard gates. However, I'm having issues getting it to work even for simple examples. For example, a permutation matrix on three qubits seems like a reasonable unitary to approximate (some could even be easily converted into SWAP-gates and X-gates by hand). But Qiskit doesn't seem to like doing this, and I could use some help understanding why. As an example, we can define a unitary (permutation) operator in Qiskit and turn it into a gate in a quantum circuit as follows:

from qiskit import *
from qiskit.quantum_info import Operator
from qiskit.compiler import transpile
%matplotlib inline

permute = Operator([[0, 0, 1, 0, 0, 0, 0, 0],
                    [1, 0, 0, 0, 0, 0, 0, 0],
                    [0, 1, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 1, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0, 1],
                    [0, 0, 0, 0, 0, 1, 0, 0],
                    [0, 0, 0, 0, 0, 0, 1, 0],
                    [0, 0, 0, 0, 1, 0, 0, 0]])

qc = QuantumCircuit(3)
qc.unitary(permute, [0,1,2], label='P')
qc.draw(output='mpl')

Now, if I try using the transpile() function in Qiskit as follows:

result = transpile(qc, basis_gates=['u1', 'u2', 'u3', 'cx'], optimization_level=3)
result.draw(output='mpl')

I get some huge long horrible error that ends with,

NotImplementedError: Not able to generate a subcircuit for a 3-qubit unitary

So, I guess my question is...WHY. LOL. No but seriously, am I just using this in the wrong way? are my expectations too high? Is there a reasonable way to do what I want? Would a different set of basis gates work? If so, how does one decide on the basis gates? I have also tried the decompose() function (see documentation) which seems to have a more limited functionality to the transpile() function when looking at the source code of each. The function decompose() is implemented (as can be seen in this video as well as this one). The transpile() function is also implemented (see this video at approximately 10:35 cell In[18], and in his discussion). You can also try running the commands using his

from qiskit import transpile

and it doesn't work with that import either. If anyone understands why the transpile() function (or the decompose() function for that matter) isn't working the way I would expect it to, I would love an explanation. Thanks!!!

---------Update----------

I have found yet another issue. If we use

from qiskit.circuit.random import random_circuit
rcirc2 = random_circuit(3, 4)
rcirc2.draw(output='mpl')

to generate random circuits, then run

from qiskit.compiler import transpile
result2 = transpile(rcirc2, basis_gates=['u1', 'u2', 'u3', 'cx'], optimization_level=3)
result2.draw(output='mpl')

some of the results (without 3-qubit gates) do not transpile, and some do. So this seems to go beyond just not having an implementation of 3-qubit or more gates for transpile(). Note: You may have to try this code several times to get a circuit without 3-qubit gates since the circuits are "random". For example, the following circuit will not transpile,

circ = QuantumCircuit(3)
circ.i(0)
circ.ch(2,1)
circ.cx(0,1)
circ.t(2)
circ.cx(2,0)
circ.x(0)
circ.u1(3.41, 1)
circ.ch(2,1)
circ.draw(output='mpl')

when we run

result3 = transpile(circ, basis_gates=['u1', 'u2', 'u3', 'cx'], optimization_level=3)
result3.draw(output='mpl')

Adding barriers to separate all independent gates into distinct steps doesn't seem to help either. So it isn't an issue of running parallel but independent gate operations.

----------Update 2----------

If we generate random 3-qubit unitaries using Qiskit, these also do not work.

from qiskit.quantum_info import Operator, random_unitary
U = random_unitary(8, seed=None)

qc = QuantumCircuit(4, 4)
qc.unitary(U, [0,1,3], label='P')
qc.draw(output='mpl')

You can redefine which qubits the unitary operates on, or reduce the circuit to a 3-qubit circuit, or generate larger n-qubit unitaries in this way. None of these examples will work.

Golightly answered 14/5, 2020 at 6:47 Comment(0)
N
2

It's possible I don't know enough about quantum computing, but I'll try to offer some assistance.

It appears transpile() doesn't yet have a way to unroll a 3 or more qubit unitary operator. It does seem to work fine for a 2-qubit unitary though.

from qiskit import *
from qiskit.quantum_info import Operator

# a subsection of your original permute operator
#   with input dimensions (2,2), and output dimensions (2,2)
#   instead of the original (2,2,2) -> (2,2,2)
perm2 = Operator(
    [[0, 0, 1, 0],
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 0, 1]
    ])

# a quantum circuit containing a 2-qubit unitary
q = QuantumCircuit(3,3)
q.unitary(perm2, [0,1], label='P')
q.h([0,1,2])
q.h([0])
q.barrier()
q.cx(1,0)
q.z(2)
q.barrier()
q.h([0])
q.barrier()
q.h([0,1,2])

# select a backend
backend = BasicAer.get_backend('qasm_simulator')

result = transpile(q, backend=backend, basis_gates=['u1', 'u2', 'u3', 'cx'], optimization_level=3)

result.draw(output='mpl')

Alternatively, you could choose to not unroll the 3-qubit unitary by removing basis_gates=['u1', 'u2', 'u3', 'cx'] from your code. That also runs fine.

Nonsectarian answered 14/5, 2020 at 7:45 Comment(3)
Can you run this on another backend (actual quantum computer)? That seems to also be an issue. I was able to get it to work without giving it a restricted set of basis gates like the basis_gates=['u1', 'u2', 'u3', 'cx'], but for specific hardware the basis gates are forced on you by the hardware.Golightly
I also just found this video on transpiling in Qiskit (youtube.com/watch?v=2T3163VjvWQ) which may prove helpful for people in the future.Golightly
Seems like this goes beyond just not having an implementation of 3-qubit or more gate transpiles (see update above).Golightly
H
1

The first issue about decomposing multi-qubit unitaries is resolved in Qiskit 0.19. Try updating your installation.

The second issue is that an identity gate in Qiskit is not quite identity. It is similar to a delay instruction, used to insert idle times into the circuit. The transpiler will not attempt to remove them, and so unrolling a circuit to basis_gates=['u1', 'u2', 'u3', 'cx'] will not work. You should augment the basis gates with id.

Haha answered 14/5, 2020 at 22:2 Comment(16)
It looks like it still does not work for arbitrary 3-qubit gates, although the update does make it work for some 3-qubit gates. As a counterexample, try the permutation matrix on 3-qubits in my question.Golightly
I also added an example with "random" unitary matrices generated by the random_unitary() function in Qiskit. None of these work either.Golightly
It seems like what Nielsen & Chuang do in 4.5.1 is working to some extent for 2-qubit gates, but nothing larger. Using 4.5.2 I think you can build up to larger gates from there. I'm not sure that the procedure of approximating 2-qubit gates is working is working properly though, so I want to verify that before trying to figure out how to use Gray Codes to build up to larger circuits. I'm looking at the source code now to verify that this is actually what Qiskit is doing, but it may go faster if you have more insight or thoughts.Golightly
It definitely doesn't work properly for 2-qubit gates either. I've tested it with different basis gates (for example with Hadamard, phase, π/8, and CNOT, which is shown to be universal in Nielsen & Chuang) and it doesn't work for randomly generated 2-qubit unitaries or custom unitaries, however the basis set of ['u1', 'u2', 'u3', 'cx'] suggested in the source code produces a result, but the result isn't always correct.Golightly
Both the permutation and random unitary examples work for me. Ensure you have the right version number. You can check it with qiskit.__qiskit_version__. You should have 'qiskit-terra': '0.14.0'` or higherHaha
Thank you for responding and looking into this. I'm enjoying investigating functionality and learning about how things are implemented. I'd really like to understand how the methods from 4.5 and Appendix 3 in Nielsen & Chuang have been implemented. Could you provide a little direction on this or give me some idea of what still needs to be implemented. I would like to contribute something meaningful to Qiskit and learn something in the process.Golightly
I'm still having issues with the 3-qubit permutation matrix in my example and I have 'qiskit-terra': '0.14.1'Golightly
I can't run this: python permute = Operator([[0, 0, 1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 1, 0, 0, 0]]) qc1 = QuantumCircuit(3) qc1.unitary(permute, [0,1,2], label='P') result_qc1 = transpile(qc1, basis_gates=['h', 'z', 'cx', 't'], optimization_level=3) result_qc1.draw(output='mpl') Golightly
With basis_gates=['u1', 'u2', 'u3', 'cx'] it works fine now, but basis_gates=['h', 'z', 'cx', 't'] still doesn't work.Golightly
I suppose if there is always a native 'u3' to whatever hardware you're using that's enough (along with a 'cx'). I would assume it is a safe assumption to make that there will be a 'u3' which is standard for future hardware, but I'm sure plenty of examples can be found where there isn't a native 'u3' at present. Would you agree? There might also be current quantum hardware that implements other gates more accurately than an arbitrary 'u3', and this would be good to consider when transpiling as well.Golightly
I'm still not sure the transpiler is working properly. I checked how it transpiles a permutation matrix corresponding to the permutation (1,2,3)(4) and with the basis_gates = ['u3', 'cx'] and it gives me back the permutation matrix corresponding to (1,3,2)(4) multiplied by a global phase factor. The global phase is probably fine considering it isn't measurable. I also noticed changing the optimization_level doesn't change anything in general when I test this on random unitary matrices.Golightly
u3 (arbitrary single qubit rotation) + cx form a universal gate set. Any circuit can be written in terms of them, exactly. You could synthesize to ['h', 'z', 'cx', 't'], but this is a discrete gate set and doing this approximate decomposition does not yet exist in Qiskit. There is an issue open for it: github.com/Qiskit/qiskit-terra/issues/3212Haha
Awesome. I'll see what I can do.Golightly
For anyone else interested in working on this, this video might be of some interest: youtube.com/watch?v=d_428En3an8Golightly
I also have found this video helpful: youtube.com/watch?v=mHtWd4wm84c&feature=youtu.be I will also say, this is not a short project for me personally and will likely take me several weeks to implement. I am quite enjoying this paper though and the mathematics behind all of this in the paper is some of my favorite.Golightly
That's great, I'm glad you found this project interesting :)Haha

© 2022 - 2024 — McMap. All rights reserved.