qml.pulse.transmon_drive

transmon_drive(amplitude, phase, freq, wires, d=2)[source]

Returns a ParametrizedHamiltonian representing the drive term of a transmon qubit.

The Hamiltonian is given by

\[\Omega(t) \sin\left(\phi(t) + \nu t\right) \sum_q Y_q\]

where \(\{Y_q\}\) are the Pauli-Y operators on wires \(\{q\}\). The arguments amplitude, phase and freq correspond to \(\Omega / (2\pi)\), \(\phi\) and \(\nu / (2\pi)\), respectively, and can all be either fixed numbers (float) or depend on time (callable). If they are time-dependent, they need to abide by the restrictions imposed in ParametrizedHamiltonian and have a signature of two parameters, (params, t).

Together with the qubit \(Z\) terms in transmon_interaction(), driving with this term can generate \(X\) and \(Y\) rotations by setting \(\phi\) accordingly and driving on resonance (see eqs. (79) - (92) in 1904.06560). Further, it can generate entangling gates by driving at cross-resonance with a coupled qubit (see eqs. (131) - (137) in 1904.06560). Such a coupling is described in transmon_interaction().

For realistic simulations, one may restrict the amplitude, phase and drive frequency parameters. For example, the authors in 2008.04302 impose the restrictions of a maximum amplitude \(\Omega_{\text{max}} = 20 \text{MHz}\) and the carrier frequency to deviate at most \(\nu - \omega = \pm 1 \text{GHz}\) from the qubit frequency \(\omega\) (see transmon_interaction()). The phase \(\phi(t)\) is typically a slowly changing function of time compared to \(\Omega(t)\).

Note

Currently only supports d=2 with qudit support planned in the future. For d>2, we have \(Y \mapsto i (\sigma^- - \sigma^+)\) with lowering and raising operators \(\sigma^{\mp}\).

Note

Due to convention in the respective fields, we omit the factor \(\frac{1}{2}\) present in the related constructor rydberg_drive()

Parameters
  • amplitude (Union[float, callable]) – Float or callable representing the amplitude of the driving field. This should be in units of frequency (GHz), and will be converted to angular frequency \(\Omega(t)\) internally where needed, i.e. multiplied by \(2 \pi\).

  • phase (Union[float, callable]) – Float or callable returning phase \(\phi(t)\) (in radians). Can be a fixed number (float) or depend on time (callable)

  • freq (Union[float, callable]) – Float or callable representing the frequency of the driving field. This should be in units of frequency (GHz), and will be converted to angular frequency \(\nu(t)\) internally where needed, i.e. multiplied by \(2 \pi\).

  • wires (Union[int, list[int]]) – Label of the qubit that the drive acts upon. Can be a list of multiple wires.

  • d (int) – Local Hilbert space dimension. Defaults to d=2 and is currently the only supported value.

Returns

a ParametrizedHamiltonian representing the transmon interaction

Return type

ParametrizedHamiltonian

Example

We can construct a drive term acting on qubit 0 in the following way. We parametrize the amplitude and phase via \(\Omega(t)/(2 \pi) = A \times \sin^2(\pi t)\) and \(\phi(t) = \phi_0 (t - \frac{1}{2})\). The squared sine ensures that the amplitude will be strictly positive (a requirement for some hardware). For simplicity, we set the drive frequency to zero \(\nu=0\).

def amp(A, t):
    return A * jnp.exp(-t**2)

def phase(phi0, t):
    return phi0

freq = 0

H = qml.pulse.transmon_drive(amp, phase, freq, 0)

t = 0.
A = 1.
phi0 = jnp.pi/2
params = [A, phi0]

Evaluated at \(t = 0\) with the parameters \(A = 1\) and \(\phi_0 = \pi/2\) we obtain \(2 \pi A \exp(0) \sin(\pi/2 + 0)\sigma^y = 2 \pi \sigma^y\).

>>> H(params, t)
6.283185307179586 * Y(0)

We can combine transmon_drive() with transmon_interaction() to create a full driven transmon Hamiltonian. Let us look at a chain of three transmon qubits that are coupled with their direct neighbors. We provide all frequencies in GHz (conversion to angular frequency, i.e. multiplication by \(2 \pi\), is taken care of internally where needed).

We use values around \(\omega = 5 \times 2\pi \text{GHz}\) for resonant frequencies, and coupling strenghts on the order of around \(g = 0.01 \times 2\pi \text{GHz}\).

We parametrize the drive Hamiltonians for the qubits with amplitudes as squared sinusodials of maximum amplitude \(A\), and constant drive frequencies of value \(\nu\). We set the phase to zero \(\phi=0\), and we make the parameters \(A\) and \(\nu\) trainable for every qubit. We simulate the evolution for a time window of \([0, 5]\text{ns}\).

import jax

jax.config.update("jax_enable_x64", True)

qubit_freqs = [5.1, 5., 5.3]
connections = [[0, 1], [1, 2]]  # qubits 0 and 1 are coupled, as are 1 and 2
g = [0.02, 0.05]
H = qml.pulse.transmon_interaction(qubit_freqs, connections, g, wires=range(3))

def amp(max_amp, t): return max_amp * jnp.sin(t) ** 2
freq = qml.pulse.constant  # Parametrized constant frequency
phase = 0.0
time = 5

for q in range(3):
    H += qml.pulse.transmon_drive(amp, phase, freq, q)  # Parametrized drive for each qubit

dev = qml.device("default.qubit", wires=range(3))

@jax.jit
@qml.qnode(dev, interface="jax")
def qnode(params):
    qml.evolve(H)(params, time)
    return qml.expval(qml.Z(0) + qml.Z(1) + qml.Z(2))

We evaluate the Hamiltonian with some arbitrarily chosen maximum amplitudes (here on the order of \(0.5 \times 2\pi \text{GHz}\)) and set the drive frequency equal to the qubit frequencies. Note how the order of the construction of H determines the order with which the parameters need to be passed to ParametrizedHamiltonian and evolve(). We made the drive frequencies trainable parameters by providing constant callables through constant() instead of fixed values (like the phase). This allows us to differentiate with respect to both the maximum amplitudes and the frequencies and optimize them.

>>> max_amp0, max_amp1, max_amp2 = [0.5, 0.3, 0.6]
>>> fr0, fr1, fr2 = qubit_freqs
>>> params = [max_amp0, fr0, max_amp1, fr1, max_amp2, fr2]
>>> qnode(params)
Array(-1.57851962, dtype=float64)
>>> jax.grad(qnode)(params)
[Array(-13.50193649, dtype=float64),
 Array(3.1112141, dtype=float64),
 Array(16.40286521, dtype=float64),
 Array(-4.30485667, dtype=float64),
 Array(4.75813949, dtype=float64),
 Array(3.43272354, dtype=float64)]