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.
Files changed (59) hide show
  1. classiq/_internals/api_wrapper.py +61 -23
  2. classiq/_internals/client.py +4 -1
  3. classiq/_internals/jobs.py +9 -2
  4. classiq/applications_model_constructors/grover_model_constructor.py +1 -1
  5. classiq/execution/__init__.py +9 -2
  6. classiq/execution/jobs.py +84 -11
  7. classiq/executor.py +3 -10
  8. classiq/interface/_version.py +1 -1
  9. classiq/interface/backend/backend_preferences.py +17 -0
  10. classiq/interface/backend/pydantic_backend.py +8 -0
  11. classiq/interface/backend/quantum_backend_providers.py +15 -1
  12. classiq/interface/chemistry/ground_state_problem.py +1 -1
  13. classiq/interface/chemistry/operator.py +198 -0
  14. classiq/interface/execution/jobs.py +28 -0
  15. classiq/interface/executor/execution_request.py +2 -12
  16. classiq/interface/generator/arith/arithmetic_expression_validator.py +1 -0
  17. classiq/interface/generator/arith/arithmetic_param_getters.py +12 -0
  18. classiq/interface/generator/arith/binary_ops.py +34 -0
  19. classiq/interface/generator/expressions/expression.py +3 -0
  20. classiq/interface/generator/expressions/qmod_sized_proxy.py +12 -2
  21. classiq/interface/generator/function_param_list_without_self_reference.py +2 -0
  22. classiq/interface/generator/function_params.py +4 -0
  23. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/atomic_quantum_functions.py +2 -2
  24. classiq/interface/generator/functions/core_lib_declarations/quantum_functions/std_lib_functions.py +42 -105
  25. classiq/interface/generator/generated_circuit.py +8 -44
  26. classiq/interface/generator/generated_circuit_data.py +2 -11
  27. classiq/interface/generator/model/preferences/preferences.py +4 -2
  28. classiq/interface/generator/quantum_function_call.py +1 -1
  29. classiq/interface/hardware.py +2 -0
  30. classiq/interface/ide/show.py +1 -14
  31. classiq/interface/model/bind_operation.py +10 -0
  32. classiq/interface/model/handle_binding.py +18 -0
  33. classiq/interface/model/model.py +12 -3
  34. classiq/interface/model/quantum_expressions/amplitude_loading_operation.py +2 -1
  35. classiq/interface/model/quantum_expressions/arithmetic_operation.py +3 -1
  36. classiq/interface/model/quantum_expressions/quantum_expression.py +9 -6
  37. classiq/interface/model/quantum_function_call.py +9 -339
  38. classiq/interface/model/quantum_statement.py +3 -2
  39. classiq/interface/server/routes.py +8 -6
  40. classiq/model/function_handler.pyi +86 -85
  41. classiq/qmod/__init__.py +2 -2
  42. classiq/qmod/builtins/__init__.py +8 -0
  43. classiq/{interface/model/clients/qmod/qmod_builtins.py → qmod/builtins/functions.py} +46 -165
  44. classiq/qmod/builtins/operations.py +19 -0
  45. classiq/qmod/builtins/structs.py +128 -0
  46. classiq/qmod/declaration_inferrer.py +34 -17
  47. classiq/qmod/model_state_container.py +6 -3
  48. classiq/qmod/qmod_parameter.py +24 -8
  49. classiq/qmod/qmod_variable.py +4 -4
  50. classiq/qmod/quantum_callable.py +2 -2
  51. classiq/qmod/quantum_expandable.py +7 -3
  52. classiq/qmod/quantum_function.py +9 -9
  53. {classiq-0.33.0.dist-info → classiq-0.35.0.dist-info}/METADATA +1 -1
  54. {classiq-0.33.0.dist-info → classiq-0.35.0.dist-info}/RECORD +56 -55
  55. classiq/interface/model/clients/qmod/__init__.py +0 -0
  56. classiq/interface/model/semantics.py +0 -15
  57. classiq/qmod/qmod_builtins.py +0 -4
  58. /classiq/interface/{model/clients → execution}/__init__.py +0 -0
  59. {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 Any, Dict, Optional, Protocol, Type, TypeVar, Union
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, http_method: str, url: str, model: pydantic.BaseModel
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(http_method, url, body)
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, url=url, body=body, params=params
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(cls, model: ModelInput) -> _Circuit:
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 _parse_job_response_multiple_outputs(result, _Circuit)
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(base_url=routes.CHEMISTRY_GENERATE_HAMILTONIAN_FULL_PATH)
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
 
@@ -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=self.make_versioned_url(url),
205
+ url=url,
203
206
  json=body,
204
207
  params=params,
205
208
  )
@@ -52,11 +52,18 @@ class JobPoller:
52
52
  DEV_INTERVAL = 0.05
53
53
 
54
54
  def __init__(
55
- self, base_url: str, required_headers: Optional[Set[str]] = None
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 = client_instance.make_versioned_url(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
 
@@ -162,7 +162,7 @@ def construct_grover_model(
162
162
  port_declarations=predicate_port_decls,
163
163
  body=[
164
164
  ArithmeticOperation(
165
- expr_str=expression,
165
+ expression=Expression(expr=expression),
166
166
  result_var=HandleBinding(name="res"),
167
167
  inplace_result=True,
168
168
  ),
@@ -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
- + ["ExecutionDetails", "VQESolverResult", "IQAEResult", "ExecutionJob"]
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
- from typing import Optional
2
-
3
- from pydantic import PrivateAttr
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
- class ExecutionJob(ExecutionJobDetails):
19
- _result: Optional[ResultsCollection] = PrivateAttr(default=None)
47
+ @property
48
+ def provider(self) -> Optional[str]:
49
+ return self._details.provider
20
50
 
21
- def __init__(self, details: ExecutionJobDetails) -> None:
22
- super().__init__(**details.dict())
51
+ @property
52
+ def backend_name(self) -> Optional[str]:
53
+ return self._details.backend_name
23
54
 
24
- def _update_details(self, details: ExecutionJobDetails) -> None:
25
- for k, v in details.dict().items():
26
- setattr(self, k, v)
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._update_details(ExecutionJobDetails.parse_obj(json_response))
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
- ) -> Union[GeneratedCircuit, ExecutionCircuit]:
44
- return parse_raw_as(
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:
@@ -3,5 +3,5 @@ from packaging.version import Version
3
3
  # This file was generated automatically
4
4
  # Please don't track in version control (DONTTRACK)
5
5
 
6
- SEMVER_VERSION = '0.33.0'
6
+ SEMVER_VERSION = '0.35.0'
7
7
  VERSION = str(Version(SEMVER_VERSION))
@@ -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 = pydantic.Field(remove_hierarchy=True)
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(