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

Fix storing of component metadata in composite experiment #510

Merged
merged 3 commits into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 12 additions & 12 deletions qiskit_experiments/framework/base_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ def run(
# Run jobs
jobs = experiment._run_jobs(circuits, **run_opts)
experiment_data.add_data(jobs)
experiment._add_job_metadata(experiment_data, jobs, **run_opts)
experiment._add_job_metadata(experiment_data.metadata, jobs, **run_opts)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks bit tricky to me, because ExperimentData.metadata only provides the getter and the metadata is defined as a protected instance member. Indeed this overrides the protected data by using mutablility of python dict (I'm fine with this if the metadata is a public member).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its same with circuit.metadata, it returns a dict that you are free to updated.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough


# Optionally run analysis
if analysis and self.__analysis_class__ is not None:
Expand Down Expand Up @@ -515,7 +515,6 @@ def _metadata(self) -> Dict[str, any]:
"experiment_type": self._type,
"num_qubits": self.num_qubits,
"physical_qubits": list(self.physical_qubits),
"job_metadata": [],
}
# Add additional metadata if subclasses specify it
for key, val in self._additional_metadata().items():
Expand All @@ -530,22 +529,23 @@ def _additional_metadata(self) -> Dict[str, any]:
"""
return {}

def _add_job_metadata(self, experiment_data: ExperimentData, jobs: BaseJob, **run_options):
def _add_job_metadata(self, metadata: Dict[str, Any], jobs: BaseJob, **run_options):
"""Add runtime job metadata to ExperimentData.

Args:
experiment_data: the experiment data container.
metadata: the metadata dict to update with job data.
jobs: the job objects.
run_options: backend run options for the job.
"""
metadata = {
"job_ids": [job.job_id() for job in jobs],
"experiment_options": copy.copy(self.experiment_options.__dict__),
"transpile_options": copy.copy(self.transpile_options.__dict__),
"analysis_options": copy.copy(self.analysis_options.__dict__),
"run_options": copy.copy(run_options),
}
experiment_data._metadata["job_metadata"].append(metadata)
metadata["job_metadata"] = [
{
"job_ids": [job.job_id() for job in jobs],
"experiment_options": copy.copy(self.experiment_options.__dict__),
"transpile_options": copy.copy(self.transpile_options.__dict__),
"analysis_options": copy.copy(self.analysis_options.__dict__),
"run_options": copy.copy(run_options),
}
]


def fix_class_docs(wrapped_cls):
Expand Down
9 changes: 4 additions & 5 deletions qiskit_experiments/framework/composite/composite_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,9 @@ def _run_analysis(self, experiment_data: ExperimentData, **options):
# analysis classes
composite_exp = experiment_data.experiment
component_exps = composite_exp.component_experiment()
if "component_job_metadata" in experiment_data.metadata:
component_metadata = experiment_data.metadata["component_job_metadata"][-1]
else:
component_metadata = [{}] * composite_exp.num_experiments
component_metadata = experiment_data.metadata.get(
"component_metadata", [{}] * composite_exp.num_experiments
)

# Initialize component data for updating and get the experiment IDs for
# the component child experiments in case there are other child experiments
Expand All @@ -94,7 +93,7 @@ def _run_analysis(self, experiment_data: ExperimentData, **options):
sub_exp_data.add_data(sub_data)

# Add component job metadata
sub_exp_data.metadata["job_metadata"] = [component_metadata[i]]
sub_exp_data.metadata.update(component_metadata[i])

# Run analysis
# Since copy for replace result is handled at the parent level
Expand Down
27 changes: 10 additions & 17 deletions qiskit_experiments/framework/composite/composite_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
Composite Experiment abstract base class.
"""

import copy
from typing import List, Sequence, Optional
from abc import abstractmethod
import warnings
Expand Down Expand Up @@ -93,13 +92,17 @@ def _initialize_experiment_data(self):
return experiment_data

def _additional_metadata(self):
return {"component_job_metadata": []}
"""Add component experiment metadata"""
return {
"component_metadata": [sub_exp._metadata() for sub_exp in self.component_experiment()]
}

def _add_job_metadata(self, experiment_data, jobs, **run_options):
# Extract component metadata
component_metadata = []
def _add_job_metadata(self, metadata, jobs, **run_options):
super()._add_job_metadata(metadata, jobs, **run_options)
# Add sub-experiment options
for sub_exp in self.component_experiment():
for sub_metadata, sub_exp in zip(
metadata["component_metadata"], self.component_experiment()
):
# Run and transpile options are always overridden
if (
sub_exp.run_options != sub_exp._default_run_options()
Expand All @@ -109,17 +112,7 @@ def _add_job_metadata(self, experiment_data, jobs, **run_options):
"Sub-experiment run and transpile options"
" are overridden by composite experiment options."
)
component_metadata.append(
{
"job_ids": [job.job_id() for job in jobs],
"experiment_options": copy.copy(sub_exp.experiment_options.__dict__),
"transpile_options": copy.copy(sub_exp.transpile_options.__dict__),
"analysis_options": copy.copy(sub_exp.analysis_options.__dict__),
"run_options": copy.copy(run_options),
}
)
super()._add_job_metadata(experiment_data, jobs, **run_options)
experiment_data._metadata["component_job_metadata"].append(component_metadata)
sub_exp._add_job_metadata(sub_metadata, jobs, **run_options)

def _postprocess_transpiled_circuits(self, circuits, **run_options):
for expr in self._experiments:
Expand Down