def _t_off_initial_guess(self) -> float:
        """Return initial guess for time offset.

        This method assumes the :py:class:`~qiskit.pulse.library.parametric_pulses.GaussianSquare`
        envelope with the Gaussian rising and falling edges with the parameter ``sigma``.

        This is intended to be overridden by a child class so that rest of the analysis class
        logic can be reused for the fitting that assumes other pulse envelopes.

        Returns:
            An initial guess for time offset parameter ``t_off`` in SI units.

        Raises:
            AnalysisError: When time unit is ``dt`` but the backend doesn't report
                the time resolution of waveforms.
        """
        n_pulses = self._extra_metadata().get("n_cr_pulses", 1)
        sigma = self._experiment_options().get("sigma", 0)
        unit = self._experiment_options().get("unit")

        # Convert sigma unit into SI
        if unit == "dt":
            try:
                prefactor = self._backend.configuration().dt
            except AttributeError as ex:
                raise AnalysisError(
                    "Backend configuration does not provide time resolution."
                ) from ex
        elif unit != "s":
            prefactor = apply_prefix(1.0, unit)
        else:
            prefactor = 1.0

        return np.sqrt(2 * np.pi) * prefactor * sigma * n_pulses
Esempio n. 2
0
    def test_get_same_value_after_attach_detach(self, value: float):
        """Test if same value can be obtained."""
        unit = "Hz"

        for prefix in ["P", "T", "G", "k", "m", "µ", "n", "p", "f"]:
            scaled_val = apply_prefix(value, prefix + unit)
            test_val, ret_prefix = detach_prefix(scaled_val)
            self.assertAlmostEqual(test_val, value)
            self.assertEqual(prefix, ret_prefix)
Esempio n. 3
0
    def circuits(self, backend: Optional[Backend] = None) -> List[QuantumCircuit]:
        """Return a list of experiment circuits.

        Each circuit consists of a Hadamard gate, followed by a fixed delay,
        a phase gate (with a linear phase), and an additional Hadamard gate.

        Args:
            backend: Optional, a backend object

        Returns:
            The experiment circuits

        Raises:
            AttributeError: if unit is 'dt', but 'dt' parameter is missing in the backend configuration.
        """
        conversion_factor = 1
        if self.experiment_options.unit == "dt":
            try:
                dt_factor = getattr(backend._configuration, "dt")
                conversion_factor = dt_factor
            except AttributeError as no_dt:
                raise AttributeError("Dt parameter is missing in backend configuration") from no_dt
        elif self.experiment_options.unit != "s":
            conversion_factor = apply_prefix(1, self.experiment_options.unit)

        circuits = []
        for delay in self.experiment_options.delays:
            circ = qiskit.QuantumCircuit(1, 1)
            circ.h(0)
            circ.delay(delay, 0, self.experiment_options.unit)
            rotation_angle = (
                2 * np.pi * self.experiment_options.osc_freq * conversion_factor * delay
            )
            circ.rz(rotation_angle, 0)
            circ.barrier(0)
            circ.h(0)
            circ.barrier(0)
            circ.measure(0, 0)

            circ.metadata = {
                "experiment_type": self._type,
                "qubit": self.physical_qubits[0],
                "osc_freq": self.experiment_options.osc_freq,
                "xval": delay,
                "unit": self.experiment_options.unit,
            }
            if self.experiment_options.unit == "dt":
                circ.metadata["dt_factor"] = dt_factor

            circuits.append(circ)

        return circuits
    def __init__(
        self,
        qubit: int,
        frequencies: Iterable[float],
        unit: str = "Hz",
        absolute: bool = True,
    ):
        """
        A spectroscopy experiment run by setting the frequency of the qubit drive.
        The parameters of the GaussianSquare spectroscopy pulse can be specified at run-time.
        The spectroscopy pulse has the following parameters:
        - amp: The amplitude of the pulse must be between 0 and 1, the default is 0.1.
        - duration: The duration of the spectroscopy pulse in samples, the default is 1000 samples.
        - sigma: The standard deviation of the pulse, the default is duration / 4.
        - width: The width of the flat-top in the pulse, the default is 0, i.e. a Gaussian.

        Args:
            qubit: The qubit on which to run spectroscopy.
            frequencies: The frequencies to scan in the experiment.
            unit: The unit in which the user specifies the frequencies. Can be one of 'Hz', 'kHz',
                'MHz', 'GHz'. Internally, all frequencies will be converted to 'Hz'.
            absolute: Boolean to specify if the frequencies are absolute or relative to the
                qubit frequency in the backend.

        Raises:
            QiskitError: if there are less than three frequency shifts or if the unit is not known.

        """
        super().__init__([qubit])

        if len(frequencies) < 3:
            raise QiskitError(
                "Spectroscopy requires at least three frequencies.")

        if unit == "Hz":
            self._frequencies = frequencies
        else:
            self._frequencies = [
                apply_prefix(freq, unit) for freq in frequencies
            ]

        self._absolute = absolute

        if not self._absolute:
            self.set_analysis_options(xlabel="Frequency shift")
        else:
            self.set_analysis_options(xlabel="Frequency")

        self.set_analysis_options(ylabel="Signal [arb. unit]")
