classiq 0.51.1__py3-none-any.whl → 0.52.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 (149) hide show
  1. classiq/_internals/api_wrapper.py +41 -15
  2. classiq/_internals/authentication/auth0.py +20 -4
  3. classiq/_internals/authentication/password_manager.py +16 -4
  4. classiq/_internals/client.py +2 -2
  5. classiq/_internals/host_checker.py +5 -3
  6. classiq/_internals/jobs.py +3 -3
  7. classiq/analyzer/analyzer_utilities.py +1 -1
  8. classiq/applications/chemistry/ground_state_problem.py +1 -1
  9. classiq/applications/combinatorial_helpers/pyomo_utils.py +3 -1
  10. classiq/applications/qnn/gradients/quantum_gradient.py +1 -1
  11. classiq/applications/qnn/qlayer.py +2 -2
  12. classiq/execution/__init__.py +3 -0
  13. classiq/execution/execution_session.py +2 -2
  14. classiq/execution/iqcc.py +63 -0
  15. classiq/execution/jobs.py +2 -2
  16. classiq/executor.py +2 -2
  17. classiq/interface/_version.py +1 -1
  18. classiq/interface/analyzer/analysis_params.py +19 -9
  19. classiq/interface/analyzer/cytoscape_graph.py +10 -3
  20. classiq/interface/analyzer/result.py +6 -5
  21. classiq/interface/applications/qsvm.py +13 -12
  22. classiq/interface/backend/backend_preferences.py +78 -105
  23. classiq/interface/backend/ionq/ionq_quantum_program.py +12 -19
  24. classiq/interface/backend/pydantic_backend.py +24 -12
  25. classiq/interface/backend/quantum_backend_providers.py +2 -0
  26. classiq/interface/chemistry/fermionic_operator.py +7 -7
  27. classiq/interface/chemistry/ground_state_problem.py +23 -18
  28. classiq/interface/chemistry/molecule.py +10 -5
  29. classiq/interface/chemistry/operator.py +71 -44
  30. classiq/interface/combinatorial_optimization/mht_qaoa_input.py +2 -1
  31. classiq/interface/debug_info/debug_info.py +3 -4
  32. classiq/interface/execution/iqcc.py +21 -0
  33. classiq/interface/execution/jobs.py +10 -10
  34. classiq/interface/executor/aws_execution_cost.py +37 -20
  35. classiq/interface/executor/execution_preferences.py +1 -2
  36. classiq/interface/executor/execution_request.py +2 -2
  37. classiq/interface/executor/execution_result.py +4 -2
  38. classiq/interface/executor/iqae_result.py +1 -1
  39. classiq/interface/executor/optimizer_preferences.py +14 -10
  40. classiq/interface/executor/quantum_code.py +21 -16
  41. classiq/interface/executor/register_initialization.py +10 -10
  42. classiq/interface/executor/result.py +19 -16
  43. classiq/interface/executor/vqe_result.py +1 -1
  44. classiq/interface/finance/function_input.py +27 -18
  45. classiq/interface/finance/log_normal_model_input.py +2 -2
  46. classiq/interface/finance/model_input.py +3 -2
  47. classiq/interface/generator/amplitude_loading.py +8 -6
  48. classiq/interface/generator/arith/argument_utils.py +24 -0
  49. classiq/interface/generator/arith/arithmetic.py +5 -3
  50. classiq/interface/generator/arith/arithmetic_expression_abc.py +36 -14
  51. classiq/interface/generator/arith/arithmetic_operations.py +6 -3
  52. classiq/interface/generator/arith/binary_ops.py +88 -63
  53. classiq/interface/generator/arith/extremum_operations.py +22 -13
  54. classiq/interface/generator/arith/logical_ops.py +6 -4
  55. classiq/interface/generator/arith/number_utils.py +3 -3
  56. classiq/interface/generator/arith/register_user_input.py +32 -17
  57. classiq/interface/generator/arith/unary_ops.py +5 -4
  58. classiq/interface/generator/chemistry_function_params.py +2 -1
  59. classiq/interface/generator/circuit_code/circuit_code.py +2 -1
  60. classiq/interface/generator/commuting_pauli_exponentiation.py +6 -5
  61. classiq/interface/generator/complex_type.py +14 -18
  62. classiq/interface/generator/control_state.py +32 -26
  63. classiq/interface/generator/expressions/expression.py +6 -5
  64. classiq/interface/generator/function_params.py +22 -39
  65. classiq/interface/generator/functions/classical_function_declaration.py +1 -1
  66. classiq/interface/generator/functions/classical_type.py +32 -23
  67. classiq/interface/generator/functions/concrete_types.py +8 -7
  68. classiq/interface/generator/functions/function_declaration.py +4 -5
  69. classiq/interface/generator/functions/type_name.py +5 -4
  70. classiq/interface/generator/generated_circuit_data.py +9 -6
  71. classiq/interface/generator/grover_diffuser.py +26 -18
  72. classiq/interface/generator/grover_operator.py +32 -22
  73. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +3 -4
  74. classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
  75. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +8 -7
  76. classiq/interface/generator/hardware/hardware_data.py +27 -26
  77. classiq/interface/generator/hardware_efficient_ansatz.py +11 -6
  78. classiq/interface/generator/hartree_fock.py +2 -1
  79. classiq/interface/generator/identity.py +7 -2
  80. classiq/interface/generator/linear_pauli_rotations.py +27 -14
  81. classiq/interface/generator/mcu.py +15 -12
  82. classiq/interface/generator/mcx.py +18 -10
  83. classiq/interface/generator/model/constraints.py +4 -2
  84. classiq/interface/generator/model/model.py +2 -1
  85. classiq/interface/generator/model/preferences/preferences.py +30 -32
  86. classiq/interface/generator/oracles/custom_oracle.py +13 -10
  87. classiq/interface/generator/piecewise_linear_amplitude_loading.py +37 -21
  88. classiq/interface/generator/qpe.py +38 -26
  89. classiq/interface/generator/qsvm.py +4 -4
  90. classiq/interface/generator/quantum_function_call.py +57 -44
  91. classiq/interface/generator/quantum_program.py +8 -6
  92. classiq/interface/generator/range_types.py +10 -11
  93. classiq/interface/generator/standard_gates/controlled_standard_gates.py +9 -5
  94. classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
  95. classiq/interface/generator/standard_gates/u_gate.py +7 -10
  96. classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
  97. classiq/interface/generator/state_preparation/distributions.py +12 -12
  98. classiq/interface/generator/state_preparation/state_preparation.py +22 -16
  99. classiq/interface/generator/types/enum_declaration.py +2 -1
  100. classiq/interface/generator/ucc.py +2 -1
  101. classiq/interface/generator/unitary_gate.py +2 -1
  102. classiq/interface/generator/user_defined_function_params.py +3 -0
  103. classiq/interface/generator/visitor.py +1 -1
  104. classiq/interface/hardware.py +18 -3
  105. classiq/interface/helpers/custom_pydantic_types.py +38 -47
  106. classiq/interface/helpers/pydantic_model_helpers.py +3 -2
  107. classiq/interface/helpers/versioned_model.py +1 -4
  108. classiq/interface/ide/ide_data.py +5 -5
  109. classiq/interface/ide/visual_model.py +5 -5
  110. classiq/interface/interface_version.py +1 -1
  111. classiq/interface/jobs.py +12 -22
  112. classiq/interface/model/bind_operation.py +2 -1
  113. classiq/interface/model/classical_parameter_declaration.py +10 -4
  114. classiq/interface/model/handle_binding.py +20 -24
  115. classiq/interface/model/inplace_binary_operation.py +16 -9
  116. classiq/interface/model/model.py +21 -11
  117. classiq/interface/model/port_declaration.py +10 -7
  118. classiq/interface/model/quantum_expressions/arithmetic_operation.py +6 -4
  119. classiq/interface/model/quantum_function_declaration.py +22 -11
  120. classiq/interface/model/quantum_statement.py +6 -7
  121. classiq/interface/model/quantum_type.py +22 -19
  122. classiq/interface/model/statement_block.py +9 -9
  123. classiq/interface/server/global_versions.py +4 -5
  124. classiq/interface/server/routes.py +8 -0
  125. classiq/model_expansions/evaluators/parameter_types.py +3 -3
  126. classiq/model_expansions/expression_renamer.py +1 -1
  127. classiq/model_expansions/quantum_operations/control.py +11 -12
  128. classiq/model_expansions/quantum_operations/emitter.py +22 -0
  129. classiq/model_expansions/quantum_operations/expression_operation.py +2 -20
  130. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +38 -9
  131. classiq/model_expansions/quantum_operations/invert.py +1 -1
  132. classiq/model_expansions/quantum_operations/phase.py +4 -5
  133. classiq/model_expansions/quantum_operations/power.py +1 -1
  134. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +50 -9
  135. classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
  136. classiq/model_expansions/quantum_operations/within_apply.py +1 -1
  137. classiq/qmod/builtins/__init__.py +1 -3
  138. classiq/qmod/builtins/functions/__init__.py +4 -0
  139. classiq/qmod/builtins/functions/arithmetic.py +10 -0
  140. classiq/qmod/create_model_function.py +4 -4
  141. classiq/qmod/quantum_expandable.py +22 -9
  142. classiq/qmod/quantum_function.py +1 -1
  143. classiq/qmod/semantics/static_semantics_visitor.py +3 -1
  144. classiq/qmod/type_attribute_remover.py +1 -1
  145. classiq/qmod/write_qmod.py +2 -4
  146. classiq/synthesis.py +11 -13
  147. {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/METADATA +3 -2
  148. {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/RECORD +149 -147
  149. {classiq-0.51.1.dist-info → classiq-0.52.0.dist-info}/WHEEL +0 -0
@@ -1,20 +1,18 @@
1
1
  from collections.abc import Sequence
2
2
  from typing import (
3
- TYPE_CHECKING,
4
3
  Any,
5
4
  Iterable as IterableType,
6
5
  List,
7
6
  Optional,
8
7
  Tuple,
8
+ Type,
9
9
  Union,
10
10
  )
11
11
 
12
12
  import numpy as np
13
13
  import pydantic
14
14
  from numpy.typing import ArrayLike
15
-
16
- if TYPE_CHECKING:
17
- from pydantic.typing import AnyClassMethod
15
+ from pydantic import ConfigDict, field_validator
18
16
 
19
17
  from classiq.interface.helpers.versioned_model import VersionedModel
20
18
 
@@ -33,8 +31,12 @@ def listify(obj: Union[IterableType, ArrayLike]) -> list:
33
31
  return list(obj) # type: ignore[arg-type]
34
32
 
35
33
 
36
- def validate_array_to_list(name: str) -> "AnyClassMethod":
37
- return pydantic.validator(name, pre=True, allow_reuse=True)(listify)
34
+ def validate_array_to_list(name: str) -> Any:
35
+ @field_validator(name, mode="before")
36
+ def _listify(cls: Type[pydantic.BaseModel], value: Any) -> Any:
37
+ return listify(value)
38
+
39
+ return _listify
38
40
 
39
41
 
40
42
  Shape = Tuple[int, ...]
@@ -89,16 +91,15 @@ class QSVMData(VersionedModel):
89
91
  data: DataList
90
92
  labels: Optional[LabelsInt] = None
91
93
  internal_state: Optional[QSVMInternalState] = None
94
+ model_config = ConfigDict(extra="forbid")
92
95
 
93
- class Config:
94
- smart_union = True
95
- extra = "forbid"
96
-
97
- @pydantic.validator("data", pre=True)
96
+ @pydantic.field_validator("data", mode="before")
97
+ @classmethod
98
98
  def set_data(cls, data: Union[IterableType, ArrayLike]) -> list:
99
99
  return listify(data)
100
100
 
101
- @pydantic.validator("labels", pre=True)
101
+ @pydantic.field_validator("labels", mode="before")
102
+ @classmethod
102
103
  def set_labels(
103
104
  cls, labels: Optional[Union[IterableType, ArrayLike]]
104
105
  ) -> Optional[list]:
@@ -3,7 +3,8 @@ from __future__ import annotations
3
3
  from typing import Any, Dict, Iterable, List, Optional, Union
4
4
 
5
5
  import pydantic
6
- from pydantic import BaseModel, validator
6
+ from pydantic import BaseModel
7
+ from pydantic_settings import BaseSettings, SettingsConfigDict
7
8
 
8
9
  from classiq.interface.backend import pydantic_backend
9
10
  from classiq.interface.backend.quantum_backend_providers import (
@@ -21,7 +22,6 @@ from classiq.interface.backend.quantum_backend_providers import (
21
22
  )
22
23
  from classiq.interface.exceptions import ClassiqValueError
23
24
  from classiq.interface.hardware import Provider
24
- from classiq.interface.helpers.pydantic_model_helpers import values_with_discriminator
25
25
 
26
26
 
27
27
  class BackendPreferences(BaseModel):
@@ -36,10 +36,7 @@ class BackendPreferences(BaseModel):
36
36
  backend_name (str): Name of the requested backend or target.
37
37
  """
38
38
 
39
- # Due to the way the field is currently implemented, i.e. it redefined with different types
40
- # in the subclass, it shouldn't be dumped with exclude_unset. This causes this field not to appear.
41
- # For example: don't use obj.dict(exclude_unset=True).
42
- backend_service_provider: str = pydantic.Field(
39
+ backend_service_provider: ProviderVendor = pydantic.Field(
43
40
  ..., description="Provider company or cloud for the requested backend."
44
41
  )
45
42
  backend_name: str = pydantic.Field(
@@ -50,12 +47,6 @@ class BackendPreferences(BaseModel):
50
47
  def hw_provider(self) -> Provider:
51
48
  return Provider(self.backend_service_provider)
52
49
 
53
- @pydantic.validator("backend_service_provider", pre=True)
54
- def validate_backend_service_provider(
55
- cls, backend_service_provider: Any
56
- ) -> Provider:
57
- return validate_backend_service_provider(backend_service_provider)
58
-
59
50
  @classmethod
60
51
  def batch_preferences(
61
52
  cls, *, backend_names: Iterable[str], **kwargs: Any
@@ -110,7 +101,9 @@ class AliceBobBackendPreferences(BackendPreferences):
110
101
  For more details, refer to the [Alice&Bob Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/alice-and-bob-backends/).
111
102
  """
112
103
 
113
- backend_service_provider: ProviderTypeVendor.ALICE_BOB
104
+ backend_service_provider: ProviderTypeVendor.ALICE_BOB = pydantic.Field(
105
+ default=ProviderVendor.ALICE_AND_BOB
106
+ )
114
107
  distance: Optional[int] = pydantic.Field(
115
108
  default=None, description="Repetition code distance"
116
109
  )
@@ -127,12 +120,6 @@ class AliceBobBackendPreferences(BackendPreferences):
127
120
  ..., description="AliceBob API key"
128
121
  )
129
122
 
130
- @pydantic.root_validator(pre=True)
131
- def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
132
- return values_with_discriminator(
133
- values, "backend_service_provider", ProviderVendor.ALICE_AND_BOB
134
- )
135
-
136
123
  @property
137
124
  def parameters(self) -> Dict[str, Any]:
138
125
  parameters = {
@@ -154,13 +141,9 @@ class ClassiqBackendPreferences(BackendPreferences):
154
141
  For more details, refer to the [Classiq Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/classiq-backends/).
155
142
  """
156
143
 
157
- backend_service_provider: ProviderTypeVendor.CLASSIQ
158
-
159
- @pydantic.root_validator(pre=True)
160
- def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
161
- return values_with_discriminator(
162
- values, "backend_service_provider", ProviderVendor.CLASSIQ
163
- )
144
+ backend_service_provider: ProviderTypeVendor.CLASSIQ = pydantic.Field(
145
+ default=ProviderVendor.CLASSIQ
146
+ )
164
147
 
165
148
  def is_nvidia_backend(self) -> bool:
166
149
  return self.backend_name in list(ClassiqNvidiaBackendNames)
@@ -197,7 +180,9 @@ class AwsBackendPreferences(BackendPreferences):
197
180
  [AwsBackendPreferences examples](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/amazon-backends/?h=awsbackend#usage)
198
181
  """
199
182
 
200
- backend_service_provider: ProviderTypeVendor.AMAZON_BRAKET
183
+ backend_service_provider: ProviderTypeVendor.AMAZON_BRAKET = pydantic.Field(
184
+ default=ProviderVendor.AMAZON_BRAKET
185
+ )
201
186
  aws_role_arn: pydantic_backend.PydanticAwsRoleArn = pydantic.Field(
202
187
  description="ARN of the role to be assumed for execution on your Braket account."
203
188
  )
@@ -206,21 +191,14 @@ class AwsBackendPreferences(BackendPreferences):
206
191
  description="S3 Folder Path Within The S3 Bucket"
207
192
  )
208
193
 
209
- @validator("s3_bucket_name")
210
- def _validate_s3_bucket_name(
211
- cls, s3_bucket_name: str, values: Dict[str, Any]
212
- ) -> str:
194
+ @pydantic.field_validator("s3_bucket_name", mode="before")
195
+ @classmethod
196
+ def _validate_s3_bucket_name(cls, s3_bucket_name: str) -> str:
213
197
  s3_bucket_name = s3_bucket_name.strip()
214
198
  if not s3_bucket_name.startswith("amazon-braket-"):
215
199
  raise ClassiqValueError('S3 bucket name should start with "amazon-braket-"')
216
200
  return s3_bucket_name
217
201
 
218
- @pydantic.root_validator(pre=True)
219
- def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
220
- return values_with_discriminator(
221
- values, "backend_service_provider", ProviderVendor.AMAZON_BRAKET
222
- )
223
-
224
202
 
225
203
  class IBMBackendProvider(BaseModel):
226
204
  """
@@ -255,7 +233,9 @@ class IBMBackendPreferences(BackendPreferences):
255
233
  See examples in the [IBM Quantum Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/ibm-backends/?h=).
256
234
  """
257
235
 
258
- backend_service_provider: ProviderTypeVendor.IBM_QUANTUM
236
+ backend_service_provider: ProviderTypeVendor.IBM_QUANTUM = pydantic.Field(
237
+ default=ProviderVendor.IBM_QUANTUM
238
+ )
259
239
  access_token: Optional[str] = pydantic.Field(
260
240
  default=None,
261
241
  description="IBM Quantum access token to be used"
@@ -270,14 +250,8 @@ class IBMBackendPreferences(BackendPreferences):
270
250
  description="QCTRL API key to access QCTRL optimization abilities",
271
251
  )
272
252
 
273
- @pydantic.root_validator(pre=True)
274
- def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
275
- return values_with_discriminator(
276
- values, "backend_service_provider", ProviderVendor.IBM_QUANTUM
277
- )
278
253
 
279
-
280
- class AzureCredential(pydantic.BaseSettings):
254
+ class AzureCredential(BaseSettings):
281
255
  """
282
256
  Represents the credentials and configuration required to authenticate with Azure services.
283
257
 
@@ -296,11 +270,20 @@ class AzureCredential(pydantic.BaseSettings):
296
270
  description="Azure Resource ID (including Azure subscription ID, resource "
297
271
  "group and workspace), for personal resource",
298
272
  )
273
+ model_config = SettingsConfigDict(
274
+ title="Azure Service Principal Credential",
275
+ env_prefix="AZURE_",
276
+ case_sensitive=False,
277
+ extra="allow",
278
+ )
299
279
 
300
- class Config:
301
- title = "Azure Service Principal Credential"
302
- env_prefix = "AZURE_"
303
- case_sensitive = False
280
+ def __init__(self, **data: Any) -> None:
281
+ initial_data = {
282
+ field: data[field] for field in data if field in self.model_fields
283
+ }
284
+ super().__init__(**data)
285
+ for field, value in initial_data.items():
286
+ setattr(self, field, value)
304
287
 
305
288
 
306
289
  class AzureBackendPreferences(BackendPreferences):
@@ -317,7 +300,9 @@ class AzureBackendPreferences(BackendPreferences):
317
300
 
318
301
  """
319
302
 
320
- backend_service_provider: ProviderTypeVendor.AZURE_QUANTUM
303
+ backend_service_provider: ProviderTypeVendor.AZURE_QUANTUM = pydantic.Field(
304
+ default=ProviderVendor.AZURE_QUANTUM
305
+ )
321
306
 
322
307
  location: str = pydantic.Field(
323
308
  default="East US", description="Azure personal resource region"
@@ -343,12 +328,6 @@ class AzureBackendPreferences(BackendPreferences):
343
328
  """
344
329
  return self.credentials is None
345
330
 
346
- @pydantic.root_validator(pre=True)
347
- def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
348
- return values_with_discriminator(
349
- values, "backend_service_provider", ProviderVendor.AZURE_QUANTUM
350
- )
351
-
352
331
 
353
332
  class IonqBackendPreferences(BackendPreferences):
354
333
  """
@@ -365,7 +344,9 @@ class IonqBackendPreferences(BackendPreferences):
365
344
  See examples in the [IonQ Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/ionq-backends/?h=).
366
345
  """
367
346
 
368
- backend_service_provider: ProviderTypeVendor.IONQ
347
+ backend_service_provider: ProviderTypeVendor.IONQ = pydantic.Field(
348
+ default=ProviderVendor.IONQ
349
+ )
369
350
  api_key: pydantic_backend.PydanticIonQApiKeyType = pydantic.Field(
370
351
  ..., description="IonQ API key"
371
352
  )
@@ -374,12 +355,6 @@ class IonqBackendPreferences(BackendPreferences):
374
355
  description="Error mitigation configuration.",
375
356
  )
376
357
 
377
- @pydantic.root_validator(pre=True)
378
- def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
379
- return values_with_discriminator(
380
- values, "backend_service_provider", ProviderVendor.IONQ
381
- )
382
-
383
358
 
384
359
  class GCPBackendPreferences(BackendPreferences):
385
360
  """
@@ -394,13 +369,9 @@ class GCPBackendPreferences(BackendPreferences):
394
369
  See examples in the [Google Cloud Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/google-backends/?h=).
395
370
  """
396
371
 
397
- backend_service_provider: ProviderTypeVendor.GOOGLE
398
-
399
- @pydantic.root_validator(pre=True)
400
- def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
401
- return values_with_discriminator(
402
- values, "backend_service_provider", ProviderVendor.GOOGLE
403
- )
372
+ backend_service_provider: ProviderTypeVendor.GOOGLE = pydantic.Field(
373
+ default=ProviderVendor.GOOGLE
374
+ )
404
375
 
405
376
  def is_nvidia_backend(self) -> bool:
406
377
  return True
@@ -417,16 +388,12 @@ class OQCBackendPreferences(BackendPreferences):
417
388
  password (str): OQC password
418
389
  """
419
390
 
420
- backend_service_provider: ProviderTypeVendor.OQC
391
+ backend_service_provider: ProviderTypeVendor.OQC = pydantic.Field(
392
+ default=ProviderVendor.OQC
393
+ )
421
394
  username: str = pydantic.Field(description="OQC username")
422
395
  password: str = pydantic.Field(description="OQC password")
423
396
 
424
- @pydantic.root_validator(pre=True)
425
- def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
426
- return values_with_discriminator(
427
- values, "backend_service_provider", ProviderVendor.OQC
428
- )
429
-
430
397
 
431
398
  class IntelBackendPreferences(BackendPreferences):
432
399
  """
@@ -438,13 +405,9 @@ class IntelBackendPreferences(BackendPreferences):
438
405
  For more details, refer to the [Classiq Backend Documentation](https://docs.classiq.io/latest/reference-manual/executor/cloud-providers/classiq-backends/).
439
406
  """
440
407
 
441
- backend_service_provider: ProviderTypeVendor.INTEL
442
-
443
- @pydantic.root_validator(pre=True)
444
- def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
445
- return values_with_discriminator(
446
- values, "backend_service_provider", ProviderVendor.INTEL
447
- )
408
+ backend_service_provider: ProviderTypeVendor.INTEL = pydantic.Field(
409
+ default=ProviderVendor.INTEL
410
+ )
448
411
 
449
412
 
450
413
  class AQTBackendPreferences(BackendPreferences):
@@ -458,17 +421,38 @@ class AQTBackendPreferences(BackendPreferences):
458
421
  workspace: The AQT workspace where the simulator/hardware is located.
459
422
  """
460
423
 
461
- # TODO[pydantic]: Add a default value
462
- backend_service_provider: ProviderTypeVendor.AQT
424
+ backend_service_provider: ProviderTypeVendor.AQT = pydantic.Field(
425
+ default=ProviderVendor.AQT
426
+ )
463
427
  api_key: str = pydantic.Field(description="AQT API key")
464
428
  workspace: str = pydantic.Field(description="AQT workspace")
465
429
 
466
- # TODO[pydantic]: Remove this validator
467
- @pydantic.root_validator(pre=True)
468
- def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
469
- return values_with_discriminator(
470
- values, "backend_service_provider", ProviderVendor.AQT
471
- )
430
+
431
+ class IQCCBackendPreferences(BackendPreferences):
432
+ """
433
+ NOTE: This is a work in progress and is subject to change.
434
+
435
+ Represents the backend preferences specific to IQCC (Israeli Quantum Computing
436
+ Center).
437
+
438
+ Attributes:
439
+ auth_token: The authorization token generated by calling `generate_iqcc_token`.
440
+ target_id: The target ID of the login node.
441
+ target_scope_id: The scope ID of the specified target.
442
+ ssh_user_name: The user name to use when connecting to the SSH server on the login node.
443
+ ssh_key: The private key to use when connecting to the SSH server on the login node.
444
+ slurm_account: The account to use when initiating SLURM jobs.
445
+ """
446
+
447
+ backend_service_provider: ProviderTypeVendor.IQCC = pydantic.Field(
448
+ default=ProviderVendor.IQCC
449
+ )
450
+ auth_token: str
451
+ target_id: str
452
+ target_scope_id: str
453
+ ssh_user_name: str
454
+ ssh_key: str
455
+ slurm_account: str
472
456
 
473
457
 
474
458
  def is_exact_simulator(backend_preferences: BackendPreferences) -> bool:
@@ -502,6 +486,7 @@ BackendPreferencesTypes = Union[
502
486
  OQCBackendPreferences,
503
487
  IntelBackendPreferences,
504
488
  AQTBackendPreferences,
489
+ IQCCBackendPreferences,
505
490
  ]
506
491
 
507
492
  __all__ = [
@@ -525,17 +510,5 @@ __all__ = [
525
510
  "OQCBackendNames",
526
511
  "IntelBackendPreferences",
527
512
  "AQTBackendPreferences",
513
+ "IQCCBackendPreferences",
528
514
  ]
529
-
530
-
531
- def validate_backend_service_provider(backend_service_provider: Any) -> Provider:
532
- if isinstance(backend_service_provider, Provider):
533
- return backend_service_provider
534
- if isinstance(backend_service_provider, str):
535
- for member in Provider:
536
- if member.lower() == backend_service_provider.lower():
537
- return Provider(member)
538
- raise ClassiqValueError(
539
- f"""Vendor {backend_service_provider} is not supported.
540
- The supported providers are {', '.join(Provider)}."""
541
- )
@@ -2,8 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, List, Optional
4
4
 
5
- import pydantic
6
- from pydantic import BaseModel
5
+ from pydantic import BaseModel, ConfigDict, Field
6
+ from typing_extensions import Annotated
7
7
 
8
8
  # This file is based on autogenerated code from: https://static.ionq.co/schemas/circuit-v0.json using
9
9
  # https://pydantic-docs.helpmanual.io/datamodel_code_generator/
@@ -12,10 +12,13 @@ from pydantic import BaseModel
12
12
  if TYPE_CHECKING:
13
13
  PydanticGateName = str
14
14
  else:
15
- PydanticGateName = pydantic.constr(
16
- regex=r"^\w+$",
17
- min_length=1,
18
- )
15
+ PydanticGateName = Annotated[
16
+ str,
17
+ Field(
18
+ pattern=r"^\w+$",
19
+ min_length=1,
20
+ ),
21
+ ]
19
22
 
20
23
 
21
24
  class Gate(BaseModel):
@@ -24,23 +27,13 @@ class Gate(BaseModel):
24
27
  control: Optional[int] = None
25
28
  targets: Optional[List[int]] = None
26
29
  controls: Optional[List[int]] = None
27
-
28
- # Ionq changes format sometimes.
29
- # One example is that `IonqQauntumCircuit` got a field name "gateset" with the value "qis"
30
- # Another is that `Gate` got a field named "rotation"
31
- class Config:
32
- extra = pydantic.Extra.allow
30
+ model_config = ConfigDict(extra="allow")
33
31
 
34
32
 
35
33
  class IonqQuantumCircuit(BaseModel):
36
34
  qubits: int
37
35
  circuit: List[Gate]
38
-
39
- # Ionq changes format sometimes.
40
- # One example is that `IonqQuantumCircuit` got a field name "gateset" with the value "qis"
41
- # Another is that `Gate` got a field named "rotation"
42
- class Config:
43
- extra = pydantic.Extra.allow
36
+ model_config = ConfigDict(extra="allow")
44
37
 
45
38
  @classmethod
46
39
  def from_string(cls, code: str) -> IonqQuantumCircuit:
@@ -48,4 +41,4 @@ class IonqQuantumCircuit(BaseModel):
48
41
  commentless_code = "\n".join(
49
42
  line for line in code_lines if not line.startswith("//")
50
43
  )
51
- return cls.parse_raw(commentless_code)
44
+ return cls.model_validate_json(commentless_code)
@@ -1,6 +1,7 @@
1
1
  from typing import TYPE_CHECKING
2
2
 
3
- import pydantic
3
+ from pydantic import Field, StrictStr, constr
4
+ from typing_extensions import Annotated
4
5
 
5
6
  AZURE_QUANTUM_RESOURCE_ID_REGEX = r"^/subscriptions/([a-fA-F0-9-]*)/resourceGroups/([^\s/]*)/providers/Microsoft\.Quantum/Workspaces/([^\s/]*)$"
6
7
 
@@ -25,20 +26,31 @@ if TYPE_CHECKING:
25
26
  else:
26
27
  # TODO Simplify regular expressions in this file
27
28
 
28
- PydanticAwsRoleArn = pydantic.constr(
29
- strip_whitespace=True,
30
- )
29
+ PydanticAwsRoleArn = Annotated[
30
+ StrictStr,
31
+ constr(
32
+ strip_whitespace=True,
33
+ ),
34
+ ]
31
35
 
32
- PydanticS3BucketKey = pydantic.constr(strip_whitespace=True, min_length=1)
36
+ PydanticS3BucketKey = Annotated[
37
+ StrictStr, constr(strip_whitespace=True, min_length=1)
38
+ ]
33
39
 
34
- PydanticAzureResourceIDType = pydantic.constr(regex=AZURE_QUANTUM_RESOURCE_ID_REGEX)
40
+ PydanticAzureResourceIDType = Annotated[
41
+ str, Field(pattern=AZURE_QUANTUM_RESOURCE_ID_REGEX)
42
+ ]
35
43
 
36
- PydanticIonQApiKeyType = pydantic.constr(
37
- regex=f"[A-Za-z0-9]{{{_IONQ_API_KEY_LENGTH}}}"
38
- )
44
+ PydanticIonQApiKeyType = Annotated[
45
+ str, Field(pattern=f"[A-Za-z0-9]{{{_IONQ_API_KEY_LENGTH}}}")
46
+ ]
39
47
 
40
- PydanticAliceBobApiKeyType = pydantic.constr(min_length=1, strip_whitespace=True)
48
+ PydanticAliceBobApiKeyType = Annotated[
49
+ StrictStr, constr(min_length=1, strip_whitespace=True)
50
+ ]
41
51
 
42
- PydanticArgumentNameType = pydantic.constr(regex="[_a-zA-Z][_a-zA-Z0-9]*")
52
+ PydanticArgumentNameType = Annotated[str, Field(pattern="[_a-zA-Z][_a-zA-Z0-9]*")]
43
53
 
44
- PydanticExecutionParameter = pydantic.constr(regex=EXECUTION_PARAMETER_PATTERN)
54
+ PydanticExecutionParameter = Annotated[
55
+ str, Field(pattern=EXECUTION_PARAMETER_PATTERN)
56
+ ]
@@ -20,6 +20,7 @@ class ProviderVendor(StrEnum):
20
20
  OQC = "OQC"
21
21
  INTEL = "Intel"
22
22
  AQT = "AQT"
23
+ IQCC = "IQCC"
23
24
 
24
25
 
25
26
  class ProviderTypeVendor:
@@ -33,6 +34,7 @@ class ProviderTypeVendor:
33
34
  OQC = Literal[ProviderVendor.OQC]
34
35
  INTEL = Literal[ProviderVendor.INTEL]
35
36
  AQT = Literal[ProviderVendor.AQT]
37
+ IQCC = Literal[ProviderVendor.IQCC]
36
38
 
37
39
 
38
40
  class ClassiqSimulatorBackendNames(StrEnum):
@@ -5,6 +5,7 @@ from typing import Set, Tuple, Union
5
5
 
6
6
  import numpy as np
7
7
  import pydantic
8
+ from pydantic import ConfigDict
8
9
 
9
10
  from classiq.interface.exceptions import ClassiqValueError
10
11
  from classiq.interface.helpers.hashable_pydantic_base_model import (
@@ -75,7 +76,8 @@ class FermionicOperator(HashablePydanticBaseModel):
75
76
 
76
77
  return (op_symbol, op_index)
77
78
 
78
- @pydantic.validator("op_list")
79
+ @pydantic.field_validator("op_list")
80
+ @classmethod
79
81
  def _validate_op_list(cls, op_list: list) -> list:
80
82
  return list(map(cls._validate_single_op, op_list))
81
83
 
@@ -99,8 +101,7 @@ class FermionicOperator(HashablePydanticBaseModel):
99
101
  "FermionicOperator can be summed together only with type FermionicOperator or SummedFermionicOperator"
100
102
  )
101
103
 
102
- class Config:
103
- frozen = True
104
+ model_config = ConfigDict(frozen=True)
104
105
 
105
106
  @staticmethod
106
107
  def _to_ladder_op(char: str) -> str:
@@ -135,9 +136,7 @@ class SummedFermionicOperator(HashablePydanticBaseModel):
135
136
  op_list: list = pydantic.Field(
136
137
  description="A list of tuples each containing a FermionicOperator and a coefficient.",
137
138
  )
138
-
139
- class Config:
140
- frozen = True
139
+ model_config = ConfigDict(frozen=True)
141
140
 
142
141
  @staticmethod
143
142
  def _validate_single_op(op: tuple) -> FermionicOperatorTuple:
@@ -166,7 +165,8 @@ class SummedFermionicOperator(HashablePydanticBaseModel):
166
165
 
167
166
  return op # type: ignore[return-value] # mypy thinks that it is `Tuple[Any, ...]`, though the asserts here tell otherwise..
168
167
 
169
- @pydantic.validator("op_list")
168
+ @pydantic.field_validator("op_list")
169
+ @classmethod
170
170
  def _validate_op_list(cls, op_list: list) -> list:
171
171
  return list(map(cls._validate_single_op, op_list))
172
172
 
@@ -1,7 +1,8 @@
1
- from typing import Any, Dict, List, Literal, Optional, Tuple, Union
1
+ from typing import List, Literal, Optional, Tuple, Union, cast
2
2
 
3
3
  import pydantic
4
- from pydantic import Field
4
+ from pydantic import ConfigDict, Field
5
+ from pydantic_core.core_schema import ValidationInfo
5
6
  from typing_extensions import Annotated
6
7
 
7
8
  from classiq.interface.chemistry.fermionic_operator import SummedFermionicOperator
@@ -52,18 +53,19 @@ class GroundStateProblem(HashablePydanticBaseModel):
52
53
  )
53
54
  num_qubits: Optional[int] = pydantic.Field(default=None)
54
55
 
55
- @pydantic.validator("z2_symmetries")
56
- def _validate_z2_symmetries(
57
- cls, z2_symmetries: bool, values: Dict[str, Any]
58
- ) -> bool:
59
- if z2_symmetries and values.get("mapping") == FermionMapping.FAST_BRAVYI_KITAEV:
56
+ @pydantic.field_validator("z2_symmetries")
57
+ @classmethod
58
+ def _validate_z2_symmetries(cls, z2_symmetries: bool, info: ValidationInfo) -> bool:
59
+ if (
60
+ z2_symmetries
61
+ and info.data.get("mapping") == FermionMapping.FAST_BRAVYI_KITAEV
62
+ ):
60
63
  raise ClassiqValueError(
61
64
  "z2 symmetries reduction can not be used for fast_bravyi_kitaev mapping"
62
65
  )
63
66
  return z2_symmetries
64
67
 
65
- class Config:
66
- frozen = True
68
+ model_config = ConfigDict(frozen=True)
67
69
 
68
70
 
69
71
  class MoleculeProblem(GroundStateProblem):
@@ -87,20 +89,23 @@ class HamiltonianProblem(GroundStateProblem):
87
89
  description="Tuple containing the numbers of alpha particles and beta particles"
88
90
  )
89
91
 
90
- @pydantic.validator("num_particles")
91
- def _validate_num_particles(cls, num_particles: List[int]) -> List[int]:
92
- assert isinstance(num_particles, list)
92
+ @pydantic.field_validator("num_particles", mode="before")
93
+ @classmethod
94
+ def _validate_num_particles(
95
+ cls,
96
+ num_particles: Union[
97
+ List[Union[int, float]], Tuple[Union[int, float], Union[int, float]]
98
+ ],
99
+ ) -> List[int]:
100
+ assert isinstance(num_particles, (list, tuple))
93
101
  assert len(num_particles) == 2
94
102
 
95
- # This probably will never happen, since pydantic automatically converts
96
- # floats to ints
97
- assert isinstance(num_particles[0], int)
98
- assert num_particles[0] >= 1
103
+ num_particles = [int(x) for x in num_particles]
99
104
 
100
- assert isinstance(num_particles[1], int)
105
+ assert num_particles[0] >= 1
101
106
  assert num_particles[1] >= 1
102
107
 
103
- return num_particles
108
+ return cast(List[int], num_particles)
104
109
 
105
110
 
106
111
  CHEMISTRY_PROBLEMS = (MoleculeProblem, HamiltonianProblem)