Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup RB module #762

Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
833621e
- remove backend and raw data dependency from RB
nkanazawa1989 Apr 4, 2022
f214707
Merge branch 'main' of github.com:Qiskit/qiskit-experiments into clea…
nkanazawa1989 Apr 4, 2022
0350cef
deprecate public methods
nkanazawa1989 Apr 4, 2022
8acb0be
update handling of gate_error_ratio
nkanazawa1989 Apr 5, 2022
7785cff
code formatting
nkanazawa1989 Apr 5, 2022
72641ac
minor bug fix
nkanazawa1989 Apr 5, 2022
8db7f10
create gate error ratio for all basis gates
nkanazawa1989 Apr 6, 2022
e98e42a
replace "skip" with False
nkanazawa1989 Apr 6, 2022
a3540b3
fix json serialization of metadata
nkanazawa1989 Apr 6, 2022
ae71972
fix gate counting bug
nkanazawa1989 Apr 6, 2022
15187b7
lint
nkanazawa1989 Apr 6, 2022
533a0c5
add more test
nkanazawa1989 Apr 6, 2022
b7c0e94
add reno
nkanazawa1989 Apr 6, 2022
e9c66b5
lint
nkanazawa1989 Apr 6, 2022
e53521b
remove redundant internal state for gate error ratio
nkanazawa1989 Apr 6, 2022
50e1269
upgrade EPG computation
nkanazawa1989 Apr 8, 2022
d55185a
replace warning with logging
nkanazawa1989 Apr 8, 2022
f8bd014
update test of deprecated methods
nkanazawa1989 Apr 9, 2022
b78fd2c
Merge branch 'main' into cleanup/rb_remove_rawdata_dependency
nkanazawa1989 Apr 9, 2022
1a33224
review comment1; cleanup utils
nkanazawa1989 Apr 20, 2022
676047b
fix doc of gate_error_ratio
nkanazawa1989 Apr 20, 2022
de07ff4
update reno
nkanazawa1989 Apr 20, 2022
3ab25f5
update documentation and move API docs to tutorial
nkanazawa1989 Apr 20, 2022
4fdc2b3
move helper function after the class
nkanazawa1989 Apr 20, 2022
5f47780
remove gate counts from analysis options
nkanazawa1989 Apr 20, 2022
357f0a4
replace baseclass of IRB analysis.
nkanazawa1989 Apr 20, 2022
af231ec
cleanup tutorial
nkanazawa1989 Apr 20, 2022
c9becae
fix #727
nkanazawa1989 Apr 20, 2022
3a9c21a
Update qiskit_experiments/curve_analysis/guess.py
nkanazawa1989 Apr 21, 2022
71df88c
lint
nkanazawa1989 Apr 21, 2022
2b142df
Merge branch 'cleanup/rb_remove_rawdata_dependency' of github.com:nka…
nkanazawa1989 Apr 21, 2022
e246f71
Merge branch 'main' into cleanup/rb_remove_rawdata_dependency
nkanazawa1989 Apr 21, 2022
6197b3c
fix bug
nkanazawa1989 Apr 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 81 additions & 167 deletions qiskit_experiments/curve_analysis/curve_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@
import inspect
import warnings
from abc import ABC
from typing import Any, Dict, List, Tuple, Callable, Union, Optional
from typing import Dict, List, Tuple, Callable, Union, Optional

import numpy as np
import uncertainties
from uncertainties import unumpy as unp

from qiskit.providers import Backend
from qiskit.utils import detach_prefix
from qiskit_experiments.curve_analysis.curve_data import (
CurveData,
Expand Down Expand Up @@ -253,14 +252,11 @@ def __init__(self):
p: self.options.get(p, None) for p in self.__fixed_parameters__
}

#: Dict[str, Any]: Experiment metadata
self.__experiment_metadata = None

#: List[CurveData]: Processed experiment data set.
self.__processed_data_set = list()

#: Backend: backend object used for experimentation
self.__backend = None
#: List[int]: Index of physical qubits
self._physical_qubits = None

@classmethod
def _fit_params(cls) -> List[str]:
Expand Down Expand Up @@ -665,92 +661,6 @@ def _is_target_series(datum, **filters):
raise AnalysisError(f"Not expected data label {formatted_data.label} != fit_ready.")
self.__processed_data_set.append(formatted_data)

@property
def _experiment_type(self) -> str:
"""Return type of experiment."""
try:
return self.__experiment_metadata["experiment_type"]
except (TypeError, KeyError):
# Ignore experiment metadata is not set or key is not found
return None

