Example: Measuring T1

Example: Measuring T1#

T1 is an experiment that measures the relaxation time of a qubit.

Information stored in a qubit decays exponentially. The time constant of the longitudinal decay is called the relaxation time $T_1$.

The experiment measures $T_1$ by preparing selected qubits in the excited state by applying an X gate, waiting some time, and measuring the qubit.

The waiting time is swept to reveal the exponential decay of the excited state probability.

import os
from iqm.pulla.pulla import Pulla
station_control_url = os.environ['PULLA_STATION_CONTROL_URL']  # or set the URL directly here

p = Pulla(station_control_url)
compiler = p.get_standard_compiler()

Preparing the circuit#

We need to select the physical qubits to work on. These are available on the QPU:

qubits = compiler.builder.chip_topology.qubits_sorted
qubits
('QB1', 'QB2', 'QB3', 'QB4', 'QB5')

Out of these, we select a few:

qubits = qubits[0:2]

Now we create all the circuits. In each circuit, we do a PRX(pi), or X, then a delay operation, then measure all qubits. We create a circuit for each delay time we want on the time axis.

from iqm.pulse import Circuit
from iqm.pulse import CircuitOperation as Op
import numpy as np

time_axis = np.linspace(0.0, 300e-6, 51) # In seconds
circuits = []
for wait_time in time_axis:
    
    instructions=[]
    for qubit in qubits:
        instructions += [
            Op("prx", (qubit,), args={"angle": np.pi, "phase": 0.0}),
            Op("delay", (qubit,), args={"duration": wait_time}),
        ]                                 
    instructions.append(Op("measure", qubits, args={"key": "M"}))
    circuits.append(Circuit("T1", instructions))
    
circuits[-1]
Circuit(name='T1', instructions=[CircuitOperation(name='prx', locus=('QB1',), args={'angle': 3.141592653589793, 'phase': 0.0}, implementation=None), CircuitOperation(name='delay', locus=('QB1',), args={'duration': 0.0003}, implementation=None), CircuitOperation(name='prx', locus=('QB2',), args={'angle': 3.141592653589793, 'phase': 0.0}, implementation=None), CircuitOperation(name='delay', locus=('QB2',), args={'duration': 0.0003}, implementation=None), CircuitOperation(name='measure', locus=('QB1', 'QB2'), args={'key': 'M'}, implementation=None)])

Then compile the circuits. We tweak the settings so that the shots are averaged by the server, so that we don’t need to. The results therefore return as sampled probabilities.

playlist, context = compiler.compile(circuits)
settings, context = compiler.build_settings(context, shots=500)

# Average over shots. In normal circuit execution, this would be equal to shots:
settings.options.averaging_bins = 1  
job = p.execute(playlist, context, settings, verbose=False)
[06-17 14:50:47;I] Created job in queue with ID: 33dac4ca-5dcd-4243-8074-7d00b43abb36
[06-17 14:50:47;I] Job link: http://varda.qc.iqm.fi/station/jobs/33dac4ca-5dcd-4243-8074-7d00b43abb36
[06-17 14:50:47;I] Waiting for the job to finish...
[06-17 14:50:48;I] Waiting for job ID: 33dac4ca-5dcd-4243-8074-7d00b43abb36
[06-17 14:51:02;I] Sweep status: ready

Extract the results

import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

def exp_func(x, a, b, c):
    return a * np.exp(- x / b) + c

plt.figure()
x = time_axis * 1e6

for i, qubit in enumerate(qubits):
    
    y = np.array([circuit_result["M"][0][i] for circuit_result in job.result])
    popt, _ = curve_fit(exp_func, time_axis, y, p0=[1,50e-6,0])  
    print(f"{qubit} T1 = {popt[1]*1e6 : .1f} µs", )
    
    plt.plot(x, y, 'o', label=qubit)
    plt.plot(x, exp_func(np.array(time_axis), *popt), 'k:')
    
plt.xlabel("Delay time (µs)")
plt.ylabel("Excited state probablility")
plt.legend();
QB1 T1 =  31.9 µs
QB2 T1 =  28.8 µs
_images/b3d63eba1828ea06e98e7212ae58c1c4b300d62d9b7b8ff5cab4a9a6e0b2b745.png

We can also visualise the final playlist. We should see that each circuit is different and the waits at the end are increasing towards the end.

from iqm.pulse.playlist.visualisation.base import inspect_playlist
from IPython.core.display import HTML

HTML(inspect_playlist(playlist, range(5))) # Show first 5 circuits
/home/ville/miniconda3/envs/exa-repo/lib/python3.11/site-packages/IPython/core/display.py:431: UserWarning: Consider using IPython.display.IFrame instead
  warnings.warn("Consider using IPython.display.IFrame instead")