From 354759babeb1f550e706d314daddcd7309fb274f Mon Sep 17 00:00:00 2001 From: ikkoham Date: Wed, 13 Sep 2023 00:04:06 +0900 Subject: [PATCH 1/6] Improve performance of sampler parameter-binds --- qiskit_aer/primitives/sampler.py | 56 ++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/qiskit_aer/primitives/sampler.py b/qiskit_aer/primitives/sampler.py index 286d7df0fe..0efeea39af 100644 --- a/qiskit_aer/primitives/sampler.py +++ b/qiskit_aer/primitives/sampler.py @@ -88,25 +88,30 @@ def _call( is_shots_none = "shots" in run_options and run_options["shots"] is None self._transpile(circuits, is_shots_none) - experiments = [] - parameter_binds = [] + experiment_manager = _ExperimentManager() for i, value in zip(circuits, parameter_values): if len(value) != len(self._parameters[i]): raise QiskitError( f"The number of values ({len(value)}) does not match " f"the number of parameters ({len(self._parameters[i])})." ) - parameter_binds.append({k: [v] for k, v in zip(self._parameters[i], value)}) - experiments.append(self._transpiled_circuits[(i, is_shots_none)]) + + experiment_manager.append( + key=i, + parameter_bind=dict(zip(self._parameters[i], value)), + experiment_circuit=self._transpiled_circuits[(i, is_shots_none)], + ) result = self._backend.run( - experiments, parameter_binds=parameter_binds, **run_options + experiment_manager.experiment_circuits, + parameter_binds=experiment_manager.parameter_binds, + **run_options, ).result() # Postprocessing metadata = [] quasis = [] - for i in range(len(experiments)): + for i in experiment_manager.experiment_indices: if is_shots_none: probabilities = result.data(i)["probabilities"] num_qubits = result.results[i].metadata["num_qubits"] @@ -186,3 +191,42 @@ def _transpile(self, circuit_indices: Sequence[int], is_shots_none: bool): ) for i, circuit in zip(to_handle, circuits): self._transpiled_circuits[(i, is_shots_none)] = circuit + + +class _ExperimentManager: + def __init__(self): + self.keys: list[int] = [] + self.experiment_circuits: list[QuantumCircuit] = [] + self.parameter_binds: list[dict[ParameterExpression, list[float]]] = [] + self._input_indices: list[list[int]] = [] + self._num_experiment: int = 0 + + def __len__(self): + return self._num_experiment + + @property + def experiment_indices(self): + """indices of experiments""" + return sum(self._input_indices, []) + + def append( + self, + key: tuple[int, int], + parameter_bind: dict[ParameterExpression, float], + experiment_circuit: QuantumCircuit, + ): + """append experiments""" + if key not in self.keys or not parameter_bind: + self.experiment_circuits.append(experiment_circuit) + + if parameter_bind and key in self.keys: + key_index = self.keys.index(key) + for k, vs in self.parameter_binds[key_index].items(): + vs.append(parameter_bind[k]) + self._input_indices[key_index].append(self._num_experiment) + else: + self.keys.append(key) + self.parameter_binds.append({k: [v] for k, v in parameter_bind.items()}) + self._input_indices.append([self._num_experiment]) + + self._num_experiment += 1 From 22a6a980fc34148961af6744342dd97fef3f1714 Mon Sep 17 00:00:00 2001 From: ikkoham Date: Wed, 13 Sep 2023 00:37:45 +0900 Subject: [PATCH 2/6] lint --- qiskit_aer/primitives/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_aer/primitives/sampler.py b/qiskit_aer/primitives/sampler.py index 0efeea39af..51696a70e8 100644 --- a/qiskit_aer/primitives/sampler.py +++ b/qiskit_aer/primitives/sampler.py @@ -18,7 +18,7 @@ from collections.abc import Sequence -from qiskit.circuit import QuantumCircuit +from qiskit.circuit import ParameterExpression, QuantumCircuit from qiskit.compiler import transpile from qiskit.exceptions import QiskitError from qiskit.primitives import BaseSampler, SamplerResult From 02b48e6fdd2417c1a2fac55c983e3066b9226f2c Mon Sep 17 00:00:00 2001 From: ikkoham Date: Wed, 13 Sep 2023 11:15:16 +0900 Subject: [PATCH 3/6] fix order --- qiskit_aer/primitives/sampler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiskit_aer/primitives/sampler.py b/qiskit_aer/primitives/sampler.py index 51696a70e8..cc1dc12b62 100644 --- a/qiskit_aer/primitives/sampler.py +++ b/qiskit_aer/primitives/sampler.py @@ -18,6 +18,7 @@ from collections.abc import Sequence +import numpy as np from qiskit.circuit import ParameterExpression, QuantumCircuit from qiskit.compiler import transpile from qiskit.exceptions import QiskitError @@ -207,7 +208,7 @@ def __len__(self): @property def experiment_indices(self): """indices of experiments""" - return sum(self._input_indices, []) + return np.argsort(sum(self._input_indices, [])).tolist() def append( self, From a43ecb2df50075629e54d6b7e02ca729a14a8ef6 Mon Sep 17 00:00:00 2001 From: ikkoham Date: Wed, 13 Sep 2023 11:34:55 +0900 Subject: [PATCH 4/6] add reno --- releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml diff --git a/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml b/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml new file mode 100644 index 0000000000..5feec8fd02 --- /dev/null +++ b/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml @@ -0,0 +1,5 @@ +--- +--- +upgrade: + - | + Improved performance when the same circuits and multiple parameters are passed to :class:`~.Sampler`. From cd8c8ca87d01ff492f1455c7256c03e6e6462d07 Mon Sep 17 00:00:00 2001 From: ikkoham Date: Wed, 13 Sep 2023 13:44:00 +0900 Subject: [PATCH 5/6] refactor --- qiskit_aer/primitives/sampler.py | 4 +--- releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/qiskit_aer/primitives/sampler.py b/qiskit_aer/primitives/sampler.py index cc1dc12b62..fa988dfbd9 100644 --- a/qiskit_aer/primitives/sampler.py +++ b/qiskit_aer/primitives/sampler.py @@ -217,15 +217,13 @@ def append( experiment_circuit: QuantumCircuit, ): """append experiments""" - if key not in self.keys or not parameter_bind: - self.experiment_circuits.append(experiment_circuit) - if parameter_bind and key in self.keys: key_index = self.keys.index(key) for k, vs in self.parameter_binds[key_index].items(): vs.append(parameter_bind[k]) self._input_indices[key_index].append(self._num_experiment) else: + self.experiment_circuits.append(experiment_circuit) self.keys.append(key) self.parameter_binds.append({k: [v] for k, v in parameter_bind.items()}) self._input_indices.append([self._num_experiment]) diff --git a/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml b/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml index 5feec8fd02..d50d97ce9f 100644 --- a/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml +++ b/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml @@ -2,4 +2,5 @@ --- upgrade: - | - Improved performance when the same circuits and multiple parameters are passed to :class:`~.Sampler`. + Improved performance when the same circuits and multiple parameters are passed to + :class:`~.Sampler`. From be952be2ee365f6f080e3bcf4560996bd37516e5 Mon Sep 17 00:00:00 2001 From: Ikko Hamamura Date: Wed, 13 Sep 2023 16:35:24 +0900 Subject: [PATCH 6/6] Update releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml --- releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml b/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml index d50d97ce9f..5b8e1f2778 100644 --- a/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml +++ b/releasenotes/notes/sampler-performance-81e1649ec4657aad.yaml @@ -1,5 +1,4 @@ --- ---- upgrade: - | Improved performance when the same circuits and multiple parameters are passed to