Processing math: 100%

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

Ω(t)sin(ϕ(t)+νt)qYq

where {Yq} are the Pauli-Y operators on wires {q}. The arguments amplitude, phase and freq correspond to Ω/(2π), ϕ and ν/(2π), 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 ϕ 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 Ωmax=20MHz and the carrier frequency to deviate at most νω=±1GHz from the qubit frequency ω (see transmon_interaction()). The phase ϕ(t) is typically a slowly changing function of time compared to Ω(t).

Note

Currently only supports d=2 with qudit support planned in the future. For d>2, we have Yi(σσ+) with lowering and raising operators σ.

Note

Due to convention in the respective fields, we omit the factor 12 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 Ω(t) internally where needed, i.e. multiplied by 2π.

  • phase (Union[float, callable]) – Float or callable returning phase ϕ(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 ν(t) internally where needed, i.e. multiplied by 2π.

  • 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 Ω(t)/(2π)=A×sin2(πt) and ϕ(t)=ϕ0(t12). 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 ν=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 ϕ0=π/2 we obtain 2πAexp(0)sin(π/2+0)σy=2πσ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π, is taken care of internally where needed).

We use values around ω=5×2πGHz for resonant frequencies, and coupling strenghts on the order of around g=0.01×2πGHz.

We parametrize the drive Hamiltonians for the qubits with amplitudes as squared sinusodials of maximum amplitude A, and constant drive frequencies of value ν. We set the phase to zero ϕ=0, and we make the parameters A and ν trainable for every qubit. We simulate the evolution for a time window of [0,5]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×2π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)]