Esempio n. 5
0
    def test_apply_prefix(self):
        """Test applying prefix to value."""
        ref_values = [
            ([1.0, "THz"], 1e12),
            ([1.0, "GHz"], 1e9),
            ([1.0, "MHz"], 1e6),
            ([1.0, "kHz"], 1e3),
            ([1.0, "mHz"], 1e-3),
            ([1.0, "µHz"], 1e-6),
            ([1.0, "uHz"], 1e-6),
            ([1.0, "nHz"], 1e-9),
            ([1.0, "pHz"], 1e-12),
        ]

        for args, ref_ret in ref_values:
            self.assertEqual(apply_prefix(*args), ref_ret)
    def test_t2ramsey_run_end2end(self):
        """
        Run the T2Ramsey backend on all possible units
        """
        for unit in ["s", "ms", "us", "ns", "dt"]:
            if unit in ("s", "dt"):
                dt_factor = 1
            else:
                dt_factor = apply_prefix(1, unit)
            osc_freq = 0.1 / dt_factor
            estimated_t2ramsey = 20
            estimated_freq = osc_freq * 1.001
            # Set up the circuits
            qubit = 0
            if unit == "dt":  # dt requires integer values for delay
                delays = list(range(1, 46))
            else:
                delays = np.append(
                    (np.linspace(1.0, 15.0, num=15)).astype(float),
                    (np.linspace(16.0, 45.0, num=59)).astype(float),
                )
            exp = T2Ramsey(qubit, delays, unit=unit, osc_freq=osc_freq)
            default_p0 = {
                "A": 0.5,
                "T2star": estimated_t2ramsey,
                "f": estimated_freq,
                "phi": 0,
                "B": 0.5,
            }
            for user_p0 in [default_p0, None]:
                exp.set_analysis_options(user_p0=user_p0, plot=True)
                backend = T2RamseyBackend(
                    p0={
                        "A": [0.5],
                        "T2star": [estimated_t2ramsey],
                        "f": [estimated_freq],
                        "phi": [0.0],
                        "B": [0.5],
                    },
                    initial_prob_plus=[0.0],
                    readout0to1=[0.02],
                    readout1to0=[0.02],
                    conversion_factor=dt_factor,
                )

            expdata = exp.run(backend=backend, shots=2000)
            expdata.block_for_results()  # Wait for job/analysis to finish.
            result = expdata.analysis_results()
            self.assertAlmostEqual(
                result[0].value.value,
                estimated_t2ramsey * dt_factor,
                delta=TestT2Ramsey.__tolerance__ * result[0].value.value,
            )
            self.assertAlmostEqual(
                result[1].value.value,
                estimated_freq,
                delta=TestT2Ramsey.__tolerance__ * result[1].value.value,
            )
            for res in result:
                self.assertEqual(res.quality, "good",
                                 "Result quality bad for unit " + str(unit))
    def circuits(self,
                 backend: Optional[Backend] = None) -> List[QuantumCircuit]:
        """Return a list of experiment circuits.

        Args:
            backend: The target backend.

        Returns:
            A list of :class:`QuantumCircuit`.

        Raises:
            AttributeError: When the backend doesn't report the time resolution of waveforms.
        """
        opt = self.experiment_options
        prefactor = 1.0

        try:
            dt_factor = backend.configuration().dt
        except AttributeError as ex:
            raise AttributeError(
                "Backend configuration does not provide time resolution."
            ) from ex

        if opt.unit != "dt":
            if opt.unit != "s":
                prefactor *= apply_prefix(1.0, opt.unit)
            prefactor /= dt_factor

        # Parametrized duration cannot be used because total duration is computed
        # on the fly with granularity validation. This validation requires
        # duration value that is not a parameter expression.

        # Note that this experiment scans flat top width rather than total duration.
        expr_circs = list()
        for flat_top_width in np.asarray(opt.flat_top_widths, dtype=float):

            # circuit duration is shown in given units (just for visualization)
            cr_gate = circuit.Gate(
                "cr_gate",
                num_qubits=2,
                params=[flat_top_width / self.__n_cr_pulses__],
            )

            for control_state in (0, 1):
                for meas_basis in ("x", "y", "z"):
                    tomo_circ = QuantumCircuit(2, 1)

                    # state prep
                    if control_state:
                        tomo_circ.x(0)

                    # add cross resonance
                    tomo_circ.compose(
                        other=self._build_cr_circuit(cr_gate),
                        qubits=[0, 1],
                        inplace=True,
                    )

                    # measure
                    if meas_basis == "x":
                        tomo_circ.h(1)
                    elif meas_basis == "y":
                        tomo_circ.sdg(1)
                        tomo_circ.h(1)
                    tomo_circ.measure(1, 0)

                    # add metadata
                    tomo_circ.metadata = {
                        "experiment_type": self.experiment_type,
                        "qubits": self.physical_qubits,
                        "xval": prefactor * flat_top_width *
                        dt_factor,  # in units of sec
                        "control_state": control_state,
                        "meas_basis": meas_basis,
                    }

                    # Create schedule and add it to the circuit.
                    # The flat top width and sigma are in units of dt
                    # width is divided by number of tones to keep total duration consistent
                    tomo_circ.add_calibration(
                        gate=cr_gate,
                        qubits=self.physical_qubits,
                        schedule=self._build_cr_schedule(
                            backend=backend,
                            flat_top_width=prefactor * flat_top_width /
                            self.__n_cr_pulses__,
                            sigma=prefactor * opt.sigma,
                        ),
                    )

                    expr_circs.append(tomo_circ)

        return expr_circs
