classiq 0.51.0__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 (150) 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/expressions/qmod_qscalar_proxy.py +3 -3
  65. classiq/interface/generator/function_params.py +22 -39
  66. classiq/interface/generator/functions/classical_function_declaration.py +1 -1
  67. classiq/interface/generator/functions/classical_type.py +32 -23
  68. classiq/interface/generator/functions/concrete_types.py +8 -7
  69. classiq/interface/generator/functions/function_declaration.py +4 -5
  70. classiq/interface/generator/functions/type_name.py +5 -4
  71. classiq/interface/generator/generated_circuit_data.py +9 -6
  72. classiq/interface/generator/grover_diffuser.py +26 -18
  73. classiq/interface/generator/grover_operator.py +32 -22
  74. classiq/interface/generator/hamiltonian_evolution/exponentiation.py +3 -4
  75. classiq/interface/generator/hamiltonian_evolution/qdrift.py +4 -4
  76. classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py +8 -7
  77. classiq/interface/generator/hardware/hardware_data.py +27 -26
  78. classiq/interface/generator/hardware_efficient_ansatz.py +11 -6
  79. classiq/interface/generator/hartree_fock.py +2 -1
  80. classiq/interface/generator/identity.py +7 -2
  81. classiq/interface/generator/linear_pauli_rotations.py +27 -14
  82. classiq/interface/generator/mcu.py +15 -12
  83. classiq/interface/generator/mcx.py +18 -10
  84. classiq/interface/generator/model/constraints.py +4 -2
  85. classiq/interface/generator/model/model.py +2 -1
  86. classiq/interface/generator/model/preferences/preferences.py +30 -32
  87. classiq/interface/generator/oracles/custom_oracle.py +13 -10
  88. classiq/interface/generator/piecewise_linear_amplitude_loading.py +37 -21
  89. classiq/interface/generator/qpe.py +38 -26
  90. classiq/interface/generator/qsvm.py +4 -4
  91. classiq/interface/generator/quantum_function_call.py +57 -44
  92. classiq/interface/generator/quantum_program.py +8 -6
  93. classiq/interface/generator/range_types.py +10 -11
  94. classiq/interface/generator/standard_gates/controlled_standard_gates.py +9 -5
  95. classiq/interface/generator/standard_gates/standard_angle_metaclass.py +2 -6
  96. classiq/interface/generator/standard_gates/u_gate.py +7 -10
  97. classiq/interface/generator/state_preparation/computational_basis_state_preparation.py +2 -1
  98. classiq/interface/generator/state_preparation/distributions.py +12 -12
  99. classiq/interface/generator/state_preparation/state_preparation.py +22 -16
  100. classiq/interface/generator/types/enum_declaration.py +2 -1
  101. classiq/interface/generator/ucc.py +2 -1
  102. classiq/interface/generator/unitary_gate.py +2 -1
  103. classiq/interface/generator/user_defined_function_params.py +3 -0
  104. classiq/interface/generator/visitor.py +1 -1
  105. classiq/interface/hardware.py +18 -3
  106. classiq/interface/helpers/custom_pydantic_types.py +38 -47
  107. classiq/interface/helpers/pydantic_model_helpers.py +3 -2
  108. classiq/interface/helpers/versioned_model.py +1 -4
  109. classiq/interface/ide/ide_data.py +5 -5
  110. classiq/interface/ide/visual_model.py +5 -5
  111. classiq/interface/interface_version.py +1 -1
  112. classiq/interface/jobs.py +12 -22
  113. classiq/interface/model/bind_operation.py +2 -1
  114. classiq/interface/model/classical_parameter_declaration.py +10 -4
  115. classiq/interface/model/handle_binding.py +20 -24
  116. classiq/interface/model/inplace_binary_operation.py +16 -9
  117. classiq/interface/model/model.py +21 -11
  118. classiq/interface/model/port_declaration.py +10 -7
  119. classiq/interface/model/quantum_expressions/arithmetic_operation.py +6 -4
  120. classiq/interface/model/quantum_function_declaration.py +22 -11
  121. classiq/interface/model/quantum_statement.py +6 -7
  122. classiq/interface/model/quantum_type.py +22 -19
  123. classiq/interface/model/statement_block.py +9 -9
  124. classiq/interface/server/global_versions.py +4 -5
  125. classiq/interface/server/routes.py +8 -0
  126. classiq/model_expansions/evaluators/parameter_types.py +3 -3
  127. classiq/model_expansions/expression_renamer.py +1 -1
  128. classiq/model_expansions/quantum_operations/control.py +11 -12
  129. classiq/model_expansions/quantum_operations/emitter.py +22 -0
  130. classiq/model_expansions/quantum_operations/expression_operation.py +2 -20
  131. classiq/model_expansions/quantum_operations/inplace_binary_operation.py +65 -14
  132. classiq/model_expansions/quantum_operations/invert.py +1 -1
  133. classiq/model_expansions/quantum_operations/phase.py +4 -5
  134. classiq/model_expansions/quantum_operations/power.py +1 -1
  135. classiq/model_expansions/quantum_operations/quantum_assignment_operation.py +50 -9
  136. classiq/model_expansions/quantum_operations/variable_decleration.py +2 -2
  137. classiq/model_expansions/quantum_operations/within_apply.py +1 -1
  138. classiq/qmod/builtins/__init__.py +1 -3
  139. classiq/qmod/builtins/functions/__init__.py +4 -0
  140. classiq/qmod/builtins/functions/arithmetic.py +10 -0
  141. classiq/qmod/create_model_function.py +14 -8
  142. classiq/qmod/quantum_expandable.py +22 -9
  143. classiq/qmod/quantum_function.py +1 -1
  144. classiq/qmod/semantics/static_semantics_visitor.py +3 -1
  145. classiq/qmod/type_attribute_remover.py +1 -1
  146. classiq/qmod/write_qmod.py +2 -4
  147. classiq/synthesis.py +11 -13
  148. {classiq-0.51.0.dist-info → classiq-0.52.0.dist-info}/METADATA +3 -2
  149. {classiq-0.51.0.dist-info → classiq-0.52.0.dist-info}/RECORD +150 -148
  150. {classiq-0.51.0.dist-info → classiq-0.52.0.dist-info}/WHEEL +0 -0
