From 3ea629bb45fea41c75a55c70da7cddb6d9d0fa25 Mon Sep 17 00:00:00 2001 From: Yao Tang Date: Thu, 4 May 2023 14:43:02 +0100 Subject: [PATCH 1/4] Add get_partial_result --- docs/changelog.rst | 1 + .../quantinuum/backends/quantinuum.py | 27 +++++++++++++- tests/api1_test.py | 36 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 66f8dfa2..952d84bb 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -7,6 +7,7 @@ Changelog * cost function now takes the same kwargs as process_circuits * add check for the number of classical registers to the backend * Updated pytket version requirement to 1.14.1rc0 +* add ``get_partial_result`` method to ``QuantinuumBackend``. 0.15.0 (April 2023) ------------------- diff --git a/pytket/extensions/quantinuum/backends/quantinuum.py b/pytket/extensions/quantinuum/backends/quantinuum.py index feed566b..982230bb 100644 --- a/pytket/extensions/quantinuum/backends/quantinuum.py +++ b/pytket/extensions/quantinuum/backends/quantinuum.py @@ -17,7 +17,7 @@ from dataclasses import dataclass import json from http import HTTPStatus -from typing import Dict, List, Set, Optional, Sequence, Union, Any, cast +from typing import Dict, List, Set, Optional, Sequence, Union, Any, cast, Tuple import warnings import numpy as np @@ -779,6 +779,31 @@ def circuit_status( ) return circ_status + def get_partial_result( + self, handle: ResultHandle + ) -> Tuple[Optional[BackendResult], CircuitStatus]: + """ + Retrieve partial results for a given job, regardless of its current state. + + :param handle: handle to results + :type handle: ResultHandle + + :return: A tuple containing the results and circuit status. If no results are available, the first element is None. + :rtype: Tuple[Optional[BackendResult], CircuitStatus] + """ + job_id = str(handle[0]) + jr = self.api_handler.retrieve_job_status(job_id) + if not jr: + raise QuantinuumAPIError(f"Unable to retrive job {job_id}") + res = jr.get("results") + circ_status = _parse_status(jr) + if res is None: + return None, circ_status + ppcirc_rep = json.loads(cast(str, handle[1])) + ppcirc = Circuit.from_dict(ppcirc_rep) if ppcirc_rep is not None else None + backres = _convert_result(res, ppcirc) + return backres, circ_status + def get_result(self, handle: ResultHandle, **kwargs: KwargTypes) -> BackendResult: """ See :py:meth:`pytket.backends.Backend.get_result`. diff --git a/tests/api1_test.py b/tests/api1_test.py index df9f442a..4c31b7cb 100644 --- a/tests/api1_test.py +++ b/tests/api1_test.py @@ -25,6 +25,7 @@ import requests from requests_mock.mocker import Mocker +from pytket.backends import ResultHandle, StatusEnum from pytket.extensions.quantinuum.backends.api_wrappers import QuantinuumAPI from pytket.extensions.quantinuum.backends import QuantinuumBackend from pytket.circuit import Circuit # type: ignore @@ -515,3 +516,38 @@ def test_submit_qasm_api( assert submitted_json["program"] == qasm assert submitted_json["count"] == 10 + + +def test_get_partial_result( + requests_mock: Mocker, + mock_quum_api_handler: QuantinuumAPI, +) -> None: + queued_job_id = "abc-123" + requests_mock.register_uri( + "GET", + f"https://qapi.quantinuum.com/v1/job/{queued_job_id}?websocket=true", + json={"job": "abc-123", "name": "job", "status": "queued"}, + headers={"Content-Type": "application/json"}, + ) + running_job_id = "abc-456" + requests_mock.register_uri( + "GET", + f"https://qapi.quantinuum.com/v1/job/{running_job_id}?websocket=true", + json={ + "job": "abc-123", + "name": "job", + "status": "running", + "results": {"c": ["10110", "10000", "10110", "01100", "10000"]}, + }, + headers={"Content-Type": "application/json"}, + ) + backend = QuantinuumBackend(device_name="H1-2SC", api_handler=mock_quum_api_handler) + h1 = ResultHandle(queued_job_id, "null") + res, status = backend.get_partial_result(h1) + assert res is None + assert status.status == StatusEnum.QUEUED + + h2 = ResultHandle(running_job_id, "null") + res, status = backend.get_partial_result(h2) + assert res is not None + assert status.status == StatusEnum.RUNNING From ed27822714b33b1e65ff34bc0184d53049def3b1 Mon Sep 17 00:00:00 2001 From: Yao Tang Date: Thu, 4 May 2023 14:51:59 +0100 Subject: [PATCH 2/4] Fix lint issue --- pytket/extensions/quantinuum/backends/quantinuum.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pytket/extensions/quantinuum/backends/quantinuum.py b/pytket/extensions/quantinuum/backends/quantinuum.py index 982230bb..316d1ce0 100644 --- a/pytket/extensions/quantinuum/backends/quantinuum.py +++ b/pytket/extensions/quantinuum/backends/quantinuum.py @@ -788,7 +788,8 @@ def get_partial_result( :param handle: handle to results :type handle: ResultHandle - :return: A tuple containing the results and circuit status. If no results are available, the first element is None. + :return: A tuple containing the results and circuit status. + If no results are available, the first element is None. :rtype: Tuple[Optional[BackendResult], CircuitStatus] """ job_id = str(handle[0]) From 3ad5b5e09c0bf8c9c6364ecd5cb37c14c05ce7ba Mon Sep 17 00:00:00 2001 From: Yao Tang Date: Fri, 5 May 2023 10:44:34 +0100 Subject: [PATCH 3/4] Fix indentation in docstring --- pytket/extensions/quantinuum/backends/quantinuum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytket/extensions/quantinuum/backends/quantinuum.py b/pytket/extensions/quantinuum/backends/quantinuum.py index 316d1ce0..0107780b 100644 --- a/pytket/extensions/quantinuum/backends/quantinuum.py +++ b/pytket/extensions/quantinuum/backends/quantinuum.py @@ -789,7 +789,7 @@ def get_partial_result( :type handle: ResultHandle :return: A tuple containing the results and circuit status. - If no results are available, the first element is None. + If no results are available, the first element is None. :rtype: Tuple[Optional[BackendResult], CircuitStatus] """ job_id = str(handle[0]) From bae48441f625ca06eb56eaa796d888ab637b8967 Mon Sep 17 00:00:00 2001 From: cqc-melf <70640934+cqc-melf@users.noreply.github.com> Date: Fri, 5 May 2023 14:53:20 +0100 Subject: [PATCH 4/4] update version requiremnt --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4b48f2ce..5347e197 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ packages=find_namespace_packages(include=["pytket.*"]), include_package_data=True, install_requires=[ - "pytket == 1.14.1rc0", + "pytket == 1.15.0rc0", "requests >= 2.2", "types-requests", "websockets >= 7.0",