Open alejomonbar opened 12 months ago
What calls are you making that it seems like transpilation is taking a long time? The first call to transpile with a new IBM Runtime backend may take a couple of seconds to initialise the backend fully, but after that, transpilation should be fast. In your example, if I delay the transpilation until after the whole circuit is constructed, the transpilation takes 37ms on my machine.
You can set the initial virtual->physical mapping for subsequent transpilations by using the initial_layout
argument to transpile
.
What calls are you making that it seems like transpilation is taking a long time? The first call to transpile with a new IBM Runtime backend may take a couple of seconds to initialise the backend fully, but after that, transpilation should be fast. In your example, if I delay the transpilation until after the whole circuit is constructed, the transpilation takes 37ms on my machine.
You can set the initial virtual->physical mapping for subsequent transpilations by using the
initial_layout
argument totranspile
.
Thank you for the quick reply, @jakelishman. For me this code is broken, isn't it for you? When I said it takes too long is as if the whole transpilation is made after combining the two layers. Maybe it does not take too long for small circuits but the idea is to make it for 127 qubits with a number of shadows around 10.000.
Sorry for the long delay between now and then. The code block exactly as presented is broken, but I was talking about how long transpile
took if you build the circuits completely and then transpile
, so I used this tweaked code-block, with the only changes indicated:
from qiskit import QuantumCircuit, ClassicalRegister
from qiskit_ibm_provider import IBMProvider
from qiskit.circuit.library import EfficientSU2
from qiskit import transpile
import numpy as np
provider = IBMProvider()
ibm_brisbane = provider.get_backend("ibm_brisbane")
num_qubits = 7
qc = QuantumCircuit(num_qubits)
for i in range(0, num_qubits-1, 2):
qc_su2 = EfficientSU2(2, reps=1)
params_i = np.pi * np.random.rand(qc_su2.num_parameters)
qc_su2 = qc_su2.assign_parameters(params_i)
qc = qc.compose(qc_su2, [i,i+1])
# I think this `transpile` line should have been outside the loop anyway:
# REMOVED: qc = transpile(qc, ibm_brisbane)
# Adding the classical shadows layer with a random projection set
n_shadow = 1
unitary_ids = np.random.randint(0, 3, size=(n_shadow, num_qubits))
qcs = []
for ns in range(n_shadow):
qc_shadow = QuantumCircuit(num_qubits) # Classical Shadows layer circuit
for i in range(num_qubits):
if unitary_ids[ns, i] == 0:
qc_shadow.h(i)
elif unitary_ids[ns, i] == 1:
qc_shadow.sdg(i)
qc_shadow.h(i)
elif unitary_ids[ns, i] == 2:
pass
# REMOVED: qc_shadow = transpile(qc_shadow, ibm_brisbane)
circuit = qc.compose(qc_shadow, range(num_qubits))
circuit.add_register(ClassicalRegister(num_qubits))
circuit.measure(range(num_qubits), range(num_qubits))
qcs.append(circuit)
At the end of this, calling
transpile(qcs, ibm_brisbane)
was timed at 36.8(6)ms on my machine, which doesn't seem excessive. Are you working at scales where you absolutely must pre-transpile the initial setup of the circuit?
In principle, the way you would do the transpile(qc_shadow, ibm_brisbane)
call using the final layout map of a pre-transpiled circuit is to find the positions that virtual qubits $0, \dots, n-1$ end up in, and set that as the initial_layout
argument to the second transpile
call. That looks something like:
qc_base_transpiled = transpile(qc_base, ibm_brisbane)
base_final_layout = qc_base_transpiled.layout.final_index_layout()
qc_shadow = <build your base shadow>
# This transpilation ensures the virtual qubits in `qc_shadow` start in the places that the
# same-numbered virtual qubits in `qc_base` finished on.
qc_shadow_transpiled = transpile(qc_shadow, ibm_brisbane, initial_layout=base_final_layout)
# We don't need to remap the qubits in the composition, because both circuits are in terms of
# the same physical qubits.
circuit = qc_base.compose(qc_shadow_transpiled)
I should note that you should add the measurements to the second circuit before you transpile it, to ensure that the remappings and any subsequent inserted swaps are respected.
Environment
What is happening?
Classical shadows is an efficient method for constructing an approximate classical description of a quantum state. There is a problem when trying to implement it on a real device, it requires the transpilation of two different layers, one that is the same for all the circuits, and one random with single-qubit operations. If I try to join the two layers and do the transpilation afterwards it takes too long. If I try to transpile the first and the second separately to reuse the first layer, I didn't find a way for my second layer to be aware of the first transpiled layer. This is a follow-up to our discussion @1ucian0.
How can we reproduce the issue?
The code below could help to understand what I found:
What should happen?
Been able to combine the two circuits while keeping the same logical qubits.
Any suggestions?
No response