classiq 0.33.0__py3-none-any.whl → 0.35.0__py3-none-any.whl
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.
- classiq/_internals/api_wrapper.py +61 -23
- classiq/_internals/client.py +4 -1
- classiq/_internals/jobs.py +9 -2
- classiq/applications_model_constructors/grover_model_constructor.py +1 -1
- classiq/execution/__init__.py +9 -2
- classiq/execution/jobs.py +84 -11
- classiq/executor.py +3 -10
- classiq/interface/_version.py +1 -1
- classiq/interface/backend/backend_preferences.py +17 -0
- classiq/interface/backend/pydantic_backend.py +8 -0
- classiq/interface/backend/quantum_backend_providers.py +15 -1
- classiq/interface/chemistry/ground_state_problem.py +1 -1
- classiq/interface/chemistry/operator.py +198 -0
- classiq/interface/execution/jobs.py +28 -0
- classiq/interface/executor/execution_request.py +2 -12
- classiq/interface/generator/arith/arithmetic_expression_validator.py +1 -0
- classiq/interface/generator/arith/arithmetic_param_getters.py +12 -0
- classiq/interface/generator/arith/binary_ops.py +34 -0
- classiq/interface/generator/expressions/expression.py +3 -0
- classiq/interface/generator/expressions/qmod_sized_proxy.py +12 -2
- classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
- classiq/interface/generator/function_params.py +4 -0
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/atomic_quantum_functions.py +2 -2
- classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +42 -105
- classiq/interface/generator/generated_circuit.py +8 -44
- classiq/interface/generator/generated_circuit_data.py +2 -11
- classiq/interface/generator/model/preferences/preferences.py +4 -2
- classiq/interface/generator/quantum_function_call.py +1 -1
- classiq/interface/hardware.py +2 -0
- classiq/interface/ide/show.py +1 -14
- classiq/interface/model/bind_operation.py +10 -0
- classiq/interface/model/handle_binding.py +18 -0
- classiq/interface/model/model.py +12 -3
- classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +2 -1
- classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -1
- classiq/interface/model/quantum_expressions/quantum_expression.py +9 -6
- classiq/interface/model/quantum_function_call.py +9 -339
- classiq/interface/model/quantum_statement.py +3 -2
- classiq/interface/server/routes.py +8 -6
- classiq/model/function_handler.pyi +86 -85
- classiq/qmod/__init__.py +2 -2
- classiq/qmod/builtins/__init__.py +8 -0
- classiq/{interface/model/clients/qmod/qmod_builtins.py → qmod/builtins/functions.py} +46 -165
- classiq/qmod/builtins/operations.py +19 -0
- classiq/qmod/builtins/structs.py +128 -0
- classiq/qmod/declaration_inferrer.py +34 -17
- classiq/qmod/model_state_container.py +6 -3
- classiq/qmod/qmod_parameter.py +24 -8
- classiq/qmod/qmod_variable.py +4 -4
- classiq/qmod/quantum_callable.py +2 -2
- classiq/qmod/quantum_expandable.py +7 -3
- classiq/qmod/quantum_function.py +9 -9
- {classiq-0.33.0.dist-info → classiq-0.35.0.dist-info}/METADATA +1 -1
- {classiq-0.33.0.dist-info → classiq-0.35.0.dist-info}/RECORD +56 -55
- classiq/interface/model/clients/qmod/__init__.py +0 -0
- classiq/interface/model/semantics.py +0 -15
- classiq/qmod/qmod_builtins.py +0 -4
- /classiq/interface/{model/clients → execution}/__init__.py +0 -0
- {classiq-0.33.0.dist-info → classiq-0.35.0.dist-info}/WHEEL +0 -0
@@ -1,13 +1,16 @@
|
|
1
1
|
import json
|
2
|
-
from typing import
|
2
|
+
from typing import Dict, Optional, Protocol, Type, TypeVar
|
3
3
|
|
4
4
|
import pydantic
|
5
|
-
from pydantic import parse_obj_as
|
6
5
|
|
7
6
|
import classiq.interface.pyomo_extension # noqa: F401 - patches pyomo to add few features
|
8
7
|
from classiq.interface.analyzer import analysis_params, result as analysis_result
|
9
8
|
from classiq.interface.analyzer.analysis_params import AnalysisRBParams
|
10
9
|
from classiq.interface.chemistry import ground_state_problem, operator
|
10
|
+
from classiq.interface.execution.jobs import (
|
11
|
+
ExecutionJobDetailsV1,
|
12
|
+
ExecutionJobsQueryResultsV1,
|
13
|
+
)
|
11
14
|
from classiq.interface.executor import execution_request, result as execute_result
|
12
15
|
from classiq.interface.generator import generated_circuit as generator_result
|
13
16
|
from classiq.interface.jobs import JobDescription, JobID, JobStatus, JSONObject
|
@@ -19,16 +22,14 @@ from classiq._internals.enum_utils import StrEnum
|
|
19
22
|
from classiq._internals.jobs import JobPoller
|
20
23
|
from classiq.exceptions import ClassiqAPIError, ClassiqValueError
|
21
24
|
|
22
|
-
_FAIL_FAST_INDICATOR = "{"
|
23
25
|
ResultType = TypeVar("ResultType", bound=pydantic.BaseModel)
|
24
|
-
OtherResultType = TypeVar("OtherResultType", bound=pydantic.BaseModel)
|
25
|
-
_Circuit = Union[generator_result.GeneratedCircuit, generator_result.ExecutionCircuit]
|
26
26
|
|
27
27
|
|
28
28
|
class HTTPMethod(StrEnum):
|
29
29
|
# Partial backport from Python 3.11
|
30
30
|
GET = "GET"
|
31
31
|
POST = "POST"
|
32
|
+
PATCH = "PATCH"
|
32
33
|
|
33
34
|
|
34
35
|
class StatusType(Protocol):
|
@@ -45,26 +46,22 @@ def _parse_job_response(
|
|
45
46
|
return output_type.parse_obj(description)
|
46
47
|
|
47
48
|
|
48
|
-
def _parse_job_response_multiple_outputs(
|
49
|
-
job_result: JobDescription[JSONObject],
|
50
|
-
output_type: Any, # UnionType in Python 3.10,
|
51
|
-
) -> Union[ResultType, OtherResultType]:
|
52
|
-
description = job_result.description
|
53
|
-
if job_result.status != JobStatus.COMPLETED:
|
54
|
-
raise ClassiqAPIError(description["details"])
|
55
|
-
return parse_obj_as(output_type, description)
|
56
|
-
|
57
|
-
|
58
49
|
class ApiWrapper:
|
59
50
|
@classmethod
|
60
51
|
async def _call_task_pydantic(
|
61
|
-
cls,
|
52
|
+
cls,
|
53
|
+
http_method: str,
|
54
|
+
url: str,
|
55
|
+
model: pydantic.BaseModel,
|
56
|
+
use_versioned_url: bool = True,
|
62
57
|
) -> dict:
|
63
58
|
# TODO: we can't use model.dict() - it doesn't serialize complex class.
|
64
59
|
# This was added because JSON serializer doesn't serialize complex type, and pydantic does.
|
65
60
|
# We should add support for smarter json serialization.
|
66
61
|
body = json.loads(model.json())
|
67
|
-
return await cls._call_task(
|
62
|
+
return await cls._call_task(
|
63
|
+
http_method, url, body, use_versioned_url=use_versioned_url
|
64
|
+
)
|
68
65
|
|
69
66
|
@classmethod
|
70
67
|
async def _call_task(
|
@@ -73,24 +70,30 @@ class ApiWrapper:
|
|
73
70
|
url: str,
|
74
71
|
body: Optional[Dict] = None,
|
75
72
|
params: Optional[Dict] = None,
|
73
|
+
use_versioned_url: bool = True,
|
76
74
|
) -> dict:
|
77
75
|
res = await client().call_api(
|
78
|
-
http_method=http_method,
|
76
|
+
http_method=http_method,
|
77
|
+
url=url,
|
78
|
+
body=body,
|
79
|
+
params=params,
|
80
|
+
use_versioned_url=use_versioned_url,
|
79
81
|
)
|
80
82
|
if not isinstance(res, dict):
|
81
83
|
raise ClassiqValueError(f"Unexpected returned value: {res}")
|
82
84
|
return res
|
83
85
|
|
84
86
|
@classmethod
|
85
|
-
async def call_generation_task(
|
87
|
+
async def call_generation_task(
|
88
|
+
cls, model: ModelInput
|
89
|
+
) -> generator_result.GeneratedCircuit:
|
86
90
|
poller = JobPoller(base_url=routes.TASKS_GENERATE_FULL_PATH)
|
87
91
|
result = await poller.run_pydantic(model, timeout_sec=None)
|
88
|
-
return
|
92
|
+
return _parse_job_response(result, generator_result.GeneratedCircuit)
|
89
93
|
|
90
94
|
@classmethod
|
91
95
|
async def call_execute_generated_circuit(
|
92
|
-
cls,
|
93
|
-
circuit: _Circuit,
|
96
|
+
cls, circuit: generator_result.GeneratedCircuit
|
94
97
|
) -> execution_request.ExecutionJobDetails:
|
95
98
|
data = await cls._call_task_pydantic(
|
96
99
|
http_method=HTTPMethod.POST,
|
@@ -121,6 +124,39 @@ class ApiWrapper:
|
|
121
124
|
)
|
122
125
|
return execution_request.ExecuteGeneratedCircuitResults.parse_obj(data)
|
123
126
|
|
127
|
+
@classmethod
|
128
|
+
async def call_patch_execution_job(
|
129
|
+
cls,
|
130
|
+
job_id: JobID,
|
131
|
+
name: str,
|
132
|
+
) -> ExecutionJobDetailsV1:
|
133
|
+
data = await cls._call_task(
|
134
|
+
http_method=HTTPMethod.PATCH,
|
135
|
+
url=f"{routes.EXECUTION_SERVICE_JOBS_FULL_PATH}/{job_id.job_id}",
|
136
|
+
params={
|
137
|
+
"name": name,
|
138
|
+
},
|
139
|
+
use_versioned_url=False,
|
140
|
+
)
|
141
|
+
return ExecutionJobDetailsV1.parse_obj(data)
|
142
|
+
|
143
|
+
@classmethod
|
144
|
+
async def call_query_execution_jobs(
|
145
|
+
cls,
|
146
|
+
offset: int,
|
147
|
+
limit: int,
|
148
|
+
) -> ExecutionJobsQueryResultsV1:
|
149
|
+
data = await cls._call_task(
|
150
|
+
http_method=HTTPMethod.GET,
|
151
|
+
url=f"{routes.EXECUTION_SERVICE_JOBS_FULL_PATH}",
|
152
|
+
params={
|
153
|
+
"offset": offset,
|
154
|
+
"limit": limit,
|
155
|
+
},
|
156
|
+
use_versioned_url=False,
|
157
|
+
)
|
158
|
+
return ExecutionJobsQueryResultsV1.parse_obj(data)
|
159
|
+
|
124
160
|
@classmethod
|
125
161
|
async def call_execute_estimate(
|
126
162
|
cls, request: execution_request.ExecutionRequest
|
@@ -231,7 +267,9 @@ class ApiWrapper:
|
|
231
267
|
async def call_generate_hamiltonian_task(
|
232
268
|
cls, problem: ground_state_problem.CHEMISTRY_PROBLEMS_TYPE
|
233
269
|
) -> operator.PauliOperator:
|
234
|
-
poller = JobPoller(
|
270
|
+
poller = JobPoller(
|
271
|
+
base_url=routes.GENERATE_HAMILTONIAN_FULL_PATH, use_versioned_url=False
|
272
|
+
)
|
235
273
|
result = await poller.run_pydantic(problem, timeout_sec=None)
|
236
274
|
return _parse_job_response(result, operator.PauliOperator)
|
237
275
|
|
classiq/_internals/client.py
CHANGED
@@ -195,11 +195,14 @@ class Client:
|
|
195
195
|
url: str,
|
196
196
|
body: Optional[Dict] = None,
|
197
197
|
params: Optional[Dict] = None,
|
198
|
+
use_versioned_url: bool = True,
|
198
199
|
) -> Union[Dict, str]:
|
200
|
+
if use_versioned_url:
|
201
|
+
url = self.make_versioned_url(url)
|
199
202
|
async with self.async_client() as async_client:
|
200
203
|
response = await async_client.request(
|
201
204
|
method=http_method,
|
202
|
-
url=
|
205
|
+
url=url,
|
203
206
|
json=body,
|
204
207
|
params=params,
|
205
208
|
)
|
classiq/_internals/jobs.py
CHANGED
@@ -52,11 +52,18 @@ class JobPoller:
|
|
52
52
|
DEV_INTERVAL = 0.05
|
53
53
|
|
54
54
|
def __init__(
|
55
|
-
self,
|
55
|
+
self,
|
56
|
+
base_url: str,
|
57
|
+
required_headers: Optional[Set[str]] = None,
|
58
|
+
use_versioned_url: bool = True,
|
56
59
|
) -> None:
|
57
60
|
self._required_headers = required_headers or set()
|
58
61
|
client_instance = client()
|
59
|
-
self._base_url =
|
62
|
+
self._base_url = (
|
63
|
+
client_instance.make_versioned_url(base_url)
|
64
|
+
if use_versioned_url
|
65
|
+
else base_url
|
66
|
+
)
|
60
67
|
self._async_client = client_instance.async_client()
|
61
68
|
self._mode = client_instance.config.mode
|
62
69
|
|
classiq/execution/__init__.py
CHANGED
@@ -9,13 +9,20 @@ from ..interface.executor.execution_preferences import __all__ as _ep_all
|
|
9
9
|
from ..interface.executor.iqae_result import IQAEResult
|
10
10
|
from ..interface.executor.result import ExecutionDetails
|
11
11
|
from ..interface.executor.vqe_result import VQESolverResult
|
12
|
-
from .jobs import ExecutionJob
|
12
|
+
from .jobs import ExecutionJob, get_execution_jobs, get_execution_jobs_async
|
13
13
|
|
14
14
|
__all__ = (
|
15
15
|
_be_all
|
16
16
|
+ _ep_all
|
17
17
|
+ _exec_all
|
18
|
-
+ [
|
18
|
+
+ [
|
19
|
+
"ExecutionDetails",
|
20
|
+
"VQESolverResult",
|
21
|
+
"IQAEResult",
|
22
|
+
"ExecutionJob",
|
23
|
+
"get_execution_jobs",
|
24
|
+
"get_execution_jobs_async",
|
25
|
+
]
|
19
26
|
)
|
20
27
|
|
21
28
|
|
classiq/execution/jobs.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
from
|
1
|
+
import webbrowser
|
2
|
+
from datetime import datetime
|
3
|
+
from typing import List, Optional, Union
|
4
|
+
from urllib.parse import urljoin
|
4
5
|
|
6
|
+
from classiq.interface.execution.jobs import ExecutionJobDetailsV1
|
5
7
|
from classiq.interface.executor.execution_request import (
|
6
8
|
ExecutionJobDetails,
|
7
9
|
ResultsCollection,
|
@@ -11,19 +13,67 @@ from classiq.interface.server.routes import EXECUTION_JOBS_FULL_PATH
|
|
11
13
|
|
12
14
|
from classiq._internals.api_wrapper import ApiWrapper
|
13
15
|
from classiq._internals.async_utils import syncify_function
|
16
|
+
from classiq._internals.client import client
|
14
17
|
from classiq._internals.jobs import JobID, JobPoller
|
15
18
|
from classiq.exceptions import ClassiqAPIError
|
16
19
|
|
20
|
+
_JobDetails = Union[ExecutionJobDetails, ExecutionJobDetailsV1]
|
21
|
+
|
22
|
+
|
23
|
+
class ExecutionJob:
|
24
|
+
_details: _JobDetails
|
25
|
+
_result: Optional[ResultsCollection]
|
26
|
+
|
27
|
+
def __init__(self, details: _JobDetails) -> None:
|
28
|
+
self._details = details
|
29
|
+
self._result = None
|
30
|
+
|
31
|
+
@property
|
32
|
+
def id(self) -> str:
|
33
|
+
return self._details.id
|
34
|
+
|
35
|
+
@property
|
36
|
+
def name(self) -> Optional[str]:
|
37
|
+
return self._details.name
|
38
|
+
|
39
|
+
@property
|
40
|
+
def start_time(self) -> datetime:
|
41
|
+
return self._details.start_time
|
42
|
+
|
43
|
+
@property
|
44
|
+
def end_time(self) -> Optional[datetime]:
|
45
|
+
return self._details.end_time
|
17
46
|
|
18
|
-
|
19
|
-
|
47
|
+
@property
|
48
|
+
def provider(self) -> Optional[str]:
|
49
|
+
return self._details.provider
|
20
50
|
|
21
|
-
|
22
|
-
|
51
|
+
@property
|
52
|
+
def backend_name(self) -> Optional[str]:
|
53
|
+
return self._details.backend_name
|
23
54
|
|
24
|
-
|
25
|
-
|
26
|
-
|
55
|
+
@property
|
56
|
+
def status(self) -> JobStatus:
|
57
|
+
return self._details.status
|
58
|
+
|
59
|
+
@property
|
60
|
+
def num_shots(self) -> Optional[int]:
|
61
|
+
return self._details.num_shots
|
62
|
+
|
63
|
+
@property
|
64
|
+
def program_id(self) -> Optional[str]:
|
65
|
+
return self._details.program_id
|
66
|
+
|
67
|
+
@property
|
68
|
+
def error(self) -> Optional[str]:
|
69
|
+
return self._details.error
|
70
|
+
|
71
|
+
def __repr__(self) -> str:
|
72
|
+
class_name = self.__class__.__name__
|
73
|
+
if self.name is None:
|
74
|
+
return f"{class_name}(id={self.id!r})"
|
75
|
+
else:
|
76
|
+
return f"{class_name}(name={self.name!r}, id={self.id!r})"
|
27
77
|
|
28
78
|
@classmethod
|
29
79
|
async def from_id_async(cls, id: str) -> "ExecutionJob":
|
@@ -64,7 +114,7 @@ class ExecutionJob(ExecutionJobDetails):
|
|
64
114
|
|
65
115
|
async def _poll_job(self, timeout_sec: Optional[float] = None) -> None:
|
66
116
|
def response_parser(json_response: JSONObject) -> Optional[bool]:
|
67
|
-
self.
|
117
|
+
self._details = ExecutionJobDetails.parse_obj(json_response)
|
68
118
|
if self.status.is_final():
|
69
119
|
return True
|
70
120
|
return None
|
@@ -75,3 +125,26 @@ class ExecutionJob(ExecutionJobDetails):
|
|
75
125
|
response_parser=response_parser,
|
76
126
|
timeout_sec=timeout_sec,
|
77
127
|
)
|
128
|
+
|
129
|
+
async def rename_async(self, name: str) -> None:
|
130
|
+
self._details = await ApiWrapper.call_patch_execution_job(self._job_id, name)
|
131
|
+
|
132
|
+
rename = syncify_function(rename_async)
|
133
|
+
|
134
|
+
@property
|
135
|
+
def ide_url(self) -> str:
|
136
|
+
base_url = client().config.ide
|
137
|
+
return urljoin(base_url, f"jobs/{self.id}")
|
138
|
+
|
139
|
+
def open_in_ide(self) -> None:
|
140
|
+
webbrowser.open_new_tab(self.ide_url)
|
141
|
+
|
142
|
+
|
143
|
+
async def get_execution_jobs_async(
|
144
|
+
offset: int = 0, limit: int = 50
|
145
|
+
) -> List[ExecutionJob]:
|
146
|
+
result = await ApiWrapper().call_query_execution_jobs(offset=offset, limit=limit)
|
147
|
+
return [ExecutionJob(details) for details in result.results]
|
148
|
+
|
149
|
+
|
150
|
+
get_execution_jobs = syncify_function(get_execution_jobs_async)
|
classiq/executor.py
CHANGED
@@ -3,7 +3,6 @@ import functools
|
|
3
3
|
from typing import Optional, Tuple, Union
|
4
4
|
|
5
5
|
import more_itertools
|
6
|
-
from pydantic import parse_raw_as
|
7
6
|
from typing_extensions import TypeAlias
|
8
7
|
|
9
8
|
from classiq.interface.backend.backend_preferences import BackendPreferencesTypes
|
@@ -19,10 +18,7 @@ from classiq.interface.executor.execution_request import (
|
|
19
18
|
from classiq.interface.executor.quantum_instruction_set import QuantumInstructionSet
|
20
19
|
from classiq.interface.executor.quantum_program import MultipleArguments, QuantumProgram
|
21
20
|
from classiq.interface.executor.result import ExecutionDetails
|
22
|
-
from classiq.interface.generator.generated_circuit import
|
23
|
-
ExecutionCircuit,
|
24
|
-
GeneratedCircuit,
|
25
|
-
)
|
21
|
+
from classiq.interface.generator.generated_circuit import GeneratedCircuit
|
26
22
|
|
27
23
|
from classiq._internals.api_wrapper import ApiWrapper
|
28
24
|
from classiq._internals.async_utils import syncify_function
|
@@ -40,11 +36,8 @@ _MAX_ARGUMENTS_SIZE = 1024
|
|
40
36
|
|
41
37
|
def _parse_serialized_qprog(
|
42
38
|
quantum_program: SerializedQuantumProgram,
|
43
|
-
) ->
|
44
|
-
return
|
45
|
-
Union[GeneratedCircuit, ExecutionCircuit], # type:ignore[arg-type]
|
46
|
-
quantum_program,
|
47
|
-
)
|
39
|
+
) -> GeneratedCircuit:
|
40
|
+
return GeneratedCircuit.parse_raw(quantum_program)
|
48
41
|
|
49
42
|
|
50
43
|
async def execute_async(quantum_program: SerializedQuantumProgram) -> ExecutionJob:
|
classiq/interface/_version.py
CHANGED
@@ -9,6 +9,7 @@ from pydantic import BaseModel, validator
|
|
9
9
|
from classiq.interface.backend import pydantic_backend
|
10
10
|
from classiq.interface.backend.quantum_backend_providers import (
|
11
11
|
EXACT_SIMULATORS,
|
12
|
+
AliceBobBackendNames,
|
12
13
|
AmazonBraketBackendNames,
|
13
14
|
AzureQuantumBackendNames,
|
14
15
|
ClassiqAerBackendNames,
|
@@ -55,6 +56,19 @@ class BackendPreferences(BaseModel):
|
|
55
56
|
AWS_DEFAULT_JOB_TIMEOUT_SECONDS = int(timedelta(minutes=5).total_seconds())
|
56
57
|
|
57
58
|
|
59
|
+
class AliceBobBackendPreferences(BackendPreferences):
|
60
|
+
backend_service_provider: ProviderTypeVendor.ALICE_BOB
|
61
|
+
api_key: pydantic_backend.PydanticAliceBobApiKeyType = pydantic.Field(
|
62
|
+
..., description="AliceBob API key"
|
63
|
+
)
|
64
|
+
|
65
|
+
@pydantic.root_validator(pre=True)
|
66
|
+
def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
67
|
+
return values_with_discriminator(
|
68
|
+
values, "backend_service_provider", ProviderVendor.ALICE_AND_BOB
|
69
|
+
)
|
70
|
+
|
71
|
+
|
58
72
|
class ClassiqBackendPreferences(BackendPreferences):
|
59
73
|
backend_service_provider: ProviderTypeVendor.CLASSIQ
|
60
74
|
|
@@ -214,6 +228,7 @@ BackendPreferencesTypes = Union[
|
|
214
228
|
AwsBackendPreferences,
|
215
229
|
IonqBackendPreferences,
|
216
230
|
GCPBackendPreferences,
|
231
|
+
AliceBobBackendPreferences,
|
217
232
|
]
|
218
233
|
|
219
234
|
__all__ = [
|
@@ -230,6 +245,8 @@ __all__ = [
|
|
230
245
|
"IonqBackendNames",
|
231
246
|
"ClassiqNvidiaBackendNames",
|
232
247
|
"GCPBackendPreferences",
|
248
|
+
"AliceBobBackendPreferences",
|
249
|
+
"AliceBobBackendNames",
|
233
250
|
]
|
234
251
|
|
235
252
|
|
@@ -6,7 +6,9 @@ import pydantic
|
|
6
6
|
AZURE_QUANTUM_RESOURCE_ID_REGEX = r"^/subscriptions/([a-fA-F0-9-]*)/resourceGroups/([^\s/]*)/providers/Microsoft\.Quantum/Workspaces/([^\s/]*)$"
|
7
7
|
|
8
8
|
_IONQ_API_KEY_LENGTH: int = 32
|
9
|
+
_ALICE_BOB_API_KEY_LENGTH: int = 72
|
9
10
|
INVALID_API_KEY: str = _IONQ_API_KEY_LENGTH * "a"
|
11
|
+
INVALID_API_KEY_ALICE_BOB: str = _ALICE_BOB_API_KEY_LENGTH * "a"
|
10
12
|
MAX_EXECUTION_TIMEOUT_SECONDS = timedelta(hours=4).total_seconds()
|
11
13
|
|
12
14
|
if TYPE_CHECKING:
|
@@ -18,6 +20,7 @@ if TYPE_CHECKING:
|
|
18
20
|
PydanticIonQApiKeyType = str
|
19
21
|
PydanticArgumentNameType = str
|
20
22
|
PydanticExecutionParameter = str
|
23
|
+
PydanticAliceBobApiKeyType = str
|
21
24
|
else:
|
22
25
|
# TODO Simplify regular expressions in this file
|
23
26
|
|
@@ -32,6 +35,11 @@ else:
|
|
32
35
|
PydanticIonQApiKeyType = pydantic.constr(
|
33
36
|
regex=f"[A-Za-z0-9]{{{_IONQ_API_KEY_LENGTH}}}"
|
34
37
|
)
|
38
|
+
|
39
|
+
PydanticAliceBobApiKeyType = pydantic.constr(
|
40
|
+
regex=f"[A-Za-z0-9]{{{_ALICE_BOB_API_KEY_LENGTH}}}"
|
41
|
+
)
|
42
|
+
|
35
43
|
PydanticExecutionTimeout = pydantic.conint(gt=0, le=MAX_EXECUTION_TIMEOUT_SECONDS)
|
36
44
|
|
37
45
|
PydanticArgumentNameType = pydantic.constr(regex="[_a-zA-Z][_a-zA-Z0-9]*")
|
@@ -16,6 +16,8 @@ class ProviderVendor(StrEnum):
|
|
16
16
|
AMAZON_BRAKET = "Amazon Braket"
|
17
17
|
IONQ = "IonQ"
|
18
18
|
GOOGLE = "Google"
|
19
|
+
ALICE_AND_BOB = "Alice and Bob"
|
20
|
+
OQC = "OQC"
|
19
21
|
|
20
22
|
|
21
23
|
class ProviderTypeVendor:
|
@@ -25,6 +27,8 @@ class ProviderTypeVendor:
|
|
25
27
|
AMAZON_BRAKET = Literal[ProviderVendor.AMAZON_BRAKET]
|
26
28
|
IONQ = Literal[ProviderVendor.IONQ]
|
27
29
|
GOOGLE = Literal[ProviderVendor.GOOGLE]
|
30
|
+
ALICE_BOB = Literal[ProviderVendor.ALICE_AND_BOB]
|
31
|
+
OQC = Literal[ProviderVendor.OQC]
|
28
32
|
|
29
33
|
|
30
34
|
class ClassiqAerBackendNames(StrEnum):
|
@@ -143,6 +147,17 @@ class GoogleNvidiaBackendNames(StrEnum):
|
|
143
147
|
CUQUANTUM = "cuquantum"
|
144
148
|
|
145
149
|
|
150
|
+
class AliceBobBackendNames(StrEnum):
|
151
|
+
PHYSICAL_CATS_40 = "EMU:40Q:PHYSICAL_CATS"
|
152
|
+
PERFECT_QUBITS = "EMU:20Q:PERFECT_QUBITS"
|
153
|
+
LOGICAL_TARGET = "EMU:40Q:LOGICAL_TARGET"
|
154
|
+
PHYSICAL_CATS_6 = "EMU:6Q:PHYSICAL_CATS"
|
155
|
+
LOGICAL_EARLY = "EMU:15Q:LOGICAL_EARLY"
|
156
|
+
LESCANNE = "EMU:1Q:LESCANNE_2020"
|
157
|
+
TRANSMONS = "EMU:7Q:TRANSMONS"
|
158
|
+
FATCAT = "QPU:1Q:FATCAT_0"
|
159
|
+
|
160
|
+
|
146
161
|
EXACT_SIMULATORS = {
|
147
162
|
IonqBackendNames.SIMULATOR,
|
148
163
|
AzureQuantumBackendNames.IONQ_SIMULATOR,
|
@@ -156,7 +171,6 @@ EXACT_SIMULATORS = {
|
|
156
171
|
|
157
172
|
AllIBMQBackendNames = IBMQHardwareNames
|
158
173
|
|
159
|
-
|
160
174
|
AllBackendsNameByVendor = Union[
|
161
175
|
AllIBMQBackendNames,
|
162
176
|
AzureQuantumBackendNames,
|
@@ -64,7 +64,7 @@ class GroundStateProblem(HashablePydanticBaseModel):
|
|
64
64
|
|
65
65
|
|
66
66
|
class MoleculeProblem(GroundStateProblem):
|
67
|
-
molecule: Molecule
|
67
|
+
molecule: Molecule
|
68
68
|
basis: str = pydantic.Field(default="sto3g", description="Molecular basis set")
|
69
69
|
freeze_core: bool = pydantic.Field(default=False)
|
70
70
|
remove_orbitals: List[int] = pydantic.Field(
|