Skip to content

Commit

Permalink
Merge pull request #809 from chriseclectic/0.3.1
Browse files Browse the repository at this point in the history
Prepare 0.3.1 patch
  • Loading branch information
chriseclectic authored May 18, 2022
2 parents db1d863 + 7be5697 commit 9926ece
Show file tree
Hide file tree
Showing 32 changed files with 1,229 additions and 445 deletions.
6 changes: 2 additions & 4 deletions docs/_ext/autodoc_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,12 @@ class ExperimentDocumenter(ClassDocumenter):
"""Sphinx extension for the custom documentation of the standard experiment class."""

objtype = "experiment"
directivetype = 'class'
directivetype = "class"
priority = 10 + ClassDocumenter.priority
option_spec = dict(ClassDocumenter.option_spec)

@classmethod
def can_document_member(
cls, member: Any, membername: str, isattr: bool, parent: Any
) -> bool:
def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any) -> bool:
return isinstance(member, BaseExperiment)

def add_content(self, more_content: Any, no_docstring: bool = False) -> None:
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
# The short X.Y version
version = "0.3"
# The full version, including alpha/beta/rc tags
release = "0.3.0"
release = "0.3.1"

rst_prolog = """
.. raw:: html
Expand Down
2 changes: 1 addition & 1 deletion qiskit_experiments/VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.3.0
0.3.1
22 changes: 12 additions & 10 deletions qiskit_experiments/curve_analysis/curve_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,11 @@ def _run_analysis(
formatted_data = self._format_data(processed_data)
if self.options.plot:
for s in self.__series__:
sub_data = formatted_data.get_subset_of(s.name)
self.drawer.draw_formatted_data(
x_data=formatted_data.x,
y_data=formatted_data.y,
y_err_data=formatted_data.y_err,
x_data=sub_data.x,
y_data=sub_data.y,
y_err_data=sub_data.y_err,
name=s.name,
ax_index=s.canvas,
color=s.plot_color,
Expand Down Expand Up @@ -244,13 +245,14 @@ def _run_analysis(
alpha=alpha,
color=s.plot_color,
)
# Write fitting report
report_description = ""
for res in analysis_results:
if isinstance(res.value, (float, UFloat)):
report_description += f"{analysis_result_to_repr(res)}\n"
report_description += r"Fit $\chi^2$ = " + f"{fit_data.reduced_chisq: .4g}"
self.drawer.draw_fit_report(description=report_description)

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

# Add raw data points
analysis_results.extend(self._create_curve_data(formatted_data, self.__series__))
Expand Down
11 changes: 9 additions & 2 deletions qiskit_experiments/database_service/db_experiment_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -1835,8 +1835,6 @@ def __json_encode__(self):
for att in [
"_metadata",
"_source",
"_service",
"_backend",
"_id",
"_parent_id",
"_type",
Expand All @@ -1861,6 +1859,15 @@ def __json_encode__(self):
# Handle non-serializable objects
json_value["_jobs"] = self._safe_serialize_jobs()

# the attribute self._service in charge of the connection and communication with the
# experiment db. It doesn't have meaning in the json format so there is no need to serialize
# it.
for att in ["_service", "_backend"]:
json_value[att] = None
value = getattr(self, att)
if value is not None:
LOG.info("%s cannot be JSON serialized", str(type(value)))

return json_value

@classmethod
Expand Down
14 changes: 14 additions & 0 deletions qiskit_experiments/framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@
- :meth:`BaseExperiment._metadata`
to add any experiment metadata to the result data.
Furthermore, some characterization and calibration experiments can be run with restless
measurements, i.e. measurements where the qubits are not reset and circuits are executed
immediately after the previous measurement. Here, the :class:`.RestlessMixin` can help
to set the appropriate run options and data processing chain.
Analysis Subclasses
*******************
Expand Down Expand Up @@ -232,6 +237,14 @@
BaseExperiment
BaseAnalysis
Mix-ins
*******
.. autosummary::
:toctree: ../stubs/
RestlessMixin
.. _create-experiment:
"""
from qiskit.providers.options import Options
Expand All @@ -252,3 +265,4 @@
CompositeAnalysis,
)
from .json import ExperimentEncoder, ExperimentDecoder
from .restless_mixin import RestlessMixin
41 changes: 37 additions & 4 deletions qiskit_experiments/framework/composite/composite_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from typing import List, Dict, Union, Optional, Tuple
import numpy as np
from qiskit.result import marginal_counts
from qiskit.result.postprocess import format_counts_memory
from qiskit_experiments.framework import BaseAnalysis, ExperimentData
from qiskit_experiments.framework.analysis_result_data import AnalysisResultData
from qiskit_experiments.framework.base_analysis import _requires_copy
Expand Down Expand Up @@ -111,7 +112,7 @@ def run(

def _run_analysis(self, experiment_data: ExperimentData):
# Return list of experiment data containers for each component experiment
# containing the marginalied data from the composite experiment
# containing the marginalized data from the composite experiment
component_expdata = self._component_experiment_data(experiment_data)

# Run the component analysis on each component data
Expand Down Expand Up @@ -194,6 +195,10 @@ def _marginalized_component_data(self, composite_data: List[Dict]) -> List[List[
composite_clbits = metadata["composite_clbits"]
else:
composite_clbits = None

# Pre-process the memory if any to avoid redundant calls to format_counts_memory
f_memory = self._format_memory(datum, composite_clbits)

for i, index in enumerate(metadata["composite_index"]):
if index not in marginalized_data:
# Initialize data list for marginalized
Expand All @@ -206,16 +211,44 @@ def _marginalized_component_data(self, composite_data: List[Dict]) -> List[List[
sub_data["counts"] = datum["counts"]
if "memory" in datum:
if composite_clbits is not None:
sub_data["memory"] = (
np.array(datum["memory"])[composite_clbits[i]]
).tolist()
# level 2
if f_memory is not None:
idx = slice(
-1 - composite_clbits[i][-1], -composite_clbits[i][0] or None
)
sub_data["memory"] = [shot[idx] for shot in f_memory]
# level 1
else:
mem = np.array(datum["memory"])

# Averaged level 1 data
if len(mem.shape) == 2:
sub_data["memory"] = mem[composite_clbits[i]].tolist()
# Single-shot level 1 data
if len(mem.shape) == 3:
sub_data["memory"] = mem[:, composite_clbits[i]].tolist()
else:
sub_data["memory"] = datum["memory"]
marginalized_data[index].append(sub_data)

# Sort by index
return [marginalized_data[i] for i in sorted(marginalized_data.keys())]

@staticmethod
def _format_memory(datum: Dict, composite_clbits: List):
"""A helper method to convert level 2 memory (if it exists) to bit-string format."""
f_memory = None
if (
"memory" in datum
and composite_clbits is not None
and isinstance(datum["memory"][0], str)
):
num_cbits = 1 + max(cbit for cbit_list in composite_clbits for cbit in cbit_list)
header = {"memory_slots": num_cbits}
f_memory = list(format_counts_memory(shot, header) for shot in datum["memory"])

return f_memory

def _add_child_data(self, experiment_data: ExperimentData):
"""Save empty component experiment data as child data.
Expand Down
2 changes: 2 additions & 0 deletions qiskit_experiments/framework/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,8 @@ def default(self, obj: Any) -> Any: # pylint: disable=arguments-differ
return {"__type__": "spmatrix", "__value__": value}
if isinstance(obj, bytes):
return _serialize_bytes(obj)
if isinstance(obj, np.number):
return obj.item()
if dataclasses.is_dataclass(obj):
return _serialize_object(obj, settings=dataclasses.asdict(obj))
if isinstance(obj, uncertainties.UFloat):
Expand Down
17 changes: 8 additions & 9 deletions qiskit_experiments/library/characterization/cr_hamiltonian.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,22 +157,21 @@ def __init__(
Raises:
QiskitError: When ``qubits`` length is not 2.
"""
super().__init__(qubits, analysis=CrossResonanceHamiltonianAnalysis(), backend=backend)
# backend parameters required to run this experiment
# random values are populated here but these are immediately updated after backend is set
# this is to keep capability of generating circuits just for checking
self._dt = 1
self._cr_channel = 0
self._granularity = 1
self._cr_gate = cr_gate

if len(qubits) != 2:
raise QiskitError(
"Length of qubits is not 2. Please provide index for control and target qubit."
)

super().__init__(qubits, analysis=CrossResonanceHamiltonianAnalysis(), backend=backend)
self.set_experiment_options(flat_top_widths=flat_top_widths, **kwargs)
self._cr_gate = cr_gate

# backend parameters required to run this experiment
# random values are populated here but these are immediately updated after backend is set
# this is to keep capability of generating circuits just for checking
self._dt = 1
self._cr_channel = 0
self._granularity = 1

@classmethod
def _default_experiment_options(cls) -> Options:
Expand Down
5 changes: 1 addition & 4 deletions qiskit_experiments/test/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@
:toctree: ../stubs/
MockIQBackend
MockRamseyXY
MockFineAmp
DragBackend
T1Backend
T2RamseyBackend
FakeJob
Expand All @@ -37,7 +34,7 @@
"""

from .utils import FakeJob
from .mock_iq_backend import MockIQBackend, MockRamseyXY, MockFineAmp, DragBackend
from .mock_iq_backend import MockIQBackend
from .t1_backend import T1Backend
from .t2ramsey_backend import T2RamseyBackend
from .fake_service import FakeService
Loading

0 comments on commit 9926ece

Please sign in to comment.