@@ -59,13 +59,15 @@ def _get_formatted_utc_current_time() -> str:
59
59
 
60
60
  class QuantumProgram(VersionedModel, CircuitCodeInterface):
61
61
  hardware_data: SynthesisHardwareData
62
- initial_values: Optional[InitialConditions]
62
+ initial_values: Optional[InitialConditions] = pydantic.Field(default=None)
63
63
  data: GeneratedCircuitData
64
64
  model: ExecutionModel
65
- transpiled_circuit: Optional[TranspiledCircuitData]
65
+ transpiled_circuit: Optional[TranspiledCircuitData] = pydantic.Field(default=None)
66
66
  creation_time: str = pydantic.Field(default_factory=_get_formatted_utc_current_time)
67
- synthesis_duration: Optional[SynthesisStepDurations]
68
- debug_info: Optional[List[FunctionDebugInfoInterface]]
67
+ synthesis_duration: Optional[SynthesisStepDurations] = pydantic.Field(default=None)
68
+ debug_info: Optional[List[FunctionDebugInfoInterface]] = pydantic.Field(
69
+ default=None
70
+ )
69
71
  program_id: str = pydantic.Field(default_factory=get_uuid_as_str)
70
72
  execution_primitives_input: Optional[PrimitivesInput] = pydantic.Field(default=None)
71
73
 
@@ -154,7 +156,7 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
154
156
  filename = f"synthesised_circuit_{self.creation_time}.json"
155
157
 
156
158
  with open(filename, "w") as file:
157
- file.write(self.json(indent=4))
159
+ file.write(self.model_dump_json(indent=4))
158
160
 
159
161
  @classmethod
160
162
  def from_qprog(cls, qprog: str) -> "QuantumProgram":
@@ -167,7 +169,7 @@ class QuantumProgram(VersionedModel, CircuitCodeInterface):
167
169
  Returns:
168
170
  QuantumProgram: The `QuantumProgram` instance.
