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

coupler_chevron improvements #1014

Merged
merged 6 commits into from
Oct 22, 2024
Merged
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
77 changes: 30 additions & 47 deletions src/qibocal/protocols/couplers/coupler_chevron.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
from dataclasses import dataclass
from typing import Optional

import numpy as np
from qibolab import AcquisitionType, AveragingMode, ExecutionParameters
from qibolab.platform import Platform
from qibolab.pulses import PulseSequence
from qibolab.pulses import PulseSequence, PulseType
from qibolab.qubits import QubitPairId
from qibolab.sweeper import Parameter, Sweeper, SweeperType

Expand All @@ -18,25 +15,8 @@
from ..two_qubit_interaction.utils import order_pair


@dataclass
class ChevronCouplersParameters(ChevronParameters):

native_gate: Optional[str] = "CZ"
"""Native gate to implement, CZ or iSWAP."""

"""ChevronCouplers protocol parameters.

Amplitude and duration are referred to the coupler pulse.
"""


@dataclass
class ChevronCouplersData(ChevronData):
"""Data structure for chevron couplers protocol."""


def _aquisition(
params: ChevronCouplersParameters,
def _acquisition(
params: ChevronParameters,
platform: Platform,
targets: list[QubitPairId],
) -> ChevronData:
Expand All @@ -50,7 +30,7 @@ def _aquisition(
targets (list): List of pairs to use sequentially.

Returns:
ChevronCouplersData: Acquisition data.
ChevronData: Acquisition data.
"""
# define the parameter to sweep and its range:
delta_amplitude_range = np.arange(
Expand All @@ -62,29 +42,27 @@ def _aquisition(
params.duration_min, params.duration_max, params.duration_step
)

# create a DataUnits object to store the results,
data = ChevronData()
# sort high and low frequency qubit
for pair in targets:
sequence = PulseSequence()

ordered_pair = order_pair(pair, platform)

# initialize in system in 11(CZ) or 10(iSWAP) state
if params.native_gate == "CZ":
# initialize system to state 11(CZ) or 10(iSWAP)
if params.native == "CZ":
initialize_lowfreq = platform.create_RX_pulse(ordered_pair[0], start=0)
sequence.add(initialize_lowfreq)

initialize_highfreq = platform.create_RX_pulse(ordered_pair[1], start=0)

sequence.add(initialize_highfreq)

if params.native_gate == "CZ":
if params.native == "CZ":
native_gate, _ = platform.create_CZ_pulse_sequence(
(ordered_pair[1], ordered_pair[0]),
start=sequence.finish + params.dt,
)
elif params.native_gate == "iSWAP":
elif params.native == "iSWAP":
native_gate, _ = platform.create_iSWAP_pulse_sequence(
(ordered_pair[1], ordered_pair[0]),
start=sequence.finish + params.dt,
Expand All @@ -103,56 +81,61 @@ def _aquisition(

sequence += ro_pulse1 + ro_pulse2

coupler_flux_pulses = [p for p in native_gate.coupler_pulses(*pair)]
assert (
len(coupler_flux_pulses) == 1
), f"coupler_chevron expects exactly one coupler flux pulse, but {len(coupler_flux_pulses)} are present."
qubit_flux_pulses = [
p for p in native_gate.get_qubit_pulses(*pair) if p.type is PulseType.FLUX
]
assert all(
len(list(filter(lambda x: x.qubit == q, qubit_flux_pulses))) < 2
for q in pair
), f"coupler_chevron expects no more than 1 flux pulse for each qubit, but more are present for the pair {pair}"
sweeper_amplitude = Sweeper(
Parameter.amplitude,
delta_amplitude_range,
pulses=[p for p in native_gate.coupler_pulses(*pair)][:1],
pulses=coupler_flux_pulses,
type=SweeperType.FACTOR,
)
sweeper_duration = Sweeper(
Parameter.duration,
delta_duration_range,
pulses=[p for p in native_gate.coupler_pulses(*pair)],
pulses=coupler_flux_pulses + qubit_flux_pulses,
)

# repeat the experiment as many times as defined by nshots
results = platform.sweep(
sequence,
ExecutionParameters(
nshots=params.nshots,
acquisition_type=AcquisitionType.INTEGRATION,
acquisition_type=AcquisitionType.DISCRIMINATION,
averaging_mode=AveragingMode.CYCLIC,
),
sweeper_duration,
sweeper_amplitude,
)

# TODO: Explore probabilities instead of magnitude
data.register_qubit(
ordered_pair[0],
ordered_pair[1],
delta_duration_range,
delta_amplitude_range * data.native_amplitude[ordered_pair],
results[ordered_pair[0]].magnitude,
results[ordered_pair[1]].magnitude,
results[ordered_pair[0]].probability(state=1),
results[ordered_pair[1]].probability(state=1),
)
data.label = "Probability of state |1>"

return data


@dataclass
class ChevronCouplersResults(Results):
"""Empty fitting outputs for chevron couplers is not implemented in this case."""


def _fit(data: ChevronCouplersData) -> ChevronCouplersResults:
""" "Results for ChevronCouplers."""
return ChevronCouplersResults()
def _fit(data: ChevronData) -> Results:
"""Results for ChevronCouplers."""
return Results()


def plot(data: ChevronCouplersData, fit: ChevronCouplersResults, target):
def plot(data: ChevronData, fit: Results, target):
return _plot(data, None, target)


coupler_chevron = Routine(_aquisition, _fit, plot, two_qubit_gates=True)
coupler_chevron = Routine(_acquisition, _fit, plot, two_qubit_gates=True)
"""Coupler cz/swap flux routine."""
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ class ChevronData(Data):
"""Sweetspot value for high frequency qubit."""
data: dict[QubitPairId, npt.NDArray[ChevronType]] = field(default_factory=dict)

label: Optional[str] = None
"""Label for the data."""

def register_qubit(self, low_qubit, high_qubit, length, amp, prob_low, prob_high):
"""Store output for single qubit."""
size = len(length) * len(amp)
Expand Down Expand Up @@ -308,7 +311,7 @@ def _plot(data: ChevronData, fit: ChevronResults, target: QubitPairId):
fig.update_layout(
xaxis_title="Duration [ns]",
xaxis2_title="Duration [ns]",
yaxis_title="Amplitude [a.u.]",
yaxis_title=data.label or "Amplitude [a.u.]",
legend=dict(orientation="h"),
)
fig.update_layout(
Expand Down
4 changes: 2 additions & 2 deletions tests/runcards/protocols_couplers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ actions:
duration_min: 50
duration_max: 100
duration_step: 10
native_gate: "CZ"
native: "CZ"
dt: 5
nshots: 10

Expand All @@ -81,6 +81,6 @@ actions:
duration_min: 50
duration_max: 100
duration_step: 10
native_gate: "iSWAP"
native: "iSWAP"
dt: 5
nshots: 10