Skip to content

Commit

Permalink
Fix T2Star experiment
Browse files Browse the repository at this point in the history
  • Loading branch information
chriseclectic committed May 26, 2021
1 parent a89fd47 commit c5479e3
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 68 deletions.
4 changes: 3 additions & 1 deletion qiskit_experiments/characterization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
:toctree: ../stubs/
T1Experiment
T2StarExperiment
Analysis
Expand All @@ -32,6 +33,7 @@
:toctree: ../stubs/
T1Analysis
T2StarAnalysis
"""
from .t1_experiment import T1Experiment, T1Analysis
from .t2star_experiment import T2StarExperiment
from .t2star_experiment import T2StarExperiment, T2StarAnalysis
106 changes: 51 additions & 55 deletions qiskit_experiments/characterization/t2star_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
import numpy as np

import qiskit
from qiskit.providers import Backend
from qiskit.circuit import QuantumCircuit
from qiskit.utils import apply_prefix
from qiskit.providers.options import Options
from qiskit_experiments.base_experiment import BaseExperiment
from qiskit_experiments.base_analysis import BaseAnalysis, AnalysisResult
from qiskit_experiments.analysis.curve_fitting import curve_fit, process_curve_data
Expand All @@ -30,49 +32,46 @@
class T2StarAnalysis(BaseAnalysis):
"""T2Star Experiment result analysis class."""

def __init__(
self,
):
self._conversion_factor = None
@classmethod
def _default_options(cls):
return Options(user_p0=None, user_bounds=None)

# pylint: disable=arguments-differ, unused-argument
def _run_analysis(
self,
experiment_data: ExperimentData,
user_p0: Dict[str, float],
user_bounds: Tuple[List[float], List[float]],
user_p0: Optional[Dict[str, float]] = None,
user_bounds: Optional[Tuple[List[float], List[float]]] = None,
plot: bool = True,
ax: Optional["AxesSubplot"] = None,
**kwargs,
) -> Tuple[AnalysisResult, List["matplotlib.figure.Figure"]]:
r"""
Calculate T2Star experiment
The probability of measuring `+` is assumed to be of the form
.. math::
f(t) = a\mathrm{e}^{-t / T_2^*}\cos(2\pi freq t + \phi) + b
r"""Calculate T2Star experiment.
The probability of measuring `+` is assumed to be of the form
:math:`f(t) = a\mathrm{e}^{-t / T_2^*}\cos(2\pi freq t + \phi) + b`
for unknown parameters :math:`a, b, freq, \phi, T_2^*`.
Args:
experiment_data (ExperimentData): the experiment data to analyze
user_p0: contains initial values given by the user, for the
fit parameters :math:`(a, T_2^*, freq, \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, T_2^*, freq, \phi, b`.
plot: if True, create the plot, otherwise, do not create the plot.
ax: the plot object
**kwargs: additional parameters
Returns:
The analysis result with the estimated :math:`T_2^*` and 'freq' (frequency)
The graph of the function.
Args:
experiment_data (ExperimentData): the experiment data to analyze
user_p0: contains initial values given by the user, for the
fit parameters :math:`(a, T_2^*, freq, \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, T_2^*, freq, \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:`T_2^*` and 'freq' (frequency)
The graph of the function.
"""

def osc_fit_fun(x, a, t2star, freq, phi, c):
"""
Decay cosine fit function
"""
"""Decay cosine fit function"""
return a * np.exp(-x / t2star) * np.cos(2 * np.pi * freq * x + phi) + c

def _format_plot(ax, unit):
Expand All @@ -84,17 +83,19 @@ def _format_plot(ax, unit):

# implementation of _run_analysis
unit = experiment_data._data[0]["metadata"]["unit"]
self._conversion_factor = experiment_data._data[0]["metadata"].get("dt_factor", None)
if self._conversion_factor is None:
self._conversion_factor = 1 if unit == "s" else apply_prefix(1, 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, "0")
)

si_xdata = xdata * self._conversion_factor
si_xdata = xdata * conversion_factor
t2star_estimate = np.mean(si_xdata)

