Skip to content

Commit 21c1a85

Browse files
committed
Update experiments
1 parent ac3681a commit 21c1a85

File tree

7 files changed

+70
-40
lines changed

7 files changed

+70
-40
lines changed

qiskit_experiments/characterization/t1_experiment.py

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from qiskit.circuit import QuantumCircuit
2020
from qiskit.utils import apply_prefix
21+
from qiskit.providers.options import Options
2122

2223
from qiskit_experiments.base_experiment import BaseExperiment
2324
from qiskit_experiments.base_analysis import BaseAnalysis
@@ -27,9 +28,29 @@
2728

2829

2930
class T1Analysis(BaseAnalysis):
30-
"""T1 Experiment result analysis class."""
31+
"""T1 Experiment result analysis class.
32+
33+
Analysis Options:
34+
t1_guess (float): Optional, an initial guess of T1
35+
amplitude_guess (float): Optional, an initial guess of the coefficient of the exponent
36+
offset_guess (float): Optional, an initial guess of the offset
37+
t1_bounds (list of two floats): Optional, lower bound and upper bound to T1
38+
amplitude_bounds (list of two floats): Optional, lower bound and upper bound to the amplitude
39+
offset_bounds (list of two floats): Optional, lower bound and upper bound to the offset
40+
"""
41+
42+
@classmethod
43+
def _default_options(cls):
44+
return Options(
45+
t1_guess=None,
46+
amplitude_guess=None,
47+
offset_guess=None,
48+
t1_bounds=None,
49+
amplitude_bounds=None,
50+
offset_bounds=None,
51+
)
3152

