quapp-common 0.0.11.dev1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quapp_common-0.0.11.dev1/LICENSE +8 -0
- quapp_common-0.0.11.dev1/PKG-INFO +41 -0
- quapp_common-0.0.11.dev1/README.md +7 -0
- quapp_common-0.0.11.dev1/pyproject.toml +31 -0
- quapp_common-0.0.11.dev1/qapp_common/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/async_tasks/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/async_tasks/async_task.py +11 -0
- quapp_common-0.0.11.dev1/qapp_common/async_tasks/export_circuit_task.py +119 -0
- quapp_common-0.0.11.dev1/qapp_common/async_tasks/post_processing_task.py +59 -0
- quapp_common-0.0.11.dev1/qapp_common/component/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/component/backend/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/component/backend/invocation.py +255 -0
- quapp_common-0.0.11.dev1/qapp_common/component/backend/job_fetching.py +247 -0
- quapp_common-0.0.11.dev1/qapp_common/component/callback/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/component/callback/update_job_metadata.py +39 -0
- quapp_common-0.0.11.dev1/qapp_common/component/device/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/component/device/device_selection.py +81 -0
- quapp_common-0.0.11.dev1/qapp_common/config/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/config/logging_config.py +8 -0
- quapp_common-0.0.11.dev1/qapp_common/config/thread_config.py +10 -0
- quapp_common-0.0.11.dev1/qapp_common/data/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/data/async_task/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/data/async_task/circuit_export/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/data/async_task/circuit_export/backend_holder.py +12 -0
- quapp_common-0.0.11.dev1/qapp_common/data/async_task/circuit_export/circuit_holder.py +11 -0
- quapp_common-0.0.11.dev1/qapp_common/data/backend/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/data/backend/backend_information.py +14 -0
- quapp_common-0.0.11.dev1/qapp_common/data/callback/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/data/callback/callback_url.py +10 -0
- quapp_common-0.0.11.dev1/qapp_common/data/device/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/data/device/circuit_running_option.py +16 -0
- quapp_common-0.0.11.dev1/qapp_common/data/promise/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/data/promise/post_processing_promise.py +18 -0
- quapp_common-0.0.11.dev1/qapp_common/data/promise/promise.py +11 -0
- quapp_common-0.0.11.dev1/qapp_common/data/request/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/data/request/invocation_request.py +24 -0
- quapp_common-0.0.11.dev1/qapp_common/data/request/job_fetching_request.py +11 -0
- quapp_common-0.0.11.dev1/qapp_common/data/request/request.py +23 -0
- quapp_common-0.0.11.dev1/qapp_common/data/response/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/data/response/authentication.py +9 -0
- quapp_common-0.0.11.dev1/qapp_common/data/response/job_response.py +32 -0
- quapp_common-0.0.11.dev1/qapp_common/data/response/project_header.py +9 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/base_enum.py +16 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/http_header.py +10 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/invocation_step.py +13 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/media_type.py +12 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/processing_unit.py +10 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/provider_tag.py +22 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/sdk.py +22 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/status/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/status/job_status.py +10 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/status/status_code.py +10 -0
- quapp_common-0.0.11.dev1/qapp_common/enum/token_type.py +8 -0
- quapp_common-0.0.11.dev1/qapp_common/factory/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/factory/device_factory.py +22 -0
- quapp_common-0.0.11.dev1/qapp_common/factory/handler_factory.py +20 -0
- quapp_common-0.0.11.dev1/qapp_common/factory/provider_factory.py +22 -0
- quapp_common-0.0.11.dev1/qapp_common/handler/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/handler/handler.py +20 -0
- quapp_common-0.0.11.dev1/qapp_common/model/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/model/device/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/model/device/custom_device.py +87 -0
- quapp_common-0.0.11.dev1/qapp_common/model/device/device.py +257 -0
- quapp_common-0.0.11.dev1/qapp_common/model/provider/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/model/provider/provider.py +34 -0
- quapp_common-0.0.11.dev1/qapp_common/util/__init__.py +0 -0
- quapp_common-0.0.11.dev1/qapp_common/util/file_utils.py +23 -0
- quapp_common-0.0.11.dev1/qapp_common/util/http_utils.py +37 -0
- quapp_common-0.0.11.dev1/qapp_common/util/json_parser_utils.py +75 -0
- quapp_common-0.0.11.dev1/qapp_common/util/response_utils.py +36 -0
- quapp_common-0.0.11.dev1/quapp_common.egg-info/PKG-INFO +41 -0
- quapp_common-0.0.11.dev1/quapp_common.egg-info/SOURCES.txt +75 -0
- quapp_common-0.0.11.dev1/quapp_common.egg-info/dependency_links.txt +1 -0
- quapp_common-0.0.11.dev1/quapp_common.egg-info/requires.txt +12 -0
- quapp_common-0.0.11.dev1/quapp_common.egg-info/top_level.txt +1 -0
- quapp_common-0.0.11.dev1/setup.cfg +4 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
5
|
+
|
|
6
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: quapp-common
|
|
3
|
+
Version: 0.0.11.dev1
|
|
4
|
+
Summary: Quapp common library supporting Quapp Platform for Quantum Computing
|
|
5
|
+
Author-email: "CITYNOW Co. Ltd. " <corp@citynow.vn>
|
|
6
|
+
License: The MIT License (MIT)
|
|
7
|
+
Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
Project-URL: Homepage, https://citynow.asia/
|
|
15
|
+
Keywords: quapp,quapp-common,quantum
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Requires-Python: >=3.7
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: loguru
|
|
23
|
+
Requires-Dist: requests
|
|
24
|
+
Requires-Dist: numpy
|
|
25
|
+
Requires-Dist: matplotlib
|
|
26
|
+
Requires-Dist: pylatexenc
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: black; extra == "dev"
|
|
29
|
+
Requires-Dist: bumpver; extra == "dev"
|
|
30
|
+
Requires-Dist: isort; extra == "dev"
|
|
31
|
+
Requires-Dist: pip-tools; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# qapp-common
|
|
36
|
+
|
|
37
|
+
# changes
|
|
38
|
+
- Add pennylane in enum sdk
|
|
39
|
+
- Change function in `device.py` to protected to override in pennylane sdk
|
|
40
|
+
|
|
41
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "quapp-common"
|
|
7
|
+
version = "0.0.11.dev1"
|
|
8
|
+
description = "Quapp common library supporting Quapp Platform for Quantum Computing"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [{ name = "CITYNOW Co. Ltd. ", email = "corp@citynow.vn" }]
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
classifiers = [
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Programming Language :: Python",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
]
|
|
17
|
+
keywords = ["quapp", "quapp-common", "quantum"]
|
|
18
|
+
dependencies = [
|
|
19
|
+
"loguru",
|
|
20
|
+
"requests",
|
|
21
|
+
"numpy",
|
|
22
|
+
"matplotlib",
|
|
23
|
+
"pylatexenc"
|
|
24
|
+
]
|
|
25
|
+
requires-python = ">=3.7"
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
dev = ["black", "bumpver", "isort", "pip-tools", "pytest"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://citynow.asia/"
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project export_circuit.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
from io import BytesIO
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
from .async_task import AsyncTask
|
|
9
|
+
from ..data.async_task.circuit_export.backend_holder import BackendDataHolder
|
|
10
|
+
from ..data.async_task.circuit_export.circuit_holder import CircuitDataHolder
|
|
11
|
+
from ..config.logging_config import logger
|
|
12
|
+
from ..enum.media_type import MediaType
|
|
13
|
+
from ..util.file_utils import FileUtils
|
|
14
|
+
from ..util.http_utils import HttpUtils
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class CircuitExportTask(AsyncTask):
|
|
18
|
+
MAX_CIRCUIT_IMAGE_SIZE = 5 * (1024 ** 2)
|
|
19
|
+
|
|
20
|
+
def __init__(self,
|
|
21
|
+
circuit_data_holder: CircuitDataHolder,
|
|
22
|
+
backend_data_holder: BackendDataHolder):
|
|
23
|
+
super().__init__()
|
|
24
|
+
self.circuit_data_holder = circuit_data_holder
|
|
25
|
+
self.backend_data_holder = backend_data_holder
|
|
26
|
+
|
|
27
|
+
def do(self):
|
|
28
|
+
"""
|
|
29
|
+
Export circuit to svg file then send to QuaO server for saving
|
|
30
|
+
"""
|
|
31
|
+
logger.debug("[Circuit export] Start")
|
|
32
|
+
|
|
33
|
+
circuit_export_url = self.circuit_data_holder.export_url
|
|
34
|
+
|
|
35
|
+
if circuit_export_url is None or len(circuit_export_url) < 1:
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
figure_buffer = self.__convert()
|
|
39
|
+
|
|
40
|
+
io_buffer_value, content_type = self.__determine_zip(figure_buffer=figure_buffer)
|
|
41
|
+
|
|
42
|
+
self.__send(io_buffer_value=io_buffer_value,
|
|
43
|
+
content_type=content_type)
|
|
44
|
+
|
|
45
|
+
def __convert(self):
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
@return:
|
|
49
|
+
"""
|
|
50
|
+
logger.debug("[Circuit export] Preparing circuit figure...")
|
|
51
|
+
transpiled_circuit = self._transpile_circuit()
|
|
52
|
+
circuit_figure = transpiled_circuit.draw(output='mpl', fold=-1)
|
|
53
|
+
|
|
54
|
+
logger.debug("[Circuit export] Converting circuit figure to svg file...")
|
|
55
|
+
figure_buffer = BytesIO()
|
|
56
|
+
circuit_figure.savefig(figure_buffer, format='svg', bbox_inches='tight')
|
|
57
|
+
|
|
58
|
+
return figure_buffer
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def __determine_zip(figure_buffer):
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
@param figure_buffer:
|
|
65
|
+
@return:
|
|
66
|
+
"""
|
|
67
|
+
buffer_value = figure_buffer.getvalue()
|
|
68
|
+
content_type = MediaType.SVG_XML
|
|
69
|
+
|
|
70
|
+
logger.debug("[Circuit export] Checking max file size")
|
|
71
|
+
estimated_file_size = len(buffer_value)
|
|
72
|
+
|
|
73
|
+
if estimated_file_size > CircuitExportTask.MAX_CIRCUIT_IMAGE_SIZE:
|
|
74
|
+
logger.debug("[Circuit export] Zip file")
|
|
75
|
+
zip_file_buffer = FileUtils.zip(io_buffer_value=buffer_value,
|
|
76
|
+
file_name="circuit_image.svg")
|
|
77
|
+
|
|
78
|
+
buffer_value = zip_file_buffer.getvalue()
|
|
79
|
+
content_type = MediaType.APPLICATION_ZIP
|
|
80
|
+
|
|
81
|
+
return buffer_value, content_type
|
|
82
|
+
|
|
83
|
+
def __send(self, io_buffer_value, content_type: MediaType):
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
@param io_buffer_value:
|
|
87
|
+
@param content_type:
|
|
88
|
+
"""
|
|
89
|
+
url = self.circuit_data_holder.export_url
|
|
90
|
+
|
|
91
|
+
logger.debug(
|
|
92
|
+
"[Circuit export] Sending circuit svg image to [{0}] with POST method ...".format(
|
|
93
|
+
url))
|
|
94
|
+
|
|
95
|
+
payload = {'circuit': (
|
|
96
|
+
'circuit_image.svg',
|
|
97
|
+
io_buffer_value,
|
|
98
|
+
content_type.value)}
|
|
99
|
+
|
|
100
|
+
response = requests.post(
|
|
101
|
+
url=url,
|
|
102
|
+
headers=HttpUtils.create_bearer_header(self.backend_data_holder.user_token),
|
|
103
|
+
files=payload)
|
|
104
|
+
|
|
105
|
+
if response.ok:
|
|
106
|
+
logger.debug("Sending request to QuaO backend successfully!")
|
|
107
|
+
else:
|
|
108
|
+
logger.debug("Sending request to QuaO backend failed with status {0}!".format(
|
|
109
|
+
response.status_code))
|
|
110
|
+
|
|
111
|
+
logger.debug("[Circuit export] Finish")
|
|
112
|
+
|
|
113
|
+
def _transpile_circuit(self):
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
@return: Transpiled circuit
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
raise NotImplemented('[CircuitExportTask] __transpile_circuit() method must be implemented')
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project post_processing_task.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
from .async_task import AsyncTask
|
|
5
|
+
from ..component.callback.update_job_metadata import update_job_metadata
|
|
6
|
+
from ..config.logging_config import logger
|
|
7
|
+
from ..data.promise.post_processing_promise import PostProcessingPromise
|
|
8
|
+
from ..data.response.job_response import JobResponse
|
|
9
|
+
from ..enum.media_type import MediaType
|
|
10
|
+
from ..enum.status.job_status import JobStatus
|
|
11
|
+
from ..enum.status.status_code import StatusCode
|
|
12
|
+
from ..util.json_parser_utils import JsonParserUtils
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PostProcessingTask(AsyncTask):
|
|
16
|
+
def __init__(self,
|
|
17
|
+
post_processing_fn,
|
|
18
|
+
promise: PostProcessingPromise):
|
|
19
|
+
self.post_processing_fn = post_processing_fn
|
|
20
|
+
self.promise = promise
|
|
21
|
+
|
|
22
|
+
def do(self):
|
|
23
|
+
"""
|
|
24
|
+
Execute post_processing and send to backend
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
job_response = JobResponse(
|
|
28
|
+
authentication=self.promise.authentication,
|
|
29
|
+
project_header=self.promise.project_header,
|
|
30
|
+
job_status=JobStatus.DONE.value,
|
|
31
|
+
status_code=StatusCode.DONE)
|
|
32
|
+
|
|
33
|
+
update_job_metadata(job_response=job_response,
|
|
34
|
+
callback_url=self.promise.callback_url.on_start)
|
|
35
|
+
|
|
36
|
+
job_response.content_type = MediaType.APPLICATION_JSON
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
|
|
40
|
+
logger.info("Execute post_processing ...")
|
|
41
|
+
job_result_post_processing = self.post_processing_fn(self.promise.job_result)
|
|
42
|
+
|
|
43
|
+
logger.debug("Parsing job result....")
|
|
44
|
+
print(job_result_post_processing)
|
|
45
|
+
job_response.job_result = JsonParserUtils.parse(job_result_post_processing)
|
|
46
|
+
|
|
47
|
+
update_job_metadata(job_response=job_response,
|
|
48
|
+
callback_url=self.promise.callback_url.on_done)
|
|
49
|
+
|
|
50
|
+
except Exception as exception:
|
|
51
|
+
job_response.job_result = {
|
|
52
|
+
"error": "Error when execute post_processing(): ",
|
|
53
|
+
"exception": str(exception),
|
|
54
|
+
}
|
|
55
|
+
job_response.status_code = StatusCode.ERROR
|
|
56
|
+
job_response.job_status = JobStatus.ERROR.value
|
|
57
|
+
|
|
58
|
+
update_job_metadata(job_response=job_response,
|
|
59
|
+
callback_url=self.promise.callback_url.on_error)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project backend.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
from abc import abstractmethod, ABC
|
|
5
|
+
|
|
6
|
+
from ..callback.update_job_metadata import update_job_metadata
|
|
7
|
+
from ...component.device.device_selection import DeviceSelection
|
|
8
|
+
from ...config.logging_config import logger
|
|
9
|
+
from ...config.thread_config import circuit_running_pool
|
|
10
|
+
from ...data.backend.backend_information import BackendInformation
|
|
11
|
+
from ...data.device.circuit_running_option import CircuitRunningOption
|
|
12
|
+
from ...data.request.invocation_request import InvocationRequest
|
|
13
|
+
from ...data.response.authentication import Authentication
|
|
14
|
+
from ...data.response.job_response import JobResponse
|
|
15
|
+
from ...data.response.project_header import ProjectHeader
|
|
16
|
+
from ...enum.invocation_step import InvocationStep
|
|
17
|
+
from ...enum.media_type import MediaType
|
|
18
|
+
from ...enum.sdk import Sdk
|
|
19
|
+
from ...enum.status.job_status import JobStatus
|
|
20
|
+
from ...enum.status.status_code import StatusCode
|
|
21
|
+
from ...model.provider.provider import Provider
|
|
22
|
+
|
|
23
|
+
EXPORT_CIRCUIT_SDK = {Sdk.QISKIT, Sdk.BRAKET}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Invocation(ABC):
|
|
27
|
+
def __init__(self, request_data: InvocationRequest):
|
|
28
|
+
self.sdk: Sdk = Sdk.resolve(request_data.sdk)
|
|
29
|
+
self.input = request_data.input
|
|
30
|
+
self.device_id = request_data.device_id
|
|
31
|
+
self.backend_information: BackendInformation
|
|
32
|
+
self.authentication: Authentication = request_data.authentication
|
|
33
|
+
self.project_header: ProjectHeader = request_data.project_header
|
|
34
|
+
self.options = CircuitRunningOption(
|
|
35
|
+
shots=request_data.shots,
|
|
36
|
+
processing_unit=request_data.processing_unit,
|
|
37
|
+
executor=circuit_running_pool,
|
|
38
|
+
max_job_size=1,
|
|
39
|
+
)
|
|
40
|
+
self.device_selection_url: str = request_data.device_selection_url
|
|
41
|
+
self.circuit_export_url: str = request_data.circuit_export_url
|
|
42
|
+
self.callback_dict: dict = {
|
|
43
|
+
InvocationStep.PREPARATION: request_data.preparation,
|
|
44
|
+
InvocationStep.EXECUTION: request_data.execution,
|
|
45
|
+
InvocationStep.ANALYSIS: request_data.analysis,
|
|
46
|
+
InvocationStep.FINALIZATION: request_data.finalization,
|
|
47
|
+
}
|
|
48
|
+
self.invoke_authentication = request_data.invoke_authentication
|
|
49
|
+
|
|
50
|
+
def submit_job(self, circuit_preparation_fn, post_processing_fn):
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
@param post_processing_fn: Post-processing function
|
|
54
|
+
@param circuit_preparation_fn: Circuit-preparation function
|
|
55
|
+
@return: Job result
|
|
56
|
+
"""
|
|
57
|
+
logger.debug("[Invocation] Invoke job")
|
|
58
|
+
|
|
59
|
+
circuit = self.__pre_execute(circuit_preparation_fn)
|
|
60
|
+
|
|
61
|
+
if circuit is None:
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
self.__execute(circuit, post_processing_fn)
|
|
65
|
+
|
|
66
|
+
def __pre_execute(self, circuit_preparation_fn):
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
@param circuit_preparation_fn: Circuit preparation function
|
|
70
|
+
"""
|
|
71
|
+
circuit = self.__prepare_circuit(circuit_preparation_fn)
|
|
72
|
+
|
|
73
|
+
if circuit is None:
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
self.__prepare_backend_data(circuit)
|
|
78
|
+
|
|
79
|
+
except Exception as exception:
|
|
80
|
+
job_response = JobResponse(
|
|
81
|
+
status_code=StatusCode.ERROR,
|
|
82
|
+
authentication=self.authentication,
|
|
83
|
+
project_header=self.project_header,
|
|
84
|
+
job_result={"error": str(exception)},
|
|
85
|
+
content_type=MediaType.APPLICATION_JSON,
|
|
86
|
+
job_status=JobStatus.ERROR.value,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
update_job_metadata(
|
|
90
|
+
job_response=job_response,
|
|
91
|
+
callback_url=self.callback_dict.get(
|
|
92
|
+
InvocationStep.PREPARATION
|
|
93
|
+
).on_error,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
self._export_circuit(circuit)
|
|
97
|
+
|
|
98
|
+
return circuit
|
|
99
|
+
|
|
100
|
+
def __execute(self, circuit, post_processing_fn):
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
@param circuit: Circuit was run
|
|
104
|
+
@param post_processing_fn: Post-processing function
|
|
105
|
+
@return: Job response
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
logger.debug("[Invocation] Execute job")
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
if self.backend_information is None:
|
|
112
|
+
raise Exception("Backend is not found")
|
|
113
|
+
|
|
114
|
+
device_name = self.backend_information.device_name
|
|
115
|
+
provider_tag = self.backend_information.provider_tag
|
|
116
|
+
backend_authentication = self.backend_information.authentication
|
|
117
|
+
|
|
118
|
+
logger.debug(
|
|
119
|
+
"[Invocation] Execute job with provider tag: {0}".format(
|
|
120
|
+
provider_tag.value
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
provider = self._create_provider()
|
|
125
|
+
|
|
126
|
+
logger.debug(
|
|
127
|
+
"[Invocation] Execute job with device name: {0}".format(device_name)
|
|
128
|
+
)
|
|
129
|
+
device = self._create_device(provider)
|
|
130
|
+
|
|
131
|
+
except Exception as exception:
|
|
132
|
+
job_response = JobResponse(
|
|
133
|
+
job_status=JobStatus.ERROR.value,
|
|
134
|
+
content_type=MediaType.APPLICATION_JSON,
|
|
135
|
+
status_code=StatusCode.ERROR,
|
|
136
|
+
authentication=self.authentication,
|
|
137
|
+
project_header=self.project_header,
|
|
138
|
+
job_result={"error": str(exception)},
|
|
139
|
+
)
|
|
140
|
+
update_job_metadata(
|
|
141
|
+
job_response=job_response,
|
|
142
|
+
callback_url=self.callback_dict.get(InvocationStep.EXECUTION).on_error,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
device.run_circuit(
|
|
148
|
+
circuit=circuit,
|
|
149
|
+
post_processing_fn=post_processing_fn,
|
|
150
|
+
options=self.options,
|
|
151
|
+
callback_dict=self.callback_dict,
|
|
152
|
+
authentication=self.authentication,
|
|
153
|
+
project_header=self.project_header,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def __prepare_circuit(self, circuit_preparation_fn):
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
@param circuit_preparation_fn: Circuit preparation function
|
|
160
|
+
@return: circuit
|
|
161
|
+
"""
|
|
162
|
+
logger.debug("[Invocation] Prepare circuit")
|
|
163
|
+
|
|
164
|
+
job_response = JobResponse(
|
|
165
|
+
status_code=StatusCode.DONE,
|
|
166
|
+
authentication=self.authentication,
|
|
167
|
+
project_header=self.project_header,
|
|
168
|
+
)
|
|
169
|
+
update_job_metadata(
|
|
170
|
+
job_response=job_response,
|
|
171
|
+
callback_url=self.callback_dict.get(InvocationStep.PREPARATION).on_start,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
circuit = circuit_preparation_fn(self.input)
|
|
176
|
+
|
|
177
|
+
if circuit is None:
|
|
178
|
+
raise Exception("Invalid circuit")
|
|
179
|
+
|
|
180
|
+
update_job_metadata(
|
|
181
|
+
job_response=job_response,
|
|
182
|
+
callback_url=self.callback_dict.get(InvocationStep.PREPARATION).on_done,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
return circuit
|
|
186
|
+
|
|
187
|
+
except Exception as exception:
|
|
188
|
+
job_response.job_status = JobStatus.ERROR.value
|
|
189
|
+
job_response.content_type = MediaType.APPLICATION_JSON
|
|
190
|
+
job_response.status_code = StatusCode.ERROR
|
|
191
|
+
job_response.job_result = {"error": str(exception)}
|
|
192
|
+
|
|
193
|
+
update_job_metadata(
|
|
194
|
+
job_response=job_response,
|
|
195
|
+
callback_url=self.callback_dict.get(
|
|
196
|
+
InvocationStep.PREPARATION
|
|
197
|
+
).on_error,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return None
|
|
201
|
+
|
|
202
|
+
def __prepare_backend_data(self, circuit):
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
@param circuit: Circuit was run
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
required_qubit_amount = self._get_qubit_amount(circuit)
|
|
209
|
+
|
|
210
|
+
device_selection = DeviceSelection(
|
|
211
|
+
required_qubit_amount,
|
|
212
|
+
self.device_id,
|
|
213
|
+
self.authentication.user_token,
|
|
214
|
+
self.device_selection_url,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
self.backend_information = device_selection.select()
|
|
218
|
+
logger.info("before")
|
|
219
|
+
logger.info(self.backend_information.authentication)
|
|
220
|
+
self.backend_information.authentication = self.invoke_authentication
|
|
221
|
+
logger.info("after")
|
|
222
|
+
logger.info(self.backend_information.authentication)
|
|
223
|
+
|
|
224
|
+
@abstractmethod
|
|
225
|
+
def _export_circuit(self, circuit):
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
@param circuit: Circuit was exported
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
raise NotImplemented('[Invocation] _export_circuit() method must be implemented')
|
|
232
|
+
|
|
233
|
+
@abstractmethod
|
|
234
|
+
def _create_provider(self, ):
|
|
235
|
+
"""
|
|
236
|
+
Create provider with ProviderFactory
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
raise NotImplemented('[Invocation] _create_provider() method must be implemented')
|
|
240
|
+
|
|
241
|
+
@abstractmethod
|
|
242
|
+
def _create_device(self, provider: Provider):
|
|
243
|
+
"""
|
|
244
|
+
Create device with DeviceFactory
|
|
245
|
+
"""
|
|
246
|
+
|
|
247
|
+
raise NotImplemented('[Invocation] _create_device() method must be implemented')
|
|
248
|
+
|
|
249
|
+
@abstractmethod
|
|
250
|
+
def _get_qubit_amount(self, circuit):
|
|
251
|
+
"""
|
|
252
|
+
Get number qubit of circuit
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
raise NotImplemented('[Invocation] _get_qubit_amount() method must be implemented')
|