Exemple #1
0
    def add_parameter_value(
        cls,
        cal: Calibrations,
        exp_data: ExperimentData,
        value: ParameterValueType,
        param: Union[Parameter, str],
        schedule: Union[ScheduleBlock, str] = None,
        group: str = "default",
    ):
        """Update the calibrations with the given value.

        Args:
            cal: The Calibrations instance to update.
            exp_data: The ExperimentData instance that contains the result and the experiment data.
            value: The value extracted by the subclasses in the :meth:`update` method.
            param: The name of the parameter, or the parameter instance, which will receive an
                updated value.
            schedule: The ScheduleBlock instance or the name of the instance to which the parameter
                is attached.
            group: The calibrations group to update.
        """

        qubits = exp_data.metadata["physical_qubits"]

        param_value = ParameterValue(
            value=value,
            date_time=cls._time_stamp(exp_data),
            group=group,
            exp_id=exp_data.experiment_id,
        )

        cal.add_parameter_value(param_value, param, qubits, schedule)
    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)
class TestAmplitudeUpdate(QiskitExperimentsTestCase):
    """Test the update functions in the update library."""
    def setUp(self):
        """Setup amplitude values."""
        super().setUp()
        self.cals = Calibrations()
        self.qubit = 1

        axp = Parameter("amp")
        chan = Parameter("ch0")
        with pulse.build(name="xp") as xp:
            pulse.play(pulse.Gaussian(duration=160, amp=axp, sigma=40),
                       pulse.DriveChannel(chan))

        ax90p = Parameter("amp")
        with pulse.build(name="x90p") as x90p:
            pulse.play(pulse.Gaussian(duration=160, amp=ax90p, sigma=40),
                       pulse.DriveChannel(chan))

        self.x90p = x90p

        self.cals.add_schedule(xp, num_qubits=1)
        self.cals.add_schedule(x90p, num_qubits=1)
        self.cals.add_parameter_value(0.2, "amp", self.qubit, "xp")
        self.cals.add_parameter_value(0.1, "amp", self.qubit, "x90p")
    def test_frequency(self):
        """Test calibrations update from spectroscopy."""

        qubit = 1
        peak_offset = 5.0e6
        backend = SpectroscopyBackend(line_width=2e6, freq_offset=peak_offset)
        freq01 = backend.defaults().qubit_freq_est[qubit]
        frequencies = np.linspace(freq01 - 10.0e6, freq01 + 10.0e6, 21)

        spec = QubitSpectroscopy(qubit, frequencies)
        spec.set_run_options(meas_level=MeasLevel.CLASSIFIED)
        exp_data = spec.run(backend)
        self.assertExperimentDone(exp_data)
        result = exp_data.analysis_results(1)
        value = result.value.n

        self.assertTrue(
            freq01 + peak_offset - 2e6 < value < freq01 + peak_offset + 2e6)
        self.assertEqual(result.quality, "good")

        # Test the integration with the Calibrations
        cals = Calibrations.from_backend(FakeAthens())
        self.assertNotEqual(
            cals.get_parameter_value(cals.__drive_freq_parameter__, qubit),
            value)
        Frequency.update(cals, exp_data)
        self.assertEqual(
            cals.get_parameter_value(cals.__drive_freq_parameter__, qubit),
            value)