Esempio n. 8
0
    def circuits(self, backend: Optional[Backend] = None) -> List[QuantumCircuit]:
        """Create the circuits for the Ramsey XY calibration experiment.

        Args:
            backend: A backend object.

        Returns:
            A list of circuits with a variable delay.

        Raises:
            AttributeError: if unit is 'dt', but 'dt' the parameter is missing
                from the backend's configuration.
        """

        conversion_factor = 1
        if self.experiment_options.unit == "dt":
            try:
                conversion_factor = getattr(backend.configuration(), "dt")
            except AttributeError as no_dt:
                raise AttributeError(
                    "Dt parameter is missing from the backend's configuration."
                ) from no_dt

        elif self.experiment_options.unit != "s":
            conversion_factor = apply_prefix(1, self.experiment_options.unit)

        # Compute the rz rotation angle to add a modulation.
        p_delay = Parameter("delay")

        rotation_angle = 2 * np.pi * self.experiment_options.osc_freq * conversion_factor * p_delay

        # Create the X and Y circuits.
        metadata = {
            "experiment_type": self._type,
            "qubits": self.physical_qubits,
            "osc_freq": self.experiment_options.osc_freq,
            "unit": "s",
        }

        ram_x = self._pre_circuit()
        ram_x.sx(0)
        ram_x.delay(p_delay, 0, self.experiment_options.unit)
        ram_x.rz(rotation_angle, 0)
        ram_x.sx(0)
        ram_x.measure_active()
        ram_x.metadata = metadata.copy()

        ram_y = self._pre_circuit()
        ram_y.sx(0)
        ram_y.delay(p_delay, 0, self.experiment_options.unit)
        ram_y.rz(rotation_angle - np.pi / 2, 0)
        ram_y.sx(0)
        ram_y.measure_active()
        ram_y.metadata = metadata.copy()

        # Add the schedule if any.
        schedule = self.experiment_options.schedule
        if schedule is not None:
            for circ in [ram_x, ram_y]:
                circ.add_calibration("sx", self.physical_qubits, schedule)

        circs = []
        for delay in self.experiment_options.delays:

            # create ramsey x
            assigned_x = ram_x.assign_parameters({p_delay: delay}, inplace=False)
            assigned_x.metadata["series"] = "X"
            assigned_x.metadata["xval"] = delay * conversion_factor

            # create ramsey y
            assigned_y = ram_y.assign_parameters({p_delay: delay}, inplace=False)
            assigned_y.metadata["series"] = "Y"
            assigned_y.metadata["xval"] = delay * conversion_factor

            circs.extend([assigned_x, assigned_y])

        return circs
    def _run_analysis(
        self,
        experiment_data,
        t1_guess=None,
        amplitude_guess=None,
        offset_guess=None,
        plot=True,
        ax=None,
    ) -> Tuple[List[AnalysisResultData], List["matplotlib.figure.Figure"]]:
        """
        Calculate T1

        Args:
            experiment_data (ExperimentData): the experiment data to analyze
            t1_guess (float): Optional, an initial guess of T1
            amplitude_guess (float): Optional, an initial guess of the coefficient
                                     of the exponent
            offset_guess (float): Optional, an initial guess of the offset
            plot (bool): Generator plot of exponential fit.
            ax (AxesSubplot): Optional, axes to add figure to.

        Returns:
            The analysis result with the estimated T1

        Raises:
            AnalysisError: if the analysis fails.
        """
        data = experiment_data.data()
        unit = data[0]["metadata"]["unit"]
        conversion_factor = data[0]["metadata"].get("dt_factor", None)
        qubit = data[0]["metadata"]["qubit"]

        if conversion_factor is None:
            conversion_factor = 1 if unit == "s" else apply_prefix(1, unit)

        xdata, ydata, sigma = process_curve_data(data, lambda datum: level2_probability(datum, "1"))
        xdata *= conversion_factor

        if t1_guess is None:
            t1_guess = np.mean(xdata)
        else:
            t1_guess = t1_guess * conversion_factor
        if offset_guess is None:
            offset_guess = ydata[-1]
        if amplitude_guess is None:
            amplitude_guess = ydata[0] - offset_guess

        # Perform fit
        def fit_fun(x, a, tau, c):
            return a * np.exp(-x / tau) + c

        init = {"a": amplitude_guess, "tau": t1_guess, "c": offset_guess}
        fit_result = curve_fit(fit_fun, xdata, ydata, init, sigma=sigma)
        fit_result = dataclasses.asdict(fit_result)
        fit_result["circuit_unit"] = unit
        if unit == "dt":
            fit_result["dt"] = conversion_factor

        # Construct analysis result
        name = "T1"
        unit = "s"
        value = FitVal(fit_result["popt"][1], fit_result["popt_err"][1], unit="s")
        chisq = fit_result["reduced_chisq"]
        quality = self._fit_quality(
            fit_result["popt"], fit_result["popt_err"], fit_result["reduced_chisq"]
        )
        analysis_results = [
            AnalysisResultData(
                name,
                value,
                chisq=chisq,
                quality=quality,
                extra=fit_result,
            )
        ]

        # Generate fit plot
        figures = []
        if plot:
            ax = plot_curve_fit(fit_fun, fit_result, ax=ax, fit_uncertainty=True)
            ax = plot_errorbar(xdata, ydata, sigma, ax=ax)
            self._format_plot(ax, fit_result, qubit=qubit)
            figures.append(ax.get_figure())

        return analysis_results, figures
