Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates in Cross Resonance calibration routines #987

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/qibocal/protocols/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
chsh_pulses,
cross_resonance,
cross_resonance_chevron,
cross_resonance_sequences,
cross_resonance_chevron_frequency,
cz_virtualz,
cz_virtualz_signal,
)
Expand Down Expand Up @@ -136,4 +138,6 @@ class Operation(Enum):
calibrate_state_discrimination = calibrate_state_discrimination
cross_resonance = cross_resonance
cross_resonance_chevron = cross_resonance_chevron
cross_resonance_chevron_frequency = cross_resonance_chevron_frequency
cross_resonance_sequences = cross_resonance_sequences
state_tomography = state_tomography
2 changes: 1 addition & 1 deletion src/qibocal/protocols/two_qubit_interaction/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .chevron import chevron, chevron_signal
from .chsh import chsh_circuits, chsh_pulses
from .cross_resonance import cross_resonance, cross_resonance_chevron
from .cross_resonance import cross_resonance, cross_resonance_chevron, cross_resonance_sequences, cross_resonance_chevron_frequency
from .cz_virtualz import cz_virtualz
from .cz_virtualz_signal import cz_virtualz_signal
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ def _plot(data: ChevronData, fit: ChevronResults, target: QubitPairId):
rows=1,
cols=2,
subplot_titles=(
f"Qubit {target[0]} - Low Frequency",
f"Qubit {target[0]} - Target",
f"Qubit {target[1]} - High Frequency",
),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from .chevron import cross_resonance_chevron
from .cross_resonance import cross_resonance
from .cross_resonance_sequences import cross_resonance_sequences
from .chevron_frequency import cross_resonance_chevron_frequency
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
("amp", np.float64),
]
)
"""Custom dtype for resonator spectroscopy."""
"""Custom dtype for cross resonance chevron."""

STATES = ["I", "X"]

@dataclass
class CrossResonanceChevronParameters(Parameters):
"""ResonatorSpectroscopy runcard inputs."""
"""cross resonance chevron runcard inputs."""

pulse_duration_start: float
"""Initial pi pulse duration [ns]."""
Expand Down Expand Up @@ -59,12 +60,12 @@ def amplitude_factor_range(self):

@dataclass
class CrossResonanceChevronResults(Results):
"""ResonatorSpectroscopy outputs."""
"""cross resonance chevron outputs."""


@dataclass
class CrossResonanceChevronData(Data):
"""Data structure for resonator spectroscopy with attenuation."""
"""Data structure for cross resonance chevron."""

