Skip to content

Commit

Permalink
put curve fit back in analysis results and deprecate access
Browse files Browse the repository at this point in the history
also deprecate accessing analysis results via numerical indices
  • Loading branch information
coruscating committed Feb 7, 2024
1 parent 2b3733e commit 74a65ba
Show file tree
Hide file tree
Showing 15 changed files with 90 additions and 62 deletions.
2 changes: 1 addition & 1 deletion docs/manuals/measurement/readout_mitigation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ circuits, one for all “0” and one for all “1” results.

exp.analysis.set_options(plot=True)
result = exp.run(backend)
mitigator = result.analysis_results(0).value
mitigator = result.analysis_results("Local Readout Mitigator").value

The resulting measurement matrix can be illustrated by comparing it to
the identity.
Expand Down
22 changes: 1 addition & 21 deletions qiskit_experiments/curve_analysis/base_curve_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def _default_options(cls) -> Options:

options.plotter = CurvePlotter(MplDrawer())
options.plot_raw_data = False
options.return_fit_parameters = False
options.return_fit_parameters = True
options.return_data_points = False
options.data_processor = None
options.normalization = False
Expand All @@ -230,26 +230,6 @@ def _default_options(cls) -> Options:

return options

def set_options(self, **fields):
"""Set the analysis options for :meth:`run` method.
Args:
fields: The fields to update the options
Raises:
KeyError: When removed option ``curve_fitter`` is set.
"""

if "return_fit_parameters" in fields:
warnings.warn(
"@Parameters_* result entry has moved to the experiment data artifact "
"regardless of option value. Setting this value doesn't affect result data.",
DeprecationWarning,
)
del fields["return_fit_parameters"]

super().set_options(**fields)

@abstractmethod
def _run_data_processing(
self,
Expand Down
13 changes: 12 additions & 1 deletion qiskit_experiments/curve_analysis/composite_curve_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
)