p0, bounds = self._t2star_default_params(user_p0, user_bounds, t2star_input=t2star_estimate)
p0, bounds = self._t2star_default_params(
conversion_factor, user_p0, user_bounds, t2star_estimate
)
fit_result = curve_fit(
osc_fit_fun, si_xdata, ydata, p0=list(p0.values()), sigma=sigma, bounds=bounds
)
Expand Down Expand Up @@ -125,39 +126,35 @@ def _format_plot(ax, unit):

analysis_result["fit"]["circuit_unit"] = unit
if unit == "dt":
analysis_result["fit"]["dt"] = self._conversion_factor
analysis_result["fit"]["dt"] = conversion_factor
return analysis_result, figures

def _t2star_default_params(
self,
user_p0,
user_bounds,
t2star_input: float,
conversion_factor,
user_p0=None,
user_bounds=None,
t2star_input=None,
) -> Tuple[List[float], Tuple[List[float]]]:
"""
Default fit parameters for oscillation data
"""Default fit parameters for oscillation data.
Note that :math:`T_2^*` and 'freq' units are converted to 'sec' and
will be output in 'sec'.
Args:
t2star_input: default for t2star if p0==None
Returns:
Fit guessed parameters: either from the input (if given) or
else assign default values.
"""
if user_p0 is None:
a = 0.5
t2star = t2star_input * self._conversion_factor
t2star = t2star_input * conversion_factor
freq = 0.1
phi = 0.0
b = 0.5
else:
a = user_p0["A"]
t2star = user_p0["t2star"]
t2star *= self._conversion_factor
t2star *= conversion_factor
freq = user_p0["f"]
phi = user_p0["phi"]
b = user_p0["B"]
freq /= self._conversion_factor
freq /= conversion_factor
p0 = {"a_guess": a, "t2star": t2star, "f_guess": freq, "phi_guess": phi, "b_guess": b}
if user_bounds is None:
a_bounds = [-0.5, 1.5]
Expand Down Expand Up @@ -200,7 +197,6 @@ def __init__(
osc_freq: float = 0.0,
experiment_type: Optional[str] = None,
):

"""Initialize the T2Star experiment class.
Args:
Expand All @@ -220,18 +216,18 @@ def __init__(
self._osc_freq = osc_freq
super().__init__([qubit], experiment_type)

def circuits(
self, backend: Optional["Backend"] = None, **circuit_options
) -> List[QuantumCircuit]:
"""
Return a list of experiment circuits
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
circuit_options: from base class, empty here
Returns:
The experiment circuits
Raises:
AttributeError: if unit is dt but dt parameter is missing in the backend configuration
"""
Expand Down
25 changes: 13 additions & 12 deletions test/test_t2star.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,15 @@ def test_t2star_run_end2end(self):
]

exp = T2StarExperiment(qubit, delays, unit=unit)
exp.set_analysis_options(
user_p0={
"A": 0.5,
"t2star": estimated_t2star,
"f": estimated_freq,
"phi": 0,
"B": 0.5,
}
)

backend = T2starBackend(
p0={
Expand All @@ -193,20 +202,14 @@ def test_t2star_run_end2end(self):
dt_factor = getattr(backend._configuration, "dt")

# run circuits
result = exp.run(

expdata = exp.run(
backend=backend,
user_p0={
"A": 0.5,
"t2star": estimated_t2star,
"f": estimated_freq,
"phi": 0,
"B": 0.5,
},
user_bounds=None,
# plot=False,
instruction_durations=instruction_durations,
shots=2000,
).analysis_result(0)
)
result = expdata.analysis_result(0)
self.assertAlmostEqual(
result["t2star_value"],
estimated_t2star * dt_factor,
Expand Down Expand Up @@ -244,8 +247,6 @@ def test_t2star_parallel(self):
backend = T2starBackend(p0)
res = par_exp.run(
backend=backend,
user_p0=None,
user_bounds=None,
# plot=False,
shots=1000,
)
Expand Down

0 comments on commit c5479e3

Please sign in to comment.