data: dict[QubitId, npt.NDArray[CrossResonanceChevronType]] = field(
default_factory=dict
Expand All @@ -87,24 +88,24 @@ def _acquisition(
platform: Platform,
targets: list[QubitPairId],
) -> CrossResonanceChevronData:
"""Data acquisition for resonator spectroscopy."""
"""Data acquisition for cross resonance chevron."""

data = CrossResonanceChevronData()

for pair in targets:
for setup in ["I", "X"]:
for setup in STATES:
target, control = pair
sequence = PulseSequence()
control_drive_freq = platform.qubits[control].native_gates.RX.frequency
target_drive_freq = platform.qubits[target].native_gates.RX.frequency

if setup == "X":
if setup == STATES[1]:
rx_control = platform.create_RX_pulse(control, 0)
pulse = platform.create_RX_pulse(target, rx_control.finish)
pulse = platform.create_RX_pulse(control, rx_control.finish)
sequence.add(rx_control)
else:
pulse = platform.create_RX_pulse(target, 0)
pulse = platform.create_RX_pulse(control, 0)

pulse.frequency = control_drive_freq
pulse.frequency = target_drive_freq
if params.pulse_amplitude is not None:
pulse.amplitude = params.pulse_amplitude
sequence.add(pulse)
Expand Down Expand Up @@ -163,41 +164,36 @@ def _plot(
target: QubitPairId,
fit: CrossResonanceChevronResults,
):
"""Plotting function for ResonatorSpectroscopy."""
# TODO: share colorbar
control_idle_data = data.data[target[0], target[1], "I"]
control_excited_data = data.data[target[0], target[1], "X"]
pair = target
figs = []

"""Plotting function for Cross Resonance Chevron ."""
fig = make_subplots(
rows=1,
cols=2,
subplot_titles=(
f"Qubit {target[1]} - |0>",
f"Qubit {target[1]} - |1>",
),
)
fig.add_trace(
go.Heatmap(
x=control_idle_data.length,
y=control_idle_data.amp,
z=control_idle_data.prob,
name="Control at 0",
f"Control Q{pair[1]} = |{STATES[0]}>",
f"Control Q{pair[1]} = |{STATES[1]}>",
),
row=1,
col=1,
)

fig.add_trace(
go.Heatmap(
x=control_excited_data.length,
y=control_excited_data.amp,
z=control_excited_data.prob,
name="Control at 1",
),
row=1,
col=2,
)

return [fig], ""
for i, setup in enumerate(STATES):
qubit_data = data.data[target[0], target[1], setup]
fig.add_trace(
go.Heatmap(
x=qubit_data.length,
y=qubit_data.amp,
z=qubit_data.prob,
name=f"Control at {setup}",
coloraxis="coloraxis"
),
row=1,
col=i+1,
)
fig.update_layout(coloraxis={'colorscale':'Plasma'})

figs.append(fig)
return figs, ""


cross_resonance_chevron = Routine(_acquisition, _fit, _plot)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
from dataclasses import dataclass, field
from typing import Optional

import numpy as np
import numpy.typing as npt
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from qibolab import AcquisitionType, AveragingMode, ExecutionParameters
from qibolab.platform import Platform
from qibolab.pulses import PulseSequence
from qibolab.qubits import QubitId, QubitPairId
from qibolab.sweeper import Parameter, Sweeper, SweeperType
from qibocal.protocols.utils import HZ_TO_GHZ
from qibocal.auto.operation import Data, Parameters, Results, Routine

CrossResonanceChevronFrequencyType = np.dtype(
[
("length", np.float64),
("freq", np.int64),
("prob", np.float64),
]
)
"""Custom dtype for resonator spectroscopy."""


@dataclass
class CrossResonanceChevronFrequencyParameters(Parameters):
"""ResonatorSpectroscopy runcard inputs."""

pulse_duration_start: float
"""Initial pi pulse duration [ns]."""
pulse_duration_end: float
"""Final pi pulse duration [ns]."""
pulse_duration_step: float
"""Step pi pulse duration [ns]."""
freq_width: int
"""Frequency range."""
freq_step: int
"""Frequency step size."""

pulse_amplitude: Optional[float] = None

@property
def duration_range(self):
return np.arange(
self.pulse_duration_start, self.pulse_duration_end, self.pulse_duration_step
)

@property
def frequency_range(self):
return np.arange(
-self.freq_width/2,
self.freq_width/2,
self.freq_step,
)
STATES = [0, 1]

@dataclass
class CrossResonanceChevronFrequencyResults(Results):
"""Chevron wih Frequency Cross Resonance Calibration outputs."""


@dataclass
class CrossResonanceChevronFrequencyData(Data):
"""Data structure for Chevron wih Frequency."""

data: dict[QubitId, npt.NDArray[CrossResonanceChevronFrequencyType]] = field(
default_factory=dict
)
"""Raw data acquired."""

def register_qubit(self, dtype, key, prob, freq, length):
"""Store output for single qubit."""
size = len(freq) * len(length)
frequency, duration = np.meshgrid(freq, length)
ar = np.empty(size, dtype=dtype)
ar["freq"] = frequency.ravel()
ar["length"] = duration.ravel()
ar["prob"] = prob.ravel()
self.data[key] = np.rec.array(ar)


def _acquisition(
params: CrossResonanceChevronFrequencyParameters,
platform: Platform,
targets: list[QubitPairId],
) -> CrossResonanceChevronFrequencyData:
"""Data acquisition for Chevron wih Frequency."""

data = CrossResonanceChevronFrequencyData()
for pair in targets:
target, control = pair
for setup in STATES:
sequence = PulseSequence()
target_drive_freq = platform.qubits[target].native_gates.RX.frequency

# add a RX control pulse if the setup is |1>
if setup == STATES[1]:
rx_control = platform.create_RX_pulse(control, 0)
pulse = platform.create_RX_pulse(control, rx_control.finish)
sequence.add(rx_control)
else:
pulse = platform.create_RX_pulse(control, 0)

pulse.frequency = target_drive_freq
if params.pulse_amplitude is not None:
pulse.amplitude = params.pulse_amplitude
sequence.add(pulse)

# add readout pulses
for qubit in pair:
sequence.add(platform.create_qubit_readout_pulse(qubit, start=pulse.finish))

# create a duration sweeper for the pulse duration
sweeper_duration = Sweeper(
Parameter.duration,
params.duration_range,
pulses=[pulse],
type=SweeperType.ABSOLUTE,
)

# create a frequency sweeper for the pulse frequency
sweeper_frequency = Sweeper(
Parameter.frequency,
params.frequency_range,
pulses=[pulse],
type=SweeperType.OFFSET,
)

# run the sweep
results = platform.sweep(
sequence,
ExecutionParameters(
nshots=params.nshots,
relaxation_time=params.relaxation_time,
acquisition_type=AcquisitionType.DISCRIMINATION,
averaging_mode=AveragingMode.SINGLESHOT,
),
sweeper_duration,
sweeper_frequency,
)

# store the results for each qubit in the pair in the data object
# NOTE: Change this to use standard qibocal>auto>operation>Data>register_qubit
for qubit in pair:
data.register_qubit(
dtype=CrossResonanceChevronFrequencyType,
key=(qubit, target, control, setup),
prob=results[qubit].probability(state=1),
length=params.duration_range,
freq=pulse.frequency + params.frequency_range,
)

# return the data
return data


def _fit(
data:CrossResonanceChevronFrequencyData,
) -> CrossResonanceChevronFrequencyResults:
"""Post-processing function for Chevron wih Frequency."""
return CrossResonanceChevronFrequencyResults()


def _plot(
data: CrossResonanceChevronFrequencyData,
target: QubitPairId,
fit: CrossResonanceChevronFrequencyResults,
):
pair = target
"""Plotting function for Chevron wih Frequency and Duration."""
figs = []
for qubit in pair:
fig = make_subplots(
rows=1,
cols=2,
subplot_titles=(
f"Q{qubit} , Control |{STATES[0]}>",
f"Q{qubit} , Control |{STATES[1]}>",
),
)
for i, setup in enumerate(STATES):
qubit_data = data.data[qubit, pair[0], pair[1], setup]
fig.add_trace(
go.Heatmap(
x=qubit_data.length,
y=qubit_data.freq * HZ_TO_GHZ,
z=qubit_data.prob,
name=f"Control at |{setup}>",
coloraxis="coloraxis"
),
row=1,
col=i+1,
)
fig.update_xaxes(title_text="Pulse Duration [ns]", row=1, col=i+1)
fig.update_yaxes(title_text="Frequency [GHz]", row=1, col=i+1)
fig.update_layout(coloraxis={'colorscale':'Plasma'})
figs.append(fig)


return figs, ""

cross_resonance_chevron_frequency = Routine(_acquisition, _fit, _plot)
"""CrossResonanceChevronFrequency Routine object."""
Loading