Exemple #5
0
    def setUp(self):
        """Initialize some cals."""
        super().setUp()

        library = FixedFrequencyTransmon()
        self.cals = Calibrations.from_backend(FakeArmonk(),
                                              libraries=[library])
    def update(
        cls,
        calibrations: Calibrations,
        exp_data: ExperimentData,
        result_index: Optional[int] = -1,
        group: str = "default",
        angles_schedules: List[Tuple[float, str, Union[str,
                                                       ScheduleBlock]]] = None,
        **options,
    ):
        """Update the amplitude of pulses.

        The value of the amplitude must be derived from the fit so the base method cannot be used.

        Args:
            calibrations: The calibrations to update.
            exp_data: The experiment data from which to update.
            result_index: The result index to use which defaults to -1.
            group: The calibrations group to update. Defaults to "default."
            angles_schedules: A list of tuples specifying which angle to update for which
                pulse schedule. Each tuple is of the form: (angle, parameter_name,
                schedule). Here, angle is the rotation angle for which to extract the amplitude,
                parameter_name is the name of the parameter whose value is to be updated, and
                schedule is the schedule or its name that contains the parameter.
            options: Trailing options.

        Raises:
            CalibrationError: If the experiment is not of the supported type.
        """
        from qiskit_experiments.library.calibration.rabi import Rabi

        if angles_schedules is None:
            angles_schedules = [(np.pi, "amp", "xp")]

        if isinstance(exp_data.experiment, Rabi):
            rate = 2 * np.pi * BaseUpdater.get_value(exp_data, "rabi_rate",
                                                     result_index)

            for angle, param, schedule in angles_schedules:
                qubits = exp_data.metadata["physical_qubits"]
                prev_amp = calibrations.get_parameter_value(param,
                                                            qubits,
                                                            schedule,
                                                            group=group)

                value = np.round(angle / rate, decimals=8) * np.exp(
                    1.0j * np.angle(prev_amp))

                cls.add_parameter_value(calibrations, exp_data, value, param,
                                        schedule, group)

        else:
            raise CalibrationError(
                f"{cls.__name__} updates from {type(Rabi.__name__)}.")
    def setUp(self):
        """Setup amplitude values."""
        super().setUp()
        self.cals = Calibrations(coupling_map=[])
        self.qubit = 1

        axp = Parameter("amp")
        chan = Parameter("ch0")
        with pulse.build(name="xp") as xp:
            pulse.play(pulse.Gaussian(duration=160, amp=axp, sigma=40),
                       pulse.DriveChannel(chan))

        ax90p = Parameter("amp")
        with pulse.build(name="x90p") as x90p:
            pulse.play(pulse.Gaussian(duration=160, amp=ax90p, sigma=40),
                       pulse.DriveChannel(chan))

        self.x90p = x90p

        self.cals.add_schedule(xp, num_qubits=1)
        self.cals.add_schedule(x90p, num_qubits=1)
        self.cals.add_parameter_value(0.2, "amp", self.qubit, "xp")
        self.cals.add_parameter_value(0.1, "amp", self.qubit, "x90p")
    def test_frequency(self):
        """Test calibrations update from spectroscopy."""

        qubit = 1
        peak_offset = 5.0e6
        backend = MockIQBackend(
            experiment_helper=SpectroscopyHelper(freq_offset=peak_offset),
            iq_cluster_centers=[((-1.0, -1.0), (1.0, 1.0))],
            iq_cluster_width=[0.2],
        )
        backend._configuration.basis_gates = ["x"]
        backend._configuration.timing_constraints = {"granularity": 16}

        freq01 = backend.defaults().qubit_freq_est[qubit]
        frequencies = np.linspace(freq01 - 10.0e6, freq01 + 10.0e6, 21)

        spec = QubitSpectroscopy(qubit, frequencies)
        spec.set_run_options(meas_level=MeasLevel.CLASSIFIED)
        exp_data = spec.run(backend)
        self.assertExperimentDone(exp_data)
        result = exp_data.analysis_results(1)
        value = result.value.n

        self.assertTrue(
            freq01 + peak_offset - 2e6 < value < freq01 + peak_offset + 2e6)
        self.assertEqual(result.quality, "good")

        # Test the integration with the Calibrations
        cals = Calibrations.from_backend(FakeAthens())
        self.assertNotEqual(
            cals.get_parameter_value(cals.__drive_freq_parameter__, qubit),
            value)
        Frequency.update(cals, exp_data)
        self.assertEqual(
            cals.get_parameter_value(cals.__drive_freq_parameter__, qubit),
            value)
Exemple #9
0
class TestAmplitudeUpdate(QiskitTestCase):
    """Test the update functions in the update library."""
    def setUp(self):
        """Setup amplitude values."""
        super().setUp()
        self.cals = Calibrations()
        self.qubit = 1

        axp = Parameter("amp")
        chan = Parameter("ch0")
        with pulse.build(name="xp") as xp:
            pulse.play(pulse.Gaussian(duration=160, amp=axp, sigma=40),
                       pulse.DriveChannel(chan))

        ax90p = Parameter("amp")
        with pulse.build(name="x90p") as x90p:
            pulse.play(pulse.Gaussian(duration=160, amp=ax90p, sigma=40),
                       pulse.DriveChannel(chan))

        self.x90p = x90p

        self.cals.add_schedule(xp, num_qubits=1)
        self.cals.add_schedule(x90p, num_qubits=1)
        self.cals.add_parameter_value(0.2, "amp", self.qubit, "xp")
        self.cals.add_parameter_value(0.1, "amp", self.qubit, "x90p")

    def test_amplitude(self):
        """Test amplitude update from Rabi."""

        rabi = Rabi(self.qubit)
        rabi.set_experiment_options(amplitudes=np.linspace(-0.95, 0.95, 21))
        exp_data = rabi.run(RabiBackend())
        exp_data.block_for_results()

        with self.assertRaises(CalibrationError):
            self.cals.get_schedule("xp", qubits=0)

        to_update = [(np.pi, "amp", "xp"), (np.pi / 2, "amp", self.x90p)]

        self.assertEqual(len(self.cals.parameters_table()), 2)

        Amplitude.update(self.cals, exp_data, angles_schedules=to_update)

        with self.assertRaises(CalibrationError):
            self.cals.get_schedule("xp", qubits=0)

        self.assertEqual(len(self.cals.parameters_table()["data"]), 4)

        # Now check the corresponding schedules
        result = exp_data.analysis_results(1)
        rate = 2 * np.pi * result.value.value
        amp = np.round(np.pi / rate, decimals=8)
        with pulse.build(name="xp") as expected:
            pulse.play(pulse.Gaussian(160, amp, 40),
                       pulse.DriveChannel(self.qubit))

        self.assertEqual(self.cals.get_schedule("xp", qubits=self.qubit),
                         expected)

        amp = np.round(0.5 * np.pi / rate, decimals=8)
        with pulse.build(name="xp") as expected:
            pulse.play(pulse.Gaussian(160, amp, 40),
                       pulse.DriveChannel(self.qubit))

        self.assertEqual(self.cals.get_schedule("x90p", qubits=self.qubit),
                         expected)
 def __init__(self):
     """A dummy class for parent order testing."""
     super().__init__(Calibrations(coupling_map=[]), 0,
                      [0, 1, 2])