From 64eaab2d7b62141a5490f5fe81036d92f6bc8538 Mon Sep 17 00:00:00 2001 From: Toru Shibamiya Date: Tue, 14 May 2024 12:32:11 +0900 Subject: [PATCH 1/7] Add return for BackendV1 AerSimulator --- packages/qiskit/quri_parts/qiskit/backend/utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/qiskit/quri_parts/qiskit/backend/utils.py b/packages/qiskit/quri_parts/qiskit/backend/utils.py index 20be9fc3..07eb4133 100644 --- a/packages/qiskit/quri_parts/qiskit/backend/utils.py +++ b/packages/qiskit/quri_parts/qiskit/backend/utils.py @@ -74,13 +74,17 @@ def _set_max_shot_to_default() -> int: if not isinstance(backend, (BackendV1, BackendV2)): raise BackendError("Backend not supported.") + # BackendV1 if isinstance(backend, BackendV1): max_shots = getattr( backend.configuration(), "max_shots", _set_max_shot_to_default() ) if max_shots > 0: return 1, max_shots + else: + return 1, _set_max_shot_to_default() + # BackendV2 if hasattr(backend, "max_shots"): return 1, backend.max_shots elif hasattr(backend, "configuration"): From 56293bd06cf126848a17134fea6910c6f740590a Mon Sep 17 00:00:00 2001 From: Toru Shibamiya Date: Tue, 14 May 2024 15:41:53 +0900 Subject: [PATCH 2/7] Fix --- .../qiskit/quri_parts/qiskit/backend/utils.py | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/packages/qiskit/quri_parts/qiskit/backend/utils.py b/packages/qiskit/quri_parts/qiskit/backend/utils.py index 07eb4133..a5b2e91c 100644 --- a/packages/qiskit/quri_parts/qiskit/backend/utils.py +++ b/packages/qiskit/quri_parts/qiskit/backend/utils.py @@ -74,25 +74,15 @@ def _set_max_shot_to_default() -> int: if not isinstance(backend, (BackendV1, BackendV2)): raise BackendError("Backend not supported.") - # BackendV1 - if isinstance(backend, BackendV1): + if hasattr(backend, "max_shots"): + return 1, backend.max_shots + if hasattr(backend, "configuration"): max_shots = getattr( backend.configuration(), "max_shots", _set_max_shot_to_default() ) if max_shots > 0: return 1, max_shots - else: - return 1, _set_max_shot_to_default() - - # BackendV2 - if hasattr(backend, "max_shots"): - return 1, backend.max_shots - elif hasattr(backend, "configuration"): - return 1, getattr( - backend.configuration(), "max_shots", _set_max_shot_to_default() - ) - else: - return 1, _set_max_shot_to_default() + return 1, _set_max_shot_to_default() def get_job_mapper_and_circuit_transpiler( @@ -124,16 +114,14 @@ def get_job_mapper_and_circuit_transpiler( circuit_transpiler = SequentialTranspiler( [circuit_transpiler, mapper.circuit_transpiler] ) - composite_job_qubit_mapper: Callable[ - [SamplingJob], SamplingJob - ] = lambda job: QubitMappedSamplingJob( - job, mapper + composite_job_qubit_mapper: Callable[[SamplingJob], SamplingJob] = ( + lambda job: QubitMappedSamplingJob(job, mapper) ) # noqa: E731 return composite_job_qubit_mapper, circuit_transpiler else: - simple_job_qubit_mapper: Callable[ - [SamplingJob], SamplingJob - ] = lambda job: job # noqa: E731 + simple_job_qubit_mapper: Callable[[SamplingJob], SamplingJob] = ( + lambda job: job + ) # noqa: E731 return simple_job_qubit_mapper, circuit_transpiler From bc451ff8a067490b3b1f2621ff6e8f2cabc55a8b Mon Sep 17 00:00:00 2001 From: Toru Shibamiya Date: Tue, 14 May 2024 17:03:36 +0900 Subject: [PATCH 3/7] Fix failing checks (linter) --- packages/qiskit/quri_parts/qiskit/backend/utils.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/qiskit/quri_parts/qiskit/backend/utils.py b/packages/qiskit/quri_parts/qiskit/backend/utils.py index a5b2e91c..bd3b06d3 100644 --- a/packages/qiskit/quri_parts/qiskit/backend/utils.py +++ b/packages/qiskit/quri_parts/qiskit/backend/utils.py @@ -114,14 +114,16 @@ def get_job_mapper_and_circuit_transpiler( circuit_transpiler = SequentialTranspiler( [circuit_transpiler, mapper.circuit_transpiler] ) - composite_job_qubit_mapper: Callable[[SamplingJob], SamplingJob] = ( - lambda job: QubitMappedSamplingJob(job, mapper) + composite_job_qubit_mapper: Callable[ + [SamplingJob], SamplingJob + ] = lambda job: QubitMappedSamplingJob( + job, mapper ) # noqa: E731 return composite_job_qubit_mapper, circuit_transpiler else: - simple_job_qubit_mapper: Callable[[SamplingJob], SamplingJob] = ( - lambda job: job - ) # noqa: E731 + simple_job_qubit_mapper: Callable[ + [SamplingJob], SamplingJob + ] = lambda job: job # noqa: E731 return simple_job_qubit_mapper, circuit_transpiler From d2992a7681079ed7b124f33103d782af0379c04d Mon Sep 17 00:00:00 2001 From: Toru Shibamiya Date: Thu, 16 May 2024 13:41:04 +0900 Subject: [PATCH 4/7] Add tests --- .../qiskit/tests/qiskit/backend/test_utils.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/packages/qiskit/tests/qiskit/backend/test_utils.py b/packages/qiskit/tests/qiskit/backend/test_utils.py index 048af590..35869342 100644 --- a/packages/qiskit/tests/qiskit/backend/test_utils.py +++ b/packages/qiskit/tests/qiskit/backend/test_utils.py @@ -8,14 +8,24 @@ # See the License for the specific language governing permissions and # limitations under the License. +from unittest.mock import Mock + +import pytest +from qiskit_ibm_runtime import IBMBackend +from quri_parts.backend import BackendError from quri_parts.circuit import NonParametricQuantumCircuit, QuantumCircuit + +from qiskit.providers.backend import Backend, BackendV1, BackendV2 +from qiskit.providers.models import QasmBackendConfiguration from quri_parts.qiskit.backend import ( QiskitSavedDataSamplingJob, QiskitSavedDataSamplingResult, convert_qiskit_sampling_count_to_qp_sampling_count, distribute_backend_shots, + get_backend_min_max_shot, get_job_mapper_and_circuit_transpiler, ) +from quri_parts.qiskit.backend.utils import DEFAULT_MAX_SHOT class TestDistributeBackendShots: @@ -121,3 +131,57 @@ def test_convert_qiskit_sampling_count_to_qp_sampling_count() -> None: {"00": 1, "01": 2, "10": 3, "11": 4} ) assert converted_sampling_count == {0: 1, 1: 2, 2: 3, 3: 4} + + +def test_get_backend_min_max_shot() -> None: + backend = Mock(spec=Backend) + with pytest.raises(BackendError, match="Backend not supported"): + get_backend_min_max_shot(backend) + + backend = Mock(spec=BackendV1) + conf = Mock(spec=QasmBackendConfiguration) + conf.max_shots = int(1e3) + backend.configuration.return_value = conf + min_shots, max_shots = get_backend_min_max_shot(backend) + assert min_shots == 1 + assert max_shots == int(1e3) + + backend = Mock(spec=BackendV1) + conf = Mock(spec=QasmBackendConfiguration) + backend.configuration.return_value = conf + with pytest.warns( + UserWarning, + match=( + "No max_shots setting is found. " + "The max shot is set to default value 1000000" + ), + ): + min_shots, max_shots = get_backend_min_max_shot(backend) + assert min_shots == 1 + assert max_shots == DEFAULT_MAX_SHOT + + backend = Mock(spec=BackendV2) + backend.max_shots = 10 + min_shots, max_shots = get_backend_min_max_shot(backend) + assert min_shots == 1 + assert max_shots == 10 + + backend = Mock(spec=BackendV2) + with pytest.warns( + UserWarning, + match=( + "No max_shots setting is found. " + "The max shot is set to default value 1000000" + ), + ): + min_shots, max_shots = get_backend_min_max_shot(backend) + assert min_shots == 1 + assert max_shots == DEFAULT_MAX_SHOT + + backend = Mock(spec=IBMBackend) + conf = Mock(spec=QasmBackendConfiguration) + conf.max_shots = int(1e3) + backend.configuration.return_value = conf + min_shots, max_shots = get_backend_min_max_shot(backend) + assert min_shots == 1 + assert max_shots == 1000 From e15327d7bd072a1ca8baeb312c094f39535b700a Mon Sep 17 00:00:00 2001 From: Toru Shibamiya Date: Thu, 16 May 2024 13:49:29 +0900 Subject: [PATCH 5/7] Fix failing checks (isort) --- packages/qiskit/tests/qiskit/backend/test_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/qiskit/tests/qiskit/backend/test_utils.py b/packages/qiskit/tests/qiskit/backend/test_utils.py index 35869342..e6d1690b 100644 --- a/packages/qiskit/tests/qiskit/backend/test_utils.py +++ b/packages/qiskit/tests/qiskit/backend/test_utils.py @@ -11,12 +11,12 @@ from unittest.mock import Mock import pytest +from qiskit.providers.backend import Backend, BackendV1, BackendV2 +from qiskit.providers.models import QasmBackendConfiguration from qiskit_ibm_runtime import IBMBackend + from quri_parts.backend import BackendError from quri_parts.circuit import NonParametricQuantumCircuit, QuantumCircuit - -from qiskit.providers.backend import Backend, BackendV1, BackendV2 -from qiskit.providers.models import QasmBackendConfiguration from quri_parts.qiskit.backend import ( QiskitSavedDataSamplingJob, QiskitSavedDataSamplingResult, From f220b40dcc33a7d6c4653c477280a7587b523953 Mon Sep 17 00:00:00 2001 From: Toru Shibamiya Date: Thu, 16 May 2024 21:51:29 +0900 Subject: [PATCH 6/7] Bug fix. Add test cases --- .../qiskit/quri_parts/qiskit/backend/utils.py | 23 +++++----- .../qiskit/tests/qiskit/backend/test_utils.py | 43 +++++++++++++++++++ 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/packages/qiskit/quri_parts/qiskit/backend/utils.py b/packages/qiskit/quri_parts/qiskit/backend/utils.py index bd3b06d3..3c34aa33 100644 --- a/packages/qiskit/quri_parts/qiskit/backend/utils.py +++ b/packages/qiskit/quri_parts/qiskit/backend/utils.py @@ -75,13 +75,16 @@ def _set_max_shot_to_default() -> int: raise BackendError("Backend not supported.") if hasattr(backend, "max_shots"): - return 1, backend.max_shots - if hasattr(backend, "configuration"): + max_shots = backend.max_shots + elif hasattr(backend, "configuration"): max_shots = getattr( backend.configuration(), "max_shots", _set_max_shot_to_default() ) - if max_shots > 0: - return 1, max_shots + else: + max_shots = _set_max_shot_to_default() + + if max_shots > 0: + return 1, max_shots return 1, _set_max_shot_to_default() @@ -114,16 +117,14 @@ def get_job_mapper_and_circuit_transpiler( circuit_transpiler = SequentialTranspiler( [circuit_transpiler, mapper.circuit_transpiler] ) - composite_job_qubit_mapper: Callable[ - [SamplingJob], SamplingJob - ] = lambda job: QubitMappedSamplingJob( - job, mapper + composite_job_qubit_mapper: Callable[[SamplingJob], SamplingJob] = ( + lambda job: QubitMappedSamplingJob(job, mapper) ) # noqa: E731 return composite_job_qubit_mapper, circuit_transpiler else: - simple_job_qubit_mapper: Callable[ - [SamplingJob], SamplingJob - ] = lambda job: job # noqa: E731 + simple_job_qubit_mapper: Callable[[SamplingJob], SamplingJob] = ( + lambda job: job + ) # noqa: E731 return simple_job_qubit_mapper, circuit_transpiler diff --git a/packages/qiskit/tests/qiskit/backend/test_utils.py b/packages/qiskit/tests/qiskit/backend/test_utils.py index e6d1690b..4f515e5e 100644 --- a/packages/qiskit/tests/qiskit/backend/test_utils.py +++ b/packages/qiskit/tests/qiskit/backend/test_utils.py @@ -160,6 +160,21 @@ def test_get_backend_min_max_shot() -> None: assert min_shots == 1 assert max_shots == DEFAULT_MAX_SHOT + backend = Mock(spec=BackendV1) + conf = Mock(spec=QasmBackendConfiguration) + conf.max_shots = 0 + backend.configuration.return_value = conf + with pytest.warns( + UserWarning, + match=( + "No max_shots setting is found. " + "The max shot is set to default value 1000000" + ), + ): + min_shots, max_shots = get_backend_min_max_shot(backend) + assert min_shots == 1 + assert max_shots == DEFAULT_MAX_SHOT + backend = Mock(spec=BackendV2) backend.max_shots = 10 min_shots, max_shots = get_backend_min_max_shot(backend) @@ -178,6 +193,19 @@ def test_get_backend_min_max_shot() -> None: assert min_shots == 1 assert max_shots == DEFAULT_MAX_SHOT + backend = Mock(spec=BackendV2) + backend.max_shots = 0 + with pytest.warns( + UserWarning, + match=( + "No max_shots setting is found. " + "The max shot is set to default value 1000000" + ), + ): + min_shots, max_shots = get_backend_min_max_shot(backend) + assert min_shots == 1 + assert max_shots == DEFAULT_MAX_SHOT + backend = Mock(spec=IBMBackend) conf = Mock(spec=QasmBackendConfiguration) conf.max_shots = int(1e3) @@ -185,3 +213,18 @@ def test_get_backend_min_max_shot() -> None: min_shots, max_shots = get_backend_min_max_shot(backend) assert min_shots == 1 assert max_shots == 1000 + + backend = Mock(spec=IBMBackend) + conf = Mock(spec=QasmBackendConfiguration) + conf.max_shots = 0 + backend.configuration.return_value = conf + with pytest.warns( + UserWarning, + match=( + "No max_shots setting is found. " + "The max shot is set to default value 1000000" + ), + ): + min_shots, max_shots = get_backend_min_max_shot(backend) + assert min_shots == 1 + assert max_shots == DEFAULT_MAX_SHOT From 2ff49a26d0146ec33f920f4dc7c11dce5b08f1c7 Mon Sep 17 00:00:00 2001 From: Toru Shibamiya Date: Fri, 17 May 2024 09:30:16 +0900 Subject: [PATCH 7/7] Fix failing checks (formatter) --- packages/qiskit/quri_parts/qiskit/backend/utils.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/qiskit/quri_parts/qiskit/backend/utils.py b/packages/qiskit/quri_parts/qiskit/backend/utils.py index 3c34aa33..bb0ef5b7 100644 --- a/packages/qiskit/quri_parts/qiskit/backend/utils.py +++ b/packages/qiskit/quri_parts/qiskit/backend/utils.py @@ -117,14 +117,16 @@ def get_job_mapper_and_circuit_transpiler( circuit_transpiler = SequentialTranspiler( [circuit_transpiler, mapper.circuit_transpiler] ) - composite_job_qubit_mapper: Callable[[SamplingJob], SamplingJob] = ( - lambda job: QubitMappedSamplingJob(job, mapper) + composite_job_qubit_mapper: Callable[ + [SamplingJob], SamplingJob + ] = lambda job: QubitMappedSamplingJob( + job, mapper ) # noqa: E731 return composite_job_qubit_mapper, circuit_transpiler else: - simple_job_qubit_mapper: Callable[[SamplingJob], SamplingJob] = ( - lambda job: job - ) # noqa: E731 + simple_job_qubit_mapper: Callable[ + [SamplingJob], SamplingJob + ] = lambda job: job # noqa: E731 return simple_job_qubit_mapper, circuit_transpiler