32-
# pylint: disable=arguments-differ, unused-argument
53+
# pylint: disable=arguments-differ
3354
def _run_analysis(
3455
self,
3556
experiment_data,
@@ -39,7 +60,6 @@ def _run_analysis(
3960
t1_bounds=None,
4061
amplitude_bounds=None,
4162
offset_bounds=None,
42-
**kwargs,
4363
) -> Tuple[AnalysisResult, None]:
4464
"""
4565
Calculate T1
@@ -52,12 +72,10 @@ def _run_analysis(
5272
t1_bounds (list of two floats): Optional, lower bound and upper bound to T1
5373
amplitude_bounds (list of two floats): Optional, lower bound and upper bound to the amplitude
5474
offset_bounds (list of two floats): Optional, lower bound and upper bound to the offset
55-
kwargs: Trailing unused function parameters
5675
5776
Returns:
5877
The analysis result with the estimated T1
5978
"""
60-
6179
unit = experiment_data._data[0]["metadata"]["unit"]
6280
conversion_factor = experiment_data._data[0]["metadata"].get("dt_factor", None)
6381
if conversion_factor is None:
@@ -135,6 +153,10 @@ class T1Experiment(BaseExperiment):
135153

136154
__analysis_class__ = T1Analysis
137155

156+
@classmethod
157+
def _default_options(cls) -> Options:
158+
return Options(delays=None, unit="s")
159+
138160
def __init__(
139161
self,
140162
qubit: int,
@@ -154,12 +176,8 @@ def __init__(
154176
"""
155177
if len(delays) < 3:
156178
raise ValueError("T1 experiment: number of delays must be at least 3")
179+
super().__init__([qubit], delays=delays, unit=unit)
157180

158-
self._delays = delays
159-
self._unit = unit
160-
super().__init__([qubit])
161-
162-
# pylint: disable=arguments-differ
163181
def circuits(self, backend: Optional["Backend"] = None) -> List[QuantumCircuit]:
164182
"""
165183
Return a list of experiment circuits
@@ -173,31 +191,30 @@ def circuits(self, backend: Optional["Backend"] = None) -> List[QuantumCircuit]:
173191
Raises:
174192
AttributeError: if unit is dt but dt parameter is missing in the backend configuration
175193
"""
176-
177-
if self._unit == "dt":
194+
if self.options.unit == "dt":
178195
try:
179196
dt_factor = getattr(backend.configuration(), "dt")
180197
except AttributeError as no_dt:
181198
raise AttributeError("Dt parameter is missing in backend configuration") from no_dt
182199

183200
circuits = []
184201

185-
for delay in self._delays:
202+
for delay in self.options.delays:
186203
circ = QuantumCircuit(1, 1)
187204
circ.x(0)
188205
circ.barrier(0)
189-
circ.delay(delay, 0, self._unit)
206+
circ.delay(delay, 0, self.options.unit)
190207
circ.barrier(0)
191208
circ.measure(0, 0)
192209

193210
circ.metadata = {
194211
"experiment_type": self._type,
195212
"qubit": self.physical_qubits[0],
196213
"xval": delay,
197-
"unit": self._unit,
214+
"unit": self.options.unit,
198215
}
199216

200-
if self._unit == "dt":
217+
if self.options.unit == "dt":
201218
circ.metadata["dt_factor"] = dt_factor
202219

203220
circuits.append(circ)

qiskit_experiments/composite/batch_experiment.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def __init__(self, experiments):
4141
qubits = tuple(self._qubit_map.keys())
4242
super().__init__(experiments, qubits)
4343

44-
def circuits(self, backend=None, **circuit_options):
44+
def circuits(self, backend=None):
4545

4646
batch_circuits = []
4747

@@ -51,7 +51,7 @@ def circuits(self, backend=None, **circuit_options):
5151
qubit_mapping = None
5252
else:
5353
qubit_mapping = [self._qubit_map[qubit] for qubit in expr.physical_qubits]
54-
for circuit in expr.circuits(**circuit_options):
54+
for circuit in expr.circuits(backend):
5555
# Update metadata
5656
circuit.metadata = {
5757
"experiment_type": self._type,

qiskit_experiments/composite/composite_analysis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def _run_analysis(self, experiment_data, **options):
4848
for expr, expr_data in zip(
4949
experiment_data._experiment._experiments, experiment_data._composite_expdata
5050
):
51-
expr.analysis().run(expr_data, **options)
51+
expr.analysis(**expr.analysis_options.__dict__).run(expr_data, **options)
5252

5353
# Add sub-experiment metadata as result of batch experiment
5454
# Note: if Analysis results had ID's these should be included here

qiskit_experiments/composite/composite_experiment.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,21 @@ class CompositeExperiment(BaseExperiment):
2626
__analysis_class__ = CompositeAnalysis
2727
__experiment_data__ = CompositeExperimentData
2828

29-
def __init__(self, experiments, qubits, experiment_type=None, circuit_options=None):
29+
def __init__(self, experiments, qubits, experiment_type=None):
3030
"""Initialize the composite experiment object.
3131
3232
Args:
3333
experiments (List[BaseExperiment]): a list of experiment objects.
3434
qubits (int or Iterable[int]): the number of qubits or list of
3535
physical qubits for the experiment.
3636
experiment_type (str): Optional, composite experiment subclass name.
37-
circuit_options (str): Optional, Optional, dictionary of allowed
38-
kwargs and default values for the `circuit`
39-
method.
4037
"""
4138
self._experiments = experiments
4239
self._num_experiments = len(experiments)
43-
super().__init__(qubits, experiment_type=experiment_type, circuit_options=circuit_options)
40+
super().__init__(qubits, experiment_type=experiment_type)
4441

4542
@abstractmethod
46-
def circuits(self, backend=None, **circuit_options):
43+
def circuits(self, backend=None):
4744
pass
4845

4946
@property
@@ -55,6 +52,6 @@ def component_experiment(self, index):
5552
"""Return the component Experiment object"""
5653
return self._experiments[index]
5754

58-
def component_analysis(self, index, **kwargs):
55+
def component_analysis(self, index, **analysis_options):
5956
"""Return the component experiment Analysis object"""
60-
return self.component_experiment(index).analysis(**kwargs)
57+
return self.component_experiment(index).analysis(**analysis_options)

qiskit_experiments/composite/parallel_experiment.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def __init__(self, experiments):
3232
qubits += exp.physical_qubits
3333
super().__init__(experiments, qubits)
3434

35-
def circuits(self, backend=None, **circuit_options):
35+
def circuits(self, backend=None):
3636

3737
sub_circuits = []
3838
sub_qubits = []
@@ -42,7 +42,7 @@ def circuits(self, backend=None, **circuit_options):
4242
# Generate data for combination
4343
for expr in self._experiments:
4444
# Add subcircuits
45-
circs = expr.circuits(**circuit_options)
45+
circs = expr.circuits(backend)
4646
sub_circuits.append(circs)
4747
sub_size.append(len(circs))
4848

qiskit_experiments/randomized_benchmarking/rb_analysis.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,23 @@
3434

3535

3636
class RBAnalysis(BaseAnalysis):
37-
"""RB Analysis class."""
37+
"""RB Analysis class.
3838
39-
# pylint: disable = arguments-differ, invalid-name, attribute-defined-outside-init
39+
Analysis Options:
40+
p0: Optional, initial parameter values for curve_fit.
41+
plot: If True generate a plot of fitted data.
42+
ax: Optional, matplotlib axis to add plot to.
43+
"""
44+
45+
@classmethod
46+
def _default_options(cls):
47+
return Options(
48+
p0=None,
49+
plot=True,
50+
ax=None,
51+
)
52+
53+
# pylint: disable = arguments-differ, invalid-name
4054
def _run_analysis(
4155
self,
4256
experiment_data,
@@ -56,21 +70,21 @@ def _run_analysis(
5670
AnalysisResult objects, and ``figures`` may be
5771
None, a single figure, or a list of figures.
5872
"""
59-
self._num_qubits = len(experiment_data.data[0]["metadata"]["qubits"])
73+
num_qubits = len(experiment_data.data[0]["metadata"]["qubits"])
6074
xdata, ydata, ydata_sigma = self._extract_data(experiment_data)
6175

6276
def fit_fun(x, a, alpha, b):
6377
return a * alpha ** x + b
6478

65-
p0 = self._p0(xdata, ydata)
79+
p0 = self._p0(xdata, ydata, num_qubits)
6680
analysis_result = curve_fit(
6781
fit_fun, xdata, ydata, p0, ydata_sigma, bounds=([0, 0, 0], [1, 1, 1])
6882
)
6983

7084
# Add EPC data
7185
popt = analysis_result["popt"]
7286
popt_err = analysis_result["popt_err"]
73-
scale = (2 ** self._num_qubits - 1) / (2 ** self._num_qubits)
87+
scale = (2 ** num_qubits - 1) / (2 ** num_qubits)
7488
analysis_result["EPC"] = scale * (1 - popt[1])
7589
analysis_result["EPC_err"] = scale * popt_err[1] / popt[1]
7690
analysis_result["plabels"] = ["A", "alpha", "B"]
@@ -83,9 +97,10 @@ def fit_fun(x, a, alpha, b):
8397
analysis_result.plt = plt
8498
return analysis_result, None
8599

86-
def _p0(self, xdata, ydata):
100+
@staticmethod
101+
def _p0(xdata, ydata, num_qubits):
87102
"""Initial guess for the fitting function"""
88-
fit_guess = [0.95, 0.99, 1 / 2 ** self._num_qubits]
103+
fit_guess = [0.95, 0.99, 1 / 2 ** num_qubits]
89104
# Use the first two points to guess the decay param
90105
dcliff = xdata[1] - xdata[0]
91106
dy = (ydata[1] - fit_guess[2]) / (ydata[0] - fit_guess[2])
@@ -98,7 +113,8 @@ def _p0(self, xdata, ydata):
98113

99114
return fit_guess
100115

101-
def _extract_data(self, experiment_data, **filters):
116+
@staticmethod
117+
def _extract_data(experiment_data, **filters):
102118
"""Extract the base data for the fitter from the experiment data.
103119
Args:
104120
data: the experiment data to analyze
@@ -122,8 +138,8 @@ def _extract_data(self, experiment_data, **filters):
122138
xdata, ydata, ydata_sigma = mean_xy_data(xdata, ydata, ydata_sigma)
123139
return (xdata, ydata, ydata_sigma)
124140

125-
@classmethod
126-
def _format_plot(cls, ax, analysis_result, add_label=True):
141+
@staticmethod
142+
def _format_plot(ax, analysis_result, add_label=True):
127143
"""Format curve fit plot"""
128144
# Formatting
129145
ax.tick_params(labelsize=14)

test/data_processing/test_data_processing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def __init__(self):
3737
self._type = None
3838
super().__init__((0,), "fake_test_experiment")
3939

40-
def circuits(self, backend=None, **circuit_options):
40+
def circuits(self, backend=None):
4141
"""Fake circuits."""
4242
return []
4343

0 commit comments

Comments
 (0)