quapp-perceval 0.0.1__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_perceval-0.0.1/LICENSE +8 -0
- quapp_perceval-0.0.1/PKG-INFO +33 -0
- quapp_perceval-0.0.1/README.md +2 -0
- quapp_perceval-0.0.1/pyproject.toml +28 -0
- quapp_perceval-0.0.1/quapp_perceval/__init__.py +1 -0
- quapp_perceval-0.0.1/quapp_perceval/async_tasks/__init__.py +0 -0
- quapp_perceval-0.0.1/quapp_perceval/async_tasks/perceval_circuit_export_task.py +10 -0
- quapp_perceval-0.0.1/quapp_perceval/component/__init__.py +0 -0
- quapp_perceval-0.0.1/quapp_perceval/component/backend/__init__.py +0 -0
- quapp_perceval-0.0.1/quapp_perceval/component/backend/perceval_invocation.py +57 -0
- quapp_perceval-0.0.1/quapp_perceval/factory/__init__.py +0 -0
- quapp_perceval-0.0.1/quapp_perceval/factory/perceval_device_factory.py +37 -0
- quapp_perceval-0.0.1/quapp_perceval/factory/perceval_handler_factory.py +27 -0
- quapp_perceval-0.0.1/quapp_perceval/factory/perceval_provider_factory.py +32 -0
- quapp_perceval-0.0.1/quapp_perceval/handler/__init__.py +0 -0
- quapp_perceval-0.0.1/quapp_perceval/handler/invocation_handler.py +35 -0
- quapp_perceval-0.0.1/quapp_perceval/model/__init__.py +0 -0
- quapp_perceval-0.0.1/quapp_perceval/model/device/__init__.py +0 -0
- quapp_perceval-0.0.1/quapp_perceval/model/device/perceval_device.py +174 -0
- quapp_perceval-0.0.1/quapp_perceval/model/device/quapp_perceval_device.py +77 -0
- quapp_perceval-0.0.1/quapp_perceval/model/provider/__init__.py +0 -0
- quapp_perceval-0.0.1/quapp_perceval/model/provider/quapp_perceval_provider.py +40 -0
- quapp_perceval-0.0.1/quapp_perceval.egg-info/PKG-INFO +33 -0
- quapp_perceval-0.0.1/quapp_perceval.egg-info/SOURCES.txt +26 -0
- quapp_perceval-0.0.1/quapp_perceval.egg-info/dependency_links.txt +1 -0
- quapp_perceval-0.0.1/quapp_perceval.egg-info/requires.txt +9 -0
- quapp_perceval-0.0.1/quapp_perceval.egg-info/top_level.txt +1 -0
- quapp_perceval-0.0.1/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,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: quapp-perceval
|
|
3
|
+
Version: 0.0.1
|
|
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://quapp.cloud/
|
|
15
|
+
Keywords: quapp,quapp-perceval,quantum
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Requires-Python: <3.11,>=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: quapp-common==0.0.13
|
|
23
|
+
Requires-Dist: perceval-quandela==1.2.1
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: black; extra == "dev"
|
|
26
|
+
Requires-Dist: bumpver; extra == "dev"
|
|
27
|
+
Requires-Dist: isort; extra == "dev"
|
|
28
|
+
Requires-Dist: pip-tools; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# quapp-perceval
|
|
33
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0.0", "wheel==0.45.1"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "quapp-perceval"
|
|
7
|
+
version = "0.0.1"
|
|
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-perceval", "quantum"]
|
|
18
|
+
dependencies = [
|
|
19
|
+
"quapp-common==0.0.13",
|
|
20
|
+
"perceval-quandela==1.2.1"
|
|
21
|
+
]
|
|
22
|
+
requires-python = ">=3.9,<3.11"
|
|
23
|
+
|
|
24
|
+
[project.optional-dependencies]
|
|
25
|
+
dev = ["black", "bumpver", "isort", "pip-tools", "pytest"]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://quapp.cloud/"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .factory.perceval_handler_factory import PercevalHandlerFactory
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Quapp Platform Project
|
|
2
|
+
# perceval_circuit_export_task.py
|
|
3
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
from quapp_common.async_tasks.export_circuit_task import CircuitExportTask
|
|
6
|
+
|
|
7
|
+
class PercevalCircuitExportTask(CircuitExportTask):
|
|
8
|
+
|
|
9
|
+
def _transpile_circuit(self):
|
|
10
|
+
return None
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Quapp Platform Project
|
|
2
|
+
# perceval_invocation.py
|
|
3
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
from quapp_common.component.backend.invocation import Invocation
|
|
6
|
+
from quapp_common.data.request.invocation_request import InvocationRequest
|
|
7
|
+
from quapp_common.model.provider.provider import Provider
|
|
8
|
+
from ...factory.perceval_device_factory import PercevalDeviceFactory
|
|
9
|
+
from ...factory.perceval_provider_factory import PercevalProviderFactory
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PercevalInvocation(Invocation):
|
|
13
|
+
|
|
14
|
+
def __init__(self, request_data: InvocationRequest):
|
|
15
|
+
super().__init__(request_data)
|
|
16
|
+
|
|
17
|
+
def _export_circuit(self, circuit):
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
def _create_provider(self):
|
|
21
|
+
try:
|
|
22
|
+
self.logger.debug(
|
|
23
|
+
f'Creating provider: provider_tag={getattr(self.backend_information, "provider_tag", None)}, sdk={getattr(self, "sdk", None)}')
|
|
24
|
+
provider = PercevalProviderFactory.create_provider(
|
|
25
|
+
provider_type=self.backend_information.provider_tag,
|
|
26
|
+
sdk=self.sdk,
|
|
27
|
+
authentication=self.backend_information.authentication, )
|
|
28
|
+
self.logger.info(
|
|
29
|
+
f'Provider created successfully: {type(provider).__name__}')
|
|
30
|
+
return provider
|
|
31
|
+
except Exception as exception:
|
|
32
|
+
self.logger.exception(f'Provider creation failed: {exception}')
|
|
33
|
+
raise
|
|
34
|
+
|
|
35
|
+
def _create_device(self, provider: Provider):
|
|
36
|
+
self.logger.debug('Creating device')
|
|
37
|
+
try:
|
|
38
|
+
device_spec = getattr(self.backend_information, "device_name", None)
|
|
39
|
+
self.logger.debug(
|
|
40
|
+
f'Creating device from provider={type(provider).__name__}, '
|
|
41
|
+
f'device_specification={device_spec}, sdk={getattr(self, "sdk", None)}', )
|
|
42
|
+
device = PercevalDeviceFactory.create_device(provider=provider,
|
|
43
|
+
device_specification=device_spec,
|
|
44
|
+
authentication=self.backend_information.authentication,
|
|
45
|
+
sdk=self.sdk)
|
|
46
|
+
self.logger.info(
|
|
47
|
+
f'Device created successfully: {type(device).__name__}')
|
|
48
|
+
return device
|
|
49
|
+
except Exception as exception:
|
|
50
|
+
self.logger.exception(f"Device creation failed: {exception}")
|
|
51
|
+
raise
|
|
52
|
+
|
|
53
|
+
def _get_qubit_amount(self, circuit):
|
|
54
|
+
try:
|
|
55
|
+
return circuit.m
|
|
56
|
+
except AttributeError:
|
|
57
|
+
return getattr(circuit, "circuit_size", None)
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Quapp Platform Project
|
|
2
|
+
# perceval_device_factory.py
|
|
3
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
from quapp_common.config.logging_config import logger
|
|
6
|
+
from quapp_common.enum.provider_tag import ProviderTag
|
|
7
|
+
from quapp_common.enum.sdk import Sdk
|
|
8
|
+
from quapp_common.factory.device_factory import DeviceFactory
|
|
9
|
+
from quapp_common.model.provider.provider import Provider
|
|
10
|
+
|
|
11
|
+
from ..model.device.quapp_perceval_device import QuappPercevalDevice
|
|
12
|
+
|
|
13
|
+
_PERCEVAL_SDK = getattr(Sdk, "PERCEVAL", None)
|
|
14
|
+
_PROVIDER_TAGS = tuple(
|
|
15
|
+
tag for tag in (
|
|
16
|
+
getattr(ProviderTag, "QUANDELA_CLOUD", None),
|
|
17
|
+
getattr(ProviderTag, "QUANDELA", None),
|
|
18
|
+
getattr(ProviderTag, "QUAO_QUANTUM_SIMULATOR", None),
|
|
19
|
+
) if tag is not None
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PercevalDeviceFactory(DeviceFactory):
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def create_device(provider: Provider, device_specification: str,
|
|
27
|
+
authentication: dict, sdk: Sdk):
|
|
28
|
+
logger.info("[PercevalDeviceFactory] create_device()")
|
|
29
|
+
|
|
30
|
+
provider_type = ProviderTag.resolve(provider.get_provider_type().value)
|
|
31
|
+
|
|
32
|
+
if provider_type in _PROVIDER_TAGS and (
|
|
33
|
+
_PERCEVAL_SDK is None or _PERCEVAL_SDK.__eq__(sdk)):
|
|
34
|
+
logger.info("Created QUAPP_PERCEVAL device")
|
|
35
|
+
return QuappPercevalDevice(provider, device_specification)
|
|
36
|
+
|
|
37
|
+
raise Exception("Unsupported device!")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Quapp Platform Project
|
|
2
|
+
# perceval_handler_factory.py
|
|
3
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
from quapp_common.config.logging_config import job_logger
|
|
6
|
+
from quapp_common.factory.handler_factory import HandlerFactory
|
|
7
|
+
from quapp_common.handler.handler import Handler
|
|
8
|
+
|
|
9
|
+
from ..handler.invocation_handler import InvocationHandler
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PercevalHandlerFactory(HandlerFactory):
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def create_handler(event, circuit_preparation_fn,
|
|
16
|
+
post_processing_fn) -> Handler:
|
|
17
|
+
logger = job_logger(getattr(event.json(), 'jobId', None))
|
|
18
|
+
logger.debug("Create Perceval Handler")
|
|
19
|
+
|
|
20
|
+
request_data = event.json()
|
|
21
|
+
provider_job_id = request_data.get("providerJobId")
|
|
22
|
+
|
|
23
|
+
if provider_job_id is None:
|
|
24
|
+
logger.debug('providerJobId is None. Create InvocationHandler')
|
|
25
|
+
return InvocationHandler(request_data=request_data,
|
|
26
|
+
circuit_preparation_fn=circuit_preparation_fn,
|
|
27
|
+
post_processing_fn=post_processing_fn, )
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Quapp Platform Project
|
|
2
|
+
# perceval_provider_factory.py
|
|
3
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
from quapp_common.config.logging_config import logger
|
|
6
|
+
from quapp_common.enum.provider_tag import ProviderTag
|
|
7
|
+
from quapp_common.enum.sdk import Sdk
|
|
8
|
+
from quapp_common.factory.provider_factory import ProviderFactory
|
|
9
|
+
|
|
10
|
+
from ..model.provider.quapp_perceval_provider import QuappPercevalProvider
|
|
11
|
+
|
|
12
|
+
_PERCEVAL_SDK = getattr(Sdk, "PERCEVAL", None)
|
|
13
|
+
_PROVIDER_TAGS = tuple(
|
|
14
|
+
tag for tag in (
|
|
15
|
+
getattr(ProviderTag, "QUANDELA_CLOUD", None),
|
|
16
|
+
getattr(ProviderTag, "QUANDELA", None),
|
|
17
|
+
getattr(ProviderTag, "QUAO_QUANTUM_SIMULATOR", None),
|
|
18
|
+
) if tag is not None
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class PercevalProviderFactory(ProviderFactory):
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def create_provider(provider_type: ProviderTag, sdk: Sdk,
|
|
26
|
+
authentication: dict):
|
|
27
|
+
logger.debug("Create Perceval Provider")
|
|
28
|
+
if provider_type in _PROVIDER_TAGS and (
|
|
29
|
+
_PERCEVAL_SDK is None or _PERCEVAL_SDK.__eq__(sdk)):
|
|
30
|
+
logger.debug("Create Quapp Perceval Provider")
|
|
31
|
+
return QuappPercevalProvider(authentication=authentication)
|
|
32
|
+
raise Exception("Unsupported provider!")
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Quapp Platform Project
|
|
2
|
+
# invocation_handler.py
|
|
3
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
from quapp_common.data.request.invocation_request import InvocationRequest
|
|
6
|
+
from quapp_common.handler.handler import Handler
|
|
7
|
+
|
|
8
|
+
from ..component.backend.perceval_invocation import PercevalInvocation
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class InvocationHandler(Handler):
|
|
12
|
+
def __init__(self, request_data: dict, circuit_preparation_fn,
|
|
13
|
+
post_processing_fn):
|
|
14
|
+
super().__init__(request_data, post_processing_fn)
|
|
15
|
+
self.circuit_preparation_fn = circuit_preparation_fn
|
|
16
|
+
|
|
17
|
+
def handle(self):
|
|
18
|
+
self.logger.debug('Handle Invocation: start')
|
|
19
|
+
try:
|
|
20
|
+
|
|
21
|
+
invocation_request = InvocationRequest(self.request_data)
|
|
22
|
+
self.logger.debug(f'Invocation request created successfully: '
|
|
23
|
+
f'{invocation_request.__dict__.keys()}')
|
|
24
|
+
|
|
25
|
+
backend = PercevalInvocation(invocation_request)
|
|
26
|
+
self.logger.info('Submitting job via PercevalInvocation')
|
|
27
|
+
|
|
28
|
+
backend.submit_job(
|
|
29
|
+
circuit_preparation_fn=self.circuit_preparation_fn,
|
|
30
|
+
post_processing_fn=self.post_processing_fn)
|
|
31
|
+
|
|
32
|
+
self.logger.debug('Job submission triggered successfully')
|
|
33
|
+
except Exception as exception:
|
|
34
|
+
self.logger.exception(f'Invocation handling failed: {exception}')
|
|
35
|
+
raise
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Quapp Platform Project
|
|
2
|
+
# perceval_device.py
|
|
3
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
from abc import ABC
|
|
6
|
+
|
|
7
|
+
from quapp_common.model.device.custom_device import CustomDevice
|
|
8
|
+
from quapp_common.data.response.job_response import JobResponse
|
|
9
|
+
|
|
10
|
+
from quapp_common.component.callback.update_job_metadata import update_job_metadata
|
|
11
|
+
from quapp_common.enum.status.job_status import JobStatus
|
|
12
|
+
from quapp_common.enum.media_type import MediaType
|
|
13
|
+
from quapp_common.enum.status.status_code import StatusCode
|
|
14
|
+
from quapp_common.data.response.authentication import Authentication
|
|
15
|
+
from quapp_common.data.response.custom_header import CustomHeader
|
|
16
|
+
from quapp_common.data.device.circuit_running_option import CircuitRunningOption
|
|
17
|
+
from quapp_common.enum.invocation_step import InvocationStep
|
|
18
|
+
|
|
19
|
+
from quapp_common.util.response_utils import build_error_job_response
|
|
20
|
+
|
|
21
|
+
from quapp_common.data.callback.callback_url import CallbackUrl
|
|
22
|
+
from quapp_common.util.json_parser_utils import parse
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PercevalDevice(CustomDevice, ABC):
|
|
27
|
+
|
|
28
|
+
def _produce_histogram_data(self, job_result) -> dict | None:
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
def _get_provider_job_id(self, job) -> str:
|
|
32
|
+
return job.get("provider_job_id") if isinstance(job, dict) else None
|
|
33
|
+
|
|
34
|
+
def _get_job_status(self, job) -> str:
|
|
35
|
+
return "DONE"
|
|
36
|
+
|
|
37
|
+
def _calculate_execution_time(self, job_result):
|
|
38
|
+
return job_result.get("execution_time", None)
|
|
39
|
+
|
|
40
|
+
def _get_job_result(self, job):
|
|
41
|
+
return job
|
|
42
|
+
def _get_shots(self, job_result) -> int | None:
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
def _on_execution(self, authentication: Authentication,
|
|
46
|
+
project_header: CustomHeader,
|
|
47
|
+
workspace_header: CustomHeader,
|
|
48
|
+
execution_callback: CallbackUrl, circuit,
|
|
49
|
+
options: CircuitRunningOption):
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
@param authentication: authentication information
|
|
53
|
+
@param project_header: project header information
|
|
54
|
+
@param execution_callback: execution step callback urls
|
|
55
|
+
@param circuit: circuit will be run
|
|
56
|
+
@param options: options will use for running
|
|
57
|
+
@return: job and job response
|
|
58
|
+
"""
|
|
59
|
+
self.logger.debug("On execution started")
|
|
60
|
+
|
|
61
|
+
job_response = JobResponse(authentication=authentication,
|
|
62
|
+
project_header=project_header,
|
|
63
|
+
workspace_header=workspace_header,
|
|
64
|
+
status_code=StatusCode.DONE)
|
|
65
|
+
|
|
66
|
+
update_job_metadata(job_response=job_response,
|
|
67
|
+
callback_url=execution_callback.on_start)
|
|
68
|
+
try:
|
|
69
|
+
job = self._create_job(circuit=circuit, options=options)
|
|
70
|
+
job_response.provider_job_id = self._get_provider_job_id(job)
|
|
71
|
+
job_response.job_status = self._get_job_status(job)
|
|
72
|
+
|
|
73
|
+
job_result = self._get_job_result(job)
|
|
74
|
+
job_response.job_result = job_result
|
|
75
|
+
original_job_result = job_result
|
|
76
|
+
|
|
77
|
+
update_job_metadata(job_response=job_response,
|
|
78
|
+
callback_url=execution_callback.on_done)
|
|
79
|
+
|
|
80
|
+
return original_job_result, job_response
|
|
81
|
+
|
|
82
|
+
except Exception as exception:
|
|
83
|
+
self.logger.debug(
|
|
84
|
+
"Execute job failed with error {}".format(str(exception)))
|
|
85
|
+
|
|
86
|
+
job_response.status_code = StatusCode.ERROR
|
|
87
|
+
job_response.content_type = MediaType.APPLICATION_JSON
|
|
88
|
+
job_response.job_status = JobStatus.ERROR.value
|
|
89
|
+
job_response.job_result = {"error": str(exception)}
|
|
90
|
+
|
|
91
|
+
update_job_metadata(job_response=job_response,
|
|
92
|
+
callback_url=execution_callback.on_error)
|
|
93
|
+
return None, None
|
|
94
|
+
|
|
95
|
+
def run_circuit(self,
|
|
96
|
+
circuit,
|
|
97
|
+
post_processing_fn,
|
|
98
|
+
options: CircuitRunningOption,
|
|
99
|
+
callback_dict: dict,
|
|
100
|
+
authentication: Authentication,
|
|
101
|
+
project_header: CustomHeader,
|
|
102
|
+
workspace_header: CustomHeader):
|
|
103
|
+
|
|
104
|
+
original_job_result, job_response = self._on_execution(
|
|
105
|
+
authentication=authentication,
|
|
106
|
+
project_header=project_header,
|
|
107
|
+
workspace_header=workspace_header,
|
|
108
|
+
execution_callback=callback_dict.get(InvocationStep.EXECUTION),
|
|
109
|
+
circuit=circuit,
|
|
110
|
+
options=options)
|
|
111
|
+
|
|
112
|
+
if original_job_result is None:
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
job_response = self._on_analysis(
|
|
116
|
+
job_response=job_response,
|
|
117
|
+
original_job_result=original_job_result,
|
|
118
|
+
analysis_callback=callback_dict.get(InvocationStep.ANALYSIS))
|
|
119
|
+
|
|
120
|
+
if job_response is None:
|
|
121
|
+
return
|
|
122
|
+
|
|
123
|
+
self._on_finalization(job_result=original_job_result.get('result'),
|
|
124
|
+
authentication=authentication,
|
|
125
|
+
post_processing_fn=post_processing_fn,
|
|
126
|
+
finalization_callback=callback_dict.get(
|
|
127
|
+
InvocationStep.FINALIZATION),
|
|
128
|
+
project_header=project_header,
|
|
129
|
+
workspace_header=workspace_header)
|
|
130
|
+
|
|
131
|
+
def _on_analysis(self, job_response: JobResponse,
|
|
132
|
+
analysis_callback: CallbackUrl, original_job_result):
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
@param job_response:
|
|
136
|
+
@param analysis_callback:
|
|
137
|
+
@param original_job_result:
|
|
138
|
+
@return:
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
self.logger.debug("On analysis started")
|
|
142
|
+
|
|
143
|
+
update_job_metadata(job_response, analysis_callback.on_start)
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
self.logger.debug(
|
|
147
|
+
"Producing histogram data from original job result")
|
|
148
|
+
|
|
149
|
+
job_response.job_histogram = self._produce_histogram_data(
|
|
150
|
+
original_job_result)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
self.logger.debug("Calculating execution time from parsed results")
|
|
154
|
+
self._calculate_execution_time(original_job_result)
|
|
155
|
+
job_response.execution_time = self.execution_time
|
|
156
|
+
|
|
157
|
+
self.logger.debug("Retrieving shot count from job result")
|
|
158
|
+
job_response.shots = self._get_shots(original_job_result)
|
|
159
|
+
|
|
160
|
+
update_job_metadata(job_response, analysis_callback.on_done)
|
|
161
|
+
|
|
162
|
+
self.logger.info("Analysis completed successfully")
|
|
163
|
+
return job_response
|
|
164
|
+
|
|
165
|
+
except Exception as exception:
|
|
166
|
+
self.logger.exception(
|
|
167
|
+
f"Exception when analyzing job result: {exception}",
|
|
168
|
+
exc_info=True)
|
|
169
|
+
|
|
170
|
+
job_response = build_error_job_response(exception, job_response,
|
|
171
|
+
message='Error when analyzing job result')
|
|
172
|
+
|
|
173
|
+
update_job_metadata(job_response, analysis_callback.on_error)
|
|
174
|
+
return None
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Quapp Platform Project quapp_perceval_device.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
# Quapp Platform Project
|
|
5
|
+
# quapp_perceval_device.py
|
|
6
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
7
|
+
|
|
8
|
+
from quapp_common.data.device.circuit_running_option import CircuitRunningOption
|
|
9
|
+
from quapp_common.model.provider.provider import Provider
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
from .perceval_device import PercevalDevice
|
|
13
|
+
|
|
14
|
+
_POLL_INTERVAL_SECONDS = 2
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class QuappPercevalDevice(PercevalDevice):
|
|
18
|
+
def __init__(self, provider: Provider, device_specification: str):
|
|
19
|
+
super().__init__(provider, device_specification)
|
|
20
|
+
|
|
21
|
+
def _create_job(self, circuit, options: CircuitRunningOption):
|
|
22
|
+
self.logger.debug(f'Creating job with {options.shots} shots')
|
|
23
|
+
|
|
24
|
+
import perceval as pcvl
|
|
25
|
+
from perceval.algorithm import Sampler
|
|
26
|
+
|
|
27
|
+
# self.device is the RemoteProcessor created by the provider
|
|
28
|
+
# (holds the Quandela Cloud token + device name). The circuit must be
|
|
29
|
+
# mounted on it so the job is submitted to the cloud, otherwise Sampler
|
|
30
|
+
# would run on a local simulator and never appear in the cloud job list.
|
|
31
|
+
remote_processor = self.device
|
|
32
|
+
remote_processor.set_circuit(circuit)
|
|
33
|
+
|
|
34
|
+
# Default input state: one photon in each input mode.
|
|
35
|
+
remote_processor.with_input(pcvl.BasicState([1] * circuit.m))
|
|
36
|
+
remote_processor.min_detected_photons_filter(1)
|
|
37
|
+
|
|
38
|
+
sampler = Sampler(remote_processor, max_shots_per_call=options.shots)
|
|
39
|
+
|
|
40
|
+
job = sampler.samples.execute_async(max_samples=options.shots)
|
|
41
|
+
provider_job_id = getattr(job, "id", None)
|
|
42
|
+
self.logger.debug(
|
|
43
|
+
f'Async job submitted to Quandela Cloud, '
|
|
44
|
+
f'provider_job_id={provider_job_id}')
|
|
45
|
+
|
|
46
|
+
while True:
|
|
47
|
+
status = job.status
|
|
48
|
+
if status.completed:
|
|
49
|
+
break
|
|
50
|
+
self.logger.debug(
|
|
51
|
+
f'Job not completed yet, polling again in '
|
|
52
|
+
f'{_POLL_INTERVAL_SECONDS}s')
|
|
53
|
+
time.sleep(_POLL_INTERVAL_SECONDS)
|
|
54
|
+
|
|
55
|
+
if not getattr(status, "success", True):
|
|
56
|
+
stop_message = getattr(status, "stop_message", None)
|
|
57
|
+
raise Exception(f'Job failed on Quandela Cloud: {stop_message}')
|
|
58
|
+
|
|
59
|
+
sample_result = job.get_results()
|
|
60
|
+
execution_time = status.duration
|
|
61
|
+
|
|
62
|
+
self.logger.debug(
|
|
63
|
+
f'Job completed in {execution_time}s, '
|
|
64
|
+
f'provider_job_id={provider_job_id}')
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
"result": str(sample_result),
|
|
68
|
+
"execution_time": execution_time,
|
|
69
|
+
"provider_job_id": provider_job_id,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _is_simulator(self) -> bool:
|
|
75
|
+
self.logger.debug('Checking if simulator')
|
|
76
|
+
self.logger.debug(f'Simulator: {False}')
|
|
77
|
+
return False
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""
|
|
2
|
+
QApp Platform Project quapp_perceval_provider.py Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
3
|
+
"""
|
|
4
|
+
# Quapp Platform Project
|
|
5
|
+
# quapp_perceval_provider.py
|
|
6
|
+
# Copyright © CITYNOW Co. Ltd. All rights reserved.
|
|
7
|
+
|
|
8
|
+
from quapp_common.config.logging_config import job_logger
|
|
9
|
+
from quapp_common.enum.provider_tag import ProviderTag
|
|
10
|
+
from quapp_common.model.provider.provider import Provider
|
|
11
|
+
|
|
12
|
+
logger = job_logger('QuappPercevalProvider')
|
|
13
|
+
|
|
14
|
+
_PROVIDER_TAG = (
|
|
15
|
+
getattr(ProviderTag, "QUANDELA_CLOUD", None)
|
|
16
|
+
or getattr(ProviderTag, "QUANDELA", None)
|
|
17
|
+
or getattr(ProviderTag, "QUAO_QUANTUM_SIMULATOR", None)
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class QuappPercevalProvider(Provider):
|
|
22
|
+
|
|
23
|
+
def collect_provider(self):
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
def __init__(self, authentication: dict = None):
|
|
27
|
+
super().__init__(_PROVIDER_TAG)
|
|
28
|
+
self._authentication = authentication or {}
|
|
29
|
+
|
|
30
|
+
def get_backend(self, device_specification):
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
from perceval import RemoteProcessor
|
|
34
|
+
|
|
35
|
+
token = self._authentication.get("apiKey")
|
|
36
|
+
|
|
37
|
+
return RemoteProcessor(device_specification, token=token)
|
|
38
|
+
except Exception:
|
|
39
|
+
logger.exception(f'Unsupported device: {device_specification}')
|
|
40
|
+
raise Exception('Unsupported device')
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: quapp-perceval
|
|
3
|
+
Version: 0.0.1
|
|
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://quapp.cloud/
|
|
15
|
+
Keywords: quapp,quapp-perceval,quantum
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Requires-Python: <3.11,>=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: quapp-common==0.0.13
|
|
23
|
+
Requires-Dist: perceval-quandela==1.2.1
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: black; extra == "dev"
|
|
26
|
+
Requires-Dist: bumpver; extra == "dev"
|
|
27
|
+
Requires-Dist: isort; extra == "dev"
|
|
28
|
+
Requires-Dist: pip-tools; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# quapp-perceval
|
|
33
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
quapp_perceval/__init__.py
|
|
5
|
+
quapp_perceval.egg-info/PKG-INFO
|
|
6
|
+
quapp_perceval.egg-info/SOURCES.txt
|
|
7
|
+
quapp_perceval.egg-info/dependency_links.txt
|
|
8
|
+
quapp_perceval.egg-info/requires.txt
|
|
9
|
+
quapp_perceval.egg-info/top_level.txt
|
|
10
|
+
quapp_perceval/async_tasks/__init__.py
|
|
11
|
+
quapp_perceval/async_tasks/perceval_circuit_export_task.py
|
|
12
|
+
quapp_perceval/component/__init__.py
|
|
13
|
+
quapp_perceval/component/backend/__init__.py
|
|
14
|
+
quapp_perceval/component/backend/perceval_invocation.py
|
|
15
|
+
quapp_perceval/factory/__init__.py
|
|
16
|
+
quapp_perceval/factory/perceval_device_factory.py
|
|
17
|
+
quapp_perceval/factory/perceval_handler_factory.py
|
|
18
|
+
quapp_perceval/factory/perceval_provider_factory.py
|
|
19
|
+
quapp_perceval/handler/__init__.py
|
|
20
|
+
quapp_perceval/handler/invocation_handler.py
|
|
21
|
+
quapp_perceval/model/__init__.py
|
|
22
|
+
quapp_perceval/model/device/__init__.py
|
|
23
|
+
quapp_perceval/model/device/perceval_device.py
|
|
24
|
+
quapp_perceval/model/device/quapp_perceval_device.py
|
|
25
|
+
quapp_perceval/model/provider/__init__.py
|
|
26
|
+
quapp_perceval/model/provider/quapp_perceval_provider.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
quapp_perceval
|