Skip to content
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
4 changes: 1 addition & 3 deletions qiskit_experiments/calibration_management/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@

BackendCalibrations
Calibrations
Frequency

Managing Calibration Data
=========================
Expand Down Expand Up @@ -147,5 +146,4 @@
from .calibrations import Calibrations
from .backend_calibrations import BackendCalibrations
from .base_calibration_experiment import BaseCalibrationExperiment

from .update_library import Frequency, FineDragUpdater
from .basis_gate_library import FixedFrequencyTransmon
60 changes: 1 addition & 59 deletions qiskit_experiments/calibration_management/update_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
from abc import ABC
from datetime import datetime, timezone
from typing import Optional, Union
import numpy as np

from qiskit.circuit import Parameter
from qiskit.pulse import ScheduleBlock, Play
from qiskit.pulse import ScheduleBlock

from qiskit_experiments.framework.experiment_data import ExperimentData
from qiskit_experiments.calibration_management.backend_calibrations import BackendCalibrations
Expand Down Expand Up @@ -182,60 +181,3 @@ def update(
group=group,
fit_parameter=fit_parameter,
)


class FineDragUpdater(BaseUpdater):
"""Updater for the fine drag calibration."""

# pylint: disable=arguments-differ,unused-argument
@classmethod
def update(
cls,
calibrations: Calibrations,
exp_data: ExperimentData,
parameter: str,
schedule: Union[ScheduleBlock, str],
result_index: Optional[int] = -1,
group: str = "default",
target_angle: float = np.pi,
**options,
):
"""Update the value of a drag parameter measured by the FineDrag experiment.
Args:
calibrations: The calibrations to update.
exp_data: The experiment data from which to update.
parameter: The name of the parameter in the calibrations to update.
schedule: The ScheduleBlock instance or the name of the instance to which the parameter
is attached.
result_index: The result index to use. By default search entry by name.
group: The calibrations group to update. Defaults to "default."
target_angle: The target rotation angle of the pulse.
options: Trailing options.
Raises:
CalibrationError: If we cannot get the pulse's standard deviation from the schedule.
"""
qubits = exp_data.metadata["physical_qubits"]

if isinstance(schedule, str):
schedule = calibrations.get_schedule(schedule, qubits)

# Obtain sigma as it is needed for the fine DRAG update rule.
sigma = None
for block in schedule.blocks:
if isinstance(block, Play) and hasattr(block.pulse, "sigma"):
sigma = getattr(block.pulse, "sigma")

if sigma is None:
raise CalibrationError(f"Could not infer sigma from {schedule}.")

d_theta = BaseUpdater.get_value(exp_data, "d_theta", result_index)

# See the documentation in fine_drag.py for the derivation of this rule.
d_beta = -np.sqrt(np.pi) * d_theta * sigma / target_angle ** 2

old_beta = calibrations.get_parameter_value(parameter, qubits, schedule, group=group)
new_beta = old_beta + d_beta

cls.add_parameter_value(calibrations, exp_data, new_beta, parameter, schedule, group)
18 changes: 12 additions & 6 deletions qiskit_experiments/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
~characterization.CrossResonanceHamiltonian
~characterization.EchoedCrossResonanceHamiltonian
~characterization.RoughDrag
~characterization.FineDrag
~characterization.FineXDrag
~characterization.FineSXDrag
~characterization.HalfAngle
~characterization.FineAmplitude
~characterization.FineXAmplitude
Expand All @@ -89,9 +92,9 @@ class instance to manage parameters and pulse schedules.

~calibration.RoughFrequencyCal
~calibration.RoughDragCal
~calibration.FineDrag
~calibration.FineXDrag
~calibration.FineSXDrag
~calibration.FineXDragCal
~calibration.FineSXDragCal
~calibration.FineDragCal
~calibration.FineAmplitudeCal
~calibration.FineXAmplitudeCal
~calibration.FineSXAmplitudeCal
Expand All @@ -102,9 +105,9 @@ class instance to manage parameters and pulse schedules.
"""
from .calibration import (
RoughDragCal,
FineDrag,
FineXDrag,
FineSXDrag,
FineDragCal,
FineXDragCal,
FineSXDragCal,
RoughAmplitudeCal,
RoughXSXAmplitudeCal,
EFRoughXSXAmplitudeCal,
Expand All @@ -122,6 +125,9 @@ class instance to manage parameters and pulse schedules.
CrossResonanceHamiltonian,
EchoedCrossResonanceHamiltonian,
RoughDrag,
FineDrag,
FineXDrag,
FineSXDrag,
Rabi,
EFRabi,
HalfAngle,
Expand Down
8 changes: 4 additions & 4 deletions qiskit_experiments/library/calibration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
RoughFrequencyCal
FrequencyCal
RoughDragCal
FineDrag
FineXDrag
FineSXDrag
FineDragCal
FineXDragCal
FineSXDragCal
FineAmplitudeCal
FineXAmplitudeCal
FineSXAmplitudeCal
Expand All @@ -71,9 +71,9 @@

from .rough_frequency import RoughFrequencyCal
from .rough_drag_cal import RoughDragCal
from .fine_drag import FineDrag, FineXDrag, FineSXDrag
from .rough_amplitude_cal import RoughAmplitudeCal, RoughXSXAmplitudeCal, EFRoughXSXAmplitudeCal
from .fine_amplitude import FineAmplitudeCal, FineXAmplitudeCal, FineSXAmplitudeCal
from .fine_drag_cal import FineDragCal, FineXDragCal, FineSXDragCal
from .frequency_cal import FrequencyCal

from .analysis.drag_analysis import DragCalAnalysis
Expand Down
6 changes: 1 addition & 5 deletions qiskit_experiments/library/calibration/fine_amplitude.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,14 @@ def __init__(
auto_update=auto_update,
)

self.transpile_options.inst_map = calibrations.default_inst_map
self.set_transpile_options(inst_map=calibrations.default_inst_map)

@classmethod
def _default_experiment_options(cls):
"""Default values for the fine amplitude calibration experiment.

Experiment Options:
result_index (int): The index of the result from which to update the calibrations.
target_angle (float): The target angle of the pulse.
group (str): The calibration group to which the parameter belongs. This will default
to the value "default".

"""
options = super()._default_experiment_options()
options.target_angle = np.pi
Expand Down
221 changes: 221 additions & 0 deletions qiskit_experiments/library/calibration/fine_drag_cal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2021.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Fine drag calibration experiment."""

from typing import List, Optional
import numpy as np

from qiskit.circuit import Gate, QuantumCircuit
from qiskit.providers.backend import Backend
from qiskit.pulse import Play

from qiskit_experiments.exceptions import CalibrationError
from qiskit_experiments.framework import ExperimentData, fix_class_docs, Options
from qiskit_experiments.calibration_management import (
BaseCalibrationExperiment,
BackendCalibrations,
)
from qiskit_experiments.calibration_management.update_library import BaseUpdater
from qiskit_experiments.library.characterization.fine_drag import FineDrag


@fix_class_docs
class FineDragCal(BaseCalibrationExperiment, FineDrag):
"""A calibration version of the fine drag experiment."""

def __init__(
self,
qubit: int,
calibrations: BackendCalibrations,
schedule_name: str,
backend: Optional[Backend] = None,
cal_parameter_name: Optional[str] = "β",
auto_update: bool = True,
):
r"""see class :class:`FineDrag` for details.

Note that this class implicitly assumes that the target angle of the gate
is :math:`\pi` as seen from the default experiment options.

Args:
qubit: The qubit for which to run the fine drag calibration.
calibrations: The calibrations instance with the schedules.
schedule_name: The name of the schedule to calibrate.
backend: Optional, the backend to run the experiment on.
cal_parameter_name: The name of the parameter in the schedule to update.
auto_update: Whether or not to automatically update the calibrations. By
default this variable is set to True.
"""
super().__init__(
calibrations,
qubit,
Gate(name=schedule_name, num_qubits=1, params=[]),
schedule_name=schedule_name,
backend=backend,
cal_parameter_name=cal_parameter_name,
auto_update=auto_update,
)

self.set_transpile_options(
inst_map=calibrations.default_inst_map,
basis_gates=["sx", schedule_name, "rz"],
)

@classmethod
def _default_experiment_options(cls) -> Options:
"""Default experiment options.

Experiment Options:
target_angle (float): The target rotation angle of the gate being calibrated.
This value is needed for the update rule.
"""
options = super()._default_experiment_options()
options.target_angle = np.pi
return options

