-
Notifications
You must be signed in to change notification settings - Fork 131
PR for saving and loading composite experiments #364
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
Changes from all commits
9d87938
563c07f
1674ebe
558a65f
49056e3
ea80555
aeab266
360f04f
257eb70
0006f1f
c7dc857
f399444
db70174
6a81e89
f251a56
1c97c7f
a7a78e5
df3b246
1ad8385
29ae28e
92041e3
7f04300
93607ab
42b617a
8df066f
14a65e6
8c9cfc3
830aa5a
9ad7243
871e361
ee81f54
c84fdf0
3d30308
5472cf0
bee575c
f7d535b
a0b1c55
4148f14
11ccf05
a7938bb
5b6a6f0
20263dd
6a072ea
6c1f5b9
e141fe9
d602aae
a4a4127
13129c5
b8ebad8
5e8ba8b
e347211
adcd38d
d540a5b
90240b0
fd896ef
3fbc4de
1ab63c8
a3c685b
6c909a1
00e57be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,40 +17,35 @@ | |
| from qiskit.result import marginal_counts | ||
| from qiskit.exceptions import QiskitError | ||
| from qiskit_experiments.framework.experiment_data import ExperimentData | ||
| from qiskit_experiments.database_service import DbExperimentDataV1, DatabaseServiceV1 | ||
|
|
||
|
|
||
| class CompositeExperimentData(ExperimentData): | ||
| """Composite experiment data class""" | ||
|
|
||
| def __init__( | ||
| self, | ||
| experiment, | ||
| backend=None, | ||
| job_ids=None, | ||
| ): | ||
| def __init__(self, experiment, backend=None, parent_id=None, job_ids=None): | ||
| """Initialize experiment data. | ||
|
|
||
| Args: | ||
| experiment (CompositeExperiment): experiment object that generated the data. | ||
| backend (Backend): Optional, Backend the experiment runs on. It can either be a | ||
| :class:`~qiskit.providers.Backend` instance or just backend name. | ||
| parent_id (str): Optional, ID of the parent experiment data | ||
| in the setting of a composite experiment. | ||
| job_ids (list[str]): Optional, IDs of jobs submitted for the experiment. | ||
|
|
||
| Raises: | ||
| ExperimentError: If an input argument is invalid. | ||
| """ | ||
|
|
||
| super().__init__( | ||
| experiment, | ||
| backend=backend, | ||
| job_ids=job_ids, | ||
| ) | ||
| super().__init__(experiment, backend=backend, parent_id=parent_id, job_ids=job_ids) | ||
|
|
||
| # Initialize sub experiments | ||
| self._components = [ | ||
| expr.__experiment_data__(expr, backend) for expr in experiment._experiments | ||
| expr.__experiment_data__(expr, backend=backend, parent_id=self.experiment_id) | ||
| for expr in experiment._experiments | ||
| ] | ||
|
|
||
| self.metadata["component_ids"] = [comp.experiment_id for comp in self._components] | ||
| self.metadata["component_classes"] = [comp.__class__.__name__ for comp in self._components] | ||
|
|
||
| def __str__(self): | ||
| line = 51 * "-" | ||
| n_res = len(self._analysis_results) | ||
|
|
@@ -103,3 +98,91 @@ def _add_single_data(self, data): | |
| else: | ||
| sub_data["counts"] = data["counts"] | ||
| self._components[index]._add_single_data(sub_data) | ||
|
|
||
| def save(self) -> None: | ||
| super().save() | ||
| for comp in self._components: | ||
| original_verbose = comp.verbose | ||
| comp.verbose = False | ||
| comp.save() | ||
| comp.verbose = original_verbose | ||
|
|
||
| def save_metadata(self) -> None: | ||
| super().save_metadata() | ||
| for comp in self._components: | ||
| comp.save_metadata() | ||
|
|
||
| @classmethod | ||
| def load(cls, experiment_id: str, service: DatabaseServiceV1) -> "CompositeExperimentData": | ||
| expdata = DbExperimentDataV1.load(experiment_id, service) | ||
yaelbh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| components = [] | ||
| for comp_id, comp_class in zip( | ||
| expdata.metadata["component_ids"], expdata.metadata["component_classes"] | ||
| ): | ||
| load_class = globals()[comp_class] | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's going on here?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have to invoke the correct load method, according to the class of the component. So we figure out the class (in |
||
| load_func = getattr(load_class, "load") | ||
| loaded_comp = load_func(comp_id, service) | ||
| components.append(loaded_comp) | ||
|
|
||
| expdata.__class__ = CompositeExperimentData | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a little sketchy and what I tried to avoid in #423. But currently composite experiment data has an issue where it requires I think it might be better to modify the
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But, even when |
||
| expdata._experiment = None | ||
| expdata._components = components | ||
|
|
||
| return expdata | ||
|
|
||
| def _set_service(self, service: DatabaseServiceV1) -> None: | ||
| """Set the service to be used for storing experiment data. | ||
|
|
||
| Args: | ||
| service: Service to be used. | ||
|
|
||
| Raises: | ||
| DbExperimentDataError: If an experiment service is already being used. | ||
| """ | ||
| super()._set_service(service) | ||
| for comp in self._components: | ||
| comp._set_service(service) | ||
|
|
||
| @ExperimentData.share_level.setter | ||
| def share_level(self, new_level: str) -> None: | ||
| """Set the experiment share level. | ||
|
|
||
| Args: | ||
| new_level: New experiment share level. Valid share levels are provider- | ||
| specified. For example, IBM Quantum experiment service allows | ||
| "public", "hub", "group", "project", and "private". | ||
| """ | ||
| self._share_level = new_level | ||
| for comp in self._components: | ||
| original_auto_save = comp.auto_save | ||
| comp.auto_save = False | ||
| comp.share_level = new_level | ||
| comp.auto_save = original_auto_save | ||
| if self.auto_save: | ||
| self.save_metadata() | ||
|
|
||
| def _copy_metadata( | ||
| self, new_instance: Optional["CompositeExperimentData"] = None | ||
| ) -> "CompositeExperimentData": | ||
| """Make a copy of the composite experiment metadata. | ||
|
|
||
| Note: | ||
| This method only copies experiment data and metadata, not its | ||
| figures nor analysis results. The copy also contains a different | ||
| experiment ID. | ||
|
|
||
| Returns: | ||
| A copy of the ``CompositeExperimentData`` object with the same data | ||
| and metadata but different ID. | ||
| """ | ||
| new_instance = super()._copy_metadata(new_instance) | ||
|
|
||
| for original_comp, new_comp in zip( | ||
| self.component_experiment_data(), new_instance.component_experiment_data() | ||
| ): | ||
| original_comp._copy_metadata(new_comp) | ||
|
|
||
| new_instance.metadata["component_ids"] = [ | ||
| comp.experiment_id for comp in new_instance.component_experiment_data() | ||
| ] | ||
| return new_instance | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| features: | ||
| - | | ||
| Adds support for saving and loading :class:`~qiskit_experiments.framework.ParallelExperiment` | ||
| and :class:`~qiskit_experiments.framework.BatchExperiment` experiment data, | ||
| including all their component experiment data and results, to the IBM experiments database service. | ||
|
|
||
| When saving one of these experiments, each component experiment will be saved under a unique experiment ID, | ||
| which references the original parent composite experiment, | ||
| via the :meth:`~qiskit_Expeirments.framework.ExperimentData.parent_id`. | ||
|
|
||
| Note that changing the share level of the parent composite experiment will also change the share level of all component experiments. | ||
|
|
Uh oh!
There was an error while loading. Please reload this page.