8

I was wondering if something like this is possible in QISKit: let's say we have two registers containing target and ancilla qubits:

$a_0$ -------------------

$a_1$--------------------

$\vdots$

$a_4$ ------------------

$t_0$ ------------------

$t_1$ ------------------

$\vdots$

$t_4$ ------------------

These two registers are stored in one quantum register qr. So to access $a_0$ we would type qr[0], to access $a_1$ - qr[1], ..., for $t_5$ - qr[9]. We can pass this quantum register as an argument to some function:

foo(qr, ...)

What I want to do is to interleave the ancilla and target qubits:

$a_0$ -------------------

$t_0$--------------------

$\vdots$

$a_i$ ------------------

$t_i$ ------------------

$\vdots$

$a_4$ ------------------

$t_4$ ------------------

so to access $a_0$ I would type qr[0], for $t_1$ - qr[1] and so on. Finally, I would like to pass such changed quantum register qr' again as an argument to some function

foo(qr', ...)

and in this function I would like to use these changed indices. Is this possible? Other solution I figured out was to pass array of indices for ancilla and target qubits, but I would like to avoid that. Another option would be to use swap gates on these qubits

Sanchayan Dutta
  • 17,497
  • 7
  • 48
  • 110
brzepkowski
  • 1,049
  • 7
  • 19

2 Answers2

5

The relationship between your indices can be captured by a map:

$$\{0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 1, 6: 3, 7: 5, 8: 7, 9: 9\}$$

You can then use this to specify where operations get applied to in a register.

Here is a simple code in QISKit (generalizes to arbitrary register length):

from qiskit import * 
from qiskit.tools.visualization import *

# build a register with k targets and k ancillas 
k = 5
qr = QuantumRegister(2*k)
circ = QuantumCircuit(qr)

# apply cx between ancillas and targets
for i in range(k):
    circ.cx(qr[i], qr[i+k])

circuit_drawer(circ)

original

# specify the desired interleaving
# {0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 1, 6: 3, 7: 5, 8: 7, 9: 9}
new_qubit_map = {i: 2*i if i < k else 2*(i-k)+1 for i in range(len(qr))}

# create the same circuit, but with the new interleaving
circ_2 = QuantumCircuit(qr)
for i in range(k):
    circ_2.cx(qr[new_qubit_map[i]], qr[new_qubit_map[i+k]])

circuit_drawer(circ_2)

interleaved

Sanchayan Dutta
  • 17,497
  • 7
  • 48
  • 110
Ali Javadi
  • 1,622
  • 1
  • 8
  • 11
3

A lot of updates have been made to Qiskit. Here's possibly the best way to achieve the desired result:

qct = transpile(qc, initial_layout=sum(zip(a,t),()))

Here, a and t are QuantumRegister objects.

Explanation

Firstly, use separate quantum registers a and t instead of the default single qr register.

from qiskit import QuantumRegister, ClassicalRegister
n = 5
a = QuantumRegister(n, 'a')
t = QuantumRegister(n, 't')
c = ClassicalRegister(n, 'c')
qc = QuantumCircuit(a,t,c)
qc.cx(a,t)
qc.draw()

Here's the output you would get:

a register is at top and t is at bottom

Now, we can remap/transpile it onto another circuit where the mapping is different. I used sum(zip(a,t), ()) to create the mapping. zip first creates a list of tupples like [..., (a[i],t[i]), ...] and then is flattened by sum(). The second argument (), an empty tuple, is the starting value for the sum.

All in all, here's the code to create the remapped/transpiled circuit:

qct = transpile(qc, initial_layout=sum(zip(a,t),()))
qct.draw()

Here's the output:

a[i] qubit is preceeded by t[i]

If you are having issues where qc gets decomposed into multiple gates (e.g. ccx), then using basis_gates={d.operation.name for d in qc.data} should fix it. It is using all the gates present in qc as basis gates.

qct = transpile(qc, basis_gates={d.operation.name for d in qc.data}, initial_layout=sum(zip(a,t),()))
Shawon
  • 51
  • 3