Download

Download this file as Jupyter notebook: parameterized_linker_native_gates_mq.ipynb.

Compiling multi-qubit native gates to waveforms

In this guide, we build on on Compiling single-qubit native gates to waveforms to demonstrate how to create a linker for a typical multi-qubit gate. We define two linkers for a cross-resonance gate, a common entangling gate in superconducting systems. The first is a basic implementation, while the second adds an extra pulse for crosstalk suppression.

Here, we only consider one of two commuting subsets of multi-qubit gates assuming linear connectivity.

Creating the Linkers

We define the cross-resonance gate and a corresponding instruction. We work with all phases in the gate being 0 for simplicity, resulting in a gate proportional to \(ZX\) with angle \(\beta\).

[2]:
import keysight.qcs as qcs
import numpy as np
import math

n_targets = 4
qubits = qcs.Qudits(range(n_targets))

# the number of commuting multi-qubit gates
n_mq = math.floor(n_targets / 2)

# create the multi-qudit targets
mq_targets = qcs.MultiQudits.from_qudits((qubits[: 2 * n_mq : 2], qubits[1::2]))

zx = qcs.PAULIS.sigma_z & qcs.PAULIS.sigma_x
cr_gate = qcs.ParametricGate([zx], ["beta"])

angles = qcs.Array(name="beta", shape=(n_mq,), dtype=float)
cr_param_gate = qcs.ParameterizedGate(cr_gate, angles)

The first linker corresponds to the basic implementation. Here, we apply a pulse to to the control qubit with the resonant frequency of the target qubit, resulting in a rotation around \(Z\) for the control and around \(X\) for the target. Note that we use the same frequencies as those in Compiling single-qubit native gates to waveforms.

[3]:
channels = qcs.Channels(range(n_targets), name="xy_channels")

sq_freqs = [5e9 + 100e6 * n for n in range(n_targets)]
freqs = qcs.Array("single_qubit_frequencies", value=sq_freqs, dtype=float)
amps = qcs.Array("multi_qubit_amplitudes", value=[0.5] * n_mq, dtype=float)
dur = qcs.Scalar("multi_qubit_duration", value=30e-9, dtype=float)

pulse = qcs.RFWaveform(dur, qcs.GaussianEnvelope(), angles * amps, freqs[1::2])

cr_prog = qcs.Program()
cr_prog.add_waveform(pulse, channels[: 2 * n_mq : 2])

# create the linker
cr_linker = qcs.ParameterizedLinker(cr_param_gate, mq_targets, cr_prog)

cr_prog.draw()
keysight-logo-svg
Program
Program
Duration 30 ns
Layers 1
Targets 2
Repetitions
Layer #0
Layer #0
Duration 30 ns
xy_channels 0
RFWaveform on ('xy_channels', 0)

Parameters
Duration Scalar(name=multi_qubit_duration, value=30 ns, dtype=float, unit=s)
Amplitude Array(name=_implicit, shape=(2,), dtype=float, unit=none)
Frequency ArraySlice(name=single_qubit_frequencies, shape=(2,), dtype=float, unit=Hz, value=[5.1 GHz, 5.3 GHz])
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad
2
RFWaveform on ('xy_channels', 2)

Parameters
Duration Scalar(name=multi_qubit_duration, value=30 ns, dtype=float, unit=s)
Amplitude Array(name=_implicit, shape=(2,), dtype=float, unit=none)
Frequency ArraySlice(name=single_qubit_frequencies, shape=(2,), dtype=float, unit=Hz, value=[5.1 GHz, 5.3 GHz])
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad

We now extend the above linker to suppress crosstalk by playing a simultaneous pulse on the target qubit at the same frequency with a fraction of the amplitude \(\alpha\).

[4]:
alpha = qcs.Scalar("alpha", value=0.3, dtype=float)
pulse_supp = qcs.RFWaveform(
    dur, qcs.GaussianEnvelope(), alpha * angles * amps, freqs[1::2]
)

cr_prog_supp = qcs.Program()
cr_prog_supp.add_waveform(pulse, channels[: 2 * n_mq : 2])
cr_prog_supp.add_waveform(pulse_supp, channels[1::2])

# create the linker
cr_linker_supp = qcs.ParameterizedLinker(cr_param_gate, mq_targets, cr_prog_supp)

cr_prog_supp.draw()
keysight-logo-svg
Program
Program
Duration 30 ns
Layers 1
Targets 4
Repetitions
Layer #0
Layer #0
Duration 30 ns
xy_channels 0
RFWaveform on ('xy_channels', 0)

Parameters
Duration Scalar(name=multi_qubit_duration, value=30 ns, dtype=float, unit=s)
Amplitude Array(name=_implicit, shape=(2,), dtype=float, unit=none)
Frequency ArraySlice(name=single_qubit_frequencies, shape=(2,), dtype=float, unit=Hz, value=[5.1 GHz, 5.3 GHz])
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad
1
RFWaveform on ('xy_channels', 1)

Parameters
Duration Scalar(name=multi_qubit_duration, value=30 ns, dtype=float, unit=s)
Amplitude Array(name=_implicit, shape=(2,), dtype=float, unit=none)
Frequency ArraySlice(name=single_qubit_frequencies, shape=(2,), dtype=float, unit=Hz, value=[5.1 GHz, 5.3 GHz])
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad
2
RFWaveform on ('xy_channels', 2)

Parameters
Duration Scalar(name=multi_qubit_duration, value=30 ns, dtype=float, unit=s)
Amplitude Array(name=_implicit, shape=(2,), dtype=float, unit=none)
Frequency ArraySlice(name=single_qubit_frequencies, shape=(2,), dtype=float, unit=Hz, value=[5.1 GHz, 5.3 GHz])
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad
3
RFWaveform on ('xy_channels', 3)

Parameters
Duration Scalar(name=multi_qubit_duration, value=30 ns, dtype=float, unit=s)
Amplitude Array(name=_implicit, shape=(2,), dtype=float, unit=none)
Frequency ArraySlice(name=single_qubit_frequencies, shape=(2,), dtype=float, unit=Hz, value=[5.1 GHz, 5.3 GHz])
Envelope GaussianEnvelope(2.0)
Instantaneous Phase 0 rad
Post-phase 0 rad

Using the Linkers

We can use either of the linkers defined above to replace cross-resonance gates. The first linker gives a single waveform.

[5]:
program = qcs.Program()
some_beta = qcs.Array("beta", value=[np.pi / 2])
program.add_parametric_gate(cr_gate, [some_beta], (qubits[0], qubits[1]))

linker_pass = qcs.LinkerPass(cr_linker)
program_compiled = linker_pass.apply(program)

program_compiled.render(
    channel_subplots=False,
    lo_frequency=5e9,
    sample_rate=qcs.SAMPLE_RATES[qcs.InstrumentEnum.M5300AWG],
)

Reusing the same program to compile, the second linker renders two waveforms on different channels.

[6]:
linker_pass_supp = qcs.LinkerPass(cr_linker_supp)
program_compiled = linker_pass_supp.apply(program)

program_compiled.render(
    channel_subplots=False,
    lo_frequency=5e9,
    sample_rate=qcs.SAMPLE_RATES[qcs.InstrumentEnum.M5300AWG],
)

Download

Download this file as Jupyter notebook: parameterized_linker_native_gates_mq.ipynb.

On this page