169
171
  """
170
- return cls.parse_raw(qprog)
172
+ return cls.model_validate_json(qprog)
171
173
 
172
174
  @property
173
175
  def _can_use_transpiled_code(self) -> bool:
@@ -1,8 +1,9 @@
1
1
  import math
2
- from typing import Any, Dict, Generic, Optional, TypeVar
2
+ from typing import Generic, Optional, TypeVar
3
3
 
4
4
  import pydantic
5
- from pydantic.generics import GenericModel
5
+ from pydantic import BaseModel, ConfigDict
6
+ from typing_extensions import Self
6
7
 
7
8
  from classiq.interface.exceptions import ClassiqValueError
8
9
 
@@ -15,17 +16,15 @@ DEF_ATOL: float = 1e-08
15
16
  DEF_RTOL: float = 1e-05
16
17
 
17
18
 
18
- class Range(GenericModel, Generic[RangeType]):
19
+ class Range(BaseModel, Generic[RangeType]):
19
20
  lower_bound: Optional[RangeType] = None
20
21
  upper_bound: Optional[RangeType] = None
22
+ model_config = ConfigDict(frozen=True)
21
23
 
22
- class Config:
23
- frozen = True
24
-
25
- @pydantic.root_validator()
26
- def _validate_bounds_order(cls, values: Dict[str, Any]) -> Dict[str, Any]:
27
- lower_bound = values.get("lower_bound")
28
- upper_bound = values.get("upper_bound")
24
+ @pydantic.model_validator(mode="after")
25
+ def _validate_bounds_order(self) -> Self:
26
+ lower_bound = self.lower_bound
27
+ upper_bound = self.upper_bound
29
28
 
30
29
  if (
31
30
  lower_bound is not None
@@ -34,7 +33,7 @@ class Range(GenericModel, Generic[RangeType]):
34
33
  ):
35
34
  raise ClassiqValueError("lower bound must not be greater than upper bound")
36
35
 
37
- return values
36
+ return self
38
37
 
39
38
  def is_lower_bound_sat_by(
40
39
  self, value: float, atol: float = DEF_ATOL, rtol: float = DEF_RTOL
@@ -1,6 +1,7 @@
1
- from typing import Any, Dict, Literal, Optional, Union
1
+ from typing import Literal, Optional, Union
2
2
 
3
3
  import pydantic
4
+ from pydantic_core.core_schema import ValidationInfo
4
5
 
5
6
  from classiq.interface.exceptions import ClassiqValueError
6
7
  from classiq.interface.generator.arith.register_user_input import RegisterUserInput
@@ -48,14 +49,17 @@ class ControlledGateWithState(ControlledGate): # type: ignore[misc]
48
49
  ctrl_state: CtrlState = pydantic.Field(
49
50
  description="The control state in decimal or as a bit string (e.g. '1011'). If not specified, the control "
50
51
  "state is 2**num_ctrl_qubits - 1.\n"
51
- "The gate will be performed if the state of the control qubits matches the control state"
52
+ "The gate will be performed if the state of the control qubits matches the control state",
53
+ default=None,
54
+ validate_default=True,
52
55
  )
53
56
 
54
- @pydantic.validator("ctrl_state", always=True)
57
+ @pydantic.field_validator("ctrl_state")
58
+ @classmethod
55
59
  def _validate_ctrl_state(
56
- cls, ctrl_state: CtrlState, values: Dict[str, Any]
60
+ cls, ctrl_state: CtrlState, info: ValidationInfo
57
61
  ) -> CtrlState:
58
- num_ctrl_qubits: int = values.get("num_ctrl_qubits", DEFAULT_NUM_CTRL_QUBITS)
62
+ num_ctrl_qubits: int = info.data.get("num_ctrl_qubits", DEFAULT_NUM_CTRL_QUBITS)
59
63
  ctrl_state = ctrl_state if ctrl_state is not None else "1" * num_ctrl_qubits
60
64
 
61
65
  if isinstance(ctrl_state, str) and len(ctrl_state) != num_ctrl_qubits:
@@ -2,7 +2,7 @@ from typing import Any
2
2
 
3
3
  import pydantic
4
4
 
5
- from classiq.interface.generator.parameters import ParameterFloatType
5
+ from classiq.interface.generator.function_params import FunctionParamsNumericParameter
6
6
 
7
7
  PydanticMetaClass: Any = type(pydantic.BaseModel)
8
8
 
@@ -16,14 +16,10 @@ class MyMetaAngledClass(type):
16
16
  @staticmethod
17
17
  def _create_new_namespace(namespace: dict, **kwargs: Any) -> dict:
18
18
  angles = kwargs.get("angles", [])
19
- annotations = {angle: ParameterFloatType for angle in angles}
20
- fields = {
21
- angle: pydantic.fields.FieldInfo(is_exec_param=True) for angle in angles
22
- }
19
+ annotations = {angle: FunctionParamsNumericParameter for angle in angles}
23
20
  original_annotations = namespace.get("__annotations__", {})
24
21
  return {
25
22
  **namespace,
26
- **fields,
27
23
  **{"__annotations__": {**original_annotations, **annotations}},
28
24
  }
29
25
 
@@ -2,7 +2,7 @@ import pydantic
2
2
 
3
3
  from classiq.interface.generator import function_params
4
4
  from classiq.interface.generator.arith.register_user_input import RegisterUserInput
5
- from classiq.interface.generator.parameters import ParameterFloatType
5
+ from classiq.interface.generator.function_params import FunctionParamsNumericParameter
6
6
  from classiq.interface.generator.standard_gates.standard_gates import (
7
7
  DEFAULT_STANDARD_GATE_ARG_NAME,
8
8
  )
@@ -18,24 +18,20 @@ class UGate(function_params.FunctionParams):
18
18
  e^(i*phi)*sin(theta/2) & e^(i*(phi+lam))*cos(theta/2) \\
19
19
  """
