seQuencing logo

Sequences

In some cases, one may want to intersperse ideal unitary gates within a sequence of time-dependent operations. This is possible using an object called a Sequence. A Sequence is essentially a list containing PulseSequences, Operations, and unitary operators. When Sequence.run(init_state) is called, the Sequence iterates over its constituent PulseSequences, Operations, and unitaries, applying each to the resulting state of the last.

Sequence is designed to behave like a Python list, so it has the following methods defined:

  • append()

  • extend()

  • insert()

  • pop()

  • clear()

  • __len__()

  • __getitem__()

  • __iter__()

Notes:

  • Just like a PulseSequence or CompiledPulseSequence, a Sequence must be associated with a System.

  • Whereas PulseSequence.run() and CompiledPulseSequence.run() return an instance of qutip.solver.Result, Sequence.run() returns a SequenceResult object, which behaves just like qutip.solver.Result. SequenceResult.states stores the quantum states after each stage of the simulation (states[0] is init_state and states[-1] is the final state of the system).

[1]:
%config InlineBackend.figure_formats = ['svg']
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import qutip
from sequencing import Transmon, Cavity, System, Sequence
[2]:
qubit = Transmon('qubit', levels=3, kerr=-200e-3)
cavity = Cavity('cavity', levels=10, kerr=-10e-6)
system = System('system', modes=[qubit, cavity])
system.set_cross_kerr(cavity, qubit, chi=-2e-3)
qubit.gaussian_pulse.drag = 5

Interleave pulses and unitaries

Here we perform a “\(\pi\)-pulse” composed of \(20\) interleaved \(\frac{\pi}{40}\)-pulses and unitary rotations.

[3]:
init_state = system.ground_state()
# calculate expectation value of |qubit=1, cavity=0>
e_ops = [system.fock_dm(qubit=1)]
n_rotations = 20
theta = np.pi / n_rotations

seq = Sequence(system)

for _ in range(n_rotations):

    # Capture a PulseSequence
    qubit.rotate_x(theta/2)

    # # Alternatively, we can append an Operation
    # operation = qubit.rotate_x(theta/2, capture=False)
    # seq.append(operation)

    # Append a unitary
    seq.append(qubit.Rx(theta/2))

result = seq.run(init_state, e_ops=e_ops, full_evolution=True, progress_bar=True)
states = result.states
100%|██████████| 40/40 [00:00<00:00, 79.17it/s]

Inspect the sequence

Sequence.plot_coefficients() plots Hamiltonian coefficients vs. time. Instantaneous unitary operations are represented by dashed vertical lines. If multiple unitaries occur at the same time, only a single dashed line is drawn.

[4]:
fig, ax = seq.plot_coefficients(subplots=False)
ax.set_xlabel('Time [ns]')
ax.set_ylabel('Hamiltonian coefficient [GHz]')
fig.set_size_inches(8,4)
fig.tight_layout()
fig.subplots_adjust(top=0.9)
../_images/notebooks_04-sequences_6_0.svg
[5]:
print('len(states):', len(states))
print(f'state fidelity: {qutip.fidelity(states[-1], qubit.Rx(np.pi) * init_state)**2:.4f}')
len(states): 821
state fidelity: 0.9996

Plot the results

[6]:
e_pops = result.expect[0] # probability of measuring the state |qubit=1, cavity=0>

fig, ax = plt.subplots(figsize=(8,4))
ax.plot(result.times, e_pops, '.')
ax.scatter(result.times[:1], e_pops[:1], marker='s', color='k', label='init_state')
# draw vertical lines at the location of each unitary rotation
for i in range(1, result.times.size // (2*n_rotations) + 1):
    t = 2 * n_rotations * i - 1
    label = 'unitaries' if i == 1 else None
    ax.axvline(t, color='k', alpha=0.25, ls='--', lw=1.5, label=label)
ax.axhline(0, color='k', lw=1)
ax.axhline(1, color='k', lw=1)
ax.set_ylabel('$P(|e\\rangle)$')
ax.set_xlabel('Times [ns]')
ax.set_title('Interleaved pulses and unitaries')
ax.legend(loc=0);
../_images/notebooks_04-sequences_9_0.svg
[7]:
print(result)
SequenceResult
--------------
Number of times: 821
states = True
expect = True, num_expect = 1
num_collapse = 0
[8]:
from qutip.ipynbtools import version_table
version_table()
[8]:
SoftwareVersion
QuTiP4.7.0
Numpy1.23.2
SciPy1.9.1
matplotlib3.5.3
Cython0.29.32
Number of CPUs2
BLAS InfoOPENBLAS
IPython8.4.0
Python3.8.6 (default, Oct 19 2020, 15:10:29) [GCC 7.5.0]
OSposix [linux]
Tue Aug 30 19:15:43 2022 UTC
[ ]: