Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ef5dc84
* First draft of half angle calibration.
eggerdj Sep 3, 2021
348235c
* inits and docstring.
eggerdj Sep 3, 2021
0be733d
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into half…
eggerdj Sep 30, 2021
6f6cfee
* Added transpile options, reference and more doc.
eggerdj Sep 30, 2021
c8c5371
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into half…
eggerdj Oct 6, 2021
a08b0e7
* First draft of half angle.
eggerdj Oct 6, 2021
d3c600d
* Docs and test
eggerdj Oct 9, 2021
1c78d0a
* removed transpile options (for a future PR).
eggerdj Oct 12, 2021
493ec5a
Merge branch 'main' into half_angle
eggerdj Oct 12, 2021
ab469e7
* fix docs.
eggerdj Oct 12, 2021
d2579e9
* Docstring
eggerdj Oct 14, 2021
79239b4
Update qiskit_experiments/library/characterization/half_angle.py
eggerdj Oct 14, 2021
b185ed6
* Added transpiler options for inst_map
eggerdj Oct 14, 2021
6dffacb
Merge branch 'half_angle' of github.com:eggerdj/qiskit-experiments in…
eggerdj Oct 14, 2021
d63a46e
Merge branch 'main' into half_angle
eggerdj Oct 14, 2021
c6cf2ac
* ParameterRepr
eggerdj Oct 14, 2021
c840ddf
Merge branch 'half_angle' of github.com:eggerdj/qiskit-experiments in…
eggerdj Oct 14, 2021
79bb283
Merge branch 'main' into half_angle
eggerdj Oct 24, 2021
0f38958
* Calibration class
eggerdj Oct 24, 2021
6a894bd
Merge branch 'main' into half_angle
eggerdj Oct 27, 2021
b5c8d36
* Improved doc.
eggerdj Oct 27, 2021
920baf8
* Fixed update rule.
eggerdj Oct 28, 2021
9d3722d
* Update for half angle cal.
eggerdj Oct 28, 2021
5f9b775
* Bug fixes.
eggerdj Oct 28, 2021
1572085
* Black
eggerdj Oct 28, 2021
38c7b04
* Test align to bug fix.
eggerdj Oct 28, 2021
5f654ee
* Lint.
eggerdj Oct 28, 2021
d3a1724
* Added comment on options.
eggerdj Oct 28, 2021
843ec67
Update qiskit_experiments/library/characterization/half_angle.py
eggerdj Oct 28, 2021
c0a7af2
Update qiskit_experiments/library/characterization/half_angle.py
eggerdj Oct 28, 2021
a8bd795
Update qiskit_experiments/library/calibration/half_angle_cal.py
eggerdj Oct 28, 2021
d6c10b0
Merge branch 'main' into half_angle
eggerdj Oct 29, 2021
086d6c1
* Changed init arg order.
eggerdj Oct 29, 2021
009534e
* refactor update rule.
eggerdj Oct 29, 2021
bf3cd3e
* Black
eggerdj Oct 29, 2021
dd12058
Update qiskit_experiments/library/calibration/analysis/fine_half_angl…
eggerdj Nov 1, 2021
ff24a78
Update qiskit_experiments/library/calibration/half_angle_cal.py
eggerdj Nov 1, 2021
4ab1352
Update qiskit_experiments/library/characterization/half_angle.py
eggerdj Nov 1, 2021
dedf7a8
Update qiskit_experiments/library/characterization/half_angle.py
eggerdj Nov 1, 2021
af71a42
Update docs/tutorials/fine_calibrations.ipynb
eggerdj Nov 1, 2021
756251a
* Doc.
eggerdj Nov 1, 2021
7f72917
Merge branch 'half_angle' of github.com:eggerdj/qiskit-experiments in…
eggerdj Nov 1, 2021
fcbe7ea
* Decorators, and decorators.
eggerdj Nov 1, 2021
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
496 changes: 303 additions & 193 deletions docs/tutorials/fine_calibrations.ipynb

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions qiskit_experiments/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
~characterization.EFSpectroscopy
~characterization.CrossResonanceHamiltonian
~characterization.EchoedCrossResonanceHamiltonian
~characterization.HalfAngle
~characterization.FineAmplitude
~characterization.FineXAmplitude
~characterization.FineSXAmplitude
Expand Down Expand Up @@ -114,6 +115,7 @@ class instance to manage parameters and pulse schedules.
EFSpectroscopy,
CrossResonanceHamiltonian,
EchoedCrossResonanceHamiltonian,
HalfAngle,
FineAmplitude,
FineXAmplitude,
FineSXAmplitude,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
"""Calibration Analysis Classes"""

from .drag_analysis import DragCalAnalysis
from .fine_half_angle_analysis import FineHalfAngleAnalysis
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 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 half angle calibration analysis."""

from qiskit_experiments.curve_analysis import ErrorAmplificationAnalysis


class FineHalfAngleAnalysis(ErrorAmplificationAnalysis):
r"""Analysis class for the HalfAngle experiment to define the fixed parameters.

# section: note

The following parameters are held fixed during fitting.

* :math:`{\rm apg}` The angle per gate is set by the user, for example pi for a pi-pulse.
* :math:`{\rm phase\_offset}` The phase offset in the cosine oscillation.
* :math:`{\rm amp}` The amplitude of the oscillation.
"""

__fixed_parameters__ = ["angle_per_gate", "phase_offset", "amp"]
148 changes: 148 additions & 0 deletions qiskit_experiments/library/calibration/half_angle_cal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# 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.

"""Half angle calibration."""

from typing import List, Optional
import numpy as np

from qiskit import QuantumCircuit
from qiskit.providers.backend import Backend

from qiskit_experiments.framework import ExperimentData, fix_class_docs
from qiskit_experiments.calibration_management import (
BaseCalibrationExperiment,
BackendCalibrations,
)
from qiskit_experiments.library.characterization import HalfAngle
from qiskit_experiments.calibration_management.update_library import BaseUpdater


Comment thread
eggerdj marked this conversation as resolved.
@fix_class_docs
class HalfAngleCal(BaseCalibrationExperiment, HalfAngle):
"""Calibration version of the half-angle experiment."""

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

Args:
qubit: The qubit for which to run the half-angle calibration.
calibrations: The calibrations instance with the schedules.
backend: Optional, the backend to run the experiment on.
schedule_name: The name of the schedule to calibrate which defaults to sx.
cal_parameter_name: The name of the parameter in the schedule to update. This will
default to amp since the complex amplitude contains the phase of the pulse.
auto_update: Whether or not to automatically update the calibrations. By
default this variable is set to True.
"""
super().__init__(
calibrations,
qubit,
backend=backend,
schedule_name=schedule_name,
cal_parameter_name=cal_parameter_name,
auto_update=auto_update,
)

self.set_transpile_options(inst_map=calibrations.default_inst_map)

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

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

"""
options = super()._default_experiment_options()

options.result_index = -1
Comment thread
wshanks marked this conversation as resolved.
options.group = "default"
Comment thread
wshanks marked this conversation as resolved.

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 pulse amplitude. This value together with
the fit result will be used to find the new value of the pulse amplitude.
cal_param_name: The name of the parameter in the calibrations.
cal_schedule: The name of the schedule in the calibrations.
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["cal_group"] = self.experiment_options.group

return circuits

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

The parameter that is updated is the phase of the sx pulse. This phase is contained
in the complex amplitude of the pulse. The update rule for the half angle calibration is
therefore:

..math::

A \to A \cdot e^{-i{\rm d}\theta_\text{hac}/2}

where :math:`A` is the complex amplitude of the sx pulse which has an angle which might be
different from the angle of the x pulse due to the non-linearity in the mixer's skew. The
angle :math:`{\rm d}\theta_\text{hac}` is the angle deviation measured through the error
amplifying pulse sequence.

Args:
experiment_data: The experiment data from which to extract the measured over/under
rotation used to adjust the amplitude.
"""

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"]
prev_amp = data[0]["metadata"]["cal_param_value"]

d_theta = BaseUpdater.get_value(experiment_data, "d_hac", result_index)
new_amp = prev_amp * np.exp(-1.0j * d_theta / 2)

BaseUpdater.add_parameter_value(
self._cals,
experiment_data,
new_amp,
self._param_name,
self._sched_name,
group,
)
2 changes: 2 additions & 0 deletions qiskit_experiments/library/characterization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
QubitSpectroscopy
CrossResonanceHamiltonian
EchoedCrossResonanceHamiltonian
HalfAngle
FineAmplitude
FineXAmplitude
FineSXAmplitude
Expand All @@ -54,4 +55,5 @@
from .t2ramsey_analysis import T2RamseyAnalysis
from .cr_hamiltonian import CrossResonanceHamiltonian, EchoedCrossResonanceHamiltonian
from .cr_hamiltonian_analysis import CrossResonanceHamiltonianAnalysis
from .half_angle import HalfAngle
from .fine_amplitude import FineAmplitude, FineXAmplitude, FineSXAmplitude
10 changes: 5 additions & 5 deletions qiskit_experiments/library/characterization/fine_amplitude.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,9 @@ class FineXAmplitude(FineAmplitude):
the appropriate values for the default options.
"""

def __init__(self, qubit: int):
def __init__(self, qubit: int, backend: Optional[Backend] = None):
"""Initialize the experiment."""
super().__init__(qubit, XGate())
super().__init__(qubit, XGate(), backend=backend)

@classmethod
def _default_experiment_options(cls) -> Options:
Expand Down Expand Up @@ -264,9 +264,9 @@ class FineSXAmplitude(FineAmplitude):
the appropriate values for the default options.
"""

def __init__(self, qubit: int):
def __init__(self, qubit: int, backend: Optional[Backend] = None):
"""Initialize the experiment."""
super().__init__(qubit, SXGate())
super().__init__(qubit, SXGate(), backend=backend)

@classmethod
def _default_experiment_options(cls) -> Options:
Expand Down Expand Up @@ -296,6 +296,6 @@ def _default_analysis_options(cls) -> Options:
"""Default analysis options."""
options = super()._default_analysis_options()
options.angle_per_gate = np.pi / 2
options.phase_offset = 0
options.phase_offset = np.pi

return options
144 changes: 144 additions & 0 deletions qiskit_experiments/library/characterization/half_angle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# 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.

"""Half angle characterization."""

from typing import List, Optional
import numpy as np

from qiskit import QuantumCircuit
from qiskit.providers import Backend

from qiskit_experiments.framework import BaseExperiment, Options, fix_class_docs
from qiskit_experiments.library.calibration.analysis import FineHalfAngleAnalysis
from qiskit_experiments.curve_analysis import ParameterRepr


Comment thread
eggerdj marked this conversation as resolved.
@fix_class_docs
class HalfAngle(BaseExperiment):
r"""An experiment class to measure the amount by which sx and x are not parallel.

# section: overview

This experiment runs circuits that repeat blocks of :code:`sx - sx - y` gates
inserted in a Ramsey type experiment, i.e. the full gate sequence is thus
:code:`Ry(π/2) - [sx - sx - y] ^ n - sx` where :code:`n` is varied.

.. parsed-literal::

┌─────────┐┌────┐┌────┐┌───┐ ┌────┐┌────┐┌───┐┌────┐ ░ ┌─┐
q_0: ┤ Ry(π/2) ├┤ sx ├┤ sx ├┤ y ├...┤ sx ├┤ sx ├┤ y ├┤ sx ├─░─┤M├
└─────────┘└────┘└────┘└───┘ └────┘└────┘└───┘└────┘ ░ └╥┘
meas: 1/════════════════════════════...═══════════════════════════╩═
0

This sequence measures angle errors where the axis of the :code:`sx` and :code:`x`
rotation are not parallel. A similar experiment is described in Ref.~[1] where the
gate sequence :code:`x - y` is repeated to amplify errors caused by non-orthogonal
:code:`x` and :code:`y` rotation axes. Such errors can occur due to phase errors.
For example, the non-linearities in the mixer's skew for :math:`\pi/2` pulses may
be different from the :math:`\pi` pulse.

# section: reference
.. ref_arxiv:: 1 1504.06597
"""