@property
def _num_qubits(self) -> int:
"""Getter for qubit number."""
try:
return len(self.__experiment_metadata["physical_qubits"])
except (TypeError, KeyError):
# Ignore experiment metadata is not set or key is not found
return None

@property
def _physical_qubits(self) -> List[int]:
"""Getter for physical qubit indices."""
try:
return list(self.__experiment_metadata["physical_qubits"])
except (TypeError, KeyError):
# Ignore experiment metadata is not set or key is not found
return None

@property
def _backend(self) -> Backend:
"""Getter for backend object."""
return self.__backend

def _experiment_options(self, index: int = -1) -> Dict[str, Any]:
"""Return the experiment options of given job index.

Args:
index: Index of job metadata to extract. Default to -1 (latest).

Returns:
Experiment options. This option is used for circuit generation.
"""
try:
return self.__experiment_metadata["job_metadata"][index]["experiment_options"]
except (TypeError, KeyError, IndexError):
# Ignore experiment metadata or job metadata is not set or key is not found
return None

def _run_options(self, index: int = -1) -> Dict[str, Any]:
"""Returns the run options of given job index.

Args:
index: Index of job metadata to extract. Default to -1 (latest).

Returns:
Run options. This option is used for backend execution.
"""
try:
return self.__experiment_metadata["job_metadata"][index]["run_options"]
except (TypeError, KeyError, IndexError):
# Ignore experiment metadata or job metadata is not set or key is not found
return None

def _transpile_options(self, index: int = -1) -> Dict[str, Any]:
"""Returns the transpile options of given job index.

Args:
index: Index of job metadata to extract. Default to -1 (latest).

Returns:
Transpile options. This option is used for circuit optimization.
"""
try:
return self.__experiment_metadata["job_metadata"][index]["transpile_options"]
except (TypeError, KeyError, IndexError):
# Ignore experiment metadata or job metadata is not set or key is not found
return None

def _extra_metadata(self) -> Dict[str, Any]:
"""Returns extra metadata.

Returns:
Extra metadata explicitly added by the experiment subclass.
"""
exclude = ["experiment_type", "num_qubits", "physical_qubits", "job_metadata"]
return {k: v for k, v in self.__experiment_metadata.items() if k not in exclude}

