From 860ae072cc1e78ef2f0654a2e91e87d48d146a43 Mon Sep 17 00:00:00 2001 From: Arianne Meijer Date: Thu, 17 Oct 2024 16:19:15 +0300 Subject: [PATCH] Remove circuit validation when sending a circuit with IQMClient (#136) * Added basic support for MOVE operations * File cleanup * Validate move gate with correct arguments * Added move gate validation * initial implementation of transpiler tests * Improved testing and operation validation to check against what is calibrated rather than assuming all operation in the gateset areallowed * wip add transpiler * Improved test coverage * Version bumb for iqm-client * Version bumb iqm-client * Version bump iqm-client * Added qubit subset option for routing. * Exposed transpile method to users directly * Updated documentation * Added compiler option support to the IQM Sampler * Update to iqm-client==18.0 * Fix formatting * Fix automatic Merge resolver * Added reviewer feedback * Removed circuit validation in create_run_request * update changelog * update changelog * Removed duplicate code * removed duplicate code * Adding pylint disable that isn't recognised locally * Remove duplicated test code * Added some test documentation * Updates for compatibility with iqm-client --------- Co-authored-by: Arianne Meijer --- CHANGELOG.rst | 7 +++++++ src/iqm/cirq_iqm/iqm_sampler.py | 16 ++++++---------- tests/test_iqm_sampler.py | 22 +++++++++++++++++++--- tox.ini | 2 ++ 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d4b57332..33bbb109 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,13 @@ Changelog ========= +Version 14.6 +============ + +* Bugfix COMP-1491: Fixed issue where `cirq_iqm` would ignore the MOVE gate validation options in CircuitCompilationOptions. `#136 `_ +* Removed `cirq_iqm` circuit validation when submitting to an IQM device because `iqm-client` already validates the circuit. +* Added `isort` formatting to `tox -e format`. + Version 14.5 ============ diff --git a/src/iqm/cirq_iqm/iqm_sampler.py b/src/iqm/cirq_iqm/iqm_sampler.py index 77575485..ca22edbe 100644 --- a/src/iqm/cirq_iqm/iqm_sampler.py +++ b/src/iqm/cirq_iqm/iqm_sampler.py @@ -29,7 +29,7 @@ from iqm.cirq_iqm.devices.iqm_device import IQMDevice, IQMDeviceMetadata from iqm.cirq_iqm.serialize import serialize_circuit -from iqm.iqm_client import Circuit, CircuitCompilationOptions, IQMClient, JobAbortionError, RunRequest +from iqm.iqm_client import CircuitCompilationOptions, IQMClient, JobAbortionError, RunRequest class IQMSampler(cirq.work.Sampler): @@ -143,7 +143,10 @@ def create_run_request( if isinstance(programs, cirq.Circuit): programs, _ = self._resolve_parameters(programs, params) - serialized_circuits = self._validate_and_serialize_circuits(programs) + serialized_circuits = [serialize_circuit(circuit) for circuit in programs] + + if not self._client: + raise RuntimeError('Cannot submit circuits since session to IQM client has been closed.') return self._client.create_run_request( serialized_circuits, @@ -188,7 +191,7 @@ def _send_circuits( return ( # pylint: disable=not-an-iterable,no-member [{k: np.array(v) for k, v in measurements.items()} for measurements in results.measurements], - ResultMetadata(job_id, results.metadata.calibration_set_id, results.metadata.request), + ResultMetadata(job_id, results.metadata.calibration_set_id, run_request), ) @staticmethod @@ -199,13 +202,6 @@ def _resolve_parameters( circuits = [cirq.protocols.resolve_parameters(program, res) for res in resolvers] if resolvers else [program] return circuits, resolvers - def _validate_and_serialize_circuits(self, circuits: list[cirq.Circuit]) -> list[Circuit]: - if not self._client: - raise RuntimeError('Cannot submit circuits since session to IQM client has been closed.') - for circuit in circuits: - self._device.validate_circuit(circuit) - return [serialize_circuit(circuit) for circuit in circuits] - @dataclass class ResultMetadata: diff --git a/tests/test_iqm_sampler.py b/tests/test_iqm_sampler.py index 1de4f293..4e921c6f 100644 --- a/tests/test_iqm_sampler.py +++ b/tests/test_iqm_sampler.py @@ -16,7 +16,7 @@ import uuid import cirq -from mockito import ANY, expect, mock, verify, verifyNoUnwantedInteractions, when +from mockito import ANY, expect, mock, unstub, verify, verifyNoUnwantedInteractions, when import numpy as np import pytest import sympy # type: ignore @@ -28,6 +28,7 @@ from iqm.iqm_client import ( Circuit, CircuitCompilationOptions, + CircuitValidationError, HeraldingMode, Instruction, IQMClient, @@ -99,7 +100,11 @@ def run_request(): @pytest.mark.usefixtures('unstub') def test_run_sweep_raises_with_non_physical_names(adonis_sampler, circuit_non_physical): - with pytest.raises(ValueError, match='Qubit not on device'): + when(adonis_sampler._client).get_quantum_architecture().thenReturn( + adonis_sampler._device.metadata.to_architecture() + ) + # Note that validation is done in iqm_client, so this is now an integration test. + with pytest.raises(CircuitValidationError, match='Qubit Alice is not allowed as locus for measure'): adonis_sampler.run_sweep(circuit_non_physical, None) @@ -245,6 +250,10 @@ def test_run_sweep_executes_circuit_with_heralding_mode_zeros( 'options': CircuitCompilationOptions(heralding_mode=HeraldingMode.ZEROS) } assert sampler._compiler_options.heralding_mode == HeraldingMode.ZEROS + kwargs = create_run_request_default_kwargs | { + 'options': CircuitCompilationOptions(heralding_mode=HeraldingMode.ZEROS) + } + assert sampler._compiler_options.heralding_mode == HeraldingMode.ZEROS when(client).create_run_request(ANY, **kwargs).thenReturn(run_request) when(client).submit_run_request(run_request).thenReturn(job_id) when(client).wait_for_results(job_id).thenReturn(run_result) @@ -329,9 +338,16 @@ def test_run_sweep_abort_job_failed( @pytest.mark.usefixtures('unstub') def test_run_iqm_batch_raises_with_non_physical_names(adonis_sampler, circuit_non_physical): - with pytest.raises(ValueError, match='Qubit not on device'): + when(adonis_sampler._client).get_quantum_architecture().thenReturn( + adonis_sampler._device.metadata.to_architecture() + ) + # Note that validation is done in iqm_client, so this is now an integration test. + with pytest.raises(CircuitValidationError, match='Qubit Alice is not allowed as locus for measure'): adonis_sampler.run_iqm_batch([circuit_non_physical]) + verifyNoUnwantedInteractions() + unstub() + @pytest.mark.usefixtures('unstub') def test_run(adonis_sampler, iqm_metadata, create_run_request_default_kwargs, job_id): diff --git a/tox.ini b/tox.ini index 6992dc2f..c80348e5 100644 --- a/tox.ini +++ b/tox.ini @@ -41,8 +41,10 @@ skip_install = True changedir = {toxinidir} deps = black ~= 23.12 + isort ~= 5.13 commands = black src tests + isort src tests [testenv:docs] description =