Esempio n. 10
0
    def _run_analysis(
        self,
        experiment_data,
        t1_guess=None,
        amplitude_guess=None,
        offset_guess=None,
        t1_bounds=None,
        amplitude_bounds=None,
        offset_bounds=None,
        **kwargs,
    ) -> Tuple[AnalysisResult, None]:
        """
        Calculate T1

        Args:
            experiment_data (ExperimentData): the experiment data to analyze
            t1_guess (float): Optional, an initial guess of T1
            amplitude_guess (float): Optional, an initial guess of the coefficient of the exponent
            offset_guess (float): Optional, an initial guess of the offset
            t1_bounds (list of two floats): Optional, lower bound and upper bound to T1
            amplitude_bounds (list of two floats): Optional, lower bound and upper bound to the amplitude
            offset_bounds (list of two floats): Optional, lower bound and upper bound to the offset
            kwargs: Trailing unused function parameters

        Returns:
            The analysis result with the estimated T1
        """

        unit = experiment_data._data[0]["metadata"]["unit"]
        conversion_factor = experiment_data._data[0]["metadata"].get("dt_factor", None)
        if conversion_factor is None:
            conversion_factor = 1 if unit == "s" else apply_prefix(1, unit)

        xdata, ydata, sigma = process_curve_data(
            experiment_data._data, lambda datum: level2_probability(datum, "1")
        )
        xdata *= conversion_factor

        if t1_guess is None:
            t1_guess = np.mean(xdata)
        else:
            t1_guess = t1_guess * conversion_factor
        if offset_guess is None:
            offset_guess = ydata[-1]
        if amplitude_guess is None:
            amplitude_guess = ydata[0] - offset_guess
        if t1_bounds is None:
            t1_bounds = [0, np.inf]
        if amplitude_bounds is None:
            amplitude_bounds = [0, 1]
        if offset_bounds is None:
            offset_bounds = [0, 1]

        fit_result = curve_fit(
            lambda x, a, tau, c: a * np.exp(-x / tau) + c,
            xdata,
            ydata,
            [amplitude_guess, t1_guess, offset_guess],
            sigma,
            tuple(
                [amp_bnd, t1_bnd, offset_bnd]
                for amp_bnd, t1_bnd, offset_bnd in zip(amplitude_bounds, t1_bounds, offset_bounds)
            ),
        )

        analysis_result = AnalysisResult(
            {
                "value": fit_result["popt"][1],
                "stderr": fit_result["popt_err"][1],
                "unit": "s",
                "label": "T1",
                "fit": fit_result,
                "quality": self._fit_quality(
                    fit_result["popt"], fit_result["popt_err"], fit_result["reduced_chisq"]
                ),
            }
        )

        analysis_result["fit"]["circuit_unit"] = unit
        if unit == "dt":
            analysis_result["fit"]["dt"] = conversion_factor

        return analysis_result, None
    def _run_analysis(
        self,
        experiment_data: ExperimentData,
        user_p0: Optional[Dict[str, float]] = None,
        user_bounds: Optional[Tuple[List[float], List[float]]] = None,
        plot: bool = False,
        ax: Optional["AxesSubplot"] = None,
        **kwargs,
    ) -> Tuple[List[AnalysisResultData], List["matplotlib.figure.Figure"]]:
        r"""Calculate T2Ramsey experiment.

        Args:
            experiment_data (ExperimentData): the experiment data to analyze
            user_p0: contains initial values given by the user, for the
            fit parameters :math:`(a, t2ramsey, f, \phi, b)`
            user_bounds: lower and upper bounds on the parameters in p0,
                         given by the user.
                         The first tuple is the lower bounds,
                         The second tuple is the upper bounds.
                         For both params, the order is :math:`a, t2ramsey, f, \phi, b`.
            plot: if True, create the plot, otherwise, do not create the plot.
            ax: the plot object
            **kwargs: additional parameters for curve fit.

        Returns:
            The analysis result with the estimated :math:`t2ramsey` and 'f' (frequency)
            The graph of the function.
        """
        def osc_fit_fun(x, a, t2ramsey, f, phi, c):
            """Decay cosine fit function"""
            return a * np.exp(
                -x / t2ramsey) * np.cos(2 * np.pi * f * x + phi) + c

        def _format_plot(ax, unit, fit_result, conversion_factor):
            """Format curve fit plot"""
            # Formatting
            ax.tick_params(labelsize=14)
            ax.set_xlabel("Delay (s)", fontsize=12)
            ax.ticklabel_format(axis="x", style="sci", scilimits=(0, 0))
            ax.set_ylabel("Probability of measuring 0", fontsize=12)
            t2ramsey = fit_result["popt"][1] / conversion_factor
            t2_err = fit_result["popt_err"][1] / conversion_factor
            box_text = "$T_2Ramsey$ = {:.2f} \u00B1 {:.2f} {}".format(
                t2ramsey, t2_err, unit)
            bbox_props = dict(boxstyle="square,pad=0.3",
                              fc="white",
                              ec="black",
                              lw=1)
            ax.text(
                0.6,
                0.9,
                box_text,
                ha="center",
                va="center",
                size=12,
                bbox=bbox_props,
                transform=ax.transAxes,
            )
            return ax

        # implementation of  _run_analysis

        data = experiment_data.data()
        circ_metadata = data[0]["metadata"]
        unit = circ_metadata["unit"]
        conversion_factor = circ_metadata.get("dt_factor", None)
        osc_freq = circ_metadata.get("osc_freq", None)
        if conversion_factor is None:
            conversion_factor = 1 if unit in ("s",
                                              "dt") else apply_prefix(1, unit)

        xdata, ydata, sigma = process_curve_data(
            data, lambda datum: level2_probability(datum, "0"))

        t2ramsey_estimate = np.mean(xdata)
        p0, bounds = self._t2ramsey_default_params(conversion_factor, user_p0,
                                                   user_bounds,
                                                   t2ramsey_estimate, osc_freq)
        xdata *= conversion_factor
        fit_result = curve_fit(osc_fit_fun,
                               xdata,
                               ydata,
                               p0=list(p0.values()),
                               sigma=sigma,
                               bounds=bounds)
        fit_result = dataclasses.asdict(fit_result)
        fit_result["circuit_unit"] = unit
        if osc_freq is not None:
            fit_result["osc_freq"] = osc_freq
        if unit == "dt":
            fit_result["dt"] = conversion_factor
        quality = self._fit_quality(fit_result["popt"], fit_result["popt_err"],
                                    fit_result["reduced_chisq"])
        chisq = fit_result["reduced_chisq"]

        if plot:
            ax = plot_curve_fit(osc_fit_fun, fit_result, ax=ax)
            ax = plot_scatter(xdata, ydata, ax=ax)
            ax = plot_errorbar(xdata, ydata, sigma, ax=ax)
            _format_plot(ax, unit, fit_result, conversion_factor)
            figures = [ax.get_figure()]
        else:
            figures = None

        # Output unit is 'sec', regardless of the unit used in the input
        result_t2star = AnalysisResultData(
            "T2star",
            value=FitVal(fit_result["popt"][1], fit_result["popt_err"][1],
                         "s"),
            quality=quality,
            chisq=chisq,
            extra=fit_result,
        )
        result_freq = AnalysisResultData(
            "Frequency",
            value=FitVal(fit_result["popt"][2], fit_result["popt_err"][2],
                         "Hz"),
            quality=quality,
            chisq=chisq,
            extra=fit_result,
        )

        return [result_t2star, result_freq], figures
Esempio n. 12
0
 def test_not_convert_meter(self):
     """Test not apply prefix to meter."""
     self.assertEqual(apply_prefix(1.0, "m"), 1.0)