from qiskit_experiments.framework.containers import FigureType, ArtifactData
from .base_curve_analysis import DATA_ENTRY_PREFIX, BaseCurveAnalysis
from .base_curve_analysis import DATA_ENTRY_PREFIX, BaseCurveAnalysis, PARAMS_ENTRY_PREFIX
from .curve_data import CurveFitResult
from .scatter_table import ScatterTable
from .utils import eval_with_uncertainties
Expand Down Expand Up @@ -363,6 +363,17 @@ def _run_analysis(
else:
quality = "bad"

if self.options.return_fit_parameters:
# Store fit status overview entry regardless of success.
# This is sometime useful when debugging the fitting code.
overview = AnalysisResultData(
name=PARAMS_ENTRY_PREFIX + analysis.name,
value=fit_data,
quality=quality,
extra=metadata,
)
result_data.append(overview)

if fit_data.success:
# Add fit data to curve data table
model_names = analysis.model_names()
Expand Down
13 changes: 12 additions & 1 deletion qiskit_experiments/curve_analysis/curve_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from qiskit_experiments.framework.containers import FigureType, ArtifactData
from qiskit_experiments.data_processing.exceptions import DataProcessorError

from .base_curve_analysis import BaseCurveAnalysis, DATA_ENTRY_PREFIX
from .base_curve_analysis import BaseCurveAnalysis, DATA_ENTRY_PREFIX, PARAMS_ENTRY_PREFIX
from .curve_data import FitOptions, CurveFitResult
from .scatter_table import ScatterTable
from .utils import (
Expand Down Expand Up @@ -484,6 +484,17 @@ def _run_analysis(
# to generate the figure
plot_bool = plot == "always" or (plot == "selective" and quality == "bad")

if self.options.return_fit_parameters:
# Store fit status overview entry regardless of success.
# This is sometime useful when debugging the fitting code.
overview = AnalysisResultData(
name=PARAMS_ENTRY_PREFIX + self.name,
value=fit_data,
quality=quality,
extra=self.options.extra,
)
result_data.append(overview)

if fit_data.success:
# Add fit data to curve data table
model_names = self.model_names()
Expand Down
15 changes: 15 additions & 0 deletions qiskit_experiments/framework/experiment_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1545,6 +1545,21 @@ def analysis_results(
)
self._retrieve_analysis_results(refresh=refresh)

if index == 0:
warnings.warn(
"Curve fit results have moved to experiment artifacts and will be removed "
"from analysis results in a future release. Use "
'expdata.artifacts("fit_summary").data to access curve fit results.',
DeprecationWarning,
)
elif isinstance(index, (int, slice)):
warnings.warn(
"Accessing analysis results via a numerical index is deprecated and will be "
"removed in a future release. Use the ID or name of the analysis result "
"instead.",
DeprecationWarning,
)

if dataframe:
return self._analysis_results.get_data(index, columns=columns)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def _run_analysis(self, experiment_data):
roerror_analysis.run(roerror_data, replace_results=True).block_for_results()

# Construct noisy measurement basis
mitigator = roerror_data.analysis_results(0).value
mitigator = roerror_data.analysis_results("Local Readout Mitigator").value

# Run mitigated tomography analysis with noisy mitigated basis
# Tomo analysis instance is internally copied by setting option with run.
Expand Down
21 changes: 12 additions & 9 deletions releasenotes/notes/experiment-artifacts-c481f4e07226ce9e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ features:
and :meth:`.delete_artifact` have been added to manipulate the artifacts. These will be uploaded
to the cloud service in JSON form along with the rest of the :class:`.ExperimentData` object
when saved. For more information, see the :doc:`artifacts how-to </howtos/artifacts>`.
upgrade:
deprecations:
- |
Setting the option ``return_data_points`` to ``True`` in curve analysis has been deprecated.
Data points are now automatically provided in :class:`ExperimentData` objects via the ``curve_data``
artifact.
- |
Direct access to the curve fit summary in :class:`.ExperimentData` has moved from
:meth:`.analysis_results` to :meth:`.artifacts`, where values are stored in the
:attr:`~.ArtifactData.data` attribute of :class:`.ArtifactData` objects. For example, to access the
chi-squared of the fit, ``expdata.analysis_results(0).chisq`` is now
``expdata.artifacts("fit_summary").data.chisq``. Note that this may also shift the indices of
analysis results that are not curve fit results. For more information, see the :doc:`artifacts how-to
</howtos/artifacts>`.
deprecations:
chi-squared of the fit, ``expdata.analysis_results(0).chisq`` is deprecated in favor of
``expdata.artifacts("fit_summary").data.chisq``. In a future release, the curve fit summary
will be removed from :meth:`.analysis_results`. For more information on artifacts, see the
:doc:`artifacts how-to </howtos/artifacts>`.
- |
Setting the option ``return_data_points`` to ``True`` in curve analysis has been deprecated.
Data points are now automatically provided in :class:`ExperimentData` objects via the ``curve_data``
artifact.
Using numerical indices with :meth:`.ExperimentData.analysis_results`, including both integers and
slices, is now deprecated. Access analysis results by analysis result name or ID instead.
2 changes: 1 addition & 1 deletion test/curve_analysis/test_baseclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ def test_selective_figure_generation(self):

for res in result.child_data():
# only generate a figure if the quality is bad
if res.analysis_results(0).quality == "bad":
if res.analysis_results("amp").quality == "bad":
self.assertEqual(len(res._figures), 1)
else:
self.assertEqual(len(res._figures), 0)
Expand Down
17 changes: 9 additions & 8 deletions test/database_service/test_db_experiment_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,14 +493,15 @@ def test_add_get_analysis_result(self):
[res.result_id for res in exp_data.analysis_results()],
result_ids,
)
self.assertEqual(
exp_data.analysis_results(1).result_id,
result_ids[1],
)
self.assertEqual(
[res.result_id for res in exp_data.analysis_results(slice(2, 4))],
result_ids[2:4],
)
with self.assertWarns(DeprecationWarning):
self.assertEqual(
exp_data.analysis_results(1).result_id,
result_ids[1],
)
self.assertEqual(
[res.result_id for res in exp_data.analysis_results(slice(2, 4))],
result_ids[2:4],
)

def test_add_get_analysis_results(self):
"""Test adding and getting a list of analysis results."""
Expand Down
10 changes: 7 additions & 3 deletions test/framework/test_composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -950,9 +950,13 @@ def test_batch_transpile_options_integrated(self):
expdata = self.batch2.run(backend, noise_model=noise_model, shots=1000)
self.assertExperimentDone(expdata)

self.assertEqual(expdata.child_data(0).analysis_results(0).value, 8)
self.assertEqual(expdata.child_data(1).child_data(0).analysis_results(0).value, 16)
self.assertEqual(expdata.child_data(1).child_data(1).analysis_results(0).value, 4)
self.assertEqual(expdata.child_data(0).analysis_results("non-zero counts").value, 8)
self.assertEqual(
expdata.child_data(1).child_data(0).analysis_results("non-zero counts").value, 16
)
self.assertEqual(
expdata.child_data(1).child_data(1).analysis_results("non-zero counts").value, 4
)

def test_separate_jobs(self):
"""Test the separate_job experiment option"""
Expand Down
4 changes: 2 additions & 2 deletions test/library/calibration/test_fine_drag.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ def test_end_to_end(self):
exp_data = drag.run(MockIQBackend(FineDragHelper()))
self.assertExperimentDone(exp_data)

self.assertEqual(exp_data.analysis_results(0).quality, "good")
self.assertEqual(exp_data.analysis_results("d_theta").quality, "good")

def test_end_to_end_no_schedule(self):
"""Test that we can run without a schedule."""
exp_data = FineXDrag([0]).run(MockIQBackend(FineDragHelper()))
self.assertExperimentDone(exp_data)

self.assertEqual(exp_data.analysis_results(0).quality, "good")
self.assertEqual(exp_data.analysis_results("d_theta").quality, "good")

def test_circuits_roundtrip_serializable(self):
"""Test circuits serialization of the experiment."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def test_integration(self, ix, iy, iz, zx, zy, zz):
exp_data = expr.run()
self.assertExperimentDone(exp_data, timeout=1000)

self.assertEqual(exp_data.analysis_results(0).quality, "good")
self.assertEqual(exp_data.analysis_results("omega_ix").quality, "good")

# These values are computed from other analysis results in post hook.
# Thus at least one of these values should be round-trip tested.
Expand Down Expand Up @@ -265,7 +265,7 @@ def test_integration_backward_compat(self):
exp_data = expr.run()
self.assertExperimentDone(exp_data, timeout=1000)

self.assertEqual(exp_data.analysis_results(0).quality, "good")
self.assertEqual(exp_data.analysis_results("omega_ix").quality, "good")

self.assertAlmostEqual(exp_data.analysis_results("omega_ix").value.n, ix, delta=delta)
self.assertAlmostEqual(exp_data.analysis_results("omega_iy").value.n, iy, delta=delta)
Expand Down
7 changes: 4 additions & 3 deletions test/library/characterization/test_readout_angle.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ def test_readout_angle_end2end(self):
exp = ReadoutAngle([0])
expdata = exp.run(backend, shots=10000)
self.assertExperimentDone(expdata)
res = expdata.analysis_results(0)

res = expdata.analysis_results("readout_angle")
self.assertAlmostEqual(res.value % (2 * np.pi), np.pi / 2, places=2)

backend = MockIQBackend(
Expand All @@ -47,7 +48,7 @@ def test_readout_angle_end2end(self):
exp = ReadoutAngle([0])
expdata = exp.run(backend, shots=10000)
self.assertExperimentDone(expdata)
res = expdata.analysis_results(0)
res = expdata.analysis_results("readout_angle")
self.assertAlmostEqual(res.value % (2 * np.pi), 15 * np.pi / 8, places=2)

def test_kerneled_expdata_serialization(self):
Expand All @@ -69,4 +70,4 @@ def test_kerneled_expdata_serialization(self):
self.assertRoundTripSerializable(expdata)

# Checking serialization of the analysis
self.assertRoundTripSerializable(expdata.analysis_results(0))
self.assertRoundTripSerializable(expdata.analysis_results("readout_angle"))
15 changes: 8 additions & 7 deletions test/library/characterization/test_readout_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ def test_local_analysis_ideal(self):
exp = LocalReadoutError(backend=backend)
expdata = exp.run(backend)
self.assertExperimentDone(expdata)
mitigator = expdata.analysis_results(0).value

mitigator = expdata.analysis_results("Local Readout Mitigator").value

qubits = list(range(num_qubits))
self.assertEqual(mitigator._num_qubits, num_qubits)
Expand All @@ -56,7 +57,7 @@ def test_correlated_analysis_ideal(self):
exp = CorrelatedReadoutError(backend=backend)
expdata = exp.run(backend)
self.assertExperimentDone(expdata)
mitigator = expdata.analysis_results(0).value
mitigator = expdata.analysis_results("Correlated Readout Mitigator").value

qubits = list(range(num_qubits))
self.assertEqual(mitigator._num_qubits, num_qubits)
Expand Down Expand Up @@ -89,7 +90,7 @@ def test_local_analysis(self):
expdata.metadata.update(run_meta)
exp = LocalReadoutError(qubits)
result = exp.analysis.run(expdata)
mitigator = result.analysis_results(0).value
mitigator = result.analysis_results("Local Readout Mitigator").value

self.assertEqual(len(qubits), mitigator._num_qubits)
self.assertEqual(qubits, mitigator._qubits)
Expand Down Expand Up @@ -159,7 +160,7 @@ def test_correlated_analysis(self):
expdata.metadata.update(run_meta)
exp = CorrelatedReadoutError(qubits)
result = exp.analysis.run(expdata)
mitigator = result.analysis_results(0).value
mitigator = result.analysis_results("Correlated Readout Mitigator").value

self.assertEqual(len(qubits), mitigator._num_qubits)
self.assertEqual(qubits, mitigator._qubits)
Expand All @@ -182,8 +183,8 @@ def test_parallel_running(self):
exp = ParallelExperiment([exp1, exp2], flatten_results=False)
expdata = exp.run(backend=backend)
self.assertExperimentDone(expdata)
mit1 = expdata.child_data(0).analysis_results(0).value
mit2 = expdata.child_data(1).analysis_results(0).value
mit1 = expdata.child_data(0).analysis_results("Correlated Readout Mitigator").value
mit2 = expdata.child_data(1).analysis_results("Correlated Readout Mitigator").value
assignment_matrix1 = mit1.assignment_matrix()
assignment_matrix2 = mit2.assignment_matrix()
self.assertFalse(matrix_equal(assignment_matrix1, assignment_matrix2))
Expand Down Expand Up @@ -211,7 +212,7 @@ def test_json_serialization(self):
exp = LocalReadoutError(qubits)
exp_data = exp.run(backend)
self.assertExperimentDone(exp_data)
mitigator = exp_data.analysis_results(0).value
mitigator = exp_data.analysis_results("Local Readout Mitigator").value
serialized = json.dumps(mitigator, cls=ExperimentEncoder)
loaded = json.loads(serialized, cls=ExperimentDecoder)
self.assertTrue(matrix_equal(mitigator.assignment_matrix(), loaded.assignment_matrix()))
Expand Down
5 changes: 3 additions & 2 deletions test/library/quantum_volume/test_qv.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,13 @@ def test_qv_sigma_decreasing(self):
qv_exp.set_experiment_options(trials=2)
expdata1 = qv_exp.run(backend)
self.assertExperimentDone(expdata1)
result_data1 = expdata1.analysis_results(0)

result_data1 = expdata1.analysis_results("mean_HOP")
expdata2 = qv_exp.run(backend, analysis=None)
self.assertExperimentDone(expdata2)
expdata2.add_data(expdata1.data())
qv_exp.analysis.run(expdata2)
result_data2 = expdata2.analysis_results(0)
result_data2 = expdata2.analysis_results("mean_HOP")

self.assertTrue(result_data1.extra["trials"] == 2, "number of trials is incorrect")
self.assertTrue(
Expand Down

0 comments on commit 74a65ba

Please sign in to comment.