20
20
 
21
- theta: ParameterFloatType = pydantic.Field(
21
+ theta: FunctionParamsNumericParameter = pydantic.Field(
22
22
  description="Angle to rotate by the Y-axis.",
23
- is_exec_param=True,
24
23
  )
25
24
 
26
- phi: ParameterFloatType = pydantic.Field(
25
+ phi: FunctionParamsNumericParameter = pydantic.Field(
27
26
  description="First angle to rotate by the Z-axis.",
28
- is_exec_param=True,
29
27
  )
30
28
 
31
- lam: ParameterFloatType = pydantic.Field(
29
+ lam: FunctionParamsNumericParameter = pydantic.Field(
32
30
  description="Second angle to rotate by the Z-axis.",
33
- is_exec_param=True,
34
31
  )
35
32
 
36
- gam: ParameterFloatType = pydantic.Field(
33
+ gam: FunctionParamsNumericParameter = pydantic.Field(
37
34
  description="Angle to apply phase gate by.",
38
- is_exec_param=True,
39
35
  )
40
36
 
41
37
  _inputs = pydantic.PrivateAttr(
@@ -56,5 +52,6 @@ class UGate(function_params.FunctionParams):
56
52
  @property
57
53
  def is_parametric(self) -> bool:
58
54
  return not all(
59
- isinstance(getattr(self, angle), (float, int)) for angle in self._params
55
+ isinstance(getattr(self, angle), (float, int))
56
+ for angle in ["theta", "phi", "lam", "gam"]
60
57
  )
@@ -12,7 +12,8 @@ class ComputationalBasisStatePreparation(StatePreparationABC):
12
12
  description="binary computational state to create"
13
13
  )
14
14
 
15
- @pydantic.validator("computational_state")
15
+ @pydantic.field_validator("computational_state")
16
+ @classmethod
16
17
  def _validate_computational_state(
17
18
  cls, computational_state: PydanticNonEmptyString
18
19
  ) -> PydanticNonEmptyString:
@@ -1,7 +1,8 @@
1
- from typing import Collection, Tuple, Union
1
+ from typing import Collection, Sequence, Tuple, Union
2
2
 
3
3
  import pydantic
4
4
  from numpy.typing import ArrayLike
5
+ from pydantic import ConfigDict
5
6
 
6
7
  from classiq.interface.generator.validations.validator_functions import (
7
8
  validate_probabilities,
@@ -11,20 +12,21 @@ from classiq.interface.helpers.custom_pydantic_types import PydanticProbabilityF
11
12
 
12
13
  class PMF(pydantic.BaseModel):
13
14
  pmf: Tuple[PydanticProbabilityFloat, ...]
14
- _validate_amplitudes = pydantic.validator("pmf", allow_reuse=True)(
15
- validate_probabilities
16
- )
17
15
 
18
- class Config:
19
- frozen = True
16
+ @pydantic.field_validator("pmf")
17
+ @classmethod
18
+ def _validate_pmf(
19
+ cls, pmf: Tuple[PydanticProbabilityFloat, ...]
20
+ ) -> Sequence[PydanticProbabilityFloat]:
21
+ return validate_probabilities(cls, pmf)
22
+
23
+ model_config = ConfigDict(frozen=True)
20
24
 
21
25
 
22
26
  class GaussianMoments(pydantic.BaseModel):
23
27
  mu: float
24
28
  sigma: pydantic.PositiveFloat
25
-
26
- class Config:
27
- frozen = True
29
+ model_config = ConfigDict(frozen=True)
28
30
 
29
31
 
30
32
  class GaussianMixture(pydantic.BaseModel):
@@ -32,9 +34,7 @@ class GaussianMixture(pydantic.BaseModel):
32
34
  num_qubits: pydantic.PositiveInt = pydantic.Field(
33
35
  description="Number of qubits for the provided state."
34
36
  )
35
-
36
- class Config:
37
- frozen = True
37
+ model_config = ConfigDict(frozen=True)
38
38
 
39
39
 
40
40
  Probabilities = Union[PMF, GaussianMixture]
@@ -1,7 +1,9 @@
1
- from typing import Any, Dict, Optional, Union
1
+ from typing import Dict, Optional, Union
2
2
 
3
3
  import numpy as np
4
4
  import pydantic
5
+ from pydantic_core.core_schema import ValidationInfo
6
+ from typing_extensions import Self
5
7
 
6
8
  from classiq.interface.exceptions import ClassiqValueError
7
9
  from classiq.interface.generator.range_types import NonNegativeFloatRange
@@ -25,10 +27,14 @@ from classiq.interface.generator.validations.validator_functions import (
25
27
 
26
28
  class StatePreparation(StatePreparationABC):
27
29
  amplitudes: Optional[Amplitudes] = pydantic.Field(
28
- description="vector of probabilities", default=None
30
+ description="vector of probabilities",
31
+ default=None,
32
+ validate_default=True,
29
33
  )
30
34
  probabilities: Optional[Probabilities] = pydantic.Field(
31
- description="vector of amplitudes", default=None
35
+ description="vector of amplitudes",
36
+ default=None,
37
+ validate_default=True,
32
38
  )
33
39
  error_metric: Dict[Metrics, NonNegativeFloatRange] = pydantic.Field(
34
40
  default_factory=lambda: {
@@ -37,7 +43,8 @@ class StatePreparation(StatePreparationABC):
37
43
  )
38
44
  # The order of validations is important: amplitudes, probabilities, error_metric
39
45
 
40
- @pydantic.validator("amplitudes", always=True, pre=True)
46
+ @pydantic.field_validator("amplitudes", mode="before")
47
+ @classmethod
41
48
  def _initialize_amplitudes(
42
49
  cls, amplitudes: Optional[FlexibleAmplitudes]
43
50
  ) -> Optional[Amplitudes]:
@@ -51,7 +58,8 @@ class StatePreparation(StatePreparationABC):
51
58
  "Invalid amplitudes were given, please ensure the amplitude is a vector of float in the form of either tuple or list or numpy array"
52
59
  )
53
60
 
54
- @pydantic.validator("probabilities", always=True, pre=True)
61
+ @pydantic.field_validator("probabilities", mode="before")
62
+ @classmethod
55
63
  def _initialize_probabilities(
56
64
  cls, probabilities: Optional[FlexibleProbabilities]
57
65
  ) -> Optional[Union[PMF, GaussianMixture, dict]]:
@@ -69,11 +77,12 @@ class StatePreparation(StatePreparationABC):
69
77
  "Invalid probabilities were given, please ensure the probabilities is a vector of float in the form of either tuple or list or numpy array"
70
78
  )
71
79
 
72
- @pydantic.validator("error_metric", always=True, pre=True)
80
+ @pydantic.field_validator("error_metric", mode="before")
81
+ @classmethod
73
82
  def _validate_error_metric(
74
- cls, error_metric: Dict[Metrics, NonNegativeFloatRange], values: Dict[str, Any]
83
+ cls, error_metric: Dict[Metrics, NonNegativeFloatRange], info: ValidationInfo
75
84
  ) -> Dict[Metrics, NonNegativeFloatRange]:
76
- if not values.get("amplitudes"):
85
+ if not info.data.get("amplitudes"):
77
86
  return error_metric
78
87
  unsupported_metrics = {
79
88
  Metrics(metric).value
@@ -86,18 +95,15 @@ class StatePreparation(StatePreparationABC):
86
95
  )
87
96
  return error_metric
88
97
 
89
- @pydantic.root_validator
90
- def _validate_either_probabilities_or_amplitudes(
91
- cls,
92
- values: Dict[str, Any],
93
- ) -> Optional[Union[PMF, GaussianMixture, dict]]:
94
- amplitudes = values.get("amplitudes")
95
- probabilities = values.get("probabilities")
98
+ @pydantic.model_validator(mode="after")
99
+ def _validate_either_probabilities_or_amplitudes(self) -> Self:
100
+ amplitudes = self.amplitudes
101
+ probabilities = self.probabilities
96
102
  if amplitudes is not None and probabilities is not None:
97
103
  raise ClassiqValueError(
98
104
  "StatePreparation can't get both probabilities and amplitudes"
99
105
  )
100
- return values
106
+ return self
101
107
 
102
108
  @property
103
109
  def num_state_qubits(self) -> int:
@@ -16,7 +16,8 @@ class EnumDeclaration(HashableASTNode):
16
16
  description="Dictionary of member names and their values",
17
17
  )
18
18
 
19
- @pydantic.validator("members")
19
+ @pydantic.field_validator("members")
20
+ @classmethod
20
21
  def _validate_members(cls, members: Dict[str, int]) -> Dict[str, int]:
21
22
  underscore_members = [
22
23
  member for member in members.keys() if member.startswith("_")
@@ -41,7 +41,8 @@ class UCC(ChemistryFunctionParams):
41
41
  description="Prefix for the generated parameters",
42
42
  )
43
43
 
44
- @pydantic.validator("excitations")
44
+ @pydantic.field_validator("excitations")
45
+ @classmethod
45
46
  def _validate_excitations(cls, excitations: EXCITATIONS_TYPE) -> EXCITATIONS_TYPE:
46
47
  if isinstance(excitations, int):
47
48
  if excitations not in _EXCITATIONS_DICT.values():
@@ -25,7 +25,8 @@ class UnitaryGate(function_params.FunctionParams):
25
25
  )
26
26
 
27
27
  # TODO - decide if to include assertion on the unitarity of the matrix. It is already done in Qiskit and could be computationally expensive
28
- @pydantic.validator("data")
28
+ @pydantic.field_validator("data")
29
+ @classmethod
29
30
  def validate_data(cls, data: DataArray) -> DataArray:
30
31
  data_np = np.array(data, dtype=object)
31
32
  if data_np.ndim != 2:
@@ -1,6 +1,7 @@
1
1
  from typing import Mapping
2
2
 
3
3
  import pydantic
4
+ from pydantic import ConfigDict
4
5
 
5
6
  from classiq.interface.generator.arith.register_user_input import RegisterArithmeticInfo
6
7
  from classiq.interface.generator.function_params import ArithmeticIODict, FunctionParams
@@ -11,6 +12,8 @@ class CustomFunction(FunctionParams):
11
12
  A user-defined custom function parameters object.
12
13
  """
13
14
 
15
+ model_config = ConfigDict(frozen=True, extra="forbid")
16
+
14
17
  _name: str = pydantic.PrivateAttr(default="")
15
18
 
16
19
  input_decls: ArithmeticIODict = pydantic.Field(
@@ -102,7 +102,7 @@ class Transformer(Visitor):
102
102
  if name not in fields_to_skip:
103
103
  result[name] = self.visit(value)
104
104
 
105
- return node.copy(update=result)
105
+ return node.model_copy(update=result)
106
106
 
107
107
  def visit_int(self, n: int) -> int:
108
108
  return n
@@ -2,9 +2,20 @@ import datetime
2
2
  from typing import TYPE_CHECKING, List, Optional, Tuple
3
3
 
4
4
  import pydantic
5
+ from typing_extensions import Annotated
5
6
 
6
7
  from classiq.interface.enum_utils import StrEnum
7
8
 
9
+ QueueTime = Annotated[
10
+ Optional[datetime.timedelta],
11
+ pydantic.PlainSerializer(
12
+ lambda _timedelta: (
13
+ _timedelta.total_seconds() if _timedelta is not None else None
14
+ ),
15
+ return_type=Optional[float],
16
+ ),
17
+ ]
18
+
8
19
 
9
20
  class Provider(StrEnum):
10
21
  """
@@ -22,6 +33,7 @@ class Provider(StrEnum):
22
33
  OQC = "OQC"
23
34
  INTEL = "Intel"
24
35
  AQT = "AQT"
36
+ IQCC = "IQCC"
25
37
 
26
38
  @property
27
39
  def id(self) -> "ProviderIDEnum":
@@ -55,8 +67,11 @@ class HardwareStatus(pydantic.BaseModel):
55
67
  default_factory=lambda: datetime.datetime.now(tz=datetime.UTC)
56
68
  )
57
69
  availability: AvailabilityStatus
58
- queue_time: Optional[datetime.timedelta]
59
- pending_jobs: Optional[int]
70
+ queue_time: QueueTime = pydantic.Field(
71
+ default=None,
72
+ description="The estimated queue time for the hardware in seconds.",
73
+ )
74
+ pending_jobs: Optional[int] = None
60
75
 
61
76
 
62
77
  if TYPE_CHECKING:
@@ -72,7 +87,7 @@ class HardwareInformation(pydantic.BaseModel):
72
87
  display_name: str
73
88
  device_type: DeviceType
74
89
  number_of_qubits: int
75
- connectivity_map: Optional[List[ConnectivityMapEntry]]
90
+ connectivity_map: Optional[List[ConnectivityMapEntry]] = None
76
91
  basis_gates: List[str]
77
92
  status: HardwareStatus
78
93
 
@@ -1,6 +1,8 @@
1
1
  from typing import TYPE_CHECKING, Any, List, Tuple
2
2
 
3
3
  import pydantic
4
+ from pydantic import Field, StrictStr, StringConstraints
5
+ from typing_extensions import Annotated
4
6
 
5
7
  from classiq.interface.generator.arith.number_utils import MAXIMAL_MACHINE_PRECISION
6
8
  from classiq.interface.generator.parameters import ParameterComplexType
@@ -13,13 +15,9 @@ if TYPE_CHECKING:
13
15
  PydanticLargerThanOneInteger = int
14
16
  PydanticMachinePrecision = int
15
17
  else:
18
+ PydanticLargerThanOneInteger = Annotated[int, Field(gt=1)]
16
19
 
17
- class PydanticLargerThanOneInteger(pydantic.ConstrainedInt):
18
- gt = 1
19
-
20
- class PydanticMachinePrecision(pydantic.ConstrainedInt):
21
- gt = 0
22
- le = MAXIMAL_MACHINE_PRECISION
20
+ PydanticMachinePrecision = Annotated[int, Field(gt=0, le=MAXIMAL_MACHINE_PRECISION)]
23
21
 
24
22
 
25
23
  # Probability float types
@@ -28,93 +26,86 @@ if TYPE_CHECKING:
28
26
  PydanticNonOneProbabilityFloat = float
29
27
  PydanticNonZeroProbabilityFloat = float
30
28
  else:
29
+ PydanticProbabilityFloat = Annotated[float, Field(ge=0.0, le=1.0)]
31
30
 
32
- class PydanticProbabilityFloat(pydantic.ConstrainedFloat):
33
- ge = 0.0
34
- le = 1.0
35
-
36
- class PydanticNonOneProbabilityFloat(pydantic.ConstrainedFloat):
37
- ge = 0.0
38
- lt = 1.0
31
+ PydanticNonOneProbabilityFloat = Annotated[float, Field(ge=0.0, lt=1.0)]
39
32
 
40
- class PydanticNonZeroProbabilityFloat(pydantic.ConstrainedFloat):
41
- gt = 0.0
42
- le = 1.0
33
+ PydanticNonZeroProbabilityFloat = Annotated[float, Field(gt=0.0, le=1.0)]
43
34
 
44
35
 
45
36
  # CVAR parameter types
46
37
  if TYPE_CHECKING:
47
38
  PydanticAlphaParamCVAR = float
48
39
  else:
49
-
50
- class PydanticAlphaParamCVAR(pydantic.ConstrainedFloat):
51
- gt = 0.0
52
- le = 1.0
40
+ PydanticAlphaParamCVAR = Annotated[float, Field(gt=0.0, le=1.0)]
53
41
 
54
42
 
55
43
  # General string types
56
44
  if TYPE_CHECKING:
57
45
  PydanticNonEmptyString = str
58
46
  else:
59
- PydanticNonEmptyString = pydantic.constr(min_length=1)
47
+ PydanticNonEmptyString = Annotated[str, Field(min_length=1)]
60
48
 
61
49
  # Name string types
62
50
  if TYPE_CHECKING:
63
51
  PydanticFunctionNameStr = str
64
52
  else:
65
- PydanticFunctionNameStr = pydantic.constr(
66
- strict=True, regex="^([A-Za-z][A-Za-z0-9_]*)$"
67
- )
53
+ PydanticFunctionNameStr = Annotated[
54
+ str, Field(strict=True, pattern="^([A-Za-z][A-Za-z0-9_]*)$")
55
+ ]
68
56
 
69
57
  if TYPE_CHECKING:
70
58
  PydanticPauliMonomial = tuple
71
59
  else:
72
- PydanticPauliMonomial = pydantic.conlist(item_type=Any, min_items=2, max_items=2)
60
+ PydanticPauliMonomial = Annotated[List[Any], Field(min_length=2, max_length=2)]
73
61
 
74
62
  if TYPE_CHECKING:
75
63
  PydanticPauliMonomialStr = str
76
64
  else:
77
- PydanticPauliMonomialStr = pydantic.constr(
78
- strict=True, strip_whitespace=True, min_length=1, regex="^[IXYZ]+$"
79
- )
65
+ PydanticPauliMonomialStr = Annotated[
66
+ StrictStr,
67
+ StringConstraints(strip_whitespace=True, min_length=1, pattern="^[IXYZ]+$"),
68
+ ]
80
69
 
81
- if TYPE_CHECKING:
82
- PydanticPauliList = List[Tuple[PydanticPauliMonomialStr, ParameterComplexType]]
83
- else:
84
- PydanticPauliList = pydantic.conlist(item_type=tuple, min_items=1)
70
+ PydanticPauliList = Annotated[
71
+ List[Tuple[PydanticPauliMonomialStr, ParameterComplexType]], Field(min_length=1)
72
+ ]
85
73
 
86
74
  if TYPE_CHECKING:
87
75
  PydanticFloatTuple = Tuple[float, float]
88
76
  else:
89
- PydanticFloatTuple = pydantic.conlist(item_type=float, min_items=2, max_items=2)
77
+ PydanticFloatTuple = Annotated[List[float], Field(min_length=2, max_length=2)]
90
78
 
91
- if TYPE_CHECKING:
92
- PydanticNonNegIntTuple = Tuple[pydantic.NonNegativeInt, pydantic.NonNegativeInt]
93
- else:
94
- PydanticNonNegIntTuple = pydantic.conlist(
95
- item_type=pydantic.NonNegativeInt, min_items=2, max_items=2
96
- )
79
+ PydanticNonNegIntTuple = Annotated[
80
+ List[pydantic.NonNegativeInt], Field(min_length=2, max_length=2)
81
+ ]
97
82
 
98
83
  if TYPE_CHECKING:
99
84
  PydanticExpressionStr = str
100
85
  else:
101
- PydanticExpressionStr = pydantic.constr(
102
- strip_whitespace=True, min_length=1, max_length=MAX_EXPRESSION_SIZE
103
- )
86
+ PydanticExpressionStr = Annotated[
87
+ str,
88
+ StringConstraints(
89
+ strip_whitespace=True, min_length=1, max_length=MAX_EXPRESSION_SIZE
90
+ ),
91
+ ]
104
92
  if TYPE_CHECKING:
105
93
  AtomType = Tuple[str, List[float]]
106
94
  else:
107
- AtomType = pydantic.conlist(item_type=Any, min_items=2, max_items=2)
95
+ AtomType = Annotated[List[Any], Field(min_length=2, max_length=2)]
108
96
 
109
97
 
110
98
  if TYPE_CHECKING:
111
99
  PydanticDataDogUuid = str
112
100
  else:
113
- PydanticDataDogUuid = pydantic.constr(
114
- regex=r"^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$"
115
- )
101
+ PydanticDataDogUuid = Annotated[
102
+ str,
103
+ Field(
104
+ pattern=r"^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$"
105
+ ),
106
+ ]
116
107
 
117
108
  if TYPE_CHECKING:
118
109
  PydanticDataDogGo = int
119
110
  else:
120
- PydanticDataDogGo = pydantic.conint(ge=0)
111
+ PydanticDataDogGo = Annotated[int, Field(ge=0)]
@@ -2,9 +2,10 @@ from typing import Any, Dict, Protocol, Sequence, TypeVar
2
2
 
3
3
 
4
4
  def values_with_discriminator(
5
- values: Dict[str, Any], discriminator: str, discriminator_value: Any
5
+ values: Any, discriminator: str, discriminator_value: Any
6
6
  ) -> Dict[str, Any]:
7
- values.setdefault(discriminator, discriminator_value)
7
+ if isinstance(values, dict):
8
+ values.setdefault(discriminator, discriminator_value)
8
9
  return values
9
10
 
10
11
 
@@ -1,10 +1,7 @@
1
1
  import pydantic
2
2
 
3
3
  from classiq.interface._version import VERSION
4
- from classiq.interface.helpers.custom_encoders import CUSTOM_ENCODERS
5
4
 
6
5
 
7
- class VersionedModel(
8
- pydantic.BaseModel, extra=pydantic.Extra.forbid, json_encoders=CUSTOM_ENCODERS
9
- ):
6
+ class VersionedModel(pydantic.BaseModel):
10
7
  version: str = pydantic.Field(default=VERSION)
@@ -13,8 +13,8 @@ Depth = int
13
13
 
14
14
  class IDEDataQubit(pydantic.BaseModel):
15
15
  id: int
16
- numChildren: Optional[int]
17
- name: Optional[str]
16
+ numChildren: Optional[int] = None
17
+ name: Optional[str] = None
18
18
 
19
19
 
20
20
  class IDEQubitDef(pydantic.BaseModel):
@@ -75,9 +75,9 @@ class IDEDataOperation(pydantic.BaseModel):
75
75
 
76
76
 
77
77
  class IDEDataProperties(pydantic.BaseModel):
78
- color: Optional[str]
79
- rightLabel: Optional[str]
80
- leftLabel: Optional[str]
78
+ color: Optional[str] = None
79
+ rightLabel: Optional[str] = None
80
+ leftLabel: Optional[str] = None
81
81
 
82
82
 
83
83
  class RegisterData(pydantic.BaseModel):