def _data(
self,
series_name: Optional[str] = None,
Expand Down Expand Up @@ -793,6 +703,10 @@ def _data(

raise AnalysisError(f"Specified series {series_name} is not defined in this analysis.")

@property
def _num_qubits(self) -> int:
return len(self._physical_qubits)

def _run_analysis(
self, experiment_data: ExperimentData
) -> Tuple[List[AnalysisResultData], List["pyplot.Figure"]]:
Expand Down Expand Up @@ -824,15 +738,8 @@ def _run_analysis(

# get experiment metadata
try:
self.__experiment_metadata = experiment_data.metadata

except AttributeError:
pass

# get backend
try:
self.__backend = experiment_data.backend
except AttributeError:
self._physical_qubits = experiment_data.metadata["physical_qubits"]
except KeyError:
pass

#
Expand All @@ -850,11 +757,42 @@ def _run_analysis(
# Qiskit DataProcessor instance. May need calibration.
data_processor.train(data=experiment_data.data())

# Initialize fit figure canvas
if self.options.plot:
self.drawer.initialize_canvas()

#
# 3. Extract curve entries from experiment data
#
self._extract_curves(experiment_data=experiment_data, data_processor=data_processor)

# TODO remove _data method dependency in follow-up
# self.__processed_data_set will be removed from instance.

# Draw raw data
if self.options.plot and self.options.plot_raw_data:
for s in self.__series__:
raw_data = self._data(label="raw_data", series_name=s.name)
self.drawer.draw_raw_data(
x_data=raw_data.x,
y_data=raw_data.y,
ax_index=s.canvas,
)

# Draw formatted data
if self.options.plot:
for s in self.__series__:
curve_data = self._data(label="fit_ready", series_name=s.name)
self.drawer.draw_formatted_data(
x_data=curve_data.x,
y_data=curve_data.y,
y_err_data=curve_data.y_err,
name=s.name,
ax_index=s.canvas,
color=s.plot_color,
marker=s.plot_symbol,
)

#
# 4. Run fitting
#
Expand Down Expand Up @@ -985,75 +923,51 @@ def _run_analysis(
)
analysis_results.append(raw_data_entry)

#
# 6. Create figures
#
if self.options.plot:
# Initialize axis
self.drawer.initialize_canvas()
# Write raw data
if self.options.plot_raw_data:
for s in self.__series__:
raw_data = self._data(label="raw_data", series_name=s.name)
self.drawer.draw_raw_data(
x_data=raw_data.x,
y_data=raw_data.y,
ax_index=s.canvas,
)
# Write data points
# Draw fit results if fitting succeeded
if self.options.plot and fit_result:
for s in self.__series__:
curve_data = self._data(label="fit_ready", series_name=s.name)
self.drawer.draw_formatted_data(
x_data=curve_data.x,
y_data=curve_data.y,
y_err_data=curve_data.y_err,
name=s.name,
interp_x = np.linspace(*fit_result.x_range, 100)

params = {}
for fitpar in s.signature:
if fitpar in self.options.fixed_parameters:
params[fitpar] = self.options.fixed_parameters[fitpar]
else:
params[fitpar] = fit_result.fitval(fitpar)

y_data_with_uncertainty = s.fit_func(interp_x, **params)
y_mean = unp.nominal_values(y_data_with_uncertainty)
y_std = unp.std_devs(y_data_with_uncertainty)
# Draw fit line
self.drawer.draw_fit_line(
x_data=interp_x,
y_data=y_mean,
ax_index=s.canvas,
color=s.plot_color,
marker=s.plot_symbol,
)
# Write fit results if fitting succeeded
if fit_result:
for s in self.__series__:
interp_x = np.linspace(*fit_result.x_range, 100)

params = {}
for fitpar in s.signature:
if fitpar in self.options.fixed_parameters:
params[fitpar] = self.options.fixed_parameters[fitpar]
else:
params[fitpar] = fit_result.fitval(fitpar)

y_data_with_uncertainty = s.fit_func(interp_x, **params)
y_mean = unp.nominal_values(y_data_with_uncertainty)
y_std = unp.std_devs(y_data_with_uncertainty)
# Draw fit line
self.drawer.draw_fit_line(
x_data=interp_x,
y_data=y_mean,
ax_index=s.canvas,
color=s.plot_color,
)
# Draw confidence intervals with different n_sigma
sigmas = unp.std_devs(y_data_with_uncertainty)
if np.isfinite(sigmas).all():
for n_sigma, alpha in self.drawer.options.plot_sigma:
self.drawer.draw_confidence_interval(
x_data=interp_x,
y_ub=y_mean + n_sigma * y_std,
y_lb=y_mean - n_sigma * y_std,
ax_index=s.canvas,
alpha=alpha,
color=s.plot_color,
)

# Write fitting report
report_description = ""
for res in analysis_results:
if isinstance(res.value, (float, uncertainties.UFloat)):
report_description += f"{analysis_result_to_repr(res)}\n"
report_description += r"Fit $\chi^2$ = " + f"{fit_result.reduced_chisq: .4g}"
self.drawer.draw_fit_report(description=report_description)
# Draw confidence intervals with different n_sigma
sigmas = unp.std_devs(y_data_with_uncertainty)
if np.isfinite(sigmas).all():
for n_sigma, alpha in self.drawer.options.plot_sigma:
self.drawer.draw_confidence_interval(
x_data=interp_x,
y_ub=y_mean + n_sigma * y_std,
y_lb=y_mean - n_sigma * y_std,
ax_index=s.canvas,
alpha=alpha,
color=s.plot_color,
)

# Draw fitting report
report_description = ""
for res in analysis_results:
if isinstance(res.value, (float, uncertainties.UFloat)):
report_description += f"{analysis_result_to_repr(res)}\n"
report_description += r"Fit $\chi^2$ = " + f"{fit_result.reduced_chisq: .4g}"
self.drawer.draw_fit_report(description=report_description)

# Output figure
if self.options.plot:
self.drawer.format_canvas()
figures = [self.drawer.figure]
else:
Expand Down
6 changes: 3 additions & 3 deletions qiskit_experiments/framework/base_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,12 @@ def run(
# Finalize experiment before executions
experiment._finalize()

# Initialize result container
experiment_data = experiment._initialize_experiment_data()

# Generate and transpile circuits
transpiled_circuits = experiment._transpiled_circuits()

# Initialize result container
experiment_data = experiment._initialize_experiment_data()

# Run options
run_opts = experiment.run_options.__dict__

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def _default_options(cls):
"""Default analysis options."""
default_options = super()._default_options()
default_options.result_parameters = ["alpha", "alpha_c"]
default_options.gate_error_ratio = False
return default_options

def _generate_fit_guesses(
Expand Down
Loading