__analysis_class__ = FineHalfAngleAnalysis

@classmethod
def _default_experiment_options(cls) -> Options:
r"""Default values for the half angle experiment.

Experiment Options:
repetitions (List[int]): A list of the number of times that the gate
sequence :code:`[sx sx y]` is repeated.
"""
options = super()._default_experiment_options()
Comment thread
nkanazawa1989 marked this conversation as resolved.
options.repetitions = list(range(15))
return options

@classmethod
def _default_transpile_options(cls) -> Options:
"""Default transpile options.

The basis gates option should not be changed since it will affect the gates and
the pulses that are run on the hardware.
"""
options = super()._default_transpile_options()
options.basis_gates = ["sx", "rz", "y"]
Comment thread
eggerdj marked this conversation as resolved.
options.inst_map = None
return options

@classmethod
def _default_analysis_options(cls) -> Options:
r"""Default analysis options.

If the rotation error is very small the fit may chose a d_theta close to
:math:`\pm\pi`. To prevent this we impose bounds on d_theta. Note that the
options angle per gate, phase offset and amp are not intended to be changed.
"""
options = super()._default_analysis_options()
options.result_parameters = [ParameterRepr("d_theta", "d_hac", "rad")]
options.normalization = True
options.angle_per_gate = np.pi
Comment thread
eggerdj marked this conversation as resolved.
options.phase_offset = -np.pi / 2
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are okay with -pi/2. I believe we might have some freedom between -pi/2 or +pi/2: the choice of + or - will change how we handle the rest of the update rule which needs to be consistent. When I ran it yesterday it gave the correct result, see the NB in the PR. In this NB a sx with an angle of 0.0 needed the update A -> A * exp(-1.0j * dhac / 2) giving an angle of -0.242 which is more or less the value of 0.250 reported by the backend.

options.amp = 1.0
options.bounds.update({"d_theta": (-np.pi / 2, np.pi / 2)})

return options

def __init__(self, qubit: int, backend: Optional[Backend] = None):
"""Setup a half angle experiment on the given qubit.

Args:
qubit: The qubit on which to run the fine amplitude calibration experiment.
backend: Optional, the backend to run the experiment on.
"""
super().__init__([qubit], backend=backend)

@staticmethod
def _pre_circuit() -> QuantumCircuit:
"""Return the preparation circuit for the experiment."""
return QuantumCircuit(1)

def circuits(self) -> List[QuantumCircuit]:
"""Create the circuits for the half angle calibration experiment."""

circuits = []

for repetition in self.experiment_options.repetitions:
circuit = self._pre_circuit()

# First ry gate
circuit.rz(np.pi / 2, 0)
circuit.sx(0)
circuit.rz(-np.pi / 2, 0)
Comment thread
eggerdj marked this conversation as resolved.

# Error amplifying sequence
for _ in range(repetition):
circuit.sx(0)
circuit.sx(0)
circuit.y(0)
Comment thread
eggerdj marked this conversation as resolved.

circuit.sx(0)
circuit.measure_all()

circuit.metadata = {
"experiment_type": self._type,
"qubits": self.physical_qubits,
"xval": repetition,
"unit": "repetition number",
}

circuits.append(circuit)

return circuits
Loading