def _add_cal_metadata(self, circuits: List[QuantumCircuit]):
"""Add metadata to the circuit to make the experiment data more self contained.

The following keys are added to each circuit's metadata:
cal_param_value: The value of the drag parameter. This value together with
the fit result will be used to find the new value of the drag parameter.
cal_param_name: The name of the parameter in the calibrations.
cal_schedule: The name of the schedule in the calibrations.
target_angle: The target angle of the gate.
cal_group: The calibration group to which the parameter belongs.
"""

param_val = self._cals.get_parameter_value(
self._param_name,
self.physical_qubits,
self._sched_name,
group=self.experiment_options.group,
)

for circuit in circuits:
circuit.metadata["cal_param_value"] = param_val
circuit.metadata["cal_param_name"] = self._param_name
circuit.metadata["cal_schedule"] = self._sched_name
circuit.metadata["target_angle"] = self.experiment_options.target_angle
circuit.metadata["cal_group"] = self.experiment_options.group

def update_calibrations(self, experiment_data: ExperimentData):
"""Update the drag parameter of the pulse in the calibrations."""

data = experiment_data.data()

# No data -> no update
if len(data) > 0:

result_index = self.experiment_options.result_index
group = data[0]["metadata"]["cal_group"]
target_angle = data[0]["metadata"]["target_angle"]
qubits = experiment_data.metadata["physical_qubits"]

schedule = self._cals.get_schedule(self._sched_name, qubits)

# Obtain sigma as it is needed for the fine DRAG update rule.
sigmas = []
for block in schedule.blocks:
if isinstance(block, Play) and hasattr(block.pulse, "sigma"):
sigmas.append(getattr(block.pulse, "sigma"))

if len(set(sigmas)) != 1:
raise CalibrationError(
"Cannot run fine Drag calibration on a schedule with multiple values of sigma."
)

if len(sigmas) == 0:
raise CalibrationError(f"Could not infer sigma from {schedule}.")

d_theta = BaseUpdater.get_value(experiment_data, "d_theta", result_index)

# See the documentation in fine_drag.py for the derivation of this rule.
d_beta = -np.sqrt(np.pi) * d_theta * sigmas[0] / target_angle ** 2
old_beta = data[0]["metadata"]["cal_param_value"]
new_beta = old_beta + d_beta

BaseUpdater.add_parameter_value(
self._cals, experiment_data, new_beta, self._param_name, schedule, group
)


@fix_class_docs
class FineXDragCal(FineDragCal):
"""Fine drag calibration of X gate."""

def __init__(
self,
qubit: int,
calibrations: BackendCalibrations,
backend: Optional[Backend] = None,
cal_parameter_name: Optional[str] = "β",
auto_update: bool = True,
):
r"""see class :class:`FineDrag` for details.

Args:
qubit: The qubit for which to run the fine drag calibration.
calibrations: The calibrations instance with the schedules.
backend: Optional, the backend to run the experiment on.
cal_parameter_name: The name of the parameter in the schedule to update.
auto_update: Whether or not to automatically update the calibrations. By
default this variable is set to True.
"""
super().__init__(
qubit,
calibrations,
schedule_name="x",
backend=backend,
cal_parameter_name=cal_parameter_name,
auto_update=auto_update,
)


@fix_class_docs
class FineSXDragCal(FineDragCal):
"""Fine drag calibration of X gate."""

def __init__(
self,
qubit: int,
calibrations: BackendCalibrations,
backend: Optional[Backend] = None,
cal_parameter_name: Optional[str] = "β",
auto_update: bool = True,
):
r"""see class :class:`FineDrag` for details.

Args:
qubit: The qubit for which to run the fine drag calibration.
calibrations: The calibrations instance with the schedules.
backend: Optional, the backend to run the experiment on.
cal_parameter_name: The name of the parameter in the schedule to update.
auto_update: Whether or not to automatically update the calibrations. By
default this variable is set to True.
"""
super().__init__(
qubit,
calibrations,
schedule_name="sx",
backend=backend,
cal_parameter_name=cal_parameter_name,
auto_update=auto_update,
)

@classmethod
def _default_experiment_options(cls) -> Options:
"""Default experiment options."""
options = super()._default_experiment_options()
options.target_angle = np.pi / 2
return options
Loading