From 9f5f8fba5145cdfb521a0ed650e2273b8830b158 Mon Sep 17 00:00:00 2001 From: Takashi Imamichi <31178928+t-imamichi@users.noreply.github.com> Date: Fri, 26 Aug 2022 12:11:26 +0900 Subject: [PATCH] Improve performance of `Estimator` and `Sampler` by avoiding deep copy at `circuit_to_instruction`. (#8403) * add simplified circuit_to_instruction * add a safe guard * optimize sampler as well as estimator Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- qiskit/primitives/estimator.py | 4 ++-- qiskit/primitives/sampler.py | 4 ++-- qiskit/primitives/utils.py | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/qiskit/primitives/estimator.py b/qiskit/primitives/estimator.py index b2e1b5215ba1..0715abfcd859 100644 --- a/qiskit/primitives/estimator.py +++ b/qiskit/primitives/estimator.py @@ -30,7 +30,7 @@ from .base_estimator import BaseEstimator from .estimator_result import EstimatorResult from .primitive_job import PrimitiveJob -from .utils import init_circuit, init_observable +from .utils import bound_circuit_to_instruction, init_circuit, init_observable class Estimator(BaseEstimator): @@ -114,7 +114,7 @@ def _call( f"The number of qubits of a circuit ({circ.num_qubits}) does not match " f"the number of qubits of a observable ({obs.num_qubits})." ) - final_state = Statevector(circ) + final_state = Statevector(bound_circuit_to_instruction(circ)) expectation_value = final_state.expectation_value(obs) if shots is None: expectation_values.append(expectation_value) diff --git a/qiskit/primitives/sampler.py b/qiskit/primitives/sampler.py index 5626ec5416ba..f9c1c2910ecb 100644 --- a/qiskit/primitives/sampler.py +++ b/qiskit/primitives/sampler.py @@ -29,7 +29,7 @@ from .base_sampler import BaseSampler from .primitive_job import PrimitiveJob from .sampler_result import SamplerResult -from .utils import final_measurement_mapping, init_circuit +from .utils import bound_circuit_to_instruction, final_measurement_mapping, init_circuit class Sampler(BaseSampler): @@ -113,7 +113,7 @@ def _call( ) qargs_list.append(self._qargs_list[i]) probabilities = [ - Statevector(circ).probabilities(qargs=qargs) + Statevector(bound_circuit_to_instruction(circ)).probabilities(qargs=qargs) for circ, qargs in zip(bound_circuits, qargs_list) ] if shots is not None: diff --git a/qiskit/primitives/utils.py b/qiskit/primitives/utils.py index 1e2c16ccad3c..36fbae8f15f9 100644 --- a/qiskit/primitives/utils.py +++ b/qiskit/primitives/utils.py @@ -15,7 +15,7 @@ from __future__ import annotations -from qiskit.circuit import ParameterExpression, QuantumCircuit +from qiskit.circuit import ParameterExpression, QuantumCircuit, Instruction from qiskit.extensions.quantum_initializer.initializer import Initialize from qiskit.opflow import PauliSumOp from qiskit.quantum_info import SparsePauliOp, Statevector @@ -111,3 +111,35 @@ def final_measurement_mapping(circuit: QuantumCircuit) -> dict[int, int]: # Sort so that classical bits are in numeric order low->high. mapping = dict(sorted(mapping.items(), key=lambda item: item[1])) return mapping + + +def bound_circuit_to_instruction(circuit: QuantumCircuit) -> Instruction: + """Build an :class:`~qiskit.circuit.Instruction` object from + a :class:`~qiskit.circuit.QuantumCircuit` + + This is a specialized version of :func:`~qiskit.converters.circuit_to_instruction` + to avoid deep copy. This requires a quantum circuit whose parameters are all bound. + Because this does not take a copy of the input circuit, this assumes that the input + circuit won't be modified. + + If https://github.com/Qiskit/qiskit-terra/issues/7983 is resolved, + we can remove this function. + + Args: + circuit(QuantumCircuit): Input quantum circuit + + Returns: + An :class:`~qiskit.circuit.Instruction` object + """ + if len(circuit.qregs) > 1: + return circuit.to_instruction() + + # len(circuit.qregs) == 1 -> No need to flatten qregs + inst = Instruction( + name=circuit.name, + num_qubits=circuit.num_qubits, + num_clbits=circuit.num_clbits, + params=[], + ) + inst.definition = circuit + return inst