title: Qiskit Transpiler for quantum circuits
body: <p>Okay, so, in Qiskit there is the <code>transpile()</code> function (see <a href="https://qiskit.org/documentation/stubs/qiskit.compiler.transpile.html" rel="noreferrer">documentation</a>). 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 <a href="https://www.cs.umd.edu/~rrand/voqc_draft.pdf" rel="noreferrer">here</a> for example...perhaps someone has used <a href="https://leanprover.github.io/" rel="noreferrer">LEAN</a> for something similar?). Sometimes variational methods are used to approximate an optimal circuit as well, but I digress.  </p>
  
  <p>A slightly different but related problem: Using the Kitaev-Solovay Theorem in Appendix 3 of <a href="http://mmrc.amss.cas.cn/tlb/201702/W020170224608149940643.pdf" rel="noreferrer">Nielsen &amp; Chuang</a>, 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. </p>
  
  <p>Given this, one would expect the Qiskit <code>transpile()</code> 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:</p>
  
  <pre class="lang-py prettyprint-override"><code>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')
  </code></pre>
  
  <p>Now, if I try using the <code>transpile()</code> function in Qiskit as follows:</p>
  
  <pre class="lang-py prettyprint-override"><code>result = transpile(qc, basis_gates=['u1', 'u2', 'u3', 'cx'], optimization_level=3)
  result.draw(output='mpl')
  </code></pre>
  
  <p>I get some huge long horrible error that ends with, </p>
  
  <pre><code>NotImplementedError: Not able to generate a subcircuit for a 3-qubit unitary
  </code></pre>
  
  <p>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 <code>decompose()</code> function (see <a href="https://qiskit.org/documentation/stubs/qiskit.circuit.QuantumCircuit.decompose.html" rel="noreferrer">documentation</a>) which seems to have a more limited functionality to the <code>transpile()</code> function when looking at the source code of each. The function <code>decompose()</code> is implemented (as can be seen in <a href="https://www.youtube.com/watch?v=krhPpzkT_z4" rel="noreferrer">this video</a> as well as <a href="https://www.youtube.com/watch?v=B-8xOWZJbaI" rel="noreferrer">this one</a>). The <code>transpile()</code> function is also implemented (see <a href="https://www.youtube.com/watch?v=Omv-bPvQ3E8&amp;t=2468s" rel="noreferrer">this video</a> at approximately 10:35 cell In[18], and in his discussion). You can also try running the commands using his </p>
  
  <pre class="lang-py prettyprint-override"><code>from qiskit import transpile
  </code></pre>
  
  <p>and it doesn't work with that import either. If anyone understands why the <code>transpile()</code> function (or the <code>decompose()</code> function for that matter) isn't working the way I would expect it to, I would love an explanation. Thanks!!!</p>
  
  <p>---------Update----------</p>
  
  <p>I have found yet another issue. If we use</p>
  
  <pre class="lang-py prettyprint-override"><code>from qiskit.circuit.random import random_circuit
  rcirc2 = random_circuit(3, 4)
  rcirc2.draw(output='mpl')
  </code></pre>
  
  <p>to generate random circuits, then run</p>
  
  <pre class="lang-py prettyprint-override"><code>from qiskit.compiler import transpile
  result2 = transpile(rcirc2, basis_gates=['u1', 'u2', 'u3', 'cx'], optimization_level=3)
  result2.draw(output='mpl')
  </code></pre>
  
  <p>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 <code>transpile()</code>. 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, </p>
  
  <pre class="lang-py prettyprint-override"><code>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')
  </code></pre>
  
  <p>when we run </p>
  
  <pre class="lang-py prettyprint-override"><code>result3 = transpile(circ, basis_gates=['u1', 'u2', 'u3', 'cx'], optimization_level=3)
  result3.draw(output='mpl')
  </code></pre>
  
  <p>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. </p>
  
  <p>----------Update 2----------</p>
  
  <p>If we generate random 3-qubit unitaries using Qiskit, these also do not work. </p>
  
  <pre class="lang-py prettyprint-override"><code>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')
  </code></pre>
  
  <p>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. </p>