diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b9fb379d..e26bf46c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,13 @@ Changelog ========= +Version 13.0 +============ + +* Require iqm-client >= 16.0. +* Remove parameter ``circuit_duration_check`` from ``IQMSampler``. +* Add parameter ``max_circuit_duration_over_t2`` to ``IQMSampler``. + Version 12.2 ============ diff --git a/docs/user_guide.rst b/docs/user_guide.rst index 99629ac2..19f64553 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide.rst @@ -279,13 +279,12 @@ The below table summarises the currently available options: - "f7d9642e-b0ca-4f2d-af2a-30195bd7a76d" - Indicates the calibration set to use. Defaults to `None`, which means the IQM server will use the best available calibration set automatically. - * - `circuit_duration_check` - - bool - - False - - Enable or disable server-side circuit duration checks. The default value is `True`, which means if any job is - estimated to take unreasonably long compared to the coherence times of the qubits, or too long in wall-clock - time, the server will reject it. This option can be used to disable this behaviour. In normal use, the - circuit duration check should always remain enabled. + * - `max_circuit_duration_over_t2` + - float + - 1.0 + - Set server-side circuit disqualification threshold. If any job is estimated to take longer than the T2 time of the qubits + multiplied by this value the server will reject it. Setting this value to ``0.0`` will disable circuit duration check. + The default value ``None`` means the server default value will be used. * - `heralding_mode` - :py:class:`~iqm_client.iqm_client.HeraldingMode` - "zeros" @@ -298,7 +297,7 @@ For example if you would like to use a particular calibration set, you can provi sampler = IQMSampler(iqm_server_url, calibration_set_id="f7d9642e-b0ca-4f2d-af2a-30195bd7a76d") -The same applies for `heralding_mode` and `circuit_duration_check`. The sampler will by default use an +The same applies for `heralding_mode` and `max_circuit_duration_over_t2`. The sampler will by default use an :class:`.IQMDevice` created based on architecture data obtained from the server, which is then available in the :attr:`.IQMSampler.device` property. Alternatively, the device can be specified directly with the ``device`` argument. diff --git a/pyproject.toml b/pyproject.toml index 68004761..5468b7af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ dependencies = [ "numpy", "cirq-core[contrib] ~= 1.2", "ply", # Required by cirq.contrib.qasm_import - "iqm-client >= 15.2, < 16.0" + "iqm-client >= 16.0, < 17.0" ] [project.urls] diff --git a/src/iqm/cirq_iqm/iqm_sampler.py b/src/iqm/cirq_iqm/iqm_sampler.py index 82182076..b42ca7db 100644 --- a/src/iqm/cirq_iqm/iqm_sampler.py +++ b/src/iqm/cirq_iqm/iqm_sampler.py @@ -57,8 +57,9 @@ class IQMSampler(cirq.work.Sampler): ID of the calibration set to use. If ``None``, use the latest one. run_sweep_timeout: timeout to poll sweep results in seconds. - circuit_duration_check: whether to enable or disable server-side circuit duration check - heralding_mode: Heralding mode to use during execution. + max_circuit_duration_over_t2: Circuits are disqualified on the server if they are longer than + this ratio of the T2 time of the qubits. If set to 0.0, no circuits are disqualified. + If set to None the server default value is used. Keyword Args: auth_server_url (str): URL of user authentication server, if required by the IQM Cortex server. @@ -76,7 +77,7 @@ def __init__( *, calibration_set_id: Optional[UUID] = None, run_sweep_timeout: Optional[int] = None, - circuit_duration_check: bool = True, + max_circuit_duration_over_t2: Optional[float] = None, heralding_mode: HeraldingMode = HeraldingMode.NONE, **user_auth_args, # contains keyword args auth_server_url, username and password ): @@ -88,7 +89,7 @@ def __init__( self._device = device self._calibration_set_id = calibration_set_id self._run_sweep_timeout = run_sweep_timeout - self._circuit_duration_check = circuit_duration_check + self._max_circuit_duration_over_t2 = max_circuit_duration_over_t2 self._heralding_mode = heralding_mode @property @@ -175,7 +176,7 @@ def _send_circuits( serialized_circuits, calibration_set_id=self._calibration_set_id, shots=repetitions, - circuit_duration_check=self._circuit_duration_check, + max_circuit_duration_over_t2=self._max_circuit_duration_over_t2, heralding_mode=self._heralding_mode, ) timeout_arg = [self._run_sweep_timeout] if self._run_sweep_timeout is not None else [] diff --git a/tests/test_iqm_sampler.py b/tests/test_iqm_sampler.py index ae7c6385..e04499e4 100644 --- a/tests/test_iqm_sampler.py +++ b/tests/test_iqm_sampler.py @@ -79,7 +79,7 @@ def submit_circuits_default_kwargs() -> dict: return { 'calibration_set_id': None, 'shots': 1, - 'circuit_duration_check': True, + 'max_circuit_duration_over_t2': None, 'heralding_mode': HeraldingMode.NONE, } @@ -137,7 +137,7 @@ def test_run_sweep_has_duration_check_enabled_by_default( client = mock(IQMClient) sampler = IQMSampler(base_url, Adonis()) run_result = RunResult(status=Status.READY, measurements=[{'some stuff': [[0], [1]]}], metadata=iqm_metadata) - kwargs = submit_circuits_default_kwargs | {'circuit_duration_check': True} + kwargs = submit_circuits_default_kwargs | {'max_circuit_duration_over_t2': None} when(client).submit_circuits(ANY, **kwargs).thenReturn(job_id) when(client).wait_for_results(job_id).thenReturn(run_result) @@ -153,9 +153,9 @@ def test_run_sweep_executes_circuit_with_duration_check_disabled( base_url, circuit_physical, iqm_metadata, submit_circuits_default_kwargs, job_id ): client = mock(IQMClient) - sampler = IQMSampler(base_url, Adonis(), circuit_duration_check=False) + sampler = IQMSampler(base_url, Adonis(), max_circuit_duration_over_t2=0.0) run_result = RunResult(status=Status.READY, measurements=[{'some stuff': [[0], [1]]}], metadata=iqm_metadata) - kwargs = submit_circuits_default_kwargs | {'circuit_duration_check': False} + kwargs = submit_circuits_default_kwargs | {'max_circuit_duration_over_t2': 0.0} when(client).submit_circuits(ANY, **kwargs).thenReturn(job_id) when(client).wait_for_results(job_